1 // Copyright 2015 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
15 "cmd/asm/internal/flags"
20 // Input is the main input: a stack of readers and some macro definitions.
21 // It also handles #include processing (by pushing onto the input stack)
22 // and parses and instantiates macro definitions.
28 macros map[string]*Macro
29 text string // Text of last token returned by Next.
35 // NewInput returns an Input from the given path.
36 func NewInput(name string) *Input {
38 // include directories: look in source dir, then -I directories.
39 includes: append([]string{filepath.Dir(name)}, flags.I...),
40 beginningOfLine: true,
41 macros: predefine(flags.D),
45 // predefine installs the macros set by the -D flag on the command line.
46 func predefine(defines flags.MultiFlag) map[string]*Macro {
47 macros := make(map[string]*Macro)
49 // Set macros for GOEXPERIMENTs so we can easily switch
50 // runtime assembly code based on them.
51 if *flags.CompilingRuntime {
52 for _, exp := range objabi.EnabledExperiments() {
54 name := "GOEXPERIMENT_" + exp
55 macros[name] = &Macro{
58 tokens: Tokenize("1"),
63 for _, name := range defines {
65 i := strings.IndexRune(name, '=')
67 name, value = name[:i], name[i+1:]
69 tokens := Tokenize(name)
70 if len(tokens) != 1 || tokens[0].ScanToken != scanner.Ident {
71 fmt.Fprintf(os.Stderr, "asm: parsing -D: %q is not a valid identifier name\n", tokens[0])
74 macros[name] = &Macro{
77 tokens: Tokenize(value),
83 var panicOnError bool // For testing.
85 func (in *Input) Error(args ...interface{}) {
87 panic(fmt.Errorf("%s:%d: %s", in.File(), in.Line(), fmt.Sprintln(args...)))
89 fmt.Fprintf(os.Stderr, "%s:%d: %s", in.File(), in.Line(), fmt.Sprintln(args...))
93 // expectText is like Error but adds "got XXX" where XXX is a quoted representation of the most recent token.
94 func (in *Input) expectText(args ...interface{}) {
95 in.Error(append(args, "; got", strconv.Quote(in.Stack.Text()))...)
98 // enabled reports whether the input is enabled by an ifdef, or is at the top level.
99 func (in *Input) enabled() bool {
100 return len(in.ifdefStack) == 0 || in.ifdefStack[len(in.ifdefStack)-1]
103 func (in *Input) expectNewline(directive string) {
104 tok := in.Stack.Next()
106 in.expectText("expected newline after", directive)
110 func (in *Input) Next() ScanToken {
114 in.text = in.peekText
117 // If we cannot generate a token after 100 macro invocations, we're in trouble.
118 // The usual case is caught by Push, below, but be safe.
119 for nesting := 0; nesting < 100; {
120 tok := in.Stack.Next()
123 if !in.beginningOfLine {
124 in.Error("'#' must be first item on line")
126 in.beginningOfLine = in.hash()
131 // Is it a macro name?
132 name := in.Stack.Text()
133 macro := in.macros[name]
136 in.invokeMacro(macro)
141 if tok == scanner.EOF && len(in.ifdefStack) > 0 {
142 // We're skipping text but have run out of input with no #endif.
143 in.Error("unclosed #ifdef or #ifndef")
145 in.beginningOfLine = tok == '\n'
147 in.text = in.Stack.Text()
152 in.Error("recursive macro invocation")
156 func (in *Input) Text() string {
160 // hash processes a # preprocessor directive. It reports whether it completes.
161 func (in *Input) hash() bool {
162 // We have a '#'; it must be followed by a known word (define, include, etc.).
163 tok := in.Stack.Next()
164 if tok != scanner.Ident {
165 in.expectText("expected identifier after '#'")
168 // Can only start including again if we are at #else or #endif but also
169 // need to keep track of nested #if[n]defs.
170 // We let #line through because it might affect errors.
171 switch in.Stack.Text() {
172 case "else", "endif", "ifdef", "ifndef", "line":
178 switch in.Stack.Text() {
196 in.Error("unexpected token after '#':", in.Stack.Text())
201 // macroName returns the name for the macro being referenced.
202 func (in *Input) macroName() string {
203 // We use the Stack's input method; no macro processing at this stage.
204 tok := in.Stack.Next()
205 if tok != scanner.Ident {
206 in.expectText("expected identifier after # directive")
208 // Name is alphanumeric by definition.
209 return in.Stack.Text()
212 // #define processing.
213 func (in *Input) define() {
214 name := in.macroName()
215 args, tokens := in.macroDefinition(name)
216 in.defineMacro(name, args, tokens)
219 // defineMacro stores the macro definition in the Input.
220 func (in *Input) defineMacro(name string, args []string, tokens []Token) {
221 if in.macros[name] != nil {
222 in.Error("redefinition of macro:", name)
224 in.macros[name] = &Macro{
231 // macroDefinition returns the list of formals and the tokens of the definition.
232 // The argument list is nil for no parens on the definition; otherwise a list of
233 // formal argument names.
234 func (in *Input) macroDefinition(name string) ([]string, []Token) {
235 prevCol := in.Stack.Col()
236 tok := in.Stack.Next()
237 if tok == '\n' || tok == scanner.EOF {
238 return nil, nil // No definition for macro
241 // The C preprocessor treats
245 // distinctly: the first is a macro with arguments, the second without.
246 // Distinguish these cases using the column number, since we don't
247 // see the space itself. Note that text/scanner reports the position at the
248 // end of the token. It's where you are now, and you just read this token.
249 if tok == '(' && in.Stack.Col() == prevCol+1 {
250 // Macro has arguments. Scan list of formals.
252 args = []string{} // Zero length but not nil.
255 tok = in.Stack.Next()
258 tok = in.Stack.Next() // First token of macro definition.
262 in.Error("bad syntax in definition for macro:", name)
267 in.Error("bad syntax in definition for macro:", name)
269 arg := in.Stack.Text()
270 if i := lookup(args, arg); i >= 0 {
271 in.Error("duplicate argument", arg, "in definition for macro:", name)
273 args = append(args, arg)
276 in.Error("bad definition for macro:", name)
281 // Scan to newline. Backslashes escape newlines.
283 if tok == scanner.EOF {
284 in.Error("missing newline in definition for macro:", name)
287 tok = in.Stack.Next()
288 if tok != '\n' && tok != '\\' {
289 in.Error(`can only escape \ or \n in definition for macro:`, name)
292 tokens = append(tokens, Make(tok, in.Stack.Text()))
293 tok = in.Stack.Next()
298 func lookup(args []string, arg string) int {
299 for i, a := range args {
307 // invokeMacro pushes onto the input Stack a Slice that holds the macro definition with the actual
308 // parameters substituted for the formals.
309 // Invoking a macro does not touch the PC/line history.
310 func (in *Input) invokeMacro(macro *Macro) {
311 // If the macro has no arguments, just substitute the text.
312 if macro.args == nil {
313 in.Push(NewSlice(in.Base(), in.Line(), macro.tokens))
316 tok := in.Stack.Next()
318 // If the macro has arguments but is invoked without them, all we push is the macro name.
319 // First, put back the token.
321 in.peekText = in.text
323 in.Push(NewSlice(in.Base(), in.Line(), []Token{Make(macroName, macro.name)}))
326 actuals := in.argsFor(macro)
328 for _, tok := range macro.tokens {
329 if tok.ScanToken != scanner.Ident {
330 tokens = append(tokens, tok)
333 substitution := actuals[tok.text]
334 if substitution == nil {
335 tokens = append(tokens, tok)
338 tokens = append(tokens, substitution...)
340 in.Push(NewSlice(in.Base(), in.Line(), tokens))
343 // argsFor returns a map from formal name to actual value for this argumented macro invocation.
344 // The opening parenthesis has been absorbed.
345 func (in *Input) argsFor(macro *Macro) map[string][]Token {
347 // One macro argument per iteration. Collect them all and check counts afterwards.
348 for argNum := 0; ; argNum++ {
349 tokens, tok := in.collectArgument(macro)
350 args = append(args, tokens)
355 // Zero-argument macros are tricky.
356 if len(macro.args) == 0 && len(args) == 1 && args[0] == nil {
358 } else if len(args) != len(macro.args) {
359 in.Error("wrong arg count for macro", macro.name)
361 argMap := make(map[string][]Token)
362 for i, arg := range args {
363 argMap[macro.args[i]] = arg
368 // collectArgument returns the actual tokens for a single argument of a macro.
369 // It also returns the token that terminated the argument, which will always
370 // be either ',' or ')'. The starting '(' has been scanned.
371 func (in *Input) collectArgument(macro *Macro) ([]Token, ScanToken) {
375 tok := in.Stack.Next()
376 if tok == scanner.EOF || tok == '\n' {
377 in.Error("unterminated arg list invoking macro:", macro.name)
379 if nesting == 0 && (tok == ')' || tok == ',') {
388 tokens = append(tokens, Make(tok, in.Stack.Text()))
392 // #ifdef and #ifndef processing.
393 func (in *Input) ifdef(truth bool) {
394 name := in.macroName()
395 in.expectNewline("#if[n]def")
398 } else if _, defined := in.macros[name]; !defined {
401 in.ifdefStack = append(in.ifdefStack, truth)
405 func (in *Input) else_() {
406 in.expectNewline("#else")
407 if len(in.ifdefStack) == 0 {
408 in.Error("unmatched #else")
410 if len(in.ifdefStack) == 1 || in.ifdefStack[len(in.ifdefStack)-2] {
411 in.ifdefStack[len(in.ifdefStack)-1] = !in.ifdefStack[len(in.ifdefStack)-1]
415 // #endif processing.
416 func (in *Input) endif() {
417 in.expectNewline("#endif")
418 if len(in.ifdefStack) == 0 {
419 in.Error("unmatched #endif")
421 in.ifdefStack = in.ifdefStack[:len(in.ifdefStack)-1]
424 // #include processing.
425 func (in *Input) include() {
426 // Find and parse string.
427 tok := in.Stack.Next()
428 if tok != scanner.String {
429 in.expectText("expected string after #include")
431 name, err := strconv.Unquote(in.Stack.Text())
433 in.Error("unquoting include file name: ", err)
435 in.expectNewline("#include")
436 // Push tokenizer for file onto stack.
437 fd, err := os.Open(name)
439 for _, dir := range in.includes {
440 fd, err = os.Open(filepath.Join(dir, name))
446 in.Error("#include:", err)
449 in.Push(NewTokenizer(name, fd, fd))
453 func (in *Input) line() {
454 // Only need to handle Plan 9 format: #line 337 "filename"
455 tok := in.Stack.Next()
456 if tok != scanner.Int {
457 in.expectText("expected line number after #line")
459 line, err := strconv.Atoi(in.Stack.Text())
461 in.Error("error parsing #line (cannot happen):", err)
463 tok = in.Stack.Next()
464 if tok != scanner.String {
465 in.expectText("expected file name in #line")
467 file, err := strconv.Unquote(in.Stack.Text())
469 in.Error("unquoting #line file name: ", err)
471 tok = in.Stack.Next()
473 in.Error("unexpected token at end of #line: ", tok)
475 pos := src.MakePos(in.Base(), uint(in.Line())+1, 1) // +1 because #line nnn means line nnn starts on next line
476 in.Stack.SetBase(src.NewLinePragmaBase(pos, file, objabi.AbsFile(objabi.WorkingDir(), file, *flags.TrimPath), uint(line), 1))
480 func (in *Input) undef() {
481 name := in.macroName()
482 if in.macros[name] == nil {
483 in.Error("#undef for undefined macro:", name)
485 // Newline must be next.
486 tok := in.Stack.Next()
488 in.Error("syntax error in #undef for macro:", name)
490 delete(in.macros, name)
493 func (in *Input) Push(r TokenReader) {
494 if len(in.tr) > 100 {
495 in.Error("input recursion")
500 func (in *Input) Close() {