mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
[dev.cc] cmd/asm: handle the case where a macro is named without arguments
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>
This commit is contained in:
parent
d6eb21e331
commit
5beec6a699
3 changed files with 53 additions and 19 deletions
|
|
@ -25,6 +25,10 @@ type Input struct {
|
||||||
beginningOfLine bool
|
beginningOfLine bool
|
||||||
ifdefStack []bool
|
ifdefStack []bool
|
||||||
macros map[string]*Macro
|
macros map[string]*Macro
|
||||||
|
text string // Text of last token returned by Next.
|
||||||
|
peek bool
|
||||||
|
peekToken ScanToken
|
||||||
|
peekText string
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewInput returns a
|
// 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.
|
// 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{}) {
|
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.
|
// 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 {
|
func (in *Input) Next() ScanToken {
|
||||||
|
if in.peek {
|
||||||
|
in.peek = false
|
||||||
|
tok := in.peekToken
|
||||||
|
in.text = in.peekText
|
||||||
|
return tok
|
||||||
|
}
|
||||||
for {
|
for {
|
||||||
tok := in.Stack.Next()
|
tok := in.Stack.Next()
|
||||||
switch tok {
|
switch tok {
|
||||||
|
|
@ -103,6 +113,7 @@ func (in *Input) Next() ScanToken {
|
||||||
default:
|
default:
|
||||||
in.beginningOfLine = tok == '\n'
|
in.beginningOfLine = tok == '\n'
|
||||||
if in.enabled() {
|
if in.enabled() {
|
||||||
|
in.text = in.Stack.Text()
|
||||||
return tok
|
return tok
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -111,6 +122,10 @@ func (in *Input) Next() ScanToken {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (in *Input) Text() string {
|
||||||
|
return in.text
|
||||||
|
}
|
||||||
|
|
||||||
// hash processes a # preprocessor directive. It returns true iff it completes.
|
// hash processes a # preprocessor directive. It returns true iff it completes.
|
||||||
func (in *Input) hash() bool {
|
func (in *Input) hash() bool {
|
||||||
// We have a '#'; it must be followed by a known word (define, include, etc.).
|
// 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() {
|
if !in.enabled() {
|
||||||
// Can only start including again if we are at #else or #endif.
|
// Can only start including again if we are at #else or #endif.
|
||||||
// We let #line through because it might affect errors.
|
// We let #line through because it might affect errors.
|
||||||
switch in.Text() {
|
switch in.Stack.Text() {
|
||||||
case "else", "endif", "line":
|
case "else", "endif", "line":
|
||||||
// Press on.
|
// Press on.
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch in.Text() {
|
switch in.Stack.Text() {
|
||||||
case "define":
|
case "define":
|
||||||
in.define()
|
in.define()
|
||||||
case "else":
|
case "else":
|
||||||
|
|
@ -146,7 +161,7 @@ func (in *Input) hash() bool {
|
||||||
case "undef":
|
case "undef":
|
||||||
in.undef()
|
in.undef()
|
||||||
default:
|
default:
|
||||||
in.Error("unexpected identifier after '#':", in.Text())
|
in.Error("unexpected token after '#':", in.Stack.Text())
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
@ -159,7 +174,7 @@ func (in *Input) macroName() string {
|
||||||
in.expectText("expected identifier after # directive")
|
in.expectText("expected identifier after # directive")
|
||||||
}
|
}
|
||||||
// Name is alphanumeric by definition.
|
// Name is alphanumeric by definition.
|
||||||
return in.Text()
|
return in.Stack.Text()
|
||||||
}
|
}
|
||||||
|
|
||||||
// #define processing.
|
// #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)
|
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()
|
tok = in.Stack.Next()
|
||||||
}
|
}
|
||||||
return args, tokens
|
return args, tokens
|
||||||
|
|
@ -249,6 +264,21 @@ func lookup(args []string, arg string) int {
|
||||||
// parameters substituted for the formals.
|
// parameters substituted for the formals.
|
||||||
// Invoking a macro does not touch the PC/line history.
|
// Invoking a macro does not touch the PC/line history.
|
||||||
func (in *Input) invokeMacro(macro *Macro) {
|
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)
|
actuals := in.argsFor(macro)
|
||||||
var tokens []Token
|
var tokens []Token
|
||||||
for _, tok := range macro.tokens {
|
for _, tok := range macro.tokens {
|
||||||
|
|
@ -266,15 +296,9 @@ func (in *Input) invokeMacro(macro *Macro) {
|
||||||
in.Push(NewSlice(in.File(), in.Line(), tokens))
|
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 {
|
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
|
var args [][]Token
|
||||||
// One macro argument per iteration. Collect them all and check counts afterwards.
|
// One macro argument per iteration. Collect them all and check counts afterwards.
|
||||||
for argNum := 0; ; argNum++ {
|
for argNum := 0; ; argNum++ {
|
||||||
|
|
@ -356,7 +380,7 @@ func (in *Input) include() {
|
||||||
if tok != scanner.String {
|
if tok != scanner.String {
|
||||||
in.expectText("expected string after #include")
|
in.expectText("expected string after #include")
|
||||||
}
|
}
|
||||||
name, err := strconv.Unquote(in.Text())
|
name, err := strconv.Unquote(in.Stack.Text())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
in.Error("unquoting include file name: ", err)
|
in.Error("unquoting include file name: ", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,10 +22,11 @@ type ScanToken rune
|
||||||
const (
|
const (
|
||||||
// Asm defines some two-character lexemes. We make up
|
// Asm defines some two-character lexemes. We make up
|
||||||
// a rune/ScanToken value for them - ugly but simple.
|
// a rune/ScanToken value for them - ugly but simple.
|
||||||
LSH ScanToken = -1000 - iota // << Left shift.
|
LSH ScanToken = -1000 - iota // << Left shift.
|
||||||
RSH // >> Logical right shift.
|
RSH // >> Logical right shift.
|
||||||
ARR // -> Used on ARM for shift type 3, arithmetic right shift.
|
ARR // -> Used on ARM for shift type 3, arithmetic right shift.
|
||||||
ROT // @> Used on ARM for shift type 4, rotate right.
|
ROT // @> Used on ARM for shift type 4, rotate right.
|
||||||
|
macroName // name of macro that should not be expanded
|
||||||
)
|
)
|
||||||
|
|
||||||
func (t ScanToken) String() string {
|
func (t ScanToken) String() string {
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,15 @@ var lexTests = []lexTest{
|
||||||
"#define A(x, y, z) x+z+y\n" + "A(1, 2, 3)\n",
|
"#define A(x, y, z) x+z+y\n" + "A(1, 2, 3)\n",
|
||||||
"1.+.3.+.2.\n",
|
"1.+.3.+.2.\n",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"argumented macro invoked without arguments",
|
||||||
|
lines(
|
||||||
|
"#define X() foo ",
|
||||||
|
"X()",
|
||||||
|
"X",
|
||||||
|
),
|
||||||
|
"foo.\n.X.\n",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"multiline macro without arguments",
|
"multiline macro without arguments",
|
||||||
lines(
|
lines(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue