source: code/trunk/vendor/modernc.org/cc/v3/cpp.go@ 822

Last change on this file since 822 was 822, checked in by yakumo.izuru, 22 months ago

Prefer immortal.run over runit and rc.d, use vendored modules
for convenience.

Signed-off-by: Izuru Yakumo <yakumo.izuru@…>

File size: 68.1 KB
Line 
1// Copyright 2019 The CC 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
5package cc // import "modernc.org/cc/v3"
6
7import (
8 "bytes"
9 "fmt"
10 gotoken "go/token"
11 "math"
12 "os"
13 "path/filepath"
14 "strconv"
15 "strings"
16 "sync"
17 "time"
18 "unicode/utf8"
19
20 "modernc.org/token"
21)
22
23const (
24 maxIncludeLevel = 200 // gcc, std is at least 15.
25)
26
27var (
28 _ tokenReader = (*cpp)(nil)
29 _ tokenWriter = (*cpp)(nil)
30
31 idCOUNTER = dict.sid("__COUNTER__")
32 idCxLimitedRange = dict.sid("CX_LIMITED_RANGE")
33 idDATE = dict.sid("__DATE__")
34 idDefault = dict.sid("DEFAULT")
35 idDefined = dict.sid("defined")
36 idEmptyString = dict.sid(`""`)
37 idFILE = dict.sid("__FILE__")
38 idFPContract = dict.sid("FP_CONTRACT")
39 idFdZero = dict.sid("FD_ZERO")
40 idFenvAccess = dict.sid("FENV_ACCESS")
41 idGNUC = dict.sid("__GNUC__")
42 idHasIncludeImpl = dict.sid("__has_include_impl")
43 idIntMaxWidth = dict.sid("__INTMAX_WIDTH__")
44 idL = dict.sid("L")
45 idLINE = dict.sid("__LINE__")
46 idNL = dict.sid("\n")
47 idOff = dict.sid("OFF")
48 idOn = dict.sid("ON")
49 idOne = dict.sid("1")
50 idPragmaSTDC = dict.sid("__pragma_stdc")
51 idSTDC = dict.sid("STDC")
52 idTIME = dict.sid("__TIME__")
53 idTclDefaultDoubleRounding = dict.sid("TCL_DEFAULT_DOUBLE_ROUNDING")
54 idTclIeeeDoubleRounding = dict.sid("TCL_IEEE_DOUBLE_ROUNDING")
55 idVaArgs = dict.sid("__VA_ARGS__")
56 idZero = dict.sid("0")
57
58 cppTokensPool = sync.Pool{New: func() interface{} { r := []cppToken{}; return &r }}
59
60 protectedMacros = hideSet{ // [0], 6.10.8, 4
61 dict.sid("__STDC_HOSTED__"): {},
62 dict.sid("__STDC_IEC_559_COMPLEX__"): {},
63 dict.sid("__STDC_IEC_559__"): {},
64 dict.sid("__STDC_ISO_10646__"): {},
65 dict.sid("__STDC_MB_MIGHT_NEQ_WC__"): {},
66 dict.sid("__STDC_VERSION__"): {},
67 dict.sid("__STDC__"): {},
68 idCOUNTER: {},
69 idDATE: {},
70 idFILE: {},
71 idLINE: {},
72 idTIME: {},
73 }
74)
75
76type tokenReader interface {
77 read() (cppToken, bool)
78 unget(cppToken)
79 ungets([]cppToken)
80}
81
82type tokenWriter interface {
83 write(cppToken)
84 writes([]cppToken)
85}
86
87// token4 is produced by translation phase 4.
88type token4 struct {
89 file *tokenFile //TODO sort fields
90 token3
91}
92
93func (t *token4) Position() (r token.Position) {
94 if t.pos != 0 && t.file != nil {
95 r = t.file.PositionFor(token.Pos(t.pos), true)
96 }
97 return r
98}
99
100type hideSet map[StringID]struct{}
101
102type cppToken struct {
103 token4
104 hs hideSet
105}
106
107func (t *cppToken) has(nm StringID) bool { _, ok := t.hs[nm]; return ok }
108
109type cppWriter struct {
110 toks []cppToken
111}
112
113func (w *cppWriter) write(tok cppToken) { w.toks = append(w.toks, tok) }
114func (w *cppWriter) writes(toks []cppToken) { w.toks = append(w.toks, toks...) }
115
116type ungetBuf []cppToken
117
118func (u *ungetBuf) unget(t cppToken) { *u = append(*u, t) }
119
120func (u *ungetBuf) read() (t cppToken) {
121 s := *u
122 n := len(s) - 1
123 t = s[n]
124 *u = s[:n]
125 return t
126}
127func (u *ungetBuf) ungets(toks []cppToken) {
128 s := *u
129 for i := len(toks) - 1; i >= 0; i-- {
130 s = append(s, toks[i])
131 }
132 *u = s
133}
134
135func cppToksStr(toks []cppToken, sep string) string {
136 var b strings.Builder
137 for i, v := range toks {
138 if i != 0 {
139 b.WriteString(sep)
140 }
141 b.WriteString(v.String())
142 }
143 return b.String()
144}
145
146func cppToksStr2(toks [][]cppToken) string {
147 panic(todo(""))
148 var a []string
149 for _, v := range toks {
150 a = append(a, fmt.Sprintf("%q", cppToksStr(v, "|")))
151 }
152 return fmt.Sprint(a)
153}
154
155type cppReader struct {
156 buf []cppToken
157 ungetBuf
158}
159
160func (r *cppReader) read() (tok cppToken, ok bool) {
161 if len(r.ungetBuf) != 0 {
162 return r.ungetBuf.read(), true
163 }
164
165 if len(r.buf) == 0 {
166 return tok, false
167 }
168
169 tok = r.buf[0]
170 r.buf = r.buf[1:]
171 return tok, true
172}
173
174type cppScanner []cppToken
175
176func (s *cppScanner) peek() (r cppToken) {
177 r.char = -1
178 if len(*s) == 0 {
179 return r
180 }
181
182 return (*s)[0]
183}
184
185func (s *cppScanner) next() (r cppToken) {
186 r.char = -1
187 if len(*s) == 0 {
188 return r
189 }
190
191 *s = (*s)[1:]
192 return s.peek()
193}
194
195func (s *cppScanner) Pos() token.Pos {
196 if len(*s) == 0 {
197 return 0
198 }
199
200 return (*s)[0].Pos()
201}
202
203// Macro represents a preprocessor macro definition.
204type Macro struct {
205 fp []StringID
206 repl []token3
207 repl2 []Token
208
209 name token4
210 pos int32
211
212 isFnLike bool
213 namedVariadic bool // foo..., note no comma before ellipsis.
214 variadic bool
215}
216
217// Position reports the position of the macro definition.
218func (m *Macro) Position() token.Position {
219 if m.pos != 0 && m.name.file != nil {
220 return m.name.file.PositionFor(token.Pos(m.pos), true)
221 }
222 return token.Position{}
223}
224
225// Parameters return the list of function-like macro parameters.
226func (m *Macro) Parameters() []StringID { return m.fp }
227
228// ReplacementTokens return the list of tokens m is replaced with. Tokens in
229// the returned list have only the Rune and Value fields valid.
230func (m *Macro) ReplacementTokens() []Token {
231 if m.repl2 != nil {
232 return m.repl2
233 }
234
235 m.repl2 = make([]Token, len(m.repl))
236 for i, v := range m.repl {
237 m.repl2[i] = Token{Rune: v.char, Value: v.value, Src: v.src}
238 }
239 return m.repl2
240}
241
242// IsFnLike reports whether m is a function-like macro.
243func (m *Macro) IsFnLike() bool { return m.isFnLike }
244
245func (m *Macro) isNamedVariadicParam(nm StringID) bool {
246 return m.namedVariadic && nm == m.fp[len(m.fp)-1]
247}
248
249func (m *Macro) param2(varArgs []cppToken, ap [][]cppToken, nm StringID, out *[]cppToken, argIndex *int) bool {
250 *out = nil
251 if nm == idVaArgs || m.isNamedVariadicParam(nm) {
252 if !m.variadic {
253 return false
254 }
255
256 *out = append([]cppToken(nil), varArgs...)
257 return true
258 }
259
260 for i, v := range m.fp {
261 if v == nm {
262 if i < len(ap) {
263 a := ap[i]
264 for len(a) != 0 && a[0].char == ' ' {
265 a = a[1:]
266 }
267 *out = a
268 }
269 if argIndex != nil {
270 *argIndex = i
271 }
272 return true
273 }
274 }
275 return false
276}
277
278func (m *Macro) param(varArgs []cppToken, ap [][]cppToken, nm StringID, out *[]cppToken) bool {
279 // trc("select (A) varArgs %q, ap %v, nm %q, out %q", cppToksStr(varArgs, "|"), cppToksStr2(ap), nm, cppToksStr(*out, "|"))
280 // defer func() {
281 // trc("select (A) varArgs %q, ap %v, nm %q, out %q", cppToksStr(varArgs, "|"), cppToksStr2(ap), nm, cppToksStr(*out, "|"))
282 // }()
283 return m.param2(varArgs, ap, nm, out, nil)
284}
285
286// --------------------------------------------------------------- Preprocessor
287
288type cpp struct {
289 counter int
290 counterMacro Macro
291 ctx *context
292 dateMacro Macro
293 file *tokenFile
294 fileMacro Macro
295 in chan []token3
296 inBuf []token3
297 includeLevel int
298 lineMacro Macro
299 macroStack map[StringID][]*Macro
300 macros map[StringID]*Macro
301 out chan *[]token4
302 outBuf *[]token4
303 pragmaOpBuf []token4
304 rq chan struct{}
305 timeMacro Macro
306 ungetBuf
307
308 last rune
309
310 intmaxChecked bool
311 nonFirstRead bool
312 seenEOF bool
313 inPragmaOp bool
314}
315
316func newCPP(ctx *context) *cpp {
317 b := token4Pool.Get().(*[]token4)
318 *b = (*b)[:0]
319 r := &cpp{
320 ctx: ctx,
321 macroStack: map[StringID][]*Macro{},
322 macros: map[StringID]*Macro{},
323 outBuf: b,
324 }
325 r.counterMacro = Macro{repl: []token3{{char: PPNUMBER}}}
326 r.dateMacro = Macro{repl: []token3{{char: STRINGLITERAL}}}
327 r.timeMacro = Macro{repl: []token3{{char: STRINGLITERAL}}}
328 r.fileMacro = Macro{repl: []token3{{char: STRINGLITERAL}}}
329 r.lineMacro = Macro{repl: []token3{{char: PPNUMBER}}}
330 r.macros = map[StringID]*Macro{
331 idCOUNTER: &r.counterMacro,
332 idDATE: &r.dateMacro,
333 idFILE: &r.fileMacro,
334 idLINE: &r.lineMacro,
335 idTIME: &r.timeMacro,
336 }
337 t := time.Now()
338 // This macro expands to a string constant that describes the date on which the
339 // preprocessor is being run. The string constant contains eleven characters
340 // and looks like "Feb 12 1996". If the day of the month is less than 10, it is
341 // padded with a space on the left.
342 r.dateMacro.repl[0].value = dict.sid(t.Format("\"Jan _2 2006\""))
343 // This macro expands to a string constant that describes the time at which the
344 // preprocessor is being run. The string constant contains eight characters and
345 // looks like "23:59:01".
346 r.timeMacro.repl[0].value = dict.sid(t.Format("\"15:04:05\""))
347 return r
348}
349
350func (c *cpp) cppToks(toks []token3) (r []cppToken) {
351 r = make([]cppToken, len(toks))
352 for i, v := range toks {
353 r[i].token4.token3 = v
354 r[i].token4.file = c.file
355 }
356 return r
357}
358
359func (c *cpp) err(n node, msg string, args ...interface{}) (stop bool) {
360 var position token.Position
361 switch x := n.(type) {
362 case nil:
363 case token4:
364 position = x.Position()
365 default:
366 if p := n.Pos(); p.IsValid() {
367 position = c.file.PositionFor(p, true)
368 }
369 }
370 return c.ctx.err(position, msg, args...)
371}
372
373func (c *cpp) read() (cppToken, bool) {
374 if len(c.ungetBuf) != 0 {
375 return c.ungetBuf.read(), true
376 }
377
378 if len(c.inBuf) == 0 {
379 if c.seenEOF {
380 return cppToken{}, false
381 }
382
383 if c.nonFirstRead {
384 c.rq <- struct{}{}
385 }
386 c.nonFirstRead = true
387
388 var ok bool
389 if c.inBuf, ok = <-c.in; !ok {
390 c.seenEOF = true
391 return cppToken{}, false
392 }
393 }
394
395 tok := c.inBuf[0]
396 c.inBuf = c.inBuf[1:]
397 return cppToken{token4{token3: tok, file: c.file}, nil}, true
398}
399
400func (c *cpp) write(tok cppToken) {
401 if tok.char == ' ' && c.last == ' ' {
402 return
403 }
404
405 if c.ctx.cfg.PreprocessOnly {
406 switch {
407 case
408 //TODO cover ALL the bad combinations
409 c.last == '+' && tok.char == '+',
410 c.last == '+' && tok.char == INC,
411 c.last == '-' && tok.char == '-',
412 c.last == '-' && tok.char == DEC,
413 c.last == IDENTIFIER && tok.char == IDENTIFIER,
414 c.last == PPNUMBER && tok.char == '+', //TODO not when ends in a digit
415 c.last == PPNUMBER && tok.char == '-': //TODO not when ends in a digit
416
417 sp := tok
418 sp.char = ' '
419 sp.value = idSpace
420 *c.outBuf = append(*c.outBuf, sp.token4)
421 }
422 }
423
424 //dbg("%T.write %q", c, tok)
425 c.last = tok.char
426 switch {
427 case c.inPragmaOp:
428 out:
429 switch tok.char {
430 case ')':
431 c.inPragmaOp = false
432 b := c.pragmaOpBuf
433 if len(b) == 0 || b[0].char != '(' {
434 c.err(b[0], "expected (")
435 break
436 }
437
438 var a []string
439 for _, v := range b[1:] {
440 if v.char != STRINGLITERAL {
441 c.err(v, "expected string literal")
442 break out
443 }
444
445 a = append(a, v.String())
446 }
447
448 if len(a) == 0 {
449 break
450 }
451
452 for i, v := range a {
453 // [0], 6.10.9, 1
454 if v[0] == 'L' {
455 v = v[1:]
456 }
457 v = v[1 : len(v)-1]
458 v = strings.ReplaceAll(v, `\"`, `"`)
459 a[i] = "#pragma " + strings.ReplaceAll(v, `\\`, `\`) + "\n"
460 }
461 src := strings.Join(a, "")
462 s := newScanner0(c.ctx, strings.NewReader(src), tokenNewFile("", len(src)), 4096)
463 if ppf := s.translationPhase3(); ppf != nil {
464 ppf.translationPhase4(c)
465 }
466 default:
467 c.pragmaOpBuf = append(c.pragmaOpBuf, tok.token4)
468 }
469 default:
470 switch {
471 case tok.char == '\n':
472 *c.outBuf = append(*c.outBuf, tok.token4)
473 c.out <- c.outBuf
474 b := token4Pool.Get().(*[]token4)
475 *b = (*b)[:0]
476 c.outBuf = b
477 case tok.char == IDENTIFIER && tok.value == idPragmaOp:
478 if len(*c.outBuf) != 0 {
479 tok.char = '\n'
480 tok.value = 0
481 *c.outBuf = append(*c.outBuf, tok.token4)
482 c.out <- c.outBuf
483 b := token4Pool.Get().(*[]token4)
484 *b = (*b)[:0]
485 c.outBuf = b
486 }
487 c.inPragmaOp = true
488 c.pragmaOpBuf = c.pragmaOpBuf[:0]
489 default:
490 *c.outBuf = append(*c.outBuf, tok.token4)
491 }
492 }
493}
494
495func ltrim4(toks []token4) []token4 {
496 for len(toks) != 0 && toks[0].char == ' ' {
497 toks = toks[1:]
498 }
499 return toks
500}
501
502func (c *cpp) writes(toks []cppToken) {
503 for _, v := range toks {
504 c.write(v)
505 }
506}
507
508// [1]pg 1.
509//
510// expand(TS) /* recur, substitute, pushback, rescan */
511// {
512// if TS is {} then
513// // ---------------------------------------------------------- A
514// return {};
515//
516// else if TS is T^HS • TS’ and T is in HS then
517// //----------------------------------------------------------- B
518// return T^HS • expand(TS’);
519//
520// else if TS is T^HS • TS’ and T is a "()-less macro" then
521// // ---------------------------------------------------------- C
522// return expand(subst(ts(T), {}, {}, HS \cup {T}, {}) • TS’ );
523//
524// else if TS is T^HS •(•TS’ and T is a "()’d macro" then
525// // ---------------------------------------------------------- D
526// check TS’ is actuals • )^HS’ • TS’’ and actuals are "correct for T"
527// return expand(subst(ts(T), fp(T), actuals,(HS \cap HS’) \cup {T }, {}) • TS’’);
528//
529// // ------------------------------------------------------------------ E
530// note TS must be T^HS • TS’
531// return T^HS • expand(TS’);
532// }
533func (c *cpp) expand(ts tokenReader, w tokenWriter, expandDefined bool) {
534 // trc("==== expand enter")
535start:
536 tok, ok := ts.read()
537 tok.file = c.file
538 // First, if TS is the empty set, the result is the empty set.
539 if !ok {
540 // ---------------------------------------------------------- A
541 // return {};
542 // trc("---- expand A")
543 return
544 }
545
546 // dbg("expand start %q", tok)
547 if tok.char == IDENTIFIER {
548 nm := tok.value
549 if nm == idDefined && expandDefined {
550 c.parseDefined(tok, ts, w)
551 goto start
552 }
553
554 // Otherwise, if the token sequence begins with a token whose
555 // hide set contains that token, then the result is the token
556 // sequence beginning with that token (including its hide set)
557 // followed by the result of expand on the rest of the token
558 // sequence.
559 if tok.has(nm) {
560 // -------------------------------------------------- B
561 // return T^HS • expand(TS’);
562 // trc("---- expand B")
563 // trc("expand write %q", tok)
564 w.write(tok)
565 goto start
566 }
567
568 m := c.macros[nm]
569 if m != nil && !m.isFnLike {
570 // Otherwise, if the token sequence begins with an
571 // object-like macro, the result is the expansion of
572 // the rest of the token sequence beginning with the
573 // sequence returned by subst invoked with the
574 // replacement token sequence for the macro, two empty
575 // sets, the union of the macro’s hide set and the
576 // macro itself, and an empty set.
577 switch nm {
578 case idLINE:
579 c.lineMacro.repl[0].value = dict.sid(fmt.Sprint(tok.Position().Line))
580 case idCOUNTER:
581 c.counterMacro.repl[0].value = dict.sid(fmt.Sprint(c.counter))
582 c.counter++
583 case idTclDefaultDoubleRounding:
584 if c.ctx.cfg.ReplaceMacroTclDefaultDoubleRounding != "" {
585 m = c.macros[dict.sid(c.ctx.cfg.ReplaceMacroTclDefaultDoubleRounding)]
586 }
587 case idTclIeeeDoubleRounding:
588 if c.ctx.cfg.ReplaceMacroTclIeeeDoubleRounding != "" {
589 m = c.macros[dict.sid(c.ctx.cfg.ReplaceMacroTclIeeeDoubleRounding)]
590 }
591 }
592 if m != nil {
593 // -------------------------------------------------- C
594 // return expand(subst(ts(T), {}, {}, HS \cup {T}, {}) • TS’ );
595 // trc("---- expand C")
596 hs := hideSet{nm: {}}
597 for k, v := range tok.hs {
598 hs[k] = v
599 }
600 os := cppTokensPool.Get().(*[]cppToken)
601 toks := c.subst(m, c.cppToks(m.repl), nil, nil, nil, hs, os, expandDefined)
602 for i := range toks {
603 toks[i].pos = tok.pos
604 }
605 if len(toks) == 1 {
606 toks[0].macro = nm
607 }
608 ts.ungets(toks)
609 (*os) = (*os)[:0]
610 cppTokensPool.Put(os)
611 goto start
612 }
613 }
614
615 if m != nil && m.isFnLike {
616 switch nm {
617 case idFdZero:
618 if c.ctx.cfg.ReplaceMacroFdZero != "" {
619 m = c.macros[dict.sid(c.ctx.cfg.ReplaceMacroFdZero)]
620 }
621 }
622 if m != nil {
623 // -------------------------------------------------- D
624 // check TS’ is actuals • )^HS’ • TS’’ and actuals are "correct for T"
625 // return expand(subst(ts(T), fp(T), actuals,(HS \cap HS’) \cup {T }, {}) • TS’’);
626 // trc("---- expand D")
627 hs := tok.hs
628 var skip []cppToken
629 again:
630 t2, ok := ts.read()
631 if !ok {
632 // dbg("expand write %q", tok)
633 w.write(tok)
634 ts.ungets(skip)
635 goto start
636 }
637
638 skip = append(skip, t2)
639 switch t2.char {
640 case '\n', ' ':
641 goto again
642 case '(':
643 // ok
644 default:
645 w.write(tok)
646 ts.ungets(skip)
647 goto start
648 }
649
650 varArgs, ap, hs2 := c.actuals(m, ts)
651 if nm == idHasIncludeImpl { //TODO-
652 if len(ap) != 1 || len(ap[0]) != 1 {
653 panic(todo("internal error"))
654 }
655
656 arg := ap[0][0].value.String()
657 switch {
658 case strings.HasPrefix(arg, `"\"`): // `"\"stdio.h\""`
659 arg = arg[2:len(arg)-3] + `"` // -> `"stdio.h"`
660 case strings.HasPrefix(arg, `"<`): // `"<stdio.h>"`
661 arg = arg[1 : len(arg)-1] // -> `<stdio.h>`
662 default:
663 arg = ""
664 }
665 var tok3 token3
666 tok3.char = PPNUMBER
667 tok3.value = idZero
668 if arg != "" {
669 if _, err := c.hasInclude(&tok, arg); err == nil {
670 tok3.value = idOne
671 }
672 }
673 tok := cppToken{token4{token3: tok3, file: c.file}, nil}
674 ts.ungets([]cppToken{tok})
675 goto start
676 }
677
678 switch {
679 case len(hs2) == 0:
680 hs2 = hideSet{nm: {}}
681 default:
682 nhs := hideSet{}
683 for k := range hs {
684 if _, ok := hs2[k]; ok {
685 nhs[k] = struct{}{}
686 }
687 }
688 nhs[nm] = struct{}{}
689 hs2 = nhs
690 }
691 os := cppTokensPool.Get().(*[]cppToken)
692 toks := c.subst(m, c.cppToks(m.repl), m.fp, varArgs, ap, hs2, os, expandDefined)
693 for i := range toks {
694 toks[i].pos = tok.pos
695 }
696 ts.ungets(toks)
697 (*os) = (*os)[:0]
698 cppTokensPool.Put(os)
699 goto start
700 }
701 }
702 }
703
704 // ------------------------------------------------------------------ E
705 // note TS must be T^HS • TS’
706 // return T^HS • expand(TS’);
707 // trc("---- expand E")
708 // trc("expand write %q", tok)
709 w.write(tok)
710 goto start
711}
712
713func (c *cpp) hasInclude(n Node, nm string) (rs string, err error) {
714 // nm0 := nm
715 // defer func() { //TODO-
716 // trc("nm0 %q nm %q rs %q err %v", nm0, nm, rs, err)
717 // }()
718 var (
719 b byte
720 paths []string
721 sys bool
722 )
723 switch {
724 case nm != "" && nm[0] == '"':
725 paths = c.ctx.includePaths
726 b = '"'
727 case nm != "" && nm[0] == '<':
728 paths = c.ctx.sysIncludePaths
729 sys = true
730 b = '>'
731 case nm == "":
732 return "", fmt.Errorf("%v: invalid empty include argument", n.Position())
733 default:
734 return "", fmt.Errorf("%v: invalid include argument %s", n.Position(), nm)
735 }
736
737 x := strings.IndexByte(nm[1:], b)
738 if x < 0 {
739 return "", fmt.Errorf("%v: invalid include argument %s", n.Position(), nm)
740 }
741
742 nm = filepath.FromSlash(nm[1 : x+1])
743 switch {
744 case filepath.IsAbs(nm):
745 fi, err := c.ctx.statFile(nm, sys)
746 if err != nil {
747 return "", fmt.Errorf("%v: %s", n.Position(), err)
748 }
749
750 if fi.IsDir() {
751 return "", fmt.Errorf("%v: %s is a directory, not a file", n.Position(), nm)
752 }
753
754 return nm, nil
755 default:
756 dir := filepath.Dir(c.file.Name())
757 for _, v := range paths {
758 if v == "@" {
759 v = dir
760 }
761
762 var p string
763 switch {
764 case strings.HasPrefix(nm, "./"):
765 wd := c.ctx.cfg.WorkingDir
766 if wd == "" {
767 var err error
768 if wd, err = os.Getwd(); err != nil {
769 return "", fmt.Errorf("%v: cannot determine working dir: %v", n.Position(), err)
770 }
771 }
772 p = filepath.Join(wd, nm)
773 default:
774 p = filepath.Join(v, nm)
775 }
776 fi, err := c.ctx.statFile(p, sys)
777 if err != nil || fi.IsDir() {
778 continue
779 }
780
781 return p, nil
782 }
783 wd, _ := os.Getwd()
784 return "", fmt.Errorf("include file not found: %s (wd %s)\nsearch paths:\n\t%s", nm, wd, strings.Join(paths, "\n\t"))
785 }
786}
787
788func (c *cpp) actuals(m *Macro, r tokenReader) (varArgs []cppToken, ap [][]cppToken, hs hideSet) {
789 var lvl, n int
790 varx := len(m.fp)
791 if m.namedVariadic {
792 varx--
793 }
794 var last rune
795 for {
796 t, ok := r.read()
797 if !ok {
798 c.err(t, "unexpected EOF")
799 return nil, nil, nil
800 }
801
802 // 6.10.3, 10
803 //
804 // Within the sequence of preprocessing tokens making up an
805 // invocation of a function-like macro, new-line is considered
806 // a normal white-space character.
807 if t.char == '\n' {
808 t.char = ' '
809 t.value = idSpace
810 }
811 if t.char == ' ' && last == ' ' {
812 continue
813 }
814
815 last = t.char
816 switch t.char {
817 case ',':
818 if lvl == 0 {
819 if n >= varx && (len(varArgs) != 0 || !isWhite(t.char)) {
820 varArgs = append(varArgs, t)
821 }
822 n++
823 continue
824 }
825 case ')':
826 if lvl == 0 {
827 for len(ap) < len(m.fp) {
828 ap = append(ap, nil)
829 }
830 for i, v := range ap {
831 ap[i] = c.trim(v)
832 }
833 // for i, v := range ap {
834 // dbg("%T.actuals %v/%v %q", c, i, len(ap), tokStr(v, "|"))
835 // }
836 return c.trim(varArgs), ap, t.hs
837 }
838 lvl--
839 case '(':
840 lvl++
841 }
842 if n >= varx && (len(varArgs) != 0 || !isWhite(t.char)) {
843 varArgs = append(varArgs, t)
844 }
845 for len(ap) <= n {
846 ap = append(ap, []cppToken{})
847 }
848 ap[n] = append(ap[n], t)
849 }
850}
851
852// [1]pg 2.
853//
854// subst(IS, FP, AP, HS, OS) /* substitute args, handle stringize and paste */
855// {
856// if IS is {} then
857// // ---------------------------------------------------------- A
858// return hsadd(HS, OS);
859//
860// else if IS is # • T • IS’ and T is FP[i] then
861// // ---------------------------------------------------------- B
862// return subst(IS’, FP, AP, HS, OS • stringize(select(i, AP)));
863//
864// else if IS is ## • T • IS’ and T is FP[i] then
865// {
866// // ---------------------------------------------------------- C
867// if select(i, AP) is {} then /* only if actuals can be empty */
868// // -------------------------------------------------- D
869// return subst(IS’, FP, AP, HS, OS);
870// else
871// // -------------------------------------------------- E
872// return subst(IS’, FP, AP, HS, glue(OS, select(i, AP)));
873// }
874//
875// else if IS is ## • T^HS’ • IS’ then
876// // ---------------------------------------------------------- F
877// return subst(IS’, FP, AP, HS, glue(OS, T^HS’));
878//
879// else if IS is T • ##^HS’ • IS’ and T is FP[i] then
880// {
881// // ---------------------------------------------------------- G
882// if select(i, AP) is {} then /* only if actuals can be empty */
883// {
884// // -------------------------------------------------- H
885// if IS’ is T’ • IS’’ and T’ is FP[j] then
886// // ------------------------------------------ I
887// return subst(IS’’, FP, AP, HS, OS • select(j, AP));
888// else
889// // ------------------------------------------ J
890// return subst(IS’, FP, AP, HS, OS);
891// }
892// else
893// // -------------------------------------------------- K
894// return subst(##^HS’ • IS’, FP, AP, HS, OS • select(i, AP));
895//
896// }
897//
898// else if IS is T • IS’ and T is FP[i] then
899// // ---------------------------------------------------------- L
900// return subst(IS’, FP, AP, HS, OS • expand(select(i, AP)));
901//
902// // ------------------------------------------------------------------ M
903// note IS must be T^HS’ • IS’
904// return subst(IS’, FP, AP, HS, OS • T^HS’);
905// }
906//
907// A quick overview of subst is that it walks through the input sequence, IS,
908// building up an output sequence, OS, by handling each token from left to
909// right. (The order that this operation takes is left to the implementation
910// also, walking from left to right is more natural since the rest of the
911// algorithm is constrained to this ordering.) Stringizing is easy, pasting
912// requires trickier handling because the operation has a bunch of
913// combinations. After the entire input sequence is finished, the updated hide
914// set is applied to the output sequence, and that is the result of subst.
915func (c *cpp) subst(m *Macro, is []cppToken, fp []StringID, varArgs []cppToken, ap [][]cppToken, hs hideSet, os *[]cppToken, expandDefined bool) (r []cppToken) {
916 var ap0 [][]cppToken
917 for _, v := range ap {
918 ap0 = append(ap0, append([]cppToken(nil), v...))
919 }
920 // trc("==== subst: is %q, fp, %v ap@%p %v", cppToksStr(is, "|"), fp, &ap, cppToksStr2(ap))
921start:
922 // trc("start: is %q, fp %v, ap@%p %v, os %q", cppToksStr(is, "|"), fp, &ap, cppToksStr2(ap), cppToksStr(*os, "|"))
923 if len(is) == 0 {
924 // ---------------------------------------------------------- A
925 // return hsadd(HS, OS);
926 // trc("---- A")
927 // trc("subst RETURNS %q", cppToksStr(*os, "|"))
928 return c.hsAdd(hs, os)
929 }
930
931 tok := is[0]
932 var arg []cppToken
933 if tok.char == '#' {
934 if len(is) > 1 && is[1].char == IDENTIFIER && m.param(varArgs, ap0, is[1].value, &arg) {
935 // -------------------------------------------------- B
936 // return subst(IS’, FP, AP, HS, OS • stringize(select(i, AP)));
937 // trc("---- subst B")
938 *os = append(*os, c.stringize(arg))
939 is = is[2:]
940 goto start
941 }
942 }
943
944 if tok.char == PPPASTE {
945 if len(is) > 1 && is[1].char == IDENTIFIER && m.param(varArgs, ap0, is[1].value, &arg) {
946 // -------------------------------------------------- C
947 // trc("---- subst C")
948 if len(arg) == 0 {
949 // TODO "only if actuals can be empty"
950 // ------------------------------------------ D
951 // return subst(IS’, FP, AP, HS, OS);
952 // trc("---- D")
953 if c := len(*os); c != 0 && (*os)[c-1].char == ',' {
954 *os = (*os)[:c-1]
955 }
956 is = is[2:]
957 goto start
958 }
959
960 // -------------------------------------------------- E
961 // return subst(IS’, FP, AP, HS, glue(OS, select(i, AP)));
962 // trc("---- subst E, arg %q", cppToksStr(arg, "|"))
963 *os = c.glue(*os, arg)
964 is = is[2:]
965 goto start
966 }
967
968 if len(is) > 1 {
969 // -------------------------------------------------- F
970 // return subst(IS’, FP, AP, HS, glue(OS, T^HS’));
971 // trc("---- subst F")
972 *os = c.glue(*os, is[1:2])
973 is = is[2:]
974 goto start
975 }
976 }
977
978 if tok.char == IDENTIFIER && (len(is) > 1 && is[1].char == PPPASTE) && m.param(varArgs, ap0, tok.value, &arg) {
979 // ---------------------------------------------------------- G
980 // trc("---- subst G")
981 if len(arg) == 0 {
982 // TODO "only if actuals can be empty"
983 // -------------------------------------------------- H
984 // trc("---- subst H")
985 is = is[2:] // skip T##
986 if len(is) > 0 && is[0].char == IDENTIFIER && m.param(varArgs, ap, is[0].value, &arg) {
987 // -------------------------------------------------- I
988 // return subst(IS’’, FP, AP, HS, OS • select(j, AP));
989 // trc("---- subst I")
990 *os = append(*os, arg...)
991 is = is[1:]
992 goto start
993 } else {
994 // -------------------------------------------------- J
995 // return subst(IS’, FP, AP, HS, OS);
996 // trc("---- subst J")
997 goto start
998 }
999 }
1000
1001 // ---------------------------------------------------------- K
1002 // return subst(##^HS’ • IS’, FP, AP, HS, OS • select(i, AP));
1003 // trc("---- subst K")
1004 *os = append(*os, arg...)
1005 is = is[1:]
1006 goto start
1007 }
1008
1009 ax := -1
1010 if tok.char == IDENTIFIER && m.param2(varArgs, ap, tok.value, &arg, &ax) {
1011 // ------------------------------------------ L
1012 // return subst(IS’, FP, AP, HS, OS • expand(select(i, AP)));
1013 // trc("---- subst L")
1014 // if toks, ok := cache[tok.value]; ok {
1015 // os = append(os, toks...)
1016 // is = is[1:]
1017 // goto start
1018 // }
1019
1020 sel := cppReader{buf: arg}
1021 var w cppWriter
1022 // trc("---- L(1) ap@%p %v", &ap, cppToksStr2(ap))
1023 c.expand(&sel, &w, expandDefined)
1024 // trc("---- L(2) ap@%p %v", &ap, cppToksStr2(ap))
1025 *os = append(*os, w.toks...)
1026 if ax >= 0 {
1027 ap[ax] = w.toks
1028 }
1029 is = is[1:]
1030 goto start
1031 }
1032
1033 // ------------------------------------------------------------------ M
1034 // note IS must be T^HS’ • IS’
1035 // return subst(IS’, FP, AP, HS, OS • T^HS’);
1036 *os = append(*os, tok)
1037 is = is[1:]
1038 // trc("---- subst M: is %q, os %q", cppToksStr(is, "|"), cppToksStr(*os, "|"))
1039 goto start
1040}
1041
1042// paste last of left side with first of right side
1043//
1044// [1] pg. 3
1045//
1046//TODO implement properly [0], 6.10.3.3, 2. Must rescan the resulting token(s).
1047//
1048// $ cat main.c
1049// #include <stdio.h>
1050//
1051// #define foo(a, b) a ## b
1052//
1053// int main() {
1054// int i = 42;
1055// i foo(+, +);
1056// printf("%i\n", i);
1057// return 0;
1058// }
1059// $ rm -f a.out ; gcc -Wall main.c && ./a.out ; echo $?
1060// 43
1061// 0
1062// $
1063//
1064// ----------------------------------------------------------------------------
1065// glue(LS,RS ) /* paste last of left side with first of right side */
1066// {
1067// if LS is L^HS and RS is R^HS’ • RS’ then
1068// return L&R^(HS∩HS’) • RS’; /* undefined if L&R is invalid */
1069
1070// // note LS must be L HS • LS’
1071// return L^HS • glue(LS’,RS );
1072// }
1073func (c *cpp) glue(ls, rs []cppToken) (out []cppToken) {
1074 // trc("ls %q, rs %q", cppToksStr(ls, "|"), cppToksStr(rs, "|"))
1075 if len(rs) == 0 {
1076 return ls
1077 }
1078
1079 if len(ls) == 0 {
1080 return rs
1081 }
1082
1083 l := ls[len(ls)-1]
1084 ls = ls[:len(ls)-1]
1085 r := rs[0]
1086 rs = rs[1:]
1087
1088 if l.char == IDENTIFIER && l.value == idL && r.char == STRINGLITERAL {
1089 l.char = LONGSTRINGLITERAL
1090 }
1091 l.value = dict.sid(l.String() + r.String())
1092 return append(append(ls, l), rs...)
1093}
1094
1095// Given a token sequence, stringize returns a single string literal token
1096// containing the concatenated spellings of the tokens.
1097//
1098// [1] pg. 3
1099func (c *cpp) stringize(s0 []cppToken) (r cppToken) {
1100 // 6.10.3.2
1101 //
1102 // Each occurrence of white space between the argument’s preprocessing
1103 // tokens becomes a single space character in the character string
1104 // literal.
1105 s := make([]cppToken, 0, len(s0))
1106 var last rune
1107 for i := range s0 {
1108 t := s0[i]
1109 if isWhite(t.char) {
1110 t.char = ' '
1111 t.value = idSpace
1112 if last == ' ' {
1113 continue
1114 }
1115 }
1116
1117 last = t.char
1118 s = append(s, t)
1119 }
1120
1121 // White space before the first preprocessing token and after the last
1122 // preprocessing token composing the argument is deleted.
1123 s = c.trim(s)
1124
1125 // The character string literal corresponding to an empty argument is
1126 // ""
1127 if len(s) == 0 {
1128 r.hs = nil
1129 r.char = STRINGLITERAL
1130 r.value = idEmptyString
1131 return r
1132 }
1133
1134 var a []string
1135 // Otherwise, the original spelling of each preprocessing token in the
1136 // argument is retained in the character string literal, except for
1137 // special handling for producing the spelling of string literals and
1138 // character constants: a \ character is inserted before each " and \
1139 // character of a character constant or string literal (including the
1140 // delimiting " characters), except that it is implementation-defined
1141 // whether a \ character is inserted before the \ character beginning a
1142 // universal character name.
1143 for _, v := range s {
1144 s := v.String()
1145 switch v.char {
1146 case CHARCONST, STRINGLITERAL:
1147 s = strings.ReplaceAll(s, `\`, `\\`)
1148 s = strings.ReplaceAll(s, `"`, `\"`)
1149 case LONGCHARCONST, LONGSTRINGLITERAL:
1150 panic("TODO")
1151 }
1152 a = append(a, s)
1153 }
1154 r = s[0]
1155 r.hs = nil
1156 r.char = STRINGLITERAL
1157 r.value = dict.sid(`"` + strings.Join(a, "") + `"`)
1158 return r
1159}
1160
1161func (c *cpp) trim(toks []cppToken) []cppToken {
1162 for len(toks) != 0 && isWhite(toks[0].char) {
1163 toks = toks[1:]
1164 }
1165 for len(toks) != 0 && isWhite(toks[len(toks)-1].char) {
1166 toks = toks[:len(toks)-1]
1167 }
1168 return toks
1169}
1170
1171func (c *cpp) hsAdd(hs hideSet, toks *[]cppToken) []cppToken {
1172 for i, v := range *toks {
1173 if v.hs == nil {
1174 v.hs = hideSet{}
1175 }
1176 for k, w := range hs {
1177 v.hs[k] = w
1178 }
1179 v.file = c.file
1180 (*toks)[i] = v
1181 }
1182 return *toks
1183}
1184
1185func (c *cpp) parseDefined(tok cppToken, r tokenReader, w tokenWriter) {
1186 toks := []cppToken{tok}
1187 if tok = c.scanToNonBlankToken(&toks, r, w); tok.char < 0 {
1188 return
1189 }
1190
1191 switch tok.char {
1192 case IDENTIFIER:
1193 // ok
1194 case '(':
1195 if tok = c.scanToNonBlankToken(&toks, r, w); tok.char < 0 {
1196 return
1197 }
1198
1199 if tok.char != IDENTIFIER {
1200 w.writes(toks)
1201 return
1202 }
1203
1204 tok2 := c.scanToNonBlankToken(&toks, r, w)
1205 if tok2.char < 0 {
1206 return
1207 }
1208
1209 if tok2.char != ')' {
1210 w.writes(toks)
1211 return
1212 }
1213 }
1214
1215 tok.char = PPNUMBER
1216 switch _, ok := c.macros[tok.value]; {
1217 case ok:
1218 tok.value = idOne
1219 default:
1220 tok.value = idZero
1221 }
1222 w.write(tok)
1223}
1224
1225func (c *cpp) scanToNonBlankToken(toks *[]cppToken, r tokenReader, w tokenWriter) cppToken {
1226 tok, ok := r.read()
1227 if !ok {
1228 w.writes(*toks)
1229 tok.char = -1
1230 return tok
1231 }
1232
1233 *toks = append(*toks, tok)
1234 if tok.char == ' ' || tok.char == '\n' {
1235 if tok, ok = r.read(); !ok {
1236 w.writes(*toks)
1237 tok.char = -1
1238 return tok
1239 }
1240
1241 *toks = append(*toks, tok)
1242 }
1243 return (*toks)[len(*toks)-1]
1244}
1245
1246// [0], 6.10.1
1247func (c *cpp) evalInclusionCondition(expr []token3) (r bool) {
1248 if !c.intmaxChecked {
1249 if m := c.macros[idIntMaxWidth]; m != nil && len(m.repl) != 0 {
1250 if val := c.intMaxWidth(); val != 0 && val != 64 {
1251 c.err(m.name, "%s is %v, but only 64 is supported", idIntMaxWidth, val)
1252 }
1253 }
1254 c.intmaxChecked = true
1255 }
1256
1257 val := c.eval(expr)
1258 return val != nil && c.isNonZero(val)
1259}
1260
1261func (c *cpp) intMaxWidth() int64 {
1262 if m := c.macros[idIntMaxWidth]; m != nil && len(m.repl) != 0 {
1263 switch x := c.eval(m.repl).(type) {
1264 case nil:
1265 return 0
1266 case int64:
1267 return x
1268 case uint64:
1269 return int64(x)
1270 default:
1271 panic(internalError())
1272 }
1273 }
1274 return 0
1275}
1276
1277func (c *cpp) eval(expr []token3) interface{} {
1278 toks := make([]cppToken, len(expr))
1279 for i, v := range expr {
1280 toks[i] = cppToken{token4{token3: v}, nil}
1281 }
1282 var w cppWriter
1283 c.expand(&cppReader{buf: toks}, &w, true)
1284 toks = w.toks
1285 p := 0
1286 for _, v := range toks {
1287 switch v.char {
1288 case ' ', '\n':
1289 // nop
1290 default:
1291 toks[p] = v
1292 p++
1293 }
1294 }
1295 toks = toks[:p]
1296 s := cppScanner(toks)
1297 val := c.expression(&s, true)
1298 switch s.peek().char {
1299 case -1, '#':
1300 // ok
1301 default:
1302 t := s.peek()
1303 c.err(t, "unexpected %s", tokName(t.char))
1304 return nil
1305 }
1306 return val
1307}
1308
1309// [0], 6.5.17 Comma operator
1310//
1311// expression:
1312// assignment-expression
1313// expression , assignment-expression
1314func (c *cpp) expression(s *cppScanner, eval bool) interface{} {
1315 for {
1316 r := c.assignmentExpression(s, eval)
1317 if s.peek().char != ',' {
1318 return r
1319 }
1320
1321 s.next()
1322 }
1323}
1324
1325// [0], 6.5.16 Assignment operators
1326//
1327// assignment-expression:
1328// conditional-expression
1329// unary-expression assignment-operator assignment-expression
1330//
1331// assignment-operator: one of
1332// = *= /= %= += -= <<= >>= &= ^= |=
1333func (c *cpp) assignmentExpression(s *cppScanner, eval bool) interface{} {
1334 return c.conditionalExpression(s, eval)
1335}
1336
1337// [0], 6.5.15 Conditional operator
1338//
1339// conditional-expression:
1340// logical-OR-expression
1341// logical-OR-expression ? expression : conditional-expression
1342func (c *cpp) conditionalExpression(s *cppScanner, eval bool) interface{} {
1343 expr := c.logicalOrExpression(s, eval)
1344 if s.peek().char == '?' {
1345 s.next()
1346 exprIsNonZero := c.isNonZero(expr)
1347 expr2 := c.conditionalExpression(s, exprIsNonZero)
1348 if tok := s.peek(); tok.char != ':' {
1349 c.err(tok, "expected ':'")
1350 return expr
1351 }
1352
1353 s.next()
1354 expr3 := c.conditionalExpression(s, !exprIsNonZero)
1355
1356 // [0] 6.5.15
1357 //
1358 // 5. If both the second and third operands have arithmetic type, the result
1359 // type that would be determined by the usual arithmetic conversions, were they
1360 // applied to those two operands, is the type of the result.
1361 x := c.operand(expr2)
1362 y := c.operand(expr3)
1363 if x != nil && y != nil {
1364 x, y = usualArithmeticConversions(c.ctx, nil, x, y, false)
1365 expr2 = c.fromOperand(x)
1366 expr3 = c.fromOperand(y)
1367 }
1368
1369 switch {
1370 case exprIsNonZero:
1371 expr = expr2
1372 default:
1373 expr = expr3
1374 }
1375 }
1376 return expr
1377}
1378
1379func (c *cpp) operand(v interface{}) Operand {
1380 switch x := v.(type) {
1381 case int64:
1382 return &operand{typ: &typeBase{size: 8, kind: byte(LongLong), flags: fSigned}, value: Int64Value(x)}
1383 case uint64:
1384 return &operand{typ: &typeBase{size: 8, kind: byte(ULongLong)}, value: Uint64Value(x)}
1385 default:
1386 return nil
1387 }
1388}
1389
1390func (c *cpp) fromOperand(op Operand) interface{} {
1391 switch x := op.Value().(type) {
1392 case Int64Value:
1393 return int64(x)
1394 case Uint64Value:
1395 return uint64(x)
1396 default:
1397 return nil
1398 }
1399}
1400
1401// [0], 6.5.14 Logical OR operator
1402//
1403// logical-OR-expression:
1404// logical-AND-expression
1405// logical-OR-expression || logical-AND-expression
1406func (c *cpp) logicalOrExpression(s *cppScanner, eval bool) interface{} {
1407 lhs := c.logicalAndExpression(s, eval)
1408 for s.peek().char == OROR {
1409 s.next()
1410 if c.isNonZero(lhs) {
1411 eval = false
1412 }
1413 rhs := c.logicalAndExpression(s, eval)
1414 if c.isNonZero(lhs) || c.isNonZero(rhs) {
1415 lhs = int64(1)
1416 }
1417 }
1418 return lhs
1419}
1420
1421// [0], 6.5.13 Logical AND operator
1422//
1423// logical-AND-expression:
1424// inclusive-OR-expression
1425// logical-AND-expression && inclusive-OR-expression
1426func (c *cpp) logicalAndExpression(s *cppScanner, eval bool) interface{} {
1427 lhs := c.inclusiveOrExpression(s, eval)
1428 for s.peek().char == ANDAND {
1429 s.next()
1430 if c.isZero(lhs) {
1431 eval = false
1432 }
1433 rhs := c.inclusiveOrExpression(s, eval)
1434 if c.isZero(lhs) || c.isZero(rhs) {
1435 lhs = int64(0)
1436 }
1437 }
1438 return lhs
1439}
1440
1441func (c *cpp) isZero(val interface{}) bool {
1442 switch x := val.(type) {
1443 case int64:
1444 return x == 0
1445 case uint64:
1446 return x == 0
1447 }
1448 panic(internalError())
1449}
1450
1451// [0], 6.5.12 Bitwise inclusive OR operator
1452//
1453// inclusive-OR-expression:
1454// exclusive-OR-expression
1455// inclusive-OR-expression | exclusive-OR-expression
1456func (c *cpp) inclusiveOrExpression(s *cppScanner, eval bool) interface{} {
1457 lhs := c.exclusiveOrExpression(s, eval)
1458 for s.peek().char == '|' {
1459 s.next()
1460 rhs := c.exclusiveOrExpression(s, eval)
1461 if eval {
1462 switch x := lhs.(type) {
1463 case int64:
1464 switch y := rhs.(type) {
1465 case int64:
1466 lhs = x | y
1467 case uint64:
1468 lhs = uint64(x) | y
1469 }
1470 case uint64:
1471 switch y := rhs.(type) {
1472 case int64:
1473 lhs = x | uint64(y)
1474 case uint64:
1475 lhs = x | y
1476 }
1477 }
1478 }
1479 }
1480 return lhs
1481}
1482
1483// [0], 6.5.11 Bitwise exclusive OR operator
1484//
1485// exclusive-OR-expression:
1486// AND-expression
1487// exclusive-OR-expression ^ AND-expression
1488func (c *cpp) exclusiveOrExpression(s *cppScanner, eval bool) interface{} {
1489 lhs := c.andExpression(s, eval)
1490 for s.peek().char == '^' {
1491 s.next()
1492 rhs := c.andExpression(s, eval)
1493 if eval {
1494 switch x := lhs.(type) {
1495 case int64:
1496 switch y := rhs.(type) {
1497 case int64:
1498 lhs = x ^ y
1499 case uint64:
1500 lhs = uint64(x) ^ y
1501 }
1502 case uint64:
1503 switch y := rhs.(type) {
1504 case int64:
1505 lhs = x ^ uint64(y)
1506 case uint64:
1507 lhs = x ^ y
1508 }
1509 }
1510 }
1511 }
1512 return lhs
1513}
1514
1515// [0], 6.5.10 Bitwise AND operator
1516//
1517// AND-expression:
1518// equality-expression
1519// AND-expression & equality-expression
1520func (c *cpp) andExpression(s *cppScanner, eval bool) interface{} {
1521 lhs := c.equalityExpression(s, eval)
1522 for s.peek().char == '&' {
1523 s.next()
1524 rhs := c.equalityExpression(s, eval)
1525 if eval {
1526 switch x := lhs.(type) {
1527 case int64:
1528 switch y := rhs.(type) {
1529 case int64:
1530 lhs = x & y
1531 case uint64:
1532 lhs = uint64(x) & y
1533 }
1534 case uint64:
1535 switch y := rhs.(type) {
1536 case int64:
1537 lhs = x & uint64(y)
1538 case uint64:
1539 lhs = x & y
1540 }
1541 }
1542 }
1543 }
1544 return lhs
1545}
1546
1547// [0], 6.5.9 Equality operators
1548//
1549// equality-expression:
1550// relational-expression
1551// equality-expression == relational-expression
1552// equality-expression != relational-expression
1553func (c *cpp) equalityExpression(s *cppScanner, eval bool) interface{} {
1554 lhs := c.relationalExpression(s, eval)
1555 for {
1556 var v bool
1557 switch s.peek().char {
1558 case EQ:
1559 s.next()
1560 rhs := c.relationalExpression(s, eval)
1561 if eval {
1562 switch x := lhs.(type) {
1563 case int64:
1564 switch y := rhs.(type) {
1565 case int64:
1566 v = x == y
1567 case uint64:
1568 v = uint64(x) == y
1569 }
1570 case uint64:
1571 switch y := rhs.(type) {
1572 case int64:
1573 v = x == uint64(y)
1574 case uint64:
1575 v = x == y
1576 }
1577 }
1578 }
1579 case NEQ:
1580 s.next()
1581 rhs := c.relationalExpression(s, eval)
1582 if eval {
1583 switch x := lhs.(type) {
1584 case int64:
1585 switch y := rhs.(type) {
1586 case int64:
1587 v = x != y
1588 case uint64:
1589 v = uint64(x) != y
1590 }
1591 case uint64:
1592 switch y := rhs.(type) {
1593 case int64:
1594 v = x != uint64(y)
1595 case uint64:
1596 v = x != y
1597 }
1598 }
1599 }
1600 default:
1601 return lhs
1602 }
1603 switch {
1604 case v:
1605 lhs = int64(1)
1606 default:
1607 lhs = int64(0)
1608 }
1609 }
1610}
1611
1612// [0], 6.5.8 Relational operators
1613//
1614// relational-expression:
1615// shift-expression
1616// relational-expression < shift-expression
1617// relational-expression > shift-expression
1618// relational-expression <= shift-expression
1619// relational-expression >= shift-expression
1620func (c *cpp) relationalExpression(s *cppScanner, eval bool) interface{} {
1621 lhs := c.shiftExpression(s, eval)
1622 for {
1623 var v bool
1624 switch s.peek().char {
1625 case '<':
1626 s.next()
1627 rhs := c.shiftExpression(s, eval)
1628 if eval {
1629 switch x := lhs.(type) {
1630 case int64:
1631 switch y := rhs.(type) {
1632 case int64:
1633 v = x < y
1634 case uint64:
1635 v = uint64(x) < y
1636 }
1637 case uint64:
1638 switch y := rhs.(type) {
1639 case int64:
1640 v = x < uint64(y)
1641 case uint64:
1642 v = x < y
1643 }
1644 }
1645 }
1646 case '>':
1647 s.next()
1648 rhs := c.shiftExpression(s, eval)
1649 if eval {
1650 switch x := lhs.(type) {
1651 case int64:
1652 switch y := rhs.(type) {
1653 case int64:
1654 v = x > y
1655 case uint64:
1656 v = uint64(x) > y
1657 }
1658 case uint64:
1659 switch y := rhs.(type) {
1660 case int64:
1661 v = x > uint64(y)
1662 case uint64:
1663 v = x > y
1664 }
1665 }
1666 }
1667 case LEQ:
1668 s.next()
1669 rhs := c.shiftExpression(s, eval)
1670 if eval {
1671 switch x := lhs.(type) {
1672 case int64:
1673 switch y := rhs.(type) {
1674 case int64:
1675 v = x <= y
1676 case uint64:
1677 v = uint64(x) <= y
1678 }
1679 case uint64:
1680 switch y := rhs.(type) {
1681 case int64:
1682 v = x <= uint64(y)
1683 case uint64:
1684 v = x <= y
1685 }
1686 }
1687 }
1688 case GEQ:
1689 s.next()
1690 rhs := c.shiftExpression(s, eval)
1691 if eval {
1692 switch x := lhs.(type) {
1693 case int64:
1694 switch y := rhs.(type) {
1695 case int64:
1696 v = x >= y
1697 case uint64:
1698 v = uint64(x) >= y
1699 }
1700 case uint64:
1701 switch y := rhs.(type) {
1702 case int64:
1703 v = x >= uint64(y)
1704 case uint64:
1705 v = x >= y
1706 }
1707 }
1708 }
1709 default:
1710 return lhs
1711 }
1712 switch {
1713 case v:
1714 lhs = int64(1)
1715 default:
1716 lhs = int64(0)
1717 }
1718 }
1719}
1720
1721// [0], 6.5.7 Bitwise shift operators
1722//
1723// shift-expression:
1724// additive-expression
1725// shift-expression << additive-expression
1726// shift-expression >> additive-expression
1727func (c *cpp) shiftExpression(s *cppScanner, eval bool) interface{} {
1728 lhs := c.additiveExpression(s, eval)
1729 for {
1730 switch s.peek().char {
1731 case LSH:
1732 s.next()
1733 rhs := c.additiveExpression(s, eval)
1734 if eval {
1735 switch x := lhs.(type) {
1736 case int64:
1737 switch y := rhs.(type) {
1738 case int64:
1739 lhs = x << uint(y)
1740 case uint64:
1741 lhs = uint64(x) << uint(y)
1742 }
1743 case uint64:
1744 switch y := rhs.(type) {
1745 case int64:
1746 lhs = x << uint(y)
1747 case uint64:
1748 lhs = x << uint(y)
1749 }
1750 }
1751 }
1752 case RSH:
1753 s.next()
1754 rhs := c.additiveExpression(s, eval)
1755 if eval {
1756 switch x := lhs.(type) {
1757 case int64:
1758 switch y := rhs.(type) {
1759 case int64:
1760 lhs = x >> uint(y)
1761 case uint64:
1762 lhs = uint64(x) >> uint(y)
1763 }
1764 case uint64:
1765 switch y := rhs.(type) {
1766 case int64:
1767 lhs = x >> uint(y)
1768 case uint64:
1769 lhs = x >> uint(y)
1770 }
1771 }
1772 }
1773 default:
1774 return lhs
1775 }
1776 }
1777}
1778
1779// [0], 6.5.6 Additive operators
1780//
1781// additive-expression:
1782// multiplicative-expression
1783// additive-expression + multiplicative-expression
1784// additive-expression - multiplicative-expression
1785func (c *cpp) additiveExpression(s *cppScanner, eval bool) interface{} {
1786 lhs := c.multiplicativeExpression(s, eval)
1787 for {
1788 switch s.peek().char {
1789 case '+':
1790 s.next()
1791 rhs := c.multiplicativeExpression(s, eval)
1792 if eval {
1793 switch x := lhs.(type) {
1794 case int64:
1795 switch y := rhs.(type) {
1796 case int64:
1797 lhs = x + y
1798 case uint64:
1799 lhs = uint64(x) + y
1800 }
1801 case uint64:
1802 switch y := rhs.(type) {
1803 case int64:
1804 lhs = x + uint64(y)
1805 case uint64:
1806 lhs = x + y
1807 }
1808 }
1809 }
1810 case '-':
1811 s.next()
1812 rhs := c.multiplicativeExpression(s, eval)
1813 if eval {
1814 switch x := lhs.(type) {
1815 case int64:
1816 switch y := rhs.(type) {
1817 case int64:
1818 lhs = x - y
1819 case uint64:
1820 lhs = uint64(x) - y
1821 }
1822 case uint64:
1823 switch y := rhs.(type) {
1824 case int64:
1825 lhs = x - uint64(y)
1826 case uint64:
1827 lhs = x - y
1828 }
1829 }
1830 }
1831 default:
1832 return lhs
1833 }
1834 }
1835}
1836
1837// [0], 6.5.5 Multiplicative operators
1838//
1839// multiplicative-expression:
1840// unary-expression // [0], 6.10.1, 1.
1841// multiplicative-expression * unary-expression
1842// multiplicative-expression / unary-expression
1843// multiplicative-expression % unary-expression
1844func (c *cpp) multiplicativeExpression(s *cppScanner, eval bool) interface{} {
1845 lhs := c.unaryExpression(s, eval)
1846 for {
1847 switch s.peek().char {
1848 case '*':
1849 s.next()
1850 rhs := c.unaryExpression(s, eval)
1851 if eval {
1852 switch x := lhs.(type) {
1853 case int64:
1854 switch y := rhs.(type) {
1855 case int64:
1856 lhs = x * y
1857 case uint64:
1858 lhs = uint64(x) * y
1859 }
1860 case uint64:
1861 switch y := rhs.(type) {
1862 case int64:
1863 lhs = x * uint64(y)
1864 case uint64:
1865 lhs = x * y
1866 }
1867 }
1868 }
1869 case '/':
1870 tok := s.next()
1871 rhs := c.unaryExpression(s, eval)
1872 if eval {
1873 switch x := lhs.(type) {
1874 case int64:
1875 switch y := rhs.(type) {
1876 case int64:
1877 if y == 0 {
1878 c.err(tok, "division by zero")
1879 break
1880 }
1881
1882 lhs = x / y
1883 case uint64:
1884 if y == 0 {
1885 c.err(tok, "division by zero")
1886 break
1887 }
1888
1889 lhs = uint64(x) / y
1890 }
1891 case uint64:
1892 switch y := rhs.(type) {
1893 case int64:
1894 if y == 0 {
1895 c.err(tok, "division by zero")
1896 break
1897 }
1898
1899 lhs = x / uint64(y)
1900 case uint64:
1901 if y == 0 {
1902 c.err(tok, "division by zero")
1903 break
1904 }
1905
1906 lhs = x / y
1907 }
1908 }
1909 }
1910 case '%':
1911 tok := s.next()
1912 rhs := c.unaryExpression(s, eval)
1913 if eval {
1914 switch x := lhs.(type) {
1915 case int64:
1916 switch y := rhs.(type) {
1917 case int64:
1918 if y == 0 {
1919 c.err(tok, "division by zero")
1920 break
1921 }
1922
1923 lhs = x % y
1924 case uint64:
1925 if y == 0 {
1926 c.err(tok, "division by zero")
1927 break
1928 }
1929
1930 lhs = uint64(x) % y
1931 }
1932 case uint64:
1933 switch y := rhs.(type) {
1934 case int64:
1935 if y == 0 {
1936 c.err(tok, "division by zero")
1937 break
1938 }
1939
1940 lhs = x % uint64(y)
1941 case uint64:
1942 if y == 0 {
1943 c.err(tok, "division by zero")
1944 break
1945 }
1946
1947 lhs = x % y
1948 }
1949 }
1950 }
1951 default:
1952 return lhs
1953 }
1954 }
1955}
1956
1957// [0], 6.5.3 Unary operators
1958//
1959// unary-expression:
1960// primary-expression
1961// unary-operator unary-expression
1962//
1963// unary-operator: one of
1964// + - ~ !
1965func (c *cpp) unaryExpression(s *cppScanner, eval bool) interface{} {
1966 switch s.peek().char {
1967 case '+':
1968 s.next()
1969 return c.unaryExpression(s, eval)
1970 case '-':
1971 s.next()
1972 expr := c.unaryExpression(s, eval)
1973 if eval {
1974 switch x := expr.(type) {
1975 case int64:
1976 expr = -x
1977 case uint64:
1978 expr = -x
1979 }
1980 }
1981 return expr
1982 case '~':
1983 s.next()
1984 expr := c.unaryExpression(s, eval)
1985 if eval {
1986 switch x := expr.(type) {
1987 case int64:
1988 expr = ^x
1989 case uint64:
1990 expr = ^x
1991 }
1992 }
1993 return expr
1994 case '!':
1995 s.next()
1996 expr := c.unaryExpression(s, eval)
1997 if eval {
1998 var v bool
1999 switch x := expr.(type) {
2000 case int64:
2001 v = x == 0
2002 case uint64:
2003 v = x == 0
2004 }
2005 switch {
2006 case v:
2007 expr = int64(1)
2008 default:
2009 expr = int64(0)
2010 }
2011 }
2012 return expr
2013 default:
2014 return c.primaryExpression(s, eval)
2015 }
2016}
2017
2018// [0], 6.5.1 Primary expressions
2019//
2020// primary-expression:
2021// identifier
2022// constant
2023// ( expression )
2024func (c *cpp) primaryExpression(s *cppScanner, eval bool) interface{} {
2025 switch tok := s.peek(); tok.char {
2026 case CHARCONST, LONGCHARCONST:
2027 s.next()
2028 r := charConst(c.ctx, tok)
2029 return int64(r)
2030 case IDENTIFIER:
2031 if c.ctx.evalIdentError {
2032 panic("cannot evaluate identifier")
2033 }
2034
2035 s.next()
2036 if s.peek().char == '(' {
2037 s.next()
2038 n := 1
2039 loop:
2040 for n != 0 {
2041 switch s.peek().char {
2042 case '(':
2043 n++
2044 case ')':
2045 n--
2046 case -1:
2047 c.err(s.peek(), "expected )")
2048 break loop
2049 }
2050 s.next()
2051 }
2052 }
2053 return int64(0)
2054 case PPNUMBER:
2055 s.next()
2056 return c.intConst(tok)
2057 case '(':
2058 s.next()
2059 expr := c.expression(s, eval)
2060 if s.peek().char == ')' {
2061 s.next()
2062 }
2063 return expr
2064 default:
2065 return int64(0)
2066 }
2067}
2068
2069// [0], 6.4.4.1 Integer constants
2070//
2071// integer-constant:
2072// decimal-constant integer-suffix_opt
2073// octal-constant integer-suffix_opt
2074// hexadecimal-constant integer-suffix_opt
2075//
2076// decimal-constant:
2077// nonzero-digit
2078// decimal-constant digit
2079//
2080// octal-constant:
2081// 0
2082// octal-constant octal-digit
2083//
2084// hexadecimal-prefix: one of
2085// 0x 0X
2086//
2087// integer-suffix_opt: one of
2088// u ul ull l lu ll llu
2089func (c *cpp) intConst(tok cppToken) (r interface{}) {
2090 var n uint64
2091 s0 := tok.String()
2092 s := strings.TrimRight(s0, "uUlL")
2093 switch {
2094 case strings.HasPrefix(s, "0x") || strings.HasPrefix(s, "0X"):
2095 var err error
2096 if n, err = strconv.ParseUint(s[2:], 16, 64); err != nil {
2097 c.err(tok, "%v", err)
2098 return int64(0)
2099 }
2100 case strings.HasPrefix(s, "0"):
2101 var err error
2102 if n, err = strconv.ParseUint(s, 8, 64); err != nil {
2103 c.err(tok, "%v", err)
2104 return int64(0)
2105 }
2106 default:
2107 var err error
2108 if n, err = strconv.ParseUint(s, 10, 64); err != nil {
2109 c.err(tok, "%v", err)
2110 return int64(0)
2111 }
2112 }
2113
2114 suffix := s0[len(s):]
2115 if suffix == "" {
2116 if n > math.MaxInt64 {
2117 return n
2118 }
2119
2120 return int64(n)
2121 }
2122
2123 switch suffix = strings.ToLower(suffix); suffix {
2124 default:
2125 c.err(tok, "invalid suffix: %v", s0)
2126 fallthrough
2127 case
2128 "l",
2129 "ll":
2130
2131 if n > math.MaxInt64 {
2132 return n
2133 }
2134
2135 return int64(n)
2136 case
2137 "llu",
2138 "lu",
2139 "u",
2140 "ul",
2141 "ull":
2142
2143 return n
2144 }
2145}
2146
2147func charConst(ctx *context, tok cppToken) rune {
2148 s := tok.String()
2149 switch tok.char {
2150 case LONGCHARCONST:
2151 s = s[1:] // Remove leading 'L'.
2152 fallthrough
2153 case CHARCONST:
2154 s = s[1 : len(s)-1] // Remove outer 's.
2155 if len(s) == 1 {
2156 return rune(s[0])
2157 }
2158
2159 var r rune
2160 var n int
2161 switch s[0] {
2162 case '\\':
2163 r, n = decodeEscapeSequence(ctx, tok, s)
2164 if r < 0 {
2165 r = -r
2166 }
2167 default:
2168 r, n = utf8.DecodeRuneInString(s)
2169 }
2170 if n != len(s) {
2171 ctx.errNode(&tok, "invalid character constant")
2172 }
2173 return r
2174 }
2175 panic(internalError())
2176}
2177
2178// escape-sequence {simple-sequence}|{octal-escape-sequence}|{hexadecimal-escape-sequence}|{universal-character-name}
2179// simple-sequence \\['\x22?\\abfnrtv]
2180// octal-escape-sequence \\{octal-digit}{octal-digit}?{octal-digit}?
2181// hexadecimal-escape-sequence \\x{hexadecimal-digit}+
2182func decodeEscapeSequence(ctx *context, tok cppToken, s string) (rune, int) {
2183 if s[0] != '\\' {
2184 panic(internalError())
2185 }
2186
2187 if len(s) == 1 {
2188 return rune(s[0]), 1
2189 }
2190
2191 r := rune(s[1])
2192 switch r {
2193 case '\'', '"', '?', '\\':
2194 return r, 2
2195 case 'a':
2196 return 7, 2
2197 case 'b':
2198 return 8, 2
2199 case 'e':
2200 return 0x1b, 2
2201 case 'f':
2202 return 12, 2
2203 case 'n':
2204 return 10, 2
2205 case 'r':
2206 return 13, 2
2207 case 't':
2208 return 9, 2
2209 case 'v':
2210 return 11, 2
2211 case 'x':
2212 v, n := 0, 2
2213 loop2:
2214 for i := 2; i < len(s); i++ {
2215 r := s[i]
2216 switch {
2217 case r >= '0' && r <= '9', r >= 'a' && r <= 'f', r >= 'A' && r <= 'F':
2218 v = v<<4 | decodeHex(r)
2219 n++
2220 default:
2221 break loop2
2222 }
2223 }
2224 return -rune(v & 0xff), n
2225 case 'u', 'U':
2226 return decodeUCN(s)
2227 }
2228
2229 if r < '0' || r > '7' {
2230 panic(internalError())
2231 }
2232
2233 v, n := 0, 1
2234 ok := false
2235loop:
2236 for i := 1; i < len(s); i++ {
2237 r := s[i]
2238 switch {
2239 case i < 4 && r >= '0' && r <= '7':
2240 ok = true
2241 v = v<<3 | (int(r) - '0')
2242 n++
2243 default:
2244 break loop
2245 }
2246 }
2247 if !ok {
2248 ctx.errNode(&tok, "invalid octal sequence")
2249 }
2250 return -rune(v), n
2251}
2252
2253// universal-character-name \\u{hex-quad}|\\U{hex-quad}{hex-quad}
2254func decodeUCN(s string) (rune, int) {
2255 if s[0] != '\\' {
2256 panic(internalError())
2257 }
2258
2259 s = s[1:]
2260 switch s[0] {
2261 case 'u':
2262 return rune(decodeHexQuad(s[1:])), 6
2263 case 'U':
2264 return rune(decodeHexQuad(s[1:])<<16 | decodeHexQuad(s[5:])), 10
2265 }
2266 panic(internalError())
2267}
2268
2269// hex-quad {hexadecimal-digit}{hexadecimal-digit}{hexadecimal-digit}{hexadecimal-digit}
2270func decodeHexQuad(s string) int {
2271 n := 0
2272 for i := 0; i < 4; i++ {
2273 n = n<<4 | decodeHex(s[i])
2274 }
2275 return n
2276}
2277
2278func decodeHex(r byte) int {
2279 switch {
2280 case r >= '0' && r <= '9':
2281 return int(r) - '0'
2282 default:
2283 x := int(r) &^ 0x20
2284 return x - 'A' + 10
2285 }
2286}
2287
2288func (c *cpp) isNonZero(val interface{}) bool {
2289 switch x := val.(type) {
2290 case int64:
2291 return x != 0
2292 case uint64:
2293 return x != 0
2294 }
2295 panic(internalError())
2296}
2297
2298type ppLine interface {
2299 getToks() []token3
2300}
2301
2302type ppIfGroupDirective interface {
2303 evalInclusionCondition(*cpp) bool
2304}
2305
2306type ppElifDirective struct {
2307 toks []token3
2308 expr []token3
2309}
2310
2311func (n *ppElifDirective) getToks() []token3 { return n.toks }
2312
2313type ppElseDirective struct {
2314 toks []token3
2315}
2316
2317func (n *ppElseDirective) getToks() []token3 { return n.toks }
2318
2319type ppEndifDirective struct {
2320 toks []token3
2321}
2322
2323func (n *ppEndifDirective) getToks() []token3 { return n.toks }
2324
2325type ppEmptyDirective struct {
2326 toks []token3
2327}
2328
2329func (n *ppEmptyDirective) getToks() []token3 { return n.toks }
2330
2331func (n *ppEmptyDirective) translationPhase4(c *cpp) {
2332 // nop
2333}
2334
2335type ppIncludeDirective struct {
2336 arg []token3
2337 toks []token3
2338
2339 includeNext bool // false: #include, true: #include_next
2340}
2341
2342func (n *ppIncludeDirective) getToks() []token3 { return n.toks }
2343
2344func (n *ppIncludeDirective) translationPhase4(c *cpp) {
2345 if c.ctx.cfg.ignoreIncludes {
2346 return
2347 }
2348
2349 args := make([]cppToken, 0, len(n.arg))
2350 for _, v := range n.arg {
2351 switch v.char {
2352 case ' ', '\t', '\v', '\f':
2353 // nop
2354 default:
2355 args = append(args, cppToken{token4{token3: v}, nil})
2356 }
2357 }
2358 var sb strings.Builder
2359 for _, v := range args {
2360 sb.WriteString(v.String())
2361 }
2362 nm := strings.TrimSpace(sb.String())
2363 if nm == "" {
2364 c.err(n.toks[0], "invalid empty include argument")
2365 return
2366 }
2367
2368 switch nm[0] {
2369 case '"', '<':
2370 // ok
2371 default:
2372 var w cppWriter
2373 c.expand(&cppReader{buf: args}, &w, false)
2374 x := 0
2375 for _, v := range w.toks {
2376 switch v.char {
2377 case ' ', '\t', '\v', '\f':
2378 // nop
2379 default:
2380 w.toks[x] = v
2381 x++
2382 }
2383 }
2384 w.toks = w.toks[:x]
2385 nm = strings.TrimSpace(cppToksStr(w.toks, ""))
2386 }
2387 toks := n.toks
2388 if c.ctx.cfg.RejectIncludeNext {
2389 c.err(toks[0], "#include_next is a GCC extension")
2390 return
2391 }
2392
2393 if c.ctx.cfg.fakeIncludes {
2394 c.send([]token3{{char: STRINGLITERAL, value: dict.sid(nm), src: dict.sid(nm)}, {char: '\n', value: idNL}})
2395 return
2396 }
2397
2398 if re := c.ctx.cfg.IgnoreInclude; re != nil && re.MatchString(nm) {
2399 return
2400 }
2401
2402 if c.includeLevel == maxIncludeLevel {
2403 c.err(toks[0], "too many include levels")
2404 return
2405 }
2406
2407 c.includeLevel++
2408
2409 defer func() { c.includeLevel-- }()
2410
2411 var (
2412 b byte
2413 paths []string
2414 sys bool
2415 )
2416 switch {
2417 case nm != "" && nm[0] == '"':
2418 paths = c.ctx.includePaths
2419 b = '"'
2420 case nm != "" && nm[0] == '<':
2421 paths = c.ctx.sysIncludePaths
2422 sys = true
2423 b = '>'
2424 case nm == "":
2425 c.err(toks[0], "invalid empty include argument")
2426 return
2427 default:
2428 c.err(toks[0], "invalid include argument %s", nm)
2429 return
2430 }
2431
2432 x := strings.IndexByte(nm[1:], b)
2433 if x < 0 {
2434 c.err(toks[0], "invalid include argument %s", nm)
2435 return
2436 }
2437
2438 nm = filepath.FromSlash(nm[1 : x+1])
2439 var path string
2440 switch {
2441 case filepath.IsAbs(nm):
2442 path = nm
2443 default:
2444 dir := filepath.Dir(c.file.Name())
2445 if n.includeNext {
2446 nmDir, _ := filepath.Split(nm)
2447 for i, v := range paths {
2448 if w, err := filepath.Abs(v); err == nil {
2449 v = w
2450 }
2451 v = filepath.Join(v, nmDir)
2452 if v == dir {
2453 paths = paths[i+1:]
2454 break
2455 }
2456 }
2457 }
2458 for _, v := range paths {
2459 if v == "@" {
2460 v = dir
2461 }
2462
2463 p := filepath.Join(v, nm)
2464 fi, err := c.ctx.statFile(p, sys)
2465 if err != nil || fi.IsDir() {
2466 continue
2467 }
2468
2469 path = p
2470 break
2471 }
2472 }
2473
2474 if path == "" {
2475 wd, _ := os.Getwd()
2476 c.err(toks[0], "include file not found: %s (wd %s)\nsearch paths:\n\t%s", nm, wd, strings.Join(paths, "\n\t"))
2477 return
2478 }
2479
2480 if h := c.ctx.cfg.IncludeFileHandler; h != nil {
2481 var position gotoken.Position
2482 if p := toks[0].Pos(); p.IsValid() {
2483 position = gotoken.Position(c.file.PositionFor(p, true))
2484 }
2485 apath, err := filepath.Abs(path)
2486 if err != nil {
2487 c.err(toks[0], "%s: cannot compute absolute path: %v", path, err)
2488 }
2489 h(position, apath)
2490 }
2491 cf, err := cache.getFile(c.ctx, path, sys, false)
2492 if err != nil {
2493 c.err(toks[0], "%s: %v", path, err)
2494 return
2495 }
2496
2497 pf, err := cf.ppFile()
2498 if err != nil {
2499 c.err(toks[0], "%s: %v", path, err)
2500 return
2501 }
2502
2503 saveFile := c.file
2504 saveFileMacro := c.fileMacro.repl[0].value
2505
2506 c.file = pf.file
2507 c.fileMacro.repl[0].value = dict.sid(fmt.Sprintf("%q", c.file.Name()))
2508
2509 defer func() {
2510 c.file = saveFile
2511 c.fileMacro.repl[0].value = saveFileMacro
2512 }()
2513
2514 pf.translationPhase4(c)
2515}
2516
2517func (c *cpp) send(toks []token3) {
2518 c.in <- toks
2519 <-c.rq
2520}
2521
2522func (c *cpp) identicalReplacementLists(a, b []token3) bool {
2523 for len(a) != 0 && a[0].char == ' ' {
2524 a = a[1:]
2525 }
2526 for len(b) != 0 && b[0].char == ' ' {
2527 b = b[1:]
2528 }
2529 for len(a) != 0 && a[len(a)-1].char == ' ' {
2530 a = a[:len(a)-1]
2531 }
2532 for len(b) != 0 && b[len(b)-1].char == ' ' {
2533 b = b[:len(b)-1]
2534 }
2535 if len(a) != len(b) {
2536 return false
2537 }
2538
2539 for i, v := range a {
2540 w := b[i]
2541 if v.char != w.char || v.value != w.value {
2542 return false
2543 }
2544 }
2545 return true
2546}
2547
2548func stringConst(ctx *context, t cppToken) string {
2549 s := t.String()
2550 switch t.char {
2551 case LONGSTRINGLITERAL:
2552 s = s[1:] // Remove leading 'L'.
2553 fallthrough
2554 case STRINGLITERAL:
2555 var buf bytes.Buffer
2556 for i := 1; i < len(s)-1; {
2557 switch c := s[i]; c {
2558 case '\\':
2559 r, n := decodeEscapeSequence(ctx, t, s[i:])
2560 switch {
2561 case r < 0:
2562 buf.WriteByte(byte(-r))
2563 default:
2564 buf.WriteRune(r)
2565 }
2566 i += n
2567 default:
2568 buf.WriteByte(c)
2569 i++
2570 }
2571 }
2572 return buf.String()
2573 }
2574 panic(internalError())
2575}
2576
2577// -------------------------------------------------------- Translation phase 4
2578
2579// [0], 5.1.1.2, 4
2580//
2581// Preprocessing directives are executed, macro invocations are expanded, and
2582// _Pragma unary operator expressions are executed. If a character sequence
2583// that matches the syntax of a universal character name is produced by token
2584// concatenation (6.10.3.3), the behavior is undefined. A #include
2585// preprocessing directive causes the named header or source file to be
2586// processed from phase 1 through phase 4, recursively. All preprocessing
2587// directives are then deleted.
2588func (c *cpp) translationPhase4(in []source) chan *[]token4 {
2589 c.rq = make(chan struct{}) // Must be unbufferred
2590 c.in = make(chan []token3) // Must be unbufferred
2591 c.out = make(chan *[]token4, 10) //DONE benchmark tuned
2592
2593 go func() {
2594 defer close(c.out)
2595
2596 c.expand(c, c, false)
2597 }()
2598
2599 go func() {
2600 defer close(c.in)
2601
2602 for _, v := range in {
2603 pf, err := v.ppFile()
2604 if err != nil {
2605 c.err(nil, "%s", err)
2606 break
2607 }
2608
2609 c.file = pf.file
2610 c.fileMacro.repl[0].value = dict.sid(fmt.Sprintf("%q", c.file.Name()))
2611 pf.translationPhase4(c)
2612 }
2613 }()
2614
2615 return c.out
2616}
2617
2618type ppErrorDirective struct {
2619 toks []token3
2620 msg []token3
2621}
2622
2623func (n *ppErrorDirective) getToks() []token3 { return n.toks }
2624
2625func (n *ppErrorDirective) translationPhase4(c *cpp) {
2626 var b strings.Builder
2627 for _, v := range n.msg {
2628 b.WriteString(v.String())
2629 }
2630 c.err(n.toks[0], "%s", strings.TrimSpace(b.String()))
2631}
2632
2633type ppPragmaDirective struct {
2634 toks []token3
2635 args []token3
2636}
2637
2638func (n *ppPragmaDirective) getToks() []token3 { return n.toks }
2639
2640func (n *ppPragmaDirective) translationPhase4(c *cpp) { parsePragma(c, n.args) }
2641
2642func parsePragma(c *cpp, args0 []token3) {
2643 if len(args0) == 1 { // \n
2644 return
2645 }
2646
2647 if t := args0[0]; t.char == IDENTIFIER && t.value == idSTDC {
2648 p := t
2649 p.char = PRAGMASTDC
2650 p.value = idPragmaSTDC
2651 send := []token3{p, {char: ' ', value: idSpace, src: idSpace, pos: t.pos}}
2652 args := ltrim3(args0[1:])
2653 if len(args) == 0 {
2654 c.err(args[0], "expected argument of STDC")
2655 return
2656 }
2657
2658 if t = args[0]; t.char != IDENTIFIER {
2659 c.err(t, "expected identifier")
2660 return
2661 }
2662
2663 switch t.value {
2664 case idFPContract, idFenvAccess, idCxLimitedRange:
2665 // ok
2666 default:
2667 c.err(t, "expected FP_CONTRACT or FENV_ACCESS or CX_LIMITED_RANGE")
2668 return
2669 }
2670
2671 args = ltrim3(args[1:])
2672 if len(args) == 0 {
2673 c.err(args[0], "expected ON or OFF or DEFAULT")
2674 return
2675 }
2676
2677 if t = args[0]; t.char != IDENTIFIER {
2678 c.err(t, "expected identifier")
2679 return
2680 }
2681
2682 switch t.value {
2683 case idOn, idOff, idDefault:
2684 c.writes(c.cppToks(append(send, args0...)))
2685 default:
2686 c.err(t, "expected ON or OFF or DEFAULT")
2687 return
2688 }
2689 }
2690
2691 if c.ctx.cfg.PragmaHandler == nil {
2692 return
2693 }
2694
2695 var toks []cppToken
2696 for _, v := range args0[:len(args0)-1] {
2697 toks = append(toks, cppToken{token4: token4{file: c.file, token3: v}})
2698 }
2699 if len(toks) == 0 {
2700 return
2701 }
2702
2703 var toks2 []Token
2704 var sep StringID
2705 for _, tok := range toks {
2706 switch tok.char {
2707 case ' ', '\n':
2708 if c.ctx.cfg.PreserveOnlyLastNonBlankSeparator {
2709 if strings.TrimSpace(tok.value.String()) != "" {
2710 sep = tok.value
2711 }
2712 break
2713 }
2714
2715 switch {
2716 case sep != 0:
2717 sep = dict.sid(sep.String() + tok.String()) //TODO quadratic
2718 default:
2719 sep = tok.value
2720 }
2721 default:
2722 var t Token
2723 t.Rune = tok.char
2724 t.Sep = sep
2725 t.Value = tok.value
2726 t.file = tok.file
2727 t.pos = tok.pos
2728 toks2 = append(toks2, t)
2729 sep = 0
2730 }
2731 }
2732 if len(toks2) == 0 {
2733 return
2734 }
2735
2736 // dbg("%v: %q", c.file.PositionFor(args0[0].Pos(), true), tokStr(toks2, "|"))
2737 c.ctx.cfg.PragmaHandler(&pragma{tok: toks[0], c: c}, toks2)
2738}
2739
2740type ppNonDirective struct {
2741 toks []token3
2742}
2743
2744func (n *ppNonDirective) getToks() []token3 { return n.toks }
2745
2746func (n *ppNonDirective) translationPhase4(c *cpp) {
2747 // nop
2748}
2749
2750type ppTextLine struct {
2751 toks []token3
2752}
2753
2754func (n *ppTextLine) getToks() []token3 { return n.toks }
2755
2756func (n *ppTextLine) translationPhase4(c *cpp) { c.send(n.toks) }
2757
2758type ppLineDirective struct {
2759 toks []token3
2760 args []token3
2761 nextPos int
2762}
2763
2764func (n *ppLineDirective) getToks() []token3 { return n.toks }
2765
2766func (n *ppLineDirective) translationPhase4(c *cpp) {
2767 toks := expandArgs(c, n.args)
2768 if len(toks) == 0 {
2769 return
2770 }
2771
2772 switch t := toks[0]; t.char {
2773 case PPNUMBER:
2774 ln, err := strconv.ParseInt(t.String(), 10, 31)
2775 if err != nil || ln < 1 {
2776 c.err(t, "expected positive integer less or equal 2147483647")
2777 return
2778 }
2779
2780 for len(toks) != 0 && toks[0].char == ' ' {
2781 toks = toks[1:]
2782 }
2783 if len(toks) == 1 {
2784 c.file.AddLineInfo(int(n.nextPos)-1, c.file.Name(), int(ln))
2785 return
2786 }
2787
2788 toks = toks[1:]
2789 for len(toks) != 0 && toks[0].char == ' ' {
2790 toks = toks[1:]
2791 }
2792 if len(toks) == 0 {
2793 c.file.AddLineInfo(int(n.nextPos)-1, c.file.Name(), int(ln))
2794 return
2795 }
2796
2797 switch t := toks[0]; t.char {
2798 case STRINGLITERAL:
2799 s := t.String()
2800 s = s[1 : len(s)-1]
2801 c.file.AddLineInfo(int(n.nextPos)-1, s, int(ln))
2802 c.fileMacro.repl[0].value = t.value
2803 for len(toks) != 0 && toks[0].char == ' ' {
2804 toks = toks[1:]
2805 }
2806 if len(toks) != 0 && c.ctx.cfg.RejectLineExtraTokens {
2807 c.err(toks[0], "expected new-line")
2808 }
2809 default:
2810 c.err(t, "expected string literal")
2811 return
2812 }
2813 default:
2814 c.err(toks[0], "expected integer literal")
2815 return
2816 }
2817}
2818
2819func expandArgs(c *cpp, args []token3) []cppToken {
2820 var w cppWriter
2821 var toks []cppToken
2822 for _, v := range args {
2823 toks = append(toks, cppToken{token4: token4{file: c.file, token3: v}})
2824 }
2825 c.expand(&cppReader{buf: toks}, &w, true)
2826 return w.toks
2827}
2828
2829type ppUndefDirective struct {
2830 name token3
2831 toks []token3
2832}
2833
2834func (n *ppUndefDirective) getToks() []token3 { return n.toks }
2835
2836func (n *ppUndefDirective) translationPhase4(c *cpp) {
2837 nm := n.name.value
2838 if _, ok := protectedMacros[nm]; ok || nm == idDefined {
2839 c.err(n.name, "cannot undefine a protected name")
2840 return
2841 }
2842
2843 // dbg("#undef %s", nm)
2844 delete(c.macros, nm)
2845}
2846
2847type ppIfdefDirective struct {
2848 name StringID
2849 toks []token3
2850}
2851
2852func (n *ppIfdefDirective) evalInclusionCondition(c *cpp) bool { _, ok := c.macros[n.name]; return ok }
2853
2854func (n *ppIfdefDirective) getToks() []token3 { return n.toks }
2855
2856type ppIfndefDirective struct {
2857 name StringID
2858 toks []token3
2859}
2860
2861func (n *ppIfndefDirective) evalInclusionCondition(c *cpp) bool {
2862 _, ok := c.macros[n.name]
2863 return !ok
2864}
2865
2866func (n *ppIfndefDirective) getToks() []token3 { return n.toks }
2867
2868type ppIfDirective struct {
2869 toks []token3
2870 expr []token3
2871}
2872
2873func (n *ppIfDirective) getToks() []token3 { return n.toks }
2874
2875func (n *ppIfDirective) evalInclusionCondition(c *cpp) bool {
2876 return c.evalInclusionCondition(n.expr)
2877}
2878
2879type ppDefineObjectMacroDirective struct {
2880 name token3
2881 toks []token3
2882 replacementList []token3
2883}
2884
2885func (n *ppDefineObjectMacroDirective) getToks() []token3 { return n.toks }
2886
2887func (n *ppDefineObjectMacroDirective) translationPhase4(c *cpp) {
2888 nm := n.name.value
2889 m := c.macros[nm]
2890 if m != nil {
2891 if _, ok := protectedMacros[nm]; ok || nm == idDefined {
2892 c.err(n.name, "cannot define protected name")
2893 return
2894 }
2895
2896 if m.isFnLike {
2897 c.err(n.name, "redefinition of a function-like macro with an object-like one")
2898 }
2899
2900 if !c.identicalReplacementLists(n.replacementList, m.repl) && c.ctx.cfg.RejectIncompatibleMacroRedef {
2901 c.err(n.name, "redefinition with different replacement list")
2902 return
2903 }
2904 }
2905
2906 // find first non-blank token to claim as our location
2907 var pos int32
2908 for _, t := range n.toks {
2909 if t.char != ' ' {
2910 pos = t.pos
2911 break
2912 }
2913 }
2914
2915 // dbg("#define %s %s // %v", n.name, tokStr(n.replacementList, " "), c.file.PositionFor(n.name.Pos(), true))
2916 c.macros[nm] = &Macro{pos: pos, name: token4{token3: n.name, file: c.file}, repl: n.replacementList}
2917 if nm != idGNUC {
2918 return
2919 }
2920
2921 c.ctx.keywords = gccKeywords
2922}
2923
2924type ppDefineFunctionMacroDirective struct {
2925 identifierList []token3
2926 toks []token3
2927 replacementList []token3
2928
2929 name token3
2930
2931 namedVariadic bool // foo..., note no comma before ellipsis.
2932 variadic bool
2933}
2934
2935func (n *ppDefineFunctionMacroDirective) getToks() []token3 { return n.toks }
2936
2937func (n *ppDefineFunctionMacroDirective) translationPhase4(c *cpp) {
2938 nm := n.name.value
2939 m := c.macros[nm]
2940 if m != nil {
2941 if _, ok := protectedMacros[nm]; ok || nm == idDefined {
2942 c.err(n.name, "cannot define protected name")
2943 return
2944 }
2945
2946 if !m.isFnLike && c.ctx.cfg.RejectIncompatibleMacroRedef {
2947 c.err(n.name, "redefinition of an object-like macro with a function-like one")
2948 return
2949 }
2950
2951 ok := len(m.fp) == len(n.identifierList)
2952 if ok {
2953 for i, v := range m.fp {
2954 if v != n.identifierList[i].value {
2955 ok = false
2956 break
2957 }
2958 }
2959 }
2960 if !ok && (len(n.replacementList) != 0 || len(m.repl) != 0) && c.ctx.cfg.RejectIncompatibleMacroRedef {
2961 c.err(n.name, "redefinition with different formal parameters")
2962 return
2963 }
2964
2965 if !c.identicalReplacementLists(n.replacementList, m.repl) && c.ctx.cfg.RejectIncompatibleMacroRedef {
2966 c.err(n.name, "redefinition with different replacement list")
2967 return
2968 }
2969
2970 if m.variadic != n.variadic && c.ctx.cfg.RejectIncompatibleMacroRedef {
2971 c.err(n.name, "redefinition differs in being variadic")
2972 return
2973 }
2974 }
2975 nms := map[StringID]struct{}{}
2976 for _, v := range n.identifierList {
2977 if _, ok := nms[v.value]; ok {
2978 c.err(v, "duplicate identifier %s", v.value)
2979 }
2980 }
2981 var fp []StringID
2982 for _, v := range n.identifierList {
2983 fp = append(fp, v.value)
2984 }
2985 // dbg("#define %s %s // %v", n.name, tokStr(n.replacementList, " "), c.file.PositionFor(n.name.Pos(), true))
2986 c.macros[nm] = &Macro{fp: fp, isFnLike: true, name: token4{token3: n.name, file: c.file}, repl: n.replacementList, variadic: n.variadic, namedVariadic: n.namedVariadic}
2987}
2988
2989// [0], 6.10.1
2990//
2991// elif-group:
2992// # elif constant-expression new-line group_opt
2993type ppElifGroup struct {
2994 elif *ppElifDirective
2995 groups []ppGroup
2996}
2997
2998func (n *ppElifGroup) evalInclusionCondition(c *cpp) bool {
2999 if !c.evalInclusionCondition(n.elif.expr) {
3000 return false
3001 }
3002
3003 for _, v := range n.groups {
3004 v.translationPhase4(c)
3005 }
3006 return true
3007}
3008
3009// [0], 6.10.1
3010//
3011// else-group:
3012// # else new-line group_opt
3013type ppElseGroup struct {
3014 elseLine *ppElseDirective
3015 groups []ppGroup
3016}
3017
3018func (n *ppElseGroup) translationPhase4(c *cpp) {
3019 if n == nil {
3020 return
3021 }
3022
3023 for _, v := range n.groups {
3024 v.translationPhase4(c)
3025 }
3026}
3027
3028// [0], 6.10.1
3029//
3030// PreprocessingFile:
3031// GroupOpt
3032type ppFile struct {
3033 file *tokenFile
3034 groups []ppGroup
3035}
3036
3037func (n *ppFile) translationPhase4(c *cpp) {
3038 c.ctx.tuSourcesAdd(1)
3039 if f := n.file; f != nil {
3040 c.ctx.tuSizeAdd(int64(f.Size()))
3041 }
3042 for _, v := range n.groups {
3043 v.translationPhase4(c)
3044 }
3045}
3046
3047// [0], 6.10.1
3048//
3049// group-part:
3050// if-section
3051// control-line
3052// text-line
3053// # non-directive
3054type ppGroup interface {
3055 translationPhase4(*cpp)
3056}
3057
3058// [0], 6.10.1
3059//
3060// if-group:
3061// # if constant-expression new-line group opt
3062// # ifdef identifier new-line group opt
3063// # ifndef identifier new-line group opt
3064type ppIfGroup struct {
3065 directive ppIfGroupDirective
3066 groups []ppGroup
3067}
3068
3069func (n *ppIfGroup) evalInclusionCondition(c *cpp) bool {
3070 if !n.directive.evalInclusionCondition(c) {
3071 return false
3072 }
3073
3074 for _, v := range n.groups {
3075 v.translationPhase4(c)
3076 }
3077 return true
3078}
3079
3080// [0], 6.10.1
3081//
3082// if-section:
3083// if-group elif-groups_opt else-group_opt endif-line
3084type ppIfSection struct {
3085 ifGroup *ppIfGroup
3086 elifGroups []*ppElifGroup
3087 elseGroup *ppElseGroup
3088 endifLine *ppEndifDirective
3089}
3090
3091func (n *ppIfSection) translationPhase4(c *cpp) {
3092 if !n.ifGroup.evalInclusionCondition(c) {
3093 for _, v := range n.elifGroups {
3094 if v.evalInclusionCondition(c) {
3095 return
3096 }
3097 }
3098
3099 n.elseGroup.translationPhase4(c)
3100 }
3101}
Note: See TracBrowser for help on using the repository browser.