]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/asm/internal/lex/input.go
aa03759c7d2908a7b4bf0eaf32cf7b07587cfd2b
[gostls13.git] / src / cmd / asm / internal / lex / input.go
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/objabi"
17         "cmd/internal/src"
18 )
19
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.
23 type Input struct {
24         Stack
25         includes        []string
26         beginningOfLine bool
27         ifdefStack      []bool
28         macros          map[string]*Macro
29         text            string // Text of last token returned by Next.
30         peek            bool
31         peekToken       ScanToken
32         peekText        string
33 }
34
35 // NewInput returns an Input from the given path.
36 func NewInput(name string) *Input {
37         return &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),
42         }
43 }
44
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)
48
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() {
53                         // Define macro.
54                         name := "GOEXPERIMENT_" + exp
55                         macros[name] = &Macro{
56                                 name:   name,
57                                 args:   nil,
58                                 tokens: Tokenize("1"),
59                         }
60                 }
61         }
62
63         for _, name := range defines {
64                 value := "1"
65                 i := strings.IndexRune(name, '=')
66                 if i > 0 {
67                         name, value = name[:i], name[i+1:]
68                 }
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])
72                         flags.Usage()
73                 }
74                 macros[name] = &Macro{
75                         name:   name,
76                         args:   nil,
77                         tokens: Tokenize(value),
78                 }
79         }
80         return macros
81 }
82
83 var panicOnError bool // For testing.
84
85 func (in *Input) Error(args ...interface{}) {
86         if panicOnError {
87                 panic(fmt.Errorf("%s:%d: %s", in.File(), in.Line(), fmt.Sprintln(args...)))
88         }
89         fmt.Fprintf(os.Stderr, "%s:%d: %s", in.File(), in.Line(), fmt.Sprintln(args...))
90         os.Exit(1)
91 }
92
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()))...)
96 }
97
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]
101 }
102
103 func (in *Input) expectNewline(directive string) {
104         tok := in.Stack.Next()
105         if tok != '\n' {
106                 in.expectText("expected newline after", directive)
107         }
108 }
109
110 func (in *Input) Next() ScanToken {
111         if in.peek {
112                 in.peek = false
113                 tok := in.peekToken
114                 in.text = in.peekText
115                 return tok
116         }
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()
121                 switch tok {
122                 case '#':
123                         if !in.beginningOfLine {
124                                 in.Error("'#' must be first item on line")
125                         }
126                         in.beginningOfLine = in.hash()
127                         in.text = "#"
128                         return '#'
129
130                 case scanner.Ident:
131                         // Is it a macro name?
132                         name := in.Stack.Text()
133                         macro := in.macros[name]
134                         if macro != nil {
135                                 nesting++
136                                 in.invokeMacro(macro)
137                                 continue
138                         }
139                         fallthrough
140                 default:
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")
144                         }
145                         in.beginningOfLine = tok == '\n'
146                         if in.enabled() {
147                                 in.text = in.Stack.Text()
148                                 return tok
149                         }
150                 }
151         }
152         in.Error("recursive macro invocation")
153         return 0
154 }
155
156 func (in *Input) Text() string {
157         return in.text
158 }
159
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 '#'")
166         }
167         if !in.enabled() {
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":
173                         // Press on.
174                 default:
175                         return false
176                 }
177         }
178         switch in.Stack.Text() {
179         case "define":
180                 in.define()
181         case "else":
182                 in.else_()
183         case "endif":
184                 in.endif()
185         case "ifdef":
186                 in.ifdef(true)
187         case "ifndef":
188                 in.ifdef(false)
189         case "include":
190                 in.include()
191         case "line":
192                 in.line()
193         case "undef":
194                 in.undef()
195         default:
196                 in.Error("unexpected token after '#':", in.Stack.Text())
197         }
198         return true
199 }
200
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")
207         }
208         // Name is alphanumeric by definition.
209         return in.Stack.Text()
210 }
211
212 // #define processing.
213 func (in *Input) define() {
214         name := in.macroName()
215         args, tokens := in.macroDefinition(name)
216         in.defineMacro(name, args, tokens)
217 }
218
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)
223         }
224         in.macros[name] = &Macro{
225                 name:   name,
226                 args:   args,
227                 tokens: tokens,
228         }
229 }
230
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
239         }
240         var args []string
241         // The C preprocessor treats
242         //      #define A(x)
243         // and
244         //      #define A (x)
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.
251                 acceptArg := true
252                 args = []string{} // Zero length but not nil.
253         Loop:
254                 for {
255                         tok = in.Stack.Next()
256                         switch tok {
257                         case ')':
258                                 tok = in.Stack.Next() // First token of macro definition.
259                                 break Loop
260                         case ',':
261                                 if acceptArg {
262                                         in.Error("bad syntax in definition for macro:", name)
263                                 }
264                                 acceptArg = true
265                         case scanner.Ident:
266                                 if !acceptArg {
267                                         in.Error("bad syntax in definition for macro:", name)
268                                 }
269                                 arg := in.Stack.Text()
270                                 if i := lookup(args, arg); i >= 0 {
271                                         in.Error("duplicate argument", arg, "in definition for macro:", name)
272                                 }
273                                 args = append(args, arg)
274                                 acceptArg = false
275                         default:
276                                 in.Error("bad definition for macro:", name)
277                         }
278                 }
279         }
280         var tokens []Token
281         // Scan to newline. Backslashes escape newlines.
282         for tok != '\n' {
283                 if tok == scanner.EOF {
284                         in.Error("missing newline in definition for macro:", name)
285                 }
286                 if tok == '\\' {
287                         tok = in.Stack.Next()
288                         if tok != '\n' && tok != '\\' {
289                                 in.Error(`can only escape \ or \n in definition for macro:`, name)
290                         }
291                 }
292                 tokens = append(tokens, Make(tok, in.Stack.Text()))
293                 tok = in.Stack.Next()
294         }
295         return args, tokens
296 }
297
298 func lookup(args []string, arg string) int {
299         for i, a := range args {
300                 if a == arg {
301                         return i
302                 }
303         }
304         return -1
305 }
306
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))
314                 return
315         }
316         tok := in.Stack.Next()
317         if tok != '(' {
318                 // If the macro has arguments but is invoked without them, all we push is the macro name.
319                 // First, put back the token.
320                 in.peekToken = tok
321                 in.peekText = in.text
322                 in.peek = true
323                 in.Push(NewSlice(in.Base(), in.Line(), []Token{Make(macroName, macro.name)}))
324                 return
325         }
326         actuals := in.argsFor(macro)
327         var tokens []Token
328         for _, tok := range macro.tokens {
329                 if tok.ScanToken != scanner.Ident {
330                         tokens = append(tokens, tok)
331                         continue
332                 }
333                 substitution := actuals[tok.text]
334                 if substitution == nil {
335                         tokens = append(tokens, tok)
336                         continue
337                 }
338                 tokens = append(tokens, substitution...)
339         }
340         in.Push(NewSlice(in.Base(), in.Line(), tokens))
341 }
342
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 {
346         var args [][]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)
351                 if tok == ')' {
352                         break
353                 }
354         }
355         // Zero-argument macros are tricky.
356         if len(macro.args) == 0 && len(args) == 1 && args[0] == nil {
357                 args = nil
358         } else if len(args) != len(macro.args) {
359                 in.Error("wrong arg count for macro", macro.name)
360         }
361         argMap := make(map[string][]Token)
362         for i, arg := range args {
363                 argMap[macro.args[i]] = arg
364         }
365         return argMap
366 }
367
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) {
372         nesting := 0
373         var tokens []Token
374         for {
375                 tok := in.Stack.Next()
376                 if tok == scanner.EOF || tok == '\n' {
377                         in.Error("unterminated arg list invoking macro:", macro.name)
378                 }
379                 if nesting == 0 && (tok == ')' || tok == ',') {
380                         return tokens, tok
381                 }
382                 if tok == '(' {
383                         nesting++
384                 }
385                 if tok == ')' {
386                         nesting--
387                 }
388                 tokens = append(tokens, Make(tok, in.Stack.Text()))
389         }
390 }
391
392 // #ifdef and #ifndef processing.
393 func (in *Input) ifdef(truth bool) {
394         name := in.macroName()
395         in.expectNewline("#if[n]def")
396         if !in.enabled() {
397                 truth = false
398         } else if _, defined := in.macros[name]; !defined {
399                 truth = !truth
400         }
401         in.ifdefStack = append(in.ifdefStack, truth)
402 }
403
404 // #else processing
405 func (in *Input) else_() {
406         in.expectNewline("#else")
407         if len(in.ifdefStack) == 0 {
408                 in.Error("unmatched #else")
409         }
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]
412         }
413 }
414
415 // #endif processing.
416 func (in *Input) endif() {
417         in.expectNewline("#endif")
418         if len(in.ifdefStack) == 0 {
419                 in.Error("unmatched #endif")
420         }
421         in.ifdefStack = in.ifdefStack[:len(in.ifdefStack)-1]
422 }
423
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")
430         }
431         name, err := strconv.Unquote(in.Stack.Text())
432         if err != nil {
433                 in.Error("unquoting include file name: ", err)
434         }
435         in.expectNewline("#include")
436         // Push tokenizer for file onto stack.
437         fd, err := os.Open(name)
438         if err != nil {
439                 for _, dir := range in.includes {
440                         fd, err = os.Open(filepath.Join(dir, name))
441                         if err == nil {
442                                 break
443                         }
444                 }
445                 if err != nil {
446                         in.Error("#include:", err)
447                 }
448         }
449         in.Push(NewTokenizer(name, fd, fd))
450 }
451
452 // #line processing.
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")
458         }
459         line, err := strconv.Atoi(in.Stack.Text())
460         if err != nil {
461                 in.Error("error parsing #line (cannot happen):", err)
462         }
463         tok = in.Stack.Next()
464         if tok != scanner.String {
465                 in.expectText("expected file name in #line")
466         }
467         file, err := strconv.Unquote(in.Stack.Text())
468         if err != nil {
469                 in.Error("unquoting #line file name: ", err)
470         }
471         tok = in.Stack.Next()
472         if tok != '\n' {
473                 in.Error("unexpected token at end of #line: ", tok)
474         }
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))
477 }
478
479 // #undef processing
480 func (in *Input) undef() {
481         name := in.macroName()
482         if in.macros[name] == nil {
483                 in.Error("#undef for undefined macro:", name)
484         }
485         // Newline must be next.
486         tok := in.Stack.Next()
487         if tok != '\n' {
488                 in.Error("syntax error in #undef for macro:", name)
489         }
490         delete(in.macros, name)
491 }
492
493 func (in *Input) Push(r TokenReader) {
494         if len(in.tr) > 100 {
495                 in.Error("input recursion")
496         }
497         in.Stack.Push(r)
498 }
499
500 func (in *Input) Close() {
501 }