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