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