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 |
|
---|
5 | package cc // import "modernc.org/cc/v3"
|
---|
6 |
|
---|
7 | import (
|
---|
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 |
|
---|
23 | const (
|
---|
24 | maxIncludeLevel = 200 // gcc, std is at least 15.
|
---|
25 | )
|
---|
26 |
|
---|
27 | var (
|
---|
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 |
|
---|
76 | type tokenReader interface {
|
---|
77 | read() (cppToken, bool)
|
---|
78 | unget(cppToken)
|
---|
79 | ungets([]cppToken)
|
---|
80 | }
|
---|
81 |
|
---|
82 | type tokenWriter interface {
|
---|
83 | write(cppToken)
|
---|
84 | writes([]cppToken)
|
---|
85 | }
|
---|
86 |
|
---|
87 | // token4 is produced by translation phase 4.
|
---|
88 | type token4 struct {
|
---|
89 | file *tokenFile //TODO sort fields
|
---|
90 | token3
|
---|
91 | }
|
---|
92 |
|
---|
93 | func (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 |
|
---|
100 | type hideSet map[StringID]struct{}
|
---|
101 |
|
---|
102 | type cppToken struct {
|
---|
103 | token4
|
---|
104 | hs hideSet
|
---|
105 | }
|
---|
106 |
|
---|
107 | func (t *cppToken) has(nm StringID) bool { _, ok := t.hs[nm]; return ok }
|
---|
108 |
|
---|
109 | type cppWriter struct {
|
---|
110 | toks []cppToken
|
---|
111 | }
|
---|
112 |
|
---|
113 | func (w *cppWriter) write(tok cppToken) { w.toks = append(w.toks, tok) }
|
---|
114 | func (w *cppWriter) writes(toks []cppToken) { w.toks = append(w.toks, toks...) }
|
---|
115 |
|
---|
116 | type ungetBuf []cppToken
|
---|
117 |
|
---|
118 | func (u *ungetBuf) unget(t cppToken) { *u = append(*u, t) }
|
---|
119 |
|
---|
120 | func (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 | }
|
---|
127 | func (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 |
|
---|
135 | func 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 |
|
---|
146 | func 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 |
|
---|
155 | type cppReader struct {
|
---|
156 | buf []cppToken
|
---|
157 | ungetBuf
|
---|
158 | }
|
---|
159 |
|
---|
160 | func (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 |
|
---|
174 | type cppScanner []cppToken
|
---|
175 |
|
---|
176 | func (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 |
|
---|
185 | func (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 |
|
---|
195 | func (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.
|
---|
204 | type 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.
|
---|
218 | func (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.
|
---|
226 | func (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.
|
---|
230 | func (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.
|
---|
243 | func (m *Macro) IsFnLike() bool { return m.isFnLike }
|
---|
244 |
|
---|
245 | func (m *Macro) isNamedVariadicParam(nm StringID) bool {
|
---|
246 | return m.namedVariadic && nm == m.fp[len(m.fp)-1]
|
---|
247 | }
|
---|
248 |
|
---|
249 | func (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 |
|
---|
278 | func (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 |
|
---|
288 | type 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 |
|
---|
316 | func 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 |
|
---|
350 | func (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 |
|
---|
359 | func (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 |
|
---|
373 | func (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 |
|
---|
400 | func (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 |
|
---|
495 | func ltrim4(toks []token4) []token4 {
|
---|
496 | for len(toks) != 0 && toks[0].char == ' ' {
|
---|
497 | toks = toks[1:]
|
---|
498 | }
|
---|
499 | return toks
|
---|
500 | }
|
---|
501 |
|
---|
502 | func (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 | // }
|
---|
533 | func (c *cpp) expand(ts tokenReader, w tokenWriter, expandDefined bool) {
|
---|
534 | // trc("==== expand enter")
|
---|
535 | start:
|
---|
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 |
|
---|
713 | func (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 |
|
---|
788 | func (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.
|
---|
915 | func (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))
|
---|
921 | start:
|
---|
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 | // }
|
---|
1073 | func (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
|
---|
1099 | func (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 |
|
---|
1161 | func (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 |
|
---|
1171 | func (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 |
|
---|
1185 | func (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 |
|
---|
1225 | func (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
|
---|
1247 | func (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 |
|
---|
1261 | func (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 |
|
---|
1277 | func (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
|
---|
1314 | func (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 | // = *= /= %= += -= <<= >>= &= ^= |=
|
---|
1333 | func (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
|
---|
1342 | func (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 |
|
---|
1379 | func (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 |
|
---|
1390 | func (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
|
---|
1406 | func (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
|
---|
1426 | func (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 |
|
---|
1441 | func (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
|
---|
1456 | func (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
|
---|
1488 | func (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
|
---|
1520 | func (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
|
---|
1553 | func (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
|
---|
1620 | func (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
|
---|
1727 | func (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
|
---|
1785 | func (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
|
---|
1844 | func (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 | // + - ~ !
|
---|
1965 | func (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 )
|
---|
2024 | func (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
|
---|
2089 | func (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 |
|
---|
2147 | func 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}+
|
---|
2182 | func 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
|
---|
2235 | loop:
|
---|
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}
|
---|
2254 | func 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}
|
---|
2270 | func 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 |
|
---|
2278 | func 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 |
|
---|
2288 | func (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 |
|
---|
2298 | type ppLine interface {
|
---|
2299 | getToks() []token3
|
---|
2300 | }
|
---|
2301 |
|
---|
2302 | type ppIfGroupDirective interface {
|
---|
2303 | evalInclusionCondition(*cpp) bool
|
---|
2304 | }
|
---|
2305 |
|
---|
2306 | type ppElifDirective struct {
|
---|
2307 | toks []token3
|
---|
2308 | expr []token3
|
---|
2309 | }
|
---|
2310 |
|
---|
2311 | func (n *ppElifDirective) getToks() []token3 { return n.toks }
|
---|
2312 |
|
---|
2313 | type ppElseDirective struct {
|
---|
2314 | toks []token3
|
---|
2315 | }
|
---|
2316 |
|
---|
2317 | func (n *ppElseDirective) getToks() []token3 { return n.toks }
|
---|
2318 |
|
---|
2319 | type ppEndifDirective struct {
|
---|
2320 | toks []token3
|
---|
2321 | }
|
---|
2322 |
|
---|
2323 | func (n *ppEndifDirective) getToks() []token3 { return n.toks }
|
---|
2324 |
|
---|
2325 | type ppEmptyDirective struct {
|
---|
2326 | toks []token3
|
---|
2327 | }
|
---|
2328 |
|
---|
2329 | func (n *ppEmptyDirective) getToks() []token3 { return n.toks }
|
---|
2330 |
|
---|
2331 | func (n *ppEmptyDirective) translationPhase4(c *cpp) {
|
---|
2332 | // nop
|
---|
2333 | }
|
---|
2334 |
|
---|
2335 | type ppIncludeDirective struct {
|
---|
2336 | arg []token3
|
---|
2337 | toks []token3
|
---|
2338 |
|
---|
2339 | includeNext bool // false: #include, true: #include_next
|
---|
2340 | }
|
---|
2341 |
|
---|
2342 | func (n *ppIncludeDirective) getToks() []token3 { return n.toks }
|
---|
2343 |
|
---|
2344 | func (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 |
|
---|
2517 | func (c *cpp) send(toks []token3) {
|
---|
2518 | c.in <- toks
|
---|
2519 | <-c.rq
|
---|
2520 | }
|
---|
2521 |
|
---|
2522 | func (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 |
|
---|
2548 | func 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.
|
---|
2588 | func (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 |
|
---|
2618 | type ppErrorDirective struct {
|
---|
2619 | toks []token3
|
---|
2620 | msg []token3
|
---|
2621 | }
|
---|
2622 |
|
---|
2623 | func (n *ppErrorDirective) getToks() []token3 { return n.toks }
|
---|
2624 |
|
---|
2625 | func (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 |
|
---|
2633 | type ppPragmaDirective struct {
|
---|
2634 | toks []token3
|
---|
2635 | args []token3
|
---|
2636 | }
|
---|
2637 |
|
---|
2638 | func (n *ppPragmaDirective) getToks() []token3 { return n.toks }
|
---|
2639 |
|
---|
2640 | func (n *ppPragmaDirective) translationPhase4(c *cpp) { parsePragma(c, n.args) }
|
---|
2641 |
|
---|
2642 | func 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 |
|
---|
2740 | type ppNonDirective struct {
|
---|
2741 | toks []token3
|
---|
2742 | }
|
---|
2743 |
|
---|
2744 | func (n *ppNonDirective) getToks() []token3 { return n.toks }
|
---|
2745 |
|
---|
2746 | func (n *ppNonDirective) translationPhase4(c *cpp) {
|
---|
2747 | // nop
|
---|
2748 | }
|
---|
2749 |
|
---|
2750 | type ppTextLine struct {
|
---|
2751 | toks []token3
|
---|
2752 | }
|
---|
2753 |
|
---|
2754 | func (n *ppTextLine) getToks() []token3 { return n.toks }
|
---|
2755 |
|
---|
2756 | func (n *ppTextLine) translationPhase4(c *cpp) { c.send(n.toks) }
|
---|
2757 |
|
---|
2758 | type ppLineDirective struct {
|
---|
2759 | toks []token3
|
---|
2760 | args []token3
|
---|
2761 | nextPos int
|
---|
2762 | }
|
---|
2763 |
|
---|
2764 | func (n *ppLineDirective) getToks() []token3 { return n.toks }
|
---|
2765 |
|
---|
2766 | func (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 |
|
---|
2819 | func 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 |
|
---|
2829 | type ppUndefDirective struct {
|
---|
2830 | name token3
|
---|
2831 | toks []token3
|
---|
2832 | }
|
---|
2833 |
|
---|
2834 | func (n *ppUndefDirective) getToks() []token3 { return n.toks }
|
---|
2835 |
|
---|
2836 | func (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 |
|
---|
2847 | type ppIfdefDirective struct {
|
---|
2848 | name StringID
|
---|
2849 | toks []token3
|
---|
2850 | }
|
---|
2851 |
|
---|
2852 | func (n *ppIfdefDirective) evalInclusionCondition(c *cpp) bool { _, ok := c.macros[n.name]; return ok }
|
---|
2853 |
|
---|
2854 | func (n *ppIfdefDirective) getToks() []token3 { return n.toks }
|
---|
2855 |
|
---|
2856 | type ppIfndefDirective struct {
|
---|
2857 | name StringID
|
---|
2858 | toks []token3
|
---|
2859 | }
|
---|
2860 |
|
---|
2861 | func (n *ppIfndefDirective) evalInclusionCondition(c *cpp) bool {
|
---|
2862 | _, ok := c.macros[n.name]
|
---|
2863 | return !ok
|
---|
2864 | }
|
---|
2865 |
|
---|
2866 | func (n *ppIfndefDirective) getToks() []token3 { return n.toks }
|
---|
2867 |
|
---|
2868 | type ppIfDirective struct {
|
---|
2869 | toks []token3
|
---|
2870 | expr []token3
|
---|
2871 | }
|
---|
2872 |
|
---|
2873 | func (n *ppIfDirective) getToks() []token3 { return n.toks }
|
---|
2874 |
|
---|
2875 | func (n *ppIfDirective) evalInclusionCondition(c *cpp) bool {
|
---|
2876 | return c.evalInclusionCondition(n.expr)
|
---|
2877 | }
|
---|
2878 |
|
---|
2879 | type ppDefineObjectMacroDirective struct {
|
---|
2880 | name token3
|
---|
2881 | toks []token3
|
---|
2882 | replacementList []token3
|
---|
2883 | }
|
---|
2884 |
|
---|
2885 | func (n *ppDefineObjectMacroDirective) getToks() []token3 { return n.toks }
|
---|
2886 |
|
---|
2887 | func (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 |
|
---|
2924 | type 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 |
|
---|
2935 | func (n *ppDefineFunctionMacroDirective) getToks() []token3 { return n.toks }
|
---|
2936 |
|
---|
2937 | func (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
|
---|
2993 | type ppElifGroup struct {
|
---|
2994 | elif *ppElifDirective
|
---|
2995 | groups []ppGroup
|
---|
2996 | }
|
---|
2997 |
|
---|
2998 | func (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
|
---|
3013 | type ppElseGroup struct {
|
---|
3014 | elseLine *ppElseDirective
|
---|
3015 | groups []ppGroup
|
---|
3016 | }
|
---|
3017 |
|
---|
3018 | func (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
|
---|
3032 | type ppFile struct {
|
---|
3033 | file *tokenFile
|
---|
3034 | groups []ppGroup
|
---|
3035 | }
|
---|
3036 |
|
---|
3037 | func (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
|
---|
3054 | type 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
|
---|
3064 | type ppIfGroup struct {
|
---|
3065 | directive ppIfGroupDirective
|
---|
3066 | groups []ppGroup
|
---|
3067 | }
|
---|
3068 |
|
---|
3069 | func (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
|
---|
3084 | type ppIfSection struct {
|
---|
3085 | ifGroup *ppIfGroup
|
---|
3086 | elifGroups []*ppElifGroup
|
---|
3087 | elseGroup *ppElseGroup
|
---|
3088 | endifLine *ppEndifDirective
|
---|
3089 | }
|
---|
3090 |
|
---|
3091 | func (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 | }
|
---|