cc.go (29618B)
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 //TODO https://todo.sr.ht/~mcf/cc-issues/34 6 //TODO http://mcpp.sourceforge.net/ "Provides a validation suite to test C/C++ preprocessor's conformance and quality comprehensively." 7 8 //go:generate rm -f lexer.go 9 //go:generate golex -o lexer.go lexer.l 10 11 //go:generate rm -f ast.go 12 //go:generate yy -o /dev/null -position -astImport "\"fmt\"\n\n\"modernc.org/token\"" -prettyString PrettyString -kind Case -noListKind -noPrivateHelpers -forceOptPos parser.yy 13 14 //go:generate stringer -output stringer.go -linecomment -type=Kind,Linkage 15 16 //go:generate sh -c "go test -run ^Example |fe" 17 18 // Package cc is a C99 compiler front end (Work in progress). 19 // 20 // Installation 21 // 22 // To install/update cc/v3 invoke: 23 // 24 // $ go get [-u] modernc.org/cc/v3 25 // 26 // Online documentation 27 // 28 // See https://godoc.org/modernc.org/cc/v3. 29 // 30 // Status 31 // 32 // Most of the functionality is now working. 33 // 34 // Supported platforms 35 // 36 // The code is known to work on Darwin, Linux and Windows, but the supported 37 // features may vary. 38 // 39 // Links 40 // 41 // Referenced from elsewhere: 42 // 43 // [0]: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf 44 // [1]: https://www.spinellis.gr/blog/20060626/cpp.algo.pdf 45 // [2]: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf 46 // [3]: http://gallium.inria.fr/~fpottier/publis/jourdan-fpottier-2016.pdf 47 // [4]: https://gcc.gnu.org/onlinedocs/gcc-8.3.0/gcc/Attribute-Syntax.html#Attribute-Syntax 48 package cc // import "modernc.org/cc/v3" 49 50 import ( 51 "fmt" 52 goscanner "go/scanner" 53 gotoken "go/token" 54 "hash/maphash" 55 "io" 56 "math" 57 "os" 58 "os/exec" 59 "reflect" 60 "regexp" 61 "runtime" 62 "sort" 63 "strconv" 64 "strings" 65 "sync" 66 "sync/atomic" 67 68 "modernc.org/strutil" 69 "modernc.org/token" 70 ) 71 72 const ( 73 scopeParent StringID = -iota - 1 74 scopeSkip 75 ) 76 77 var ( 78 _ Pragma = (*pragma)(nil) 79 80 cache = newPPCache() 81 dict = newDictionary() 82 dictStrings [math.MaxUint8 + 1]string 83 noPos token.Position 84 85 debugIncludePaths bool 86 debugWorkingDir bool 87 isTesting bool 88 isTestingMingw bool 89 90 idPtrdiffT = dict.sid("ptrdiff_t") 91 idSizeT = dict.sid("size_t") 92 idWCharT = dict.sid("wchar_t") 93 94 token4Pool = sync.Pool{New: func() interface{} { r := make([]token4, 0); return &r }} //DONE benchmrk tuned capacity 95 tokenPool = sync.Pool{New: func() interface{} { r := make([]Token, 0); return &r }} //DONE benchmrk tuned capacity 96 97 printHooks = strutil.PrettyPrintHooks{ 98 reflect.TypeOf(Token{}): func(f strutil.Formatter, v interface{}, prefix, suffix string) { 99 t := v.(Token) 100 if (t == Token{}) { 101 return 102 } 103 104 f.Format(prefix) 105 r := t.Rune 106 if p := t.Position(); p.IsValid() { 107 f.Format("%v: ", p) 108 } 109 s := tokName(r) 110 if x := s[0]; x >= '0' && x <= '9' { 111 s = strconv.QuoteRune(r) 112 } 113 f.Format("%s", s) 114 if s := t.Value.String(); len(s) != 0 { 115 f.Format(" %q", s) 116 } 117 f.Format(suffix) 118 }, 119 reflect.TypeOf((*operand)(nil)): func(f strutil.Formatter, v interface{}, prefix, suffix string) { 120 op := v.(*operand) 121 f.Format(prefix) 122 f.Format("[%v %T(%[2]v)]", op.Type(), op.Value()) 123 f.Format(suffix) 124 }, 125 } 126 ) 127 128 func todo(s string, args ...interface{}) string { //TODO- 129 switch { 130 case s == "": 131 s = fmt.Sprintf(strings.Repeat("%v ", len(args)), args...) 132 default: 133 s = fmt.Sprintf(s, args...) 134 } 135 pc, fn, fl, _ := runtime.Caller(1) 136 f := runtime.FuncForPC(pc) 137 var fns string 138 if f != nil { 139 fns = f.Name() 140 if x := strings.LastIndex(fns, "."); x > 0 { 141 fns = fns[x+1:] 142 } 143 } 144 r := fmt.Sprintf("%s:%d:%s: TODOTODO %s", fn, fl, fns, s) //TODOOK 145 fmt.Fprintf(os.Stdout, "%s\n", r) 146 os.Stdout.Sync() 147 return r 148 } 149 150 func trc(s string, args ...interface{}) string { //TODO- 151 switch { 152 case s == "": 153 s = fmt.Sprintf(strings.Repeat("%v ", len(args)), args...) 154 default: 155 s = fmt.Sprintf(s, args...) 156 } 157 pc, fn, fl, _ := runtime.Caller(1) 158 f := runtime.FuncForPC(pc) 159 var fns string 160 if f != nil { 161 fns = f.Name() 162 if x := strings.LastIndex(fns, "."); x > 0 { 163 fns = fns[x+1:] 164 } 165 } 166 r := fmt.Sprintf("%s:%d:%s: TRC %s", fn, fl, fns, s) 167 fmt.Fprintf(os.Stdout, "%s\n", r) 168 os.Stdout.Sync() 169 return r 170 } 171 172 func origin(skip int) string { 173 pc, fn, fl, _ := runtime.Caller(skip) 174 f := runtime.FuncForPC(pc) 175 var fns string 176 if f != nil { 177 fns = f.Name() 178 if x := strings.LastIndex(fns, "."); x > 0 { 179 fns = fns[x+1:] 180 } 181 } 182 return fmt.Sprintf("%s:%d:%s", fn, fl, fns) 183 } 184 185 // String returns a StringID for a given value. 186 func String(s string) StringID { 187 return dict.sid(s) 188 } 189 190 // Linkage represents identifier linkage. 191 // 192 // [0]6.2.2: An identifier declared in different scopes or in the same scope 193 // more than once can be made to refer to the same object or function by a 194 // process called linkage. There are three kinds of linkage: External, 195 // Internal, and None. 196 type Linkage int 197 198 // StorageClass determines storage duration. 199 // 200 // [0]6.2.4: An object has a storage duration that determines its lifetime. 201 // There are three storage durations: Static, Automatic, and Allocated. 202 type StorageClass int 203 204 // Pragma defines behavior of the object passed to Config.PragmaHandler. 205 type Pragma interface { 206 Error(msg string, args ...interface{}) // Report error. 207 MaxAligment() int // Returns the current maximum alignment. May return zero. 208 MaxInitialAligment() int // Support #pragma pack(). Returns the maximum alignment in effect at start. May return zero. 209 PopMacro(string) 210 PushMacro(string) 211 SetAlignment(n int) // Support #pragma pack(n) 212 } 213 214 type pragma struct { 215 tok cppToken 216 c *cpp 217 } 218 219 func (p *pragma) Error(msg string, args ...interface{}) { p.c.err(p.tok, msg, args...) } 220 221 func (p *pragma) MaxAligment() int { return p.c.ctx.maxAlign } 222 223 func (p *pragma) MaxInitialAligment() int { return p.c.ctx.maxAlign0 } 224 225 func (p *pragma) SetAlignment(n int) { 226 if n <= 0 { 227 p.Error("%T.SetAlignment(%d): invalid argument", p, n) 228 return 229 } 230 231 p.c.ctx.maxAlign = n 232 } 233 234 func (p *pragma) PushMacro(nm string) { 235 id := dict.sid(nm) 236 if p.c.macroStack == nil { 237 p.c.macroStack = map[StringID][]*Macro{} 238 } 239 if m := p.c.macros[id]; m != nil { 240 p.c.macroStack[id] = append(p.c.macroStack[id], p.c.macros[id]) 241 } 242 } 243 244 func (p *pragma) PopMacro(nm string) { 245 id := dict.sid(nm) 246 a := p.c.macroStack[id] 247 if n := len(a); n != 0 { 248 p.c.macros[id] = a[n-1] 249 p.c.macroStack[id] = a[:n-1] 250 } 251 } 252 253 // PrettyString returns a formatted representation of things produced by this package. 254 func PrettyString(v interface{}) string { 255 return strutil.PrettyString(v, "", "", printHooks) 256 } 257 258 // StringID is a process-unique string numeric identifier. Its zero value 259 // represents an empty string. 260 type StringID int32 261 262 // String implements fmt.Stringer. 263 func (n StringID) String() (r string) { 264 if n < 256 { 265 return dictStrings[byte(n)] 266 } 267 268 dict.mu.RLock() 269 r = dict.strings[n] 270 dict.mu.RUnlock() 271 return r 272 } 273 274 // Node is implemented by Token and all AST nodes. 275 type Node interface { 276 Position() token.Position 277 } 278 279 type noder struct{} 280 281 func (noder) Position() token.Position { panic(internalError()) } 282 283 // Scope maps identifiers to definitions. 284 type Scope map[StringID][]Node 285 286 func (s *Scope) new() (r Scope) { 287 if *s == nil { 288 *s = Scope{} 289 } 290 r = Scope{scopeParent: []Node{struct { 291 noder 292 Scope 293 }{Scope: *s}}} 294 return r 295 } 296 297 func (s *Scope) declare(nm StringID, n Node) { 298 sc := *s 299 if sc == nil { 300 *s = map[StringID][]Node{nm: {n}} 301 // t := "" 302 // if x, ok := n.(*Declarator); ok && x.IsTypedefName { 303 // t = ", typedefname" 304 // } 305 // dbg("declared %s%s at %v in scope %p", nm, t, n.Position(), *s) 306 return 307 } 308 309 switch x := n.(type) { 310 case *Declarator, *StructDeclarator, *LabeledStatement, *BlockItem: 311 // nop 312 case *StructOrUnionSpecifier, *EnumSpecifier, *Enumerator: 313 for { 314 if _, ok := sc[scopeSkip]; !ok { 315 break 316 } 317 318 sc = sc.Parent() 319 } 320 default: 321 panic(todo("%T", x)) 322 } 323 324 sc[nm] = append(sc[nm], n) 325 // t := "" 326 // if x, ok := n.(*Declarator); ok && x.IsTypedefName { 327 // t = ", typedefname" 328 // } 329 // dbg("declared %s%s at %v in scope %p", nm, t, n.Position(), sc) 330 } 331 332 // Parent returns s's outer scope, if any. 333 func (s Scope) Parent() Scope { 334 if s == nil { 335 return nil 336 } 337 338 if x, ok := s[scopeParent]; ok { 339 return x[0].(struct { 340 noder 341 Scope 342 }).Scope 343 } 344 345 return nil 346 } 347 348 func (s *Scope) typedef(nm StringID, tok Token) *Declarator { 349 seq := tok.seq 350 for s := *s; s != nil; s = s.Parent() { 351 for _, v := range s[nm] { 352 switch x := v.(type) { 353 case *Declarator: 354 if !x.isVisible(seq) { 355 continue 356 } 357 358 if x.IsTypedefName { 359 return x 360 } 361 362 return nil 363 case *Enumerator: 364 return nil 365 case *EnumSpecifier, *StructOrUnionSpecifier, *StructDeclarator: 366 // nop 367 default: 368 panic(internalError()) 369 } 370 } 371 } 372 return nil 373 } 374 375 func (s *Scope) declarator(nm StringID, tok Token) *Declarator { 376 seq := tok.seq 377 for s := *s; s != nil; s = s.Parent() { 378 defs := s[nm] 379 for _, v := range defs { 380 switch x := v.(type) { 381 case *Declarator: 382 if !x.isVisible(seq) { 383 continue 384 } 385 386 for _, v := range defs { 387 if x, ok := v.(*Declarator); ok { 388 t := x.Type() 389 if t != nil && t.Kind() == Function { 390 if x.fnDef { 391 return x 392 } 393 394 continue 395 } 396 397 if t != nil && !x.Type().IsIncomplete() { 398 return x 399 } 400 } 401 402 } 403 return x 404 case *Enumerator: 405 return nil 406 case *EnumSpecifier, *StructOrUnionSpecifier, *StructDeclarator: 407 // nop 408 default: 409 panic(internalError()) 410 } 411 } 412 } 413 return nil 414 } 415 416 func (s *Scope) enumerator(nm StringID, tok Token) *Enumerator { 417 seq := tok.seq 418 for s := *s; s != nil; s = s.Parent() { 419 for _, v := range s[nm] { 420 switch x := v.(type) { 421 case *Declarator: 422 if !x.isVisible(seq) { 423 continue 424 } 425 426 return nil 427 case *Enumerator: 428 return x 429 case *EnumSpecifier, *StructOrUnionSpecifier, *StructDeclarator: 430 // nop 431 default: 432 panic(internalError()) 433 } 434 } 435 } 436 return nil 437 } 438 439 // Config3 amends behavior of translation phases 1 to 3. 440 type Config3 struct { 441 // If IgnoreInclude is not nil, its MatchString method will be called by the 442 // preprocessor with the argument any include directive expands to. If the call 443 // evaluates to is true the include directive will be ignored completely. 444 IgnoreInclude *regexp.Regexp 445 446 // Name of a macro to use instead of FD_ZERO. 447 // 448 // Note: Temporary solution will be removed/replaced 449 ReplaceMacroFdZero string 450 // Name of a macro to use instead of TCL_DEFAULT_DOUBLE_ROUNDING. 451 // 452 // Note: Temporary solution will be removed/replaced 453 ReplaceMacroTclDefaultDoubleRounding string // Name of a macro to use instead of TCL_DEFAULT_DOUBLE_ROUNDING. Note: Temporrary solution will be removed/replaced 454 // Name of a macro to use instead of TCL_IEEE_DOUBLE_ROUNDING. 455 // 456 // Note: Temporary solution will be removed/replaced 457 ReplaceMacroTclIeeeDoubleRounding string 458 459 WorkingDir string // Overrides os.Getwd if non empty. 460 Filesystem Filesystem // Overrides filesystem access if not empty. 461 462 MaxSourceLine int // Zero: Scanner will use default buffer. Non zero: Scanner will use max(default buffer size, MaxSourceLine). 463 464 // DisableBuiltinResolution disables resolution of undefined identifiers such 465 // that eg. abort, becomes the same as __builtin_abort, prototype of which is 466 // expected to be provided by one of the sources passed to Parse, Preprocess or 467 // Translate. 468 DisableBuiltinResolution bool 469 470 DisableTrigraphs bool // GCC ignores them unless -trigraphs is used: https://gcc.gnu.org/onlinedocs/cpp/Initial-processing.html 471 GCCStructs bool // Assume __attribute__(gcc_struct) applied to structs by default. 472 //TODO MSStructs bool // Assume __attribute__(ms_struct) applied to structs by default. 473 NoFieldAndBitfieldOverlap bool // Only bitfields can be grouped together. 474 PreserveOnlyLastNonBlankSeparator bool // If PreserveWhiteSpace is true, keep only the last white space, do not combine 475 PreserveWhiteSpace bool // Including also comments. 476 RejectElseExtraTokens bool // Pedantic: do not silently accept "#else foo". 477 RejectEndifExtraTokens bool // Pedantic: do not silently accept "#endif foo". 478 RejectFinalBackslash bool // Pedantic: do not silently accept "foo\\\n". 479 RejectFunctionMacroEmptyReplacementList bool // Pedantic: do not silently accept "#define foo(bar)\n". 480 RejectIfdefExtraTokens bool // Pedantic: do not silently accept "#ifdef foo bar". 481 RejectIfndefExtraTokens bool // Pedantic: do not silently accept "#ifndef foo bar". 482 RejectIncludeNext bool // Pedantic: do not silently accept "#include_next". 483 RejectInvalidVariadicMacros bool // Pedantic: do not silently accept "#define foo(bar...)". Standard allows only #define foo(bar, ...) 484 RejectLineExtraTokens bool // Pedantic: do not silently accept "#line 1234 \"foo.c\" bar". 485 RejectMissingFinalNewline bool // Pedantic: do not silently accept "foo\nbar". 486 RejectUndefExtraTokens bool // Pedantic: do not silently accept "#undef foo bar". 487 UnsignedEnums bool // GCC compatibility: enums with no negative values will have unsigned type. 488 } 489 490 type SharedFunctionDefinitions struct { 491 M map[*FunctionDefinition]struct{} 492 m map[sharedFunctionDefinitionKey]*FunctionDefinition //TODO 493 hash maphash.Hash 494 } 495 496 type sharedFunctionDefinitionKey struct { 497 pos StringID 498 nm StringID 499 hash uint64 500 } 501 502 // Config amends behavior of translation phase 4 and above. Instances of Config 503 // are not mutated by this package and it's safe to share/reuse them. 504 // 505 // The *Config passed to Parse or Translate should not be mutated afterwards. 506 type Config struct { 507 Config3 508 ABI ABI 509 510 PragmaHandler func(Pragma, []Token) // Called on pragmas, other than #pragma STDC ..., if non nil 511 512 // SharedFunctionDefinitions collects function definitions having the same 513 // position and definition. This can happen, for example, when a function is 514 // defined in a header file included multiple times. Either within a single 515 // translation unit or across translation units. In the later case just supply 516 // the same SharedFunctionDefinitions in Config when translating/parsing each 517 // translation unit. 518 SharedFunctionDefinitions *SharedFunctionDefinitions 519 520 // IncludeFileHandler, when non nil, is called by the preprocessor for every 521 // successfully included file. 522 IncludeFileHandler func(pos gotoken.Position, includePath string) 523 524 MaxErrors int // 0: default (10), < 0: unlimited, n: n. 525 526 CheckExternInlineFnBodies bool // Translate will consider extern inline function bodies. 527 DebugIncludePaths bool // Output to stderr. 528 DebugWorkingDir bool // Output to stderr. 529 DoNotTypecheckAsm bool 530 EnableAssignmentCompatibilityChecking bool // No such checks performed up to v3.31.0. Currently only partially implemented. 531 FixBitfieldPadding bool // Fix a bug in calculating field positions after a bitfield. 532 InjectTracingCode bool // Output to stderr. 533 LongDoubleIsDouble bool 534 PreprocessOnly bool 535 RejectAnonymousFields bool // Pedantic: do not silently accept "struct{int;}". 536 RejectCaseRange bool // Pedantic: do not silently accept "case 'a'...'z':". 537 RejectEmptyCompositeLiterals bool // Pedantic: do not silently accept "foo = (T){}". 538 RejectEmptyDeclarations bool // Pedantic: do not silently accept "int foo(){};". 539 RejectEmptyFields bool // Pedantic: do not silently accept "struct {int a;;} foo;". 540 RejectEmptyInitializerList bool // Pedantic: do not silently accept "foo f = {};". 541 RejectEmptyStructDeclaration bool // Pedantic: do not silently accept "struct{; int i}". 542 RejectEmptyStructs bool // Pedantic: do not silently accept "struct foo {};". 543 RejectIncompatibleMacroRedef bool // Pedantic: do not silently accept "#define MIN(A,B) ...\n#define MIN(a,b) ...\n" etc. 544 RejectLabelValues bool // Pedantic: do not silently accept "foo: bar(); void *ptr = &&foo;" or "goto *ptr". 545 RejectLateBinding bool // Pedantic: do not silently accept void f() { g(); } void g() {} 546 RejectMissingConditionalExpr bool // Pedantic: do not silently accept "foo = bar ? : baz;". 547 RejectMissingDeclarationSpecifiers bool // Pedantic: do not silently accept "main() {}". 548 RejectMissingFinalStructFieldSemicolon bool // Pedantic: do not silently accept "struct{int i; int j}". 549 RejectNestedFunctionDefinitions bool // Pedantic: do not silently accept nested function definitons. 550 RejectParamSemicolon bool // Pedantic: do not silently accept "int f(int a; int b)". 551 RejectStatementExpressions bool // Pedantic: do not silently accept "i = ({foo();})". 552 RejectTypeof bool // Pedantic: do not silently accept "typeof foo" or "typeof(bar*)". 553 RejectUninitializedDeclarators bool // Reject int f() { int j; return j; } 554 TrackAssignments bool // Collect a list of LHS declarators a declarator is used in RHS or as an function argument. 555 doNotSanityCheckComplexTypes bool // Testing only 556 fakeIncludes bool // Testing only. 557 ignoreErrors bool // Testing only. 558 ignoreIncludes bool // Testing only. 559 ignoreUndefinedIdentifiers bool // Testing only. 560 } 561 562 type context struct { 563 ast *AST 564 breakCtx Node 565 breaks int 566 casePromote Type 567 cases []*LabeledStatement // switch 568 cfg *Config 569 checkFn *FunctionDefinition 570 closure map[StringID]struct{} 571 continues int 572 enums map[StringID]Operand //TODO putting this in alphabetical order within the struct causes crashes in VirtualBox/386 ??? 573 goscanner.ErrorList 574 includePaths []string 575 intBits int 576 intMaxWidth int64 // Set if the preprocessor saw __INTMAX_WIDTH__. 577 keywords map[StringID]rune 578 maxAlign int // If non zero: maximum alignment of members of structures (other than zero-width bitfields). 579 maxAlign0 int 580 maxErrors int 581 mode mode 582 modes []mode 583 mu sync.Mutex 584 ptrdiffT Type 585 readDelta int 586 sizeT Type 587 structTypes map[StringID]Type 588 structs map[StructInfo]struct{} 589 switches int 590 sysIncludePaths []string 591 tuSize0 int64 // Sum of sizes of processed inputs 592 tuSources0 int32 // Number of processed inputs 593 wcharT Type 594 595 capture bool 596 evalIdentError bool 597 } 598 599 func newContext(cfg *Config) *context { 600 maxErrors := cfg.MaxErrors 601 if maxErrors == 0 { 602 maxErrors = 10 603 } 604 return &context{ 605 cfg: cfg, 606 enums: map[StringID]Operand{}, 607 keywords: keywords, 608 maxErrors: maxErrors, 609 structTypes: map[StringID]Type{}, 610 structs: map[StructInfo]struct{}{}, 611 } 612 } 613 614 func (c *context) tuSizeAdd(n int64) { atomic.AddInt64(&c.tuSize0, n) } 615 func (c *context) tuSize() int64 { return atomic.LoadInt64(&c.tuSize0) } 616 func (c *context) tuSourcesAdd(n int32) { atomic.AddInt32(&c.tuSources0, n) } 617 func (c *context) tuSources() int { return int(atomic.LoadInt32(&c.tuSources0)) } 618 619 func (c *context) stddef(nm StringID, s Scope, tok Token) Type { 620 if d := s.typedef(nm, tok); d != nil { 621 if t := d.Type(); t != nil && t.Kind() != Invalid { 622 return t 623 } 624 } 625 626 c.errNode(&tok, "front-end: undefined: %s", nm) 627 return noType 628 } 629 630 func (c *context) assignmentCompatibilityErrorCond(n Node, a, b Type) (stop bool) { 631 if !c.cfg.EnableAssignmentCompatibilityChecking { 632 return 633 } 634 635 return c.errNode(n, "invalid type combination of conditional operator: %v and %v", a, b) 636 } 637 638 func (c *context) assignmentCompatibilityError(n Node, lhs, rhs Type) (stop bool) { 639 if !c.cfg.EnableAssignmentCompatibilityChecking { 640 return 641 } 642 643 return c.errNode(n, "cannot use %v as type %v in assignment", rhs, lhs) 644 } 645 646 func (c *context) errNode(n Node, msg string, args ...interface{}) (stop bool) { 647 return c.err(n.Position(), msg, args...) 648 } 649 650 func (c *context) err(pos token.Position, msg string, args ...interface{}) (stop bool) { 651 // dbg("FAIL "+msg, args...) 652 //fmt.Printf("FAIL "+msg+"\n", args...) 653 if c.cfg.ignoreErrors { 654 return false 655 } 656 657 s := fmt.Sprintf(msg, args...) 658 c.mu.Lock() 659 max := c.maxErrors 660 switch { 661 case max < 0 || max > len(c.ErrorList): 662 c.ErrorList.Add(gotoken.Position(pos), s) 663 default: 664 stop = true 665 } 666 c.mu.Unlock() 667 return stop 668 } 669 670 func (c *context) errs(list goscanner.ErrorList) (stop bool) { 671 c.mu.Lock() 672 673 defer c.mu.Unlock() 674 675 max := c.maxErrors 676 for _, v := range list { 677 switch { 678 case max < 0 || max > len(c.ErrorList): 679 c.ErrorList = append(c.ErrorList, v) 680 default: 681 return true 682 } 683 } 684 return false 685 } 686 687 func (c *context) Err() error { 688 c.mu.Lock() 689 switch x := c.ErrorList.Err().(type) { 690 case goscanner.ErrorList: 691 x = append(goscanner.ErrorList(nil), x...) 692 c.mu.Unlock() 693 var lpos gotoken.Position 694 w := 0 695 for _, v := range x { 696 if lpos.Filename != "" { 697 if v.Pos.Filename == lpos.Filename && v.Pos.Line == lpos.Line { 698 continue 699 } 700 } 701 702 x[w] = v 703 w++ 704 lpos = v.Pos 705 } 706 x = x[:w] 707 sort.Slice(x, func(i, j int) bool { 708 a := x[i] 709 b := x[j] 710 if !a.Pos.IsValid() && b.Pos.IsValid() { 711 return true 712 } 713 714 if a.Pos.IsValid() && !b.Pos.IsValid() { 715 return false 716 } 717 718 if a.Pos.Filename < b.Pos.Filename { 719 return true 720 } 721 722 if a.Pos.Filename > b.Pos.Filename { 723 return false 724 } 725 726 if a.Pos.Line < b.Pos.Line { 727 return true 728 } 729 730 if a.Pos.Line > b.Pos.Line { 731 return false 732 } 733 734 return a.Pos.Column < b.Pos.Column 735 }) 736 a := make([]string, 0, len(x)) 737 for _, v := range x { 738 a = append(a, v.Error()) 739 } 740 return fmt.Errorf("%s", strings.Join(a, "\n")) 741 default: 742 c.mu.Unlock() 743 return x 744 } 745 } 746 747 func (c *context) not(n Node, mode mode) { 748 if c.mode&mode != 0 { 749 switch mode { 750 case mIntConstExpr: 751 c.errNode(n, "invalid integer constant expression") 752 default: 753 panic(internalError()) 754 } 755 } 756 } 757 758 func (c *context) push(mode mode) { 759 c.modes = append(c.modes, c.mode) 760 c.mode = mode 761 } 762 763 func (c *context) pop() { 764 n := len(c.modes) 765 c.mode = c.modes[n-1] 766 c.modes = c.modes[:n-1] 767 } 768 769 func (c *context) statFile(name string, sys bool) (os.FileInfo, error) { 770 fs := c.cfg.Config3.Filesystem 771 if fs == nil { 772 fs = LocalFS() 773 } 774 return fs.Stat(name, sys) 775 } 776 777 func (c *context) openFile(name string, sys bool) (io.ReadCloser, error) { 778 fs := c.cfg.Config3.Filesystem 779 if fs == nil { 780 fs = LocalFS() 781 } 782 return fs.Open(name, sys) 783 } 784 785 // HostConfig returns the system C preprocessor/compiler configuration, or an 786 // error, if any. The configuration is obtained by running the command named 787 // by the cpp argumnent or "cpp" when it's empty. For the predefined macros 788 // list the '-dM' options is added. For the include paths lists, the option 789 // '-v' is added and the output is parsed to extract the "..." include and 790 // <...> include paths. To add any other options to cpp, list them in opts. 791 // 792 // The function relies on a POSIX/GCC compatible C preprocessor installed. 793 // Execution of HostConfig is not free, so caching of the results is 794 // recommended. 795 func HostConfig(cpp string, opts ...string) (predefined string, includePaths, sysIncludePaths []string, err error) { 796 if predefined, includePaths, sysIncludePaths, err = hostConfigv3(cpp, opts...); err == nil { 797 return predefined, includePaths, sysIncludePaths, nil 798 } 799 800 return hostConfigv4(opts) 801 } 802 803 func hostConfigv3(cpp string, opts ...string) (predefined string, includePaths, sysIncludePaths []string, err error) { 804 if cpp == "" { 805 cpp = "cpp" 806 } 807 args := append(append([]string{"-dM"}, opts...), os.DevNull) 808 pre, err := exec.Command(cpp, args...).Output() 809 if err != nil { 810 return "", nil, nil, err 811 } 812 813 args = append(append([]string{"-v"}, opts...), os.DevNull) 814 out, err := exec.Command(cpp, args...).CombinedOutput() 815 if err != nil { 816 return "", nil, nil, err 817 } 818 819 sep := "\n" 820 if env("GOOS", runtime.GOOS) == "windows" { 821 sep = "\r\n" 822 } 823 824 a := strings.Split(string(out), sep) 825 for i := 0; i < len(a); { 826 switch a[i] { 827 case "#include \"...\" search starts here:": 828 loop: 829 for i = i + 1; i < len(a); { 830 switch v := a[i]; { 831 case strings.HasPrefix(v, "#") || v == "End of search list.": 832 break loop 833 default: 834 includePaths = append(includePaths, strings.TrimSpace(v)) 835 i++ 836 } 837 } 838 case "#include <...> search starts here:": 839 for i = i + 1; i < len(a); { 840 switch v := a[i]; { 841 case strings.HasPrefix(v, "#") || v == "End of search list.": 842 return string(pre), includePaths, sysIncludePaths, nil 843 default: 844 sysIncludePaths = append(sysIncludePaths, strings.TrimSpace(v)) 845 i++ 846 } 847 } 848 default: 849 i++ 850 } 851 } 852 return "", nil, nil, fmt.Errorf("failed parsing %s -v output", cpp) 853 } 854 855 func hostConfigv4(opts []string) (predefined string, includePaths, sysIncludePaths []string, err error) { 856 for _, cc := range []string{os.Getenv("CC"), "cc", "gcc"} { 857 if cc == "" { 858 continue 859 } 860 861 cc, err = exec.LookPath(cc) 862 if err != nil { 863 continue 864 } 865 866 args := append(opts, "-dM", "-E", "-") 867 pre, err := exec.Command(cc, args...).CombinedOutput() 868 if err != nil { 869 continue 870 } 871 872 sep := "\n" 873 if env("GOOS", runtime.GOOS) == "windows" { 874 sep = "\r\n" 875 } 876 a := strings.Split(string(pre), sep) 877 w := 0 878 for _, v := range a { 879 if strings.HasPrefix(v, "#") { 880 a[w] = v 881 w++ 882 } 883 } 884 predefined = strings.Join(a[:w], "\n") 885 args = append(opts, "-v", "-E", "-") 886 out, err := exec.Command(cc, args...).CombinedOutput() 887 if err != nil { 888 continue 889 } 890 891 a = strings.Split(string(out), sep) 892 for i := 0; i < len(a); { 893 switch a[i] { 894 case "#include \"...\" search starts here:": 895 loop: 896 for i = i + 1; i < len(a); { 897 switch v := a[i]; { 898 case strings.HasPrefix(v, "#") || v == "End of search list.": 899 break loop 900 default: 901 includePaths = append(includePaths, strings.TrimSpace(v)) 902 i++ 903 } 904 } 905 case "#include <...> search starts here:": 906 for i = i + 1; i < len(a); { 907 switch v := a[i]; { 908 case strings.HasPrefix(v, "#") || v == "End of search list.": 909 return predefined, includePaths, sysIncludePaths, nil 910 default: 911 sysIncludePaths = append(sysIncludePaths, strings.TrimSpace(v)) 912 i++ 913 } 914 } 915 default: 916 i++ 917 } 918 } 919 } 920 return "", nil, nil, fmt.Errorf("cannot determine C compiler configuration") 921 } 922 923 func env(key, val string) string { 924 if s := os.Getenv(key); s != "" { 925 return s 926 } 927 928 return val 929 } 930 931 // Token is a grammar terminal. 932 type Token struct { 933 Rune rune // ';' or IDENTIFIER etc. 934 Sep StringID // If Config3.PreserveWhiteSpace is in effect: All preceding white space combined, including comments. 935 Value StringID // ";" or "foo" etc. 936 Src StringID 937 file *tokenFile 938 macro StringID 939 pos int32 940 seq int32 941 } 942 943 // Seq returns t's sequential number. 944 // 945 // Comparing positions as in 'before', 'after' is complicated as tokens in a 946 // translation unit usually come from more than one source file. Macro 947 // expansion further complicates that. The solution is sequentially numbering 948 // the tokens as they are finally seen by the parser, so the usual arithmetic 949 // '<', '>' operators can be used for that purpose. 950 func (t Token) Seq() int { return int(t.seq) } 951 952 // Macro returns the name of a macro that expanded to this token, if any. 953 func (t *Token) Macro() StringID { return t.macro } 954 955 // String implements fmt.Stringer. 956 func (t Token) String() string { return t.Value.String() } 957 958 // Position implements Node. 959 func (t *Token) Position() (r token.Position) { 960 if t.pos != 0 && t.file != nil { 961 r = t.file.PositionFor(token.Pos(t.pos), true) 962 } 963 return r 964 } 965 966 func tokStr(toks interface{}, sep string) string { 967 var b strings.Builder 968 switch x := toks.(type) { 969 case []token3: 970 for i, v := range x { 971 if i != 0 { 972 b.WriteString(sep) 973 } 974 b.WriteString(v.String()) 975 } 976 case []token4: 977 for i, v := range x { 978 if i != 0 { 979 b.WriteString(sep) 980 } 981 b.WriteString(v.String()) 982 } 983 case []cppToken: 984 for i, v := range x { 985 if i != 0 { 986 b.WriteString(sep) 987 } 988 b.WriteString(v.String()) 989 } 990 case []Token: 991 for i, v := range x { 992 if i != 0 { 993 b.WriteString(sep) 994 } 995 b.WriteString(v.String()) 996 } 997 default: 998 panic(internalError()) 999 } 1000 return b.String() 1001 } 1002 1003 func internalError() int { 1004 panic(fmt.Errorf("%v: internal error", origin(2))) 1005 } 1006 1007 func internalErrorf(s string, args ...interface{}) int { 1008 s = fmt.Sprintf(s, args) 1009 panic(fmt.Errorf("%v: %s", origin(2), s)) 1010 } 1011 1012 func detectMingw(s string) bool { 1013 return strings.Contains(s, "#define __MINGW") 1014 } 1015 1016 func nodeSource(n ...Node) (r string) { 1017 if len(n) == 0 { 1018 return "" 1019 } 1020 1021 var a []*Token 1022 for _, v := range n { 1023 Inspect(v, func(n Node, _ bool) bool { 1024 if x, ok := n.(*Token); ok && x.Seq() != 0 { 1025 a = append(a, x) 1026 } 1027 return true 1028 }) 1029 } 1030 sort.Slice(a, func(i, j int) bool { 1031 return a[i].Seq() < a[j].Seq() 1032 }) 1033 w := 0 1034 seq := -1 1035 for _, v := range a { 1036 if n := v.Seq(); n != seq { 1037 seq = n 1038 a[w] = v 1039 w++ 1040 } 1041 } 1042 a = a[:w] 1043 var b strings.Builder 1044 for _, v := range a { 1045 b.WriteString(v.Sep.String()) 1046 b.WriteString(v.Src.String()) 1047 } 1048 return b.String() 1049 }