diff options
| author | Rob Pike <r@golang.org> | 2015-01-29 16:33:36 -0800 |
|---|---|---|
| committer | Rob Pike <r@golang.org> | 2015-01-30 16:38:25 +0000 |
| commit | d6eb21e331ba73d235b9014ce5b710d5e7bde545 (patch) | |
| tree | 0b09da696887a8ddbe07648f408c383703b22342 /src/cmd/asm/internal/lex/input.go | |
| parent | b528063099adfbaea3319ca8de57eee3130c5d4c (diff) | |
| download | go-d6eb21e331ba73d235b9014ce5b710d5e7bde545.tar.xz | |
[dev.cc] cmd/asm: rewrite the macro processor
The previous one was too broken, so just rewrite the code that invokes
a macro. Basically it was evaluating things too early, and mishandling
nested invocations. It's also easier to understand now.
Keep backslash-newline around in macro definitions. They get
processed when the body is evaluated.
Write some golden tests.
Change-Id: I27435f77f258a0873f80932bdc8d13ad39821ac1
Reviewed-on: https://go-review.googlesource.com/3550
Reviewed-by: Russ Cox <rsc@golang.org>
Diffstat (limited to 'src/cmd/asm/internal/lex/input.go')
| -rw-r--r-- | src/cmd/asm/internal/lex/input.go | 67 |
1 files changed, 39 insertions, 28 deletions
diff --git a/src/cmd/asm/internal/lex/input.go b/src/cmd/asm/internal/lex/input.go index a193649fee..529fd13f26 100644 --- a/src/cmd/asm/internal/lex/input.go +++ b/src/cmd/asm/internal/lex/input.go @@ -229,10 +229,6 @@ func (in *Input) macroDefinition(name string) ([]string, []Token) { if tok != '\n' && tok != '\\' { in.Error(`can only escape \ or \n in definition for macro:`, name) } - if tok == '\n' { // backslash-newline is discarded - tok = in.Stack.Next() - continue - } } tokens = append(tokens, Make(tok, in.Text())) tok = in.Stack.Next() @@ -279,34 +275,49 @@ func (in *Input) argsFor(macro *Macro) map[string][]Token { 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++ { + tokens, tok := in.collectArgument(macro) + args = append(args, tokens) + if tok == ')' { + break + } + } + // Zero-argument macros are tricky. + if len(macro.args) == 0 && len(args) == 1 && args[0] == nil { + args = nil + } else if len(args) != len(macro.args) { + in.Error("wrong arg count for macro", macro.name) + } + argMap := make(map[string][]Token) + for i, arg := range args { + argMap[macro.args[i]] = arg + } + return argMap +} + +// collectArgument returns the actual tokens for a single argument of a macro. +// It also returns the token that terminated the argument, which will always +// be either ',' or ')'. The starting '(' has been scanned. +func (in *Input) collectArgument(macro *Macro) ([]Token, ScanToken) { + nesting := 0 var tokens []Token - args := make(map[string][]Token) - argNum := 0 for { - tok = in.Stack.Next() - switch tok { - case scanner.EOF, '\n': + tok := in.Stack.Next() + if tok == scanner.EOF || tok == '\n' { in.Error("unterminated arg list invoking macro:", macro.name) - case ',', ')': - if argNum >= len(macro.args) { - in.Error("too many arguments for macro:", macro.name) - } - if len(macro.args) == 0 && argNum == 0 && len(tokens) == 0 { - // Zero-argument macro invoked with no arguments. - return args - } - args[macro.args[argNum]] = tokens - tokens = nil - argNum++ - if tok == ')' { - if argNum != len(macro.args) { - in.Error("too few arguments for macro:", macro.name) - } - return args - } - default: - tokens = append(tokens, Make(tok, in.Stack.Text())) } + if nesting == 0 && (tok == ')' || tok == ',') { + return tokens, tok + } + if tok == '(' { + nesting++ + } + if tok == ')' { + nesting-- + } + tokens = append(tokens, Make(tok, in.Stack.Text())) } } |
