aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/asm/internal/lex/input.go
diff options
context:
space:
mode:
authorRob Pike <r@golang.org>2015-01-29 16:33:36 -0800
committerRob Pike <r@golang.org>2015-01-30 16:38:25 +0000
commitd6eb21e331ba73d235b9014ce5b710d5e7bde545 (patch)
tree0b09da696887a8ddbe07648f408c383703b22342 /src/cmd/asm/internal/lex/input.go
parentb528063099adfbaea3319ca8de57eee3130c5d4c (diff)
downloadgo-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.go67
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()))
}
}