1
2
3
4
5 package lex
6
7 import (
8 "fmt"
9 "internal/buildcfg"
10 "os"
11 "path/filepath"
12 "strconv"
13 "strings"
14 "text/scanner"
15
16 "cmd/asm/internal/flags"
17 "cmd/internal/objabi"
18 "cmd/internal/src"
19 )
20
21
22
23
24 type Input struct {
25 Stack
26 includes []string
27 beginningOfLine bool
28 ifdefStack []bool
29 macros map[string]*Macro
30 text string
31 peek bool
32 peekToken ScanToken
33 peekText string
34 }
35
36
37 func NewInput(name string) *Input {
38 return &Input{
39
40 includes: append([]string{filepath.Dir(name)}, flags.I...),
41 beginningOfLine: true,
42 macros: predefine(flags.D),
43 }
44 }
45
46
47 func predefine(defines flags.MultiFlag) map[string]*Macro {
48 macros := make(map[string]*Macro)
49
50
51
52 if *flags.CompilingRuntime {
53 for _, exp := range buildcfg.EnabledExperiments() {
54
55 name := "GOEXPERIMENT_" + exp
56 macros[name] = &Macro{
57 name: name,
58 args: nil,
59 tokens: Tokenize("1"),
60 }
61 }
62 }
63
64 for _, name := range defines {
65 value := "1"
66 i := strings.IndexRune(name, '=')
67 if i > 0 {
68 name, value = name[:i], name[i+1:]
69 }
70 tokens := Tokenize(name)
71 if len(tokens) != 1 || tokens[0].ScanToken != scanner.Ident {
72 fmt.Fprintf(os.Stderr, "asm: parsing -D: %q is not a valid identifier name\n", tokens[0])
73 flags.Usage()
74 }
75 macros[name] = &Macro{
76 name: name,
77 args: nil,
78 tokens: Tokenize(value),
79 }
80 }
81 return macros
82 }
83
84 var panicOnError bool
85
86 func (in *Input) Error(args ...interface{}) {
87 if panicOnError {
88 panic(fmt.Errorf("%s:%d: %s", in.File(), in.Line(), fmt.Sprintln(args...)))
89 }
90 fmt.Fprintf(os.Stderr, "%s:%d: %s", in.File(), in.Line(), fmt.Sprintln(args...))
91 os.Exit(1)
92 }
93
94
95 func (in *Input) expectText(args ...interface{}) {
96 in.Error(append(args, "; got", strconv.Quote(in.Stack.Text()))...)
97 }
98
99
100 func (in *Input) enabled() bool {
101 return len(in.ifdefStack) == 0 || in.ifdefStack[len(in.ifdefStack)-1]
102 }
103
104 func (in *Input) expectNewline(directive string) {
105 tok := in.Stack.Next()
106 if tok != '\n' {
107 in.expectText("expected newline after", directive)
108 }
109 }
110
111 func (in *Input) Next() ScanToken {
112 if in.peek {
113 in.peek = false
114 tok := in.peekToken
115 in.text = in.peekText
116 return tok
117 }
118
119
120 for nesting := 0; nesting < 100; {
121 tok := in.Stack.Next()
122 switch tok {
123 case '#':
124 if !in.beginningOfLine {
125 in.Error("'#' must be first item on line")
126 }
127 in.beginningOfLine = in.hash()
128 in.text = "#"
129 return '#'
130
131 case scanner.Ident:
132
133 name := in.Stack.Text()
134 macro := in.macros[name]
135 if macro != nil {
136 nesting++
137 in.invokeMacro(macro)
138 continue
139 }
140 fallthrough
141 default:
142 if tok == scanner.EOF && len(in.ifdefStack) > 0 {
143
144 in.Error("unclosed #ifdef or #ifndef")
145 }
146 in.beginningOfLine = tok == '\n'
147 if in.enabled() {
148 in.text = in.Stack.Text()
149 return tok
150 }
151 }
152 }
153 in.Error("recursive macro invocation")
154 return 0
155 }
156
157 func (in *Input) Text() string {
158 return in.text
159 }
160
161
162 func (in *Input) hash() bool {
163
164 tok := in.Stack.Next()
165 if tok != scanner.Ident {
166 in.expectText("expected identifier after '#'")
167 }
168 if !in.enabled() {
169
170
171
172 switch in.Stack.Text() {
173 case "else", "endif", "ifdef", "ifndef", "line":
174
175 default:
176 return false
177 }
178 }
179 switch in.Stack.Text() {
180 case "define":
181 in.define()
182 case "else":
183 in.else_()
184 case "endif":
185 in.endif()
186 case "ifdef":
187 in.ifdef(true)
188 case "ifndef":
189 in.ifdef(false)
190 case "include":
191 in.include()
192 case "line":
193 in.line()
194 case "undef":
195 in.undef()
196 default:
197 in.Error("unexpected token after '#':", in.Stack.Text())
198 }
199 return true
200 }
201
202
203 func (in *Input) macroName() string {
204
205 tok := in.Stack.Next()
206 if tok != scanner.Ident {
207 in.expectText("expected identifier after # directive")
208 }
209
210 return in.Stack.Text()
211 }
212
213
214 func (in *Input) define() {
215 name := in.macroName()
216 args, tokens := in.macroDefinition(name)
217 in.defineMacro(name, args, tokens)
218 }
219
220
221 func (in *Input) defineMacro(name string, args []string, tokens []Token) {
222 if in.macros[name] != nil {
223 in.Error("redefinition of macro:", name)
224 }
225 in.macros[name] = &Macro{
226 name: name,
227 args: args,
228 tokens: tokens,
229 }
230 }
231
232
233
234
235 func (in *Input) macroDefinition(name string) ([]string, []Token) {
236 prevCol := in.Stack.Col()
237 tok := in.Stack.Next()
238 if tok == '\n' || tok == scanner.EOF {
239 return nil, nil
240 }
241 var args []string
242
243
244
245
246
247
248
249
250 if tok == '(' && in.Stack.Col() == prevCol+1 {
251
252 acceptArg := true
253 args = []string{}
254 Loop:
255 for {
256 tok = in.Stack.Next()
257 switch tok {
258 case ')':
259 tok = in.Stack.Next()
260 break Loop
261 case ',':
262 if acceptArg {
263 in.Error("bad syntax in definition for macro:", name)
264 }
265 acceptArg = true
266 case scanner.Ident:
267 if !acceptArg {
268 in.Error("bad syntax in definition for macro:", name)
269 }
270 arg := in.Stack.Text()
271 if i := lookup(args, arg); i >= 0 {
272 in.Error("duplicate argument", arg, "in definition for macro:", name)
273 }
274 args = append(args, arg)
275 acceptArg = false
276 default:
277 in.Error("bad definition for macro:", name)
278 }
279 }
280 }
281 var tokens []Token
282
283 for tok != '\n' {
284 if tok == scanner.EOF {
285 in.Error("missing newline in definition for macro:", name)
286 }
287 if tok == '\\' {
288 tok = in.Stack.Next()
289 if tok != '\n' && tok != '\\' {
290 in.Error(`can only escape \ or \n in definition for macro:`, name)
291 }
292 }
293 tokens = append(tokens, Make(tok, in.Stack.Text()))
294 tok = in.Stack.Next()
295 }
296 return args, tokens
297 }
298
299 func lookup(args []string, arg string) int {
300 for i, a := range args {
301 if a == arg {
302 return i
303 }
304 }
305 return -1
306 }
307
308
309
310
311 func (in *Input) invokeMacro(macro *Macro) {
312
313 if macro.args == nil {
314 in.Push(NewSlice(in.Base(), in.Line(), macro.tokens))
315 return
316 }
317 tok := in.Stack.Next()
318 if tok != '(' {
319
320
321 in.peekToken = tok
322 in.peekText = in.text
323 in.peek = true
324 in.Push(NewSlice(in.Base(), in.Line(), []Token{Make(macroName, macro.name)}))
325 return
326 }
327 actuals := in.argsFor(macro)
328 var tokens []Token
329 for _, tok := range macro.tokens {
330 if tok.ScanToken != scanner.Ident {
331 tokens = append(tokens, tok)
332 continue
333 }
334 substitution := actuals[tok.text]
335 if substitution == nil {
336 tokens = append(tokens, tok)
337 continue
338 }
339 tokens = append(tokens, substitution...)
340 }
341 in.Push(NewSlice(in.Base(), in.Line(), tokens))
342 }
343
344
345
346 func (in *Input) argsFor(macro *Macro) map[string][]Token {
347 var args [][]Token
348
349 for argNum := 0; ; argNum++ {
350 tokens, tok := in.collectArgument(macro)
351 args = append(args, tokens)
352 if tok == ')' {
353 break
354 }
355 }
356
357 if len(macro.args) == 0 && len(args) == 1 && args[0] == nil {
358 args = nil
359 } else if len(args) != len(macro.args) {
360 in.Error("wrong arg count for macro", macro.name)
361 }
362 argMap := make(map[string][]Token)
363 for i, arg := range args {
364 argMap[macro.args[i]] = arg
365 }
366 return argMap
367 }
368
369
370
371
372 func (in *Input) collectArgument(macro *Macro) ([]Token, ScanToken) {
373 nesting := 0
374 var tokens []Token
375 for {
376 tok := in.Stack.Next()
377 if tok == scanner.EOF || tok == '\n' {
378 in.Error("unterminated arg list invoking macro:", macro.name)
379 }
380 if nesting == 0 && (tok == ')' || tok == ',') {
381 return tokens, tok
382 }
383 if tok == '(' {
384 nesting++
385 }
386 if tok == ')' {
387 nesting--
388 }
389 tokens = append(tokens, Make(tok, in.Stack.Text()))
390 }
391 }
392
393
394 func (in *Input) ifdef(truth bool) {
395 name := in.macroName()
396 in.expectNewline("#if[n]def")
397 if !in.enabled() {
398 truth = false
399 } else if _, defined := in.macros[name]; !defined {
400 truth = !truth
401 }
402 in.ifdefStack = append(in.ifdefStack, truth)
403 }
404
405
406 func (in *Input) else_() {
407 in.expectNewline("#else")
408 if len(in.ifdefStack) == 0 {
409 in.Error("unmatched #else")
410 }
411 if len(in.ifdefStack) == 1 || in.ifdefStack[len(in.ifdefStack)-2] {
412 in.ifdefStack[len(in.ifdefStack)-1] = !in.ifdefStack[len(in.ifdefStack)-1]
413 }
414 }
415
416
417 func (in *Input) endif() {
418 in.expectNewline("#endif")
419 if len(in.ifdefStack) == 0 {
420 in.Error("unmatched #endif")
421 }
422 in.ifdefStack = in.ifdefStack[:len(in.ifdefStack)-1]
423 }
424
425
426 func (in *Input) include() {
427
428 tok := in.Stack.Next()
429 if tok != scanner.String {
430 in.expectText("expected string after #include")
431 }
432 name, err := strconv.Unquote(in.Stack.Text())
433 if err != nil {
434 in.Error("unquoting include file name: ", err)
435 }
436 in.expectNewline("#include")
437
438 fd, err := os.Open(name)
439 if err != nil {
440 for _, dir := range in.includes {
441 fd, err = os.Open(filepath.Join(dir, name))
442 if err == nil {
443 break
444 }
445 }
446 if err != nil {
447 in.Error("#include:", err)
448 }
449 }
450 in.Push(NewTokenizer(name, fd, fd))
451 }
452
453
454 func (in *Input) line() {
455
456 tok := in.Stack.Next()
457 if tok != scanner.Int {
458 in.expectText("expected line number after #line")
459 }
460 line, err := strconv.Atoi(in.Stack.Text())
461 if err != nil {
462 in.Error("error parsing #line (cannot happen):", err)
463 }
464 tok = in.Stack.Next()
465 if tok != scanner.String {
466 in.expectText("expected file name in #line")
467 }
468 file, err := strconv.Unquote(in.Stack.Text())
469 if err != nil {
470 in.Error("unquoting #line file name: ", err)
471 }
472 tok = in.Stack.Next()
473 if tok != '\n' {
474 in.Error("unexpected token at end of #line: ", tok)
475 }
476 pos := src.MakePos(in.Base(), uint(in.Line())+1, 1)
477 in.Stack.SetBase(src.NewLinePragmaBase(pos, file, objabi.AbsFile(objabi.WorkingDir(), file, *flags.TrimPath), uint(line), 1))
478 }
479
480
481 func (in *Input) undef() {
482 name := in.macroName()
483 if in.macros[name] == nil {
484 in.Error("#undef for undefined macro:", name)
485 }
486
487 tok := in.Stack.Next()
488 if tok != '\n' {
489 in.Error("syntax error in #undef for macro:", name)
490 }
491 delete(in.macros, name)
492 }
493
494 func (in *Input) Push(r TokenReader) {
495 if len(in.tr) > 100 {
496 in.Error("input recursion")
497 }
498 in.Stack.Push(r)
499 }
500
501 func (in *Input) Close() {
502 }
503
View as plain text