]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.cc] cmd/asm: handle the case where a macro is named without arguments
authorRob Pike <r@golang.org>
Fri, 30 Jan 2015 17:57:11 +0000 (09:57 -0800)
committerRob Pike <r@golang.org>
Fri, 30 Jan 2015 21:19:49 +0000 (21:19 +0000)
Given
#define X() foo
X()
X
cpp produces
foo
X
Asm does now as well.

Change-Id: Ia36b88a23ce1660e6a02559c4f730593d62066f1
Reviewed-on: https://go-review.googlesource.com/3611
Reviewed-by: Russ Cox <rsc@golang.org>
src/cmd/asm/internal/lex/input.go
src/cmd/asm/internal/lex/lex.go
src/cmd/asm/internal/lex/lex_test.go

index 529fd13f262a4181421d5d4ddfe65509da6bf536..b3d86ca364b42f0779a906b15e03b314aba62d62 100644 (file)
@@ -25,6 +25,10 @@ type Input struct {
        beginningOfLine bool
        ifdefStack      []bool
        macros          map[string]*Macro
+       text            string // Text of last token returned by Next.
+       peek            bool
+       peekToken       ScanToken
+       peekText        string
 }
 
 // NewInput returns a
@@ -67,7 +71,7 @@ func (in *Input) Error(args ...interface{}) {
 
 // expectText is like Error but adds "got XXX" where XXX is a quoted representation of the most recent token.
 func (in *Input) expectText(args ...interface{}) {
-       in.Error(append(args, "; got", strconv.Quote(in.Text()))...)
+       in.Error(append(args, "; got", strconv.Quote(in.Stack.Text()))...)
 }
 
 // enabled reports whether the input is enabled by an ifdef, or is at the top level.
@@ -83,6 +87,12 @@ func (in *Input) expectNewline(directive string) {
 }
 
 func (in *Input) Next() ScanToken {
+       if in.peek {
+               in.peek = false
+               tok := in.peekToken
+               in.text = in.peekText
+               return tok
+       }
        for {
                tok := in.Stack.Next()
                switch tok {
@@ -103,6 +113,7 @@ func (in *Input) Next() ScanToken {
                default:
                        in.beginningOfLine = tok == '\n'
                        if in.enabled() {
+                               in.text = in.Stack.Text()
                                return tok
                        }
                }
@@ -111,6 +122,10 @@ func (in *Input) Next() ScanToken {
        return 0
 }
 
+func (in *Input) Text() string {
+       return in.text
+}
+
 // hash processes a # preprocessor directive. It returns true iff it completes.
 func (in *Input) hash() bool {
        // We have a '#'; it must be followed by a known word (define, include, etc.).
@@ -121,14 +136,14 @@ func (in *Input) hash() bool {
        if !in.enabled() {
                // Can only start including again if we are at #else or #endif.
                // We let #line through because it might affect errors.
-               switch in.Text() {
+               switch in.Stack.Text() {
                case "else", "endif", "line":
                        // Press on.
                default:
                        return false
                }
        }
-       switch in.Text() {
+       switch in.Stack.Text() {
        case "define":
                in.define()
        case "else":
@@ -146,7 +161,7 @@ func (in *Input) hash() bool {
        case "undef":
                in.undef()
        default:
-               in.Error("unexpected identifier after '#':", in.Text())
+               in.Error("unexpected token after '#':", in.Stack.Text())
        }
        return true
 }
@@ -159,7 +174,7 @@ func (in *Input) macroName() string {
                in.expectText("expected identifier after # directive")
        }
        // Name is alphanumeric by definition.
-       return in.Text()
+       return in.Stack.Text()
 }
 
 // #define processing.
@@ -230,7 +245,7 @@ func (in *Input) macroDefinition(name string) ([]string, []Token) {
                                in.Error(`can only escape \ or \n in definition for macro:`, name)
                        }
                }
-               tokens = append(tokens, Make(tok, in.Text()))
+               tokens = append(tokens, Make(tok, in.Stack.Text()))
                tok = in.Stack.Next()
        }
        return args, tokens
@@ -249,6 +264,21 @@ func lookup(args []string, arg string) int {
 // parameters substituted for the formals.
 // Invoking a macro does not touch the PC/line history.
 func (in *Input) invokeMacro(macro *Macro) {
+       // If the macro has no arguments, just substitute the text.
+       if macro.args == nil {
+               in.Push(NewSlice(in.File(), in.Line(), macro.tokens))
+               return
+       }
+       tok := in.Stack.Next()
+       if tok != '(' {
+               // If the macro has arguments but is invoked without them, all we push is the macro name.
+               // First, put back the token.
+               in.peekToken = tok
+               in.peekText = in.text
+               in.peek = true
+               in.Push(NewSlice(in.File(), in.Line(), []Token{Make(macroName, macro.name)}))
+               return
+       }
        actuals := in.argsFor(macro)
        var tokens []Token
        for _, tok := range macro.tokens {
@@ -266,15 +296,9 @@ func (in *Input) invokeMacro(macro *Macro) {
        in.Push(NewSlice(in.File(), in.Line(), tokens))
 }
 
-// argsFor returns a map from formal name to actual value for this macro invocation.
+// argsFor returns a map from formal name to actual value for this argumented macro invocation.
+// The opening parenthesis has been absorbed.
 func (in *Input) argsFor(macro *Macro) map[string][]Token {
-       if macro.args == nil {
-               return nil
-       }
-       tok := in.Stack.Next()
-       if tok != '(' {
-               in.Error("missing arguments for invocation of macro:", macro.name)
-       }
        var args [][]Token
        // One macro argument per iteration. Collect them all and check counts afterwards.
        for argNum := 0; ; argNum++ {
@@ -356,7 +380,7 @@ func (in *Input) include() {
        if tok != scanner.String {
                in.expectText("expected string after #include")
        }
-       name, err := strconv.Unquote(in.Text())
+       name, err := strconv.Unquote(in.Stack.Text())
        if err != nil {
                in.Error("unquoting include file name: ", err)
        }
index 45224fe1b38e6a8608e250a067dc8fd51d148cb1..b4b0a8c3040928e93dca5cf56fbda39fcdba5e33 100644 (file)
@@ -22,10 +22,11 @@ type ScanToken rune
 const (
        // Asm defines some two-character lexemes. We make up
        // a rune/ScanToken value for them - ugly but simple.
-       LSH ScanToken = -1000 - iota // << Left shift.
-       RSH                          // >> Logical right shift.
-       ARR                          // -> Used on ARM for shift type 3, arithmetic right shift.
-       ROT                          // @> Used on ARM for shift type 4, rotate right.
+       LSH       ScanToken = -1000 - iota // << Left shift.
+       RSH                                // >> Logical right shift.
+       ARR                                // -> Used on ARM for shift type 3, arithmetic right shift.
+       ROT                                // @> Used on ARM for shift type 4, rotate right.
+       macroName                          // name of macro that should not be expanded
 )
 
 func (t ScanToken) String() string {
index 7ac689fb762bd83c40d60649fb1025f27392c9e8..64f6784495b6c0d232a2b7b405136978b4d5d53b 100644 (file)
@@ -46,6 +46,15 @@ var lexTests = []lexTest{
                "#define A(x, y, z) x+z+y\n" + "A(1, 2, 3)\n",
                "1.+.3.+.2.\n",
        },
+       {
+               "argumented macro invoked without arguments",
+               lines(
+                       "#define X() foo ",
+                       "X()",
+                       "X",
+               ),
+               "foo.\n.X.\n",
+       },
        {
                "multiline macro without arguments",
                lines(