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