mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
[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>
This commit is contained in:
parent
b528063099
commit
d6eb21e331
4 changed files with 174 additions and 33 deletions
|
|
@ -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,35 +275,50 @@ func (in *Input) argsFor(macro *Macro) map[string][]Token {
|
|||
if tok != '(' {
|
||||
in.Error("missing arguments for invocation of macro:", macro.name)
|
||||
}
|
||||
var tokens []Token
|
||||
args := make(map[string][]Token)
|
||||
argNum := 0
|
||||
for {
|
||||
tok = in.Stack.Next()
|
||||
switch tok {
|
||||
case scanner.EOF, '\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()))
|
||||
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
|
||||
for {
|
||||
tok := in.Stack.Next()
|
||||
if tok == scanner.EOF || tok == '\n' {
|
||||
in.Error("unterminated arg list invoking macro:", macro.name)
|
||||
}
|
||||
if nesting == 0 && (tok == ')' || tok == ',') {
|
||||
return tokens, tok
|
||||
}
|
||||
if tok == '(' {
|
||||
nesting++
|
||||
}
|
||||
if tok == ')' {
|
||||
nesting--
|
||||
}
|
||||
tokens = append(tokens, Make(tok, in.Stack.Text()))
|
||||
}
|
||||
}
|
||||
|
||||
// #ifdef and #ifndef processing.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue