]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.cc] cmd/asm: fix macro definition bug in the lexer
authorRob Pike <r@golang.org>
Sat, 14 Feb 2015 00:55:33 +0000 (16:55 -0800)
committerRob Pike <r@golang.org>
Tue, 17 Feb 2015 03:37:01 +0000 (03:37 +0000)
Because text/scanner hides the spaces, the lexer treated
#define A(x)
and
#define A (x)
the same, but they are not: the first is an argument with macros, the
second is a simple one-word macro whose definition contains parentheses.
Fix this by noticing the relative column number as we move from A to (.
Hacky but simple.

Also add a helper to recognize the peculiar ARM shifted register operators.

Change-Id: I2cad22f5f1e11d8dad40ad13955793d178afb3ae
Reviewed-on: https://go-review.googlesource.com/4872
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
src/cmd/asm/internal/lex/slice.go
src/cmd/asm/internal/lex/stack.go
src/cmd/asm/internal/lex/tokenizer.go

index 8768b4f6484033cfbc915a8c0e5c633cde7b7857..737b12e134c19297128c05e47f7fd0ed6e2c67b9 100644 (file)
@@ -203,12 +203,21 @@ func (in *Input) defineMacro(name string, args []string, tokens []Token) {
 // The argument list is nil for no parens on the definition; otherwise a list of
 // formal argument names.
 func (in *Input) macroDefinition(name string) ([]string, []Token) {
+       prevCol := in.Stack.Col()
        tok := in.Stack.Next()
        if tok == '\n' || tok == scanner.EOF {
                in.Error("no definition for macro:", name)
        }
        var args []string
-       if tok == '(' {
+       // The C preprocessor treats
+       //      #define A(x)
+       // and
+       //      #define A (x)
+       // distinctly: the first is a macro with arguments, the second without.
+       // Distinguish these cases using the column number, since we don't
+       // see the space itself. Note that text/scanner reports the position at the
+       // end of the token. It's where you are now, and you just read this token.
+       if tok == '(' && in.Stack.Col() == prevCol+1 {
                // Macro has arguments. Scan list of formals.
                acceptArg := true
                args = []string{} // Zero length but not nil.
index 3bd832db86c12a153893e562adcb5848bcf0db92..c48b74a101cb68b36fbd1717082d543d1653157e 100644 (file)
@@ -29,6 +29,11 @@ const (
        macroName                          // name of macro that should not be expanded
 )
 
+// IsRegisterShift reports whether the token is one of the ARM register shift operators.
+func IsRegisterShift(r ScanToken) bool {
+       return ROT <= r && r <= LSH // Order looks backwards because these are negative.
+}
+
 func (t ScanToken) String() string {
        switch t {
        case scanner.EOF:
@@ -94,6 +99,8 @@ type TokenReader interface {
        File() string
        // Line reports the source line number of the token.
        Line() int
+       // Col reports the source column number of the token.
+       Col() int
        // SetPos sets the file and line number.
        SetPos(line int, file string)
        // Close does any teardown required.
index 64f6784495b6c0d232a2b7b405136978b4d5d53b..59e01c6699eba3242ececc2338c56bb8b7975a98 100644 (file)
@@ -41,6 +41,16 @@ var lexTests = []lexTest{
                "#define A() 1234\n" + "A()\n",
                "1234.\n",
        },
+       {
+               "macro with just parens as body",
+               "#define A () \n" + "A\n",
+               "(.).\n",
+       },
+       {
+               "macro with parens but no arguments",
+               "#define A (x) \n" + "A\n",
+               "(.x.).\n",
+       },
        {
                "macro with arguments",
                "#define A(x, y, z) x+z+y\n" + "A(1, 2, 3)\n",
index 6ac72f469e45ad361d4c682fbb7ff3699270a7fe..e94106b0af5a34a196ce4aa7078368d83b0c253d 100644 (file)
@@ -43,6 +43,11 @@ func (s *Slice) Line() int {
        return s.line
 }
 
+func (s *Slice) Col() int {
+       // Col is only called when defining a macro, which can't reach here.
+       panic("cannot happen: slice col")
+}
+
 func (s *Slice) SetPos(line int, file string) {
        // Cannot happen because we only have slices of already-scanned
        // text, but be prepared.
index 9766af51de36aeea33105df3ff88edc4117d4d83..72d7f8a165f28c991cac858bc9f99381d2c31008 100644 (file)
@@ -41,6 +41,10 @@ func (s *Stack) Line() int {
        return s.tr[len(s.tr)-1].Line()
 }
 
+func (s *Stack) Col() int {
+       return s.tr[len(s.tr)-1].Col()
+}
+
 func (s *Stack) SetPos(line int, file string) {
        s.tr[len(s.tr)-1].SetPos(line, file)
 }
index 24a72479db54eec985cfbf4b5aafa56f828367b1..28a4b852534d440d2f211cbe6b8d7eb9c779bfed 100644 (file)
@@ -89,6 +89,10 @@ func (t *Tokenizer) Line() int {
        return t.line
 }
 
+func (t *Tokenizer) Col() int {
+       return t.s.Pos().Column
+}
+
 func (t *Tokenizer) SetPos(line int, file string) {
        t.line = line
        t.fileName = file