github.com/zebozhuang/go@v0.0.0-20200207033046-f8a98f6f5c5d/src/cmd/asm/internal/lex/input.go (about)

     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.
     4  
     5  package lex
     6  
     7  import (
     8  	"fmt"
     9  	"os"
    10  	"path/filepath"
    11  	"strconv"
    12  	"strings"
    13  	"text/scanner"
    14  
    15  	"cmd/asm/internal/flags"
    16  	"cmd/internal/src"
    17  )
    18  
    19  // Input is the main input: a stack of readers and some macro definitions.
    20  // It also handles #include processing (by pushing onto the input stack)
    21  // and parses and instantiates macro definitions.
    22  type Input struct {
    23  	Stack
    24  	includes        []string
    25  	beginningOfLine bool
    26  	ifdefStack      []bool
    27  	macros          map[string]*Macro
    28  	text            string // Text of last token returned by Next.
    29  	peek            bool
    30  	peekToken       ScanToken
    31  	peekText        string
    32  }
    33  
    34  // NewInput returns an Input from the given path.
    35  func NewInput(name string) *Input {
    36  	return &Input{
    37  		// include directories: look in source dir, then -I directories.
    38  		includes:        append([]string{filepath.Dir(name)}, flags.I...),
    39  		beginningOfLine: true,
    40  		macros:          predefine(flags.D),
    41  	}
    42  }
    43  
    44  // predefine installs the macros set by the -D flag on the command line.
    45  func predefine(defines flags.MultiFlag) map[string]*Macro {
    46  	macros := make(map[string]*Macro)
    47  	for _, name := range defines {
    48  		value := "1"
    49  		i := strings.IndexRune(name, '=')
    50  		if i > 0 {
    51  			name, value = name[:i], name[i+1:]
    52  		}
    53  		tokens := Tokenize(name)
    54  		if len(tokens) != 1 || tokens[0].ScanToken != scanner.Ident {
    55  			fmt.Fprintf(os.Stderr, "asm: parsing -D: %q is not a valid identifier name\n", tokens[0])
    56  			flags.Usage()
    57  		}
    58  		macros[name] = &Macro{
    59  			name:   name,
    60  			args:   nil,
    61  			tokens: Tokenize(value),
    62  		}
    63  	}
    64  	return macros
    65  }
    66  
    67  var panicOnError bool // For testing.
    68  
    69  func (in *Input) Error(args ...interface{}) {
    70  	if panicOnError {
    71  		panic(fmt.Errorf("%s:%d: %s", in.File(), in.Line(), fmt.Sprintln(args...)))
    72  	}
    73  	fmt.Fprintf(os.Stderr, "%s:%d: %s", in.File(), in.Line(), fmt.Sprintln(args...))
    74  	os.Exit(1)
    75  }
    76  
    77  // expectText is like Error but adds "got XXX" where XXX is a quoted representation of the most recent token.
    78  func (in *Input) expectText(args ...interface{}) {
    79  	in.Error(append(args, "; got", strconv.Quote(in.Stack.Text()))...)
    80  }
    81  
    82  // enabled reports whether the input is enabled by an ifdef, or is at the top level.
    83  func (in *Input) enabled() bool {
    84  	return len(in.ifdefStack) == 0 || in.ifdefStack[len(in.ifdefStack)-1]
    85  }
    86  
    87  func (in *Input) expectNewline(directive string) {
    88  	tok := in.Stack.Next()
    89  	if tok != '\n' {
    90  		in.expectText("expected newline after", directive)
    91  	}
    92  }
    93  
    94  func (in *Input) Next() ScanToken {
    95  	if in.peek {
    96  		in.peek = false
    97  		tok := in.peekToken
    98  		in.text = in.peekText
    99  		return tok
   100  	}
   101  	// If we cannot generate a token after 100 macro invocations, we're in trouble.
   102  	// The usual case is caught by Push, below, but be safe.
   103  	for nesting := 0; nesting < 100; {
   104  		tok := in.Stack.Next()
   105  		switch tok {
   106  		case '#':
   107  			if !in.beginningOfLine {
   108  				in.Error("'#' must be first item on line")
   109  			}
   110  			in.beginningOfLine = in.hash()
   111  		case scanner.Ident:
   112  			// Is it a macro name?
   113  			name := in.Stack.Text()
   114  			macro := in.macros[name]
   115  			if macro != nil {
   116  				nesting++
   117  				in.invokeMacro(macro)
   118  				continue
   119  			}
   120  			fallthrough
   121  		default:
   122  			if tok == scanner.EOF && len(in.ifdefStack) > 0 {
   123  				// We're skipping text but have run out of input with no #endif.
   124  				in.Error("unclosed #ifdef or #ifndef")
   125  			}
   126  			in.beginningOfLine = tok == '\n'
   127  			if in.enabled() {
   128  				in.text = in.Stack.Text()
   129  				return tok
   130  			}
   131  		}
   132  	}
   133  	in.Error("recursive macro invocation")
   134  	return 0
   135  }
   136  
   137  func (in *Input) Text() string {
   138  	return in.text
   139  }
   140  
   141  // hash processes a # preprocessor directive. It returns true iff it completes.
   142  func (in *Input) hash() bool {
   143  	// We have a '#'; it must be followed by a known word (define, include, etc.).
   144  	tok := in.Stack.Next()
   145  	if tok != scanner.Ident {
   146  		in.expectText("expected identifier after '#'")
   147  	}
   148  	if !in.enabled() {
   149  		// Can only start including again if we are at #else or #endif but also
   150  		// need to keep track of nested #if[n]defs.
   151  		// We let #line through because it might affect errors.
   152  		switch in.Stack.Text() {
   153  		case "else", "endif", "ifdef", "ifndef", "line":
   154  			// Press on.
   155  		default:
   156  			return false
   157  		}
   158  	}
   159  	switch in.Stack.Text() {
   160  	case "define":
   161  		in.define()
   162  	case "else":
   163  		in.else_()
   164  	case "endif":
   165  		in.endif()
   166  	case "ifdef":
   167  		in.ifdef(true)
   168  	case "ifndef":
   169  		in.ifdef(false)
   170  	case "include":
   171  		in.include()
   172  	case "line":
   173  		in.line()
   174  	case "undef":
   175  		in.undef()
   176  	default:
   177  		in.Error("unexpected token after '#':", in.Stack.Text())
   178  	}
   179  	return true
   180  }
   181  
   182  // macroName returns the name for the macro being referenced.
   183  func (in *Input) macroName() string {
   184  	// We use the Stack's input method; no macro processing at this stage.
   185  	tok := in.Stack.Next()
   186  	if tok != scanner.Ident {
   187  		in.expectText("expected identifier after # directive")
   188  	}
   189  	// Name is alphanumeric by definition.
   190  	return in.Stack.Text()
   191  }
   192  
   193  // #define processing.
   194  func (in *Input) define() {
   195  	name := in.macroName()
   196  	args, tokens := in.macroDefinition(name)
   197  	in.defineMacro(name, args, tokens)
   198  }
   199  
   200  // defineMacro stores the macro definition in the Input.
   201  func (in *Input) defineMacro(name string, args []string, tokens []Token) {
   202  	if in.macros[name] != nil {
   203  		in.Error("redefinition of macro:", name)
   204  	}
   205  	in.macros[name] = &Macro{
   206  		name:   name,
   207  		args:   args,
   208  		tokens: tokens,
   209  	}
   210  }
   211  
   212  // macroDefinition returns the list of formals and the tokens of the definition.
   213  // The argument list is nil for no parens on the definition; otherwise a list of
   214  // formal argument names.
   215  func (in *Input) macroDefinition(name string) ([]string, []Token) {
   216  	prevCol := in.Stack.Col()
   217  	tok := in.Stack.Next()
   218  	if tok == '\n' || tok == scanner.EOF {
   219  		return nil, nil // No definition for macro
   220  	}
   221  	var args []string
   222  	// The C preprocessor treats
   223  	//	#define A(x)
   224  	// and
   225  	//	#define A (x)
   226  	// distinctly: the first is a macro with arguments, the second without.
   227  	// Distinguish these cases using the column number, since we don't
   228  	// see the space itself. Note that text/scanner reports the position at the
   229  	// end of the token. It's where you are now, and you just read this token.
   230  	if tok == '(' && in.Stack.Col() == prevCol+1 {
   231  		// Macro has arguments. Scan list of formals.
   232  		acceptArg := true
   233  		args = []string{} // Zero length but not nil.
   234  	Loop:
   235  		for {
   236  			tok = in.Stack.Next()
   237  			switch tok {
   238  			case ')':
   239  				tok = in.Stack.Next() // First token of macro definition.
   240  				break Loop
   241  			case ',':
   242  				if acceptArg {
   243  					in.Error("bad syntax in definition for macro:", name)
   244  				}
   245  				acceptArg = true
   246  			case scanner.Ident:
   247  				if !acceptArg {
   248  					in.Error("bad syntax in definition for macro:", name)
   249  				}
   250  				arg := in.Stack.Text()
   251  				if i := lookup(args, arg); i >= 0 {
   252  					in.Error("duplicate argument", arg, "in definition for macro:", name)
   253  				}
   254  				args = append(args, arg)
   255  				acceptArg = false
   256  			default:
   257  				in.Error("bad definition for macro:", name)
   258  			}
   259  		}
   260  	}
   261  	var tokens []Token
   262  	// Scan to newline. Backslashes escape newlines.
   263  	for tok != '\n' {
   264  		if tok == scanner.EOF {
   265  			in.Error("missing newline in definition for macro:", name)
   266  		}
   267  		if tok == '\\' {
   268  			tok = in.Stack.Next()
   269  			if tok != '\n' && tok != '\\' {
   270  				in.Error(`can only escape \ or \n in definition for macro:`, name)
   271  			}
   272  		}
   273  		tokens = append(tokens, Make(tok, in.Stack.Text()))
   274  		tok = in.Stack.Next()
   275  	}
   276  	return args, tokens
   277  }
   278  
   279  func lookup(args []string, arg string) int {
   280  	for i, a := range args {
   281  		if a == arg {
   282  			return i
   283  		}
   284  	}
   285  	return -1
   286  }
   287  
   288  // invokeMacro pushes onto the input Stack a Slice that holds the macro definition with the actual
   289  // parameters substituted for the formals.
   290  // Invoking a macro does not touch the PC/line history.
   291  func (in *Input) invokeMacro(macro *Macro) {
   292  	// If the macro has no arguments, just substitute the text.
   293  	if macro.args == nil {
   294  		in.Push(NewSlice(in.Base(), in.Line(), macro.tokens))
   295  		return
   296  	}
   297  	tok := in.Stack.Next()
   298  	if tok != '(' {
   299  		// If the macro has arguments but is invoked without them, all we push is the macro name.
   300  		// First, put back the token.
   301  		in.peekToken = tok
   302  		in.peekText = in.text
   303  		in.peek = true
   304  		in.Push(NewSlice(in.Base(), in.Line(), []Token{Make(macroName, macro.name)}))
   305  		return
   306  	}
   307  	actuals := in.argsFor(macro)
   308  	var tokens []Token
   309  	for _, tok := range macro.tokens {
   310  		if tok.ScanToken != scanner.Ident {
   311  			tokens = append(tokens, tok)
   312  			continue
   313  		}
   314  		substitution := actuals[tok.text]
   315  		if substitution == nil {
   316  			tokens = append(tokens, tok)
   317  			continue
   318  		}
   319  		tokens = append(tokens, substitution...)
   320  	}
   321  	in.Push(NewSlice(in.Base(), in.Line(), tokens))
   322  }
   323  
   324  // argsFor returns a map from formal name to actual value for this argumented macro invocation.
   325  // The opening parenthesis has been absorbed.
   326  func (in *Input) argsFor(macro *Macro) map[string][]Token {
   327  	var args [][]Token
   328  	// One macro argument per iteration. Collect them all and check counts afterwards.
   329  	for argNum := 0; ; argNum++ {
   330  		tokens, tok := in.collectArgument(macro)
   331  		args = append(args, tokens)
   332  		if tok == ')' {
   333  			break
   334  		}
   335  	}
   336  	// Zero-argument macros are tricky.
   337  	if len(macro.args) == 0 && len(args) == 1 && args[0] == nil {
   338  		args = nil
   339  	} else if len(args) != len(macro.args) {
   340  		in.Error("wrong arg count for macro", macro.name)
   341  	}
   342  	argMap := make(map[string][]Token)
   343  	for i, arg := range args {
   344  		argMap[macro.args[i]] = arg
   345  	}
   346  	return argMap
   347  }
   348  
   349  // collectArgument returns the actual tokens for a single argument of a macro.
   350  // It also returns the token that terminated the argument, which will always
   351  // be either ',' or ')'. The starting '(' has been scanned.
   352  func (in *Input) collectArgument(macro *Macro) ([]Token, ScanToken) {
   353  	nesting := 0
   354  	var tokens []Token
   355  	for {
   356  		tok := in.Stack.Next()
   357  		if tok == scanner.EOF || tok == '\n' {
   358  			in.Error("unterminated arg list invoking macro:", macro.name)
   359  		}
   360  		if nesting == 0 && (tok == ')' || tok == ',') {
   361  			return tokens, tok
   362  		}
   363  		if tok == '(' {
   364  			nesting++
   365  		}
   366  		if tok == ')' {
   367  			nesting--
   368  		}
   369  		tokens = append(tokens, Make(tok, in.Stack.Text()))
   370  	}
   371  }
   372  
   373  // #ifdef and #ifndef processing.
   374  func (in *Input) ifdef(truth bool) {
   375  	name := in.macroName()
   376  	in.expectNewline("#if[n]def")
   377  	if !in.enabled() {
   378  		truth = false
   379  	} else if _, defined := in.macros[name]; !defined {
   380  		truth = !truth
   381  	}
   382  	in.ifdefStack = append(in.ifdefStack, truth)
   383  }
   384  
   385  // #else processing
   386  func (in *Input) else_() {
   387  	in.expectNewline("#else")
   388  	if len(in.ifdefStack) == 0 {
   389  		in.Error("unmatched #else")
   390  	}
   391  	if len(in.ifdefStack) == 1 || in.ifdefStack[len(in.ifdefStack)-2] {
   392  		in.ifdefStack[len(in.ifdefStack)-1] = !in.ifdefStack[len(in.ifdefStack)-1]
   393  	}
   394  }
   395  
   396  // #endif processing.
   397  func (in *Input) endif() {
   398  	in.expectNewline("#endif")
   399  	if len(in.ifdefStack) == 0 {
   400  		in.Error("unmatched #endif")
   401  	}
   402  	in.ifdefStack = in.ifdefStack[:len(in.ifdefStack)-1]
   403  }
   404  
   405  // #include processing.
   406  func (in *Input) include() {
   407  	// Find and parse string.
   408  	tok := in.Stack.Next()
   409  	if tok != scanner.String {
   410  		in.expectText("expected string after #include")
   411  	}
   412  	name, err := strconv.Unquote(in.Stack.Text())
   413  	if err != nil {
   414  		in.Error("unquoting include file name: ", err)
   415  	}
   416  	in.expectNewline("#include")
   417  	// Push tokenizer for file onto stack.
   418  	fd, err := os.Open(name)
   419  	if err != nil {
   420  		for _, dir := range in.includes {
   421  			fd, err = os.Open(filepath.Join(dir, name))
   422  			if err == nil {
   423  				break
   424  			}
   425  		}
   426  		if err != nil {
   427  			in.Error("#include:", err)
   428  		}
   429  	}
   430  	in.Push(NewTokenizer(name, fd, fd))
   431  }
   432  
   433  // #line processing.
   434  func (in *Input) line() {
   435  	// Only need to handle Plan 9 format: #line 337 "filename"
   436  	tok := in.Stack.Next()
   437  	if tok != scanner.Int {
   438  		in.expectText("expected line number after #line")
   439  	}
   440  	line, err := strconv.Atoi(in.Stack.Text())
   441  	if err != nil {
   442  		in.Error("error parsing #line (cannot happen):", err)
   443  	}
   444  	tok = in.Stack.Next()
   445  	if tok != scanner.String {
   446  		in.expectText("expected file name in #line")
   447  	}
   448  	file, err := strconv.Unquote(in.Stack.Text())
   449  	if err != nil {
   450  		in.Error("unquoting #line file name: ", err)
   451  	}
   452  	tok = in.Stack.Next()
   453  	if tok != '\n' {
   454  		in.Error("unexpected token at end of #line: ", tok)
   455  	}
   456  	pos := src.MakePos(in.Base(), uint(in.Line()), uint(in.Col()))
   457  	in.Stack.SetBase(src.NewLinePragmaBase(pos, file, uint(line)))
   458  }
   459  
   460  // #undef processing
   461  func (in *Input) undef() {
   462  	name := in.macroName()
   463  	if in.macros[name] == nil {
   464  		in.Error("#undef for undefined macro:", name)
   465  	}
   466  	// Newline must be next.
   467  	tok := in.Stack.Next()
   468  	if tok != '\n' {
   469  		in.Error("syntax error in #undef for macro:", name)
   470  	}
   471  	delete(in.macros, name)
   472  }
   473  
   474  func (in *Input) Push(r TokenReader) {
   475  	if len(in.tr) > 100 {
   476  		in.Error("input recursion")
   477  	}
   478  	in.Stack.Push(r)
   479  }
   480  
   481  func (in *Input) Close() {
   482  }