gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

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 }