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