mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-31 00:32:25 -05:00 
			
		
		
		
	
		
			
	
	
		
			4312 lines
		
	
	
	
		
			119 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
		
		
			
		
	
	
			4312 lines
		
	
	
	
		
			119 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
|  | // Copyright 2019 The CC Authors. All rights reserved. | ||
|  | // Use of this source code is governed by a BSD-style | ||
|  | // license that can be found in the LICENSE file. | ||
|  | 
 | ||
|  | package cc // import "modernc.org/cc/v3" | ||
|  | 
 | ||
|  | import ( | ||
|  | 	"bytes" | ||
|  | 	"fmt" | ||
|  | 	"hash/maphash" | ||
|  | 	"strings" | ||
|  | ) | ||
|  | 
 | ||
|  | const ( | ||
|  | 	unicodePrivateAreaFirst = 0xe000 | ||
|  | 	unicodePrivateAreaLast  = 0xf8ff | ||
|  | ) | ||
|  | 
 | ||
|  | var ( | ||
|  | 	noDeclSpecs        = &DeclarationSpecifiers{} | ||
|  | 	panicOnParserError bool //TODOOK | ||
|  | 
 | ||
|  | 	idChar      = dict.sid("char") | ||
|  | 	idComma     = dict.sid(",") | ||
|  | 	idConst     = dict.sid("const") | ||
|  | 	idEq        = dict.sid("=") | ||
|  | 	idFFlush    = dict.sid("fflush") | ||
|  | 	idFprintf   = dict.sid("fprintf") | ||
|  | 	idFunc      = dict.sid("__func__") | ||
|  | 	idLBracket  = dict.sid("[") | ||
|  | 	idLParen    = dict.sid("(") | ||
|  | 	idRBracket  = dict.sid("]") | ||
|  | 	idRParen    = dict.sid(")") | ||
|  | 	idSemicolon = dict.sid(";") | ||
|  | 	idStatic    = dict.sid("static") | ||
|  | 	idStderr    = dict.sid("stderr") | ||
|  | ) | ||
|  | 
 | ||
|  | // Values of Token.Rune for lexemes. | ||
|  | const ( | ||
|  | 	_ = iota + unicodePrivateAreaFirst //TODOOK | ||
|  | 
 | ||
|  | 	ACCUM                  // _Accum | ||
|  | 	ADDASSIGN              // += | ||
|  | 	ALIGNAS                // _Alignas | ||
|  | 	ALIGNOF                // _Alignof | ||
|  | 	ANDAND                 // && | ||
|  | 	ANDASSIGN              // &= | ||
|  | 	ARROW                  // -> | ||
|  | 	ASM                    // __asm__ | ||
|  | 	ATOMIC                 // _Atomic | ||
|  | 	ATTRIBUTE              // __attribute__ | ||
|  | 	AUTO                   // auto | ||
|  | 	BOOL                   // _Bool | ||
|  | 	BREAK                  // break | ||
|  | 	BUILTINCHOOSEEXPR      // __builtin_choose_expr | ||
|  | 	BUILTINTYPESCOMPATIBLE // __builtin_types_compatible_p | ||
|  | 	CASE                   // case | ||
|  | 	CHAR                   // char | ||
|  | 	CHARCONST              // 'a' | ||
|  | 	COMPLEX                // _Complex | ||
|  | 	CONST                  // const | ||
|  | 	CONTINUE               // continue | ||
|  | 	DDD                    // ... | ||
|  | 	DEC                    // -- | ||
|  | 	DECIMAL128             // _Decimal128 | ||
|  | 	DECIMAL32              // _Decimal32 | ||
|  | 	DECIMAL64              // _Decimal64 | ||
|  | 	DEFAULT                // default | ||
|  | 	DIVASSIGN              // /= | ||
|  | 	DO                     // do | ||
|  | 	DOUBLE                 // double | ||
|  | 	ELSE                   // else | ||
|  | 	ENUM                   // enum | ||
|  | 	ENUMCONST              // foo in enum x { foo, bar }; | ||
|  | 	EQ                     // == | ||
|  | 	EXTERN                 // extern | ||
|  | 	FLOAT                  // float | ||
|  | 	FLOAT128               // _Float128 | ||
|  | 	FLOAT16                // __fp16 | ||
|  | 	FLOAT32                // _Float32 | ||
|  | 	FLOAT32X               // _Float32x | ||
|  | 	FLOAT64                // _Float64 | ||
|  | 	FLOAT64X               // _Float64x | ||
|  | 	FLOAT80                // __float80 | ||
|  | 	FLOATCONST             // 1.23 | ||
|  | 	FOR                    // for | ||
|  | 	FRACT                  // _Fract | ||
|  | 	GEQ                    // >= | ||
|  | 	GOTO                   // goto | ||
|  | 	IDENTIFIER             // foo | ||
|  | 	IF                     // if | ||
|  | 	IMAG                   // __imag__ | ||
|  | 	INC                    // ++ | ||
|  | 	INLINE                 // inline | ||
|  | 	INT                    // int | ||
|  | 	INT8                   // __int8 | ||
|  | 	INT16                  // __int16 | ||
|  | 	INT32                  // __int32 | ||
|  | 	INT64                  // __int64 | ||
|  | 	INT128                 // __int128 | ||
|  | 	INTCONST               // 42 | ||
|  | 	LABEL                  // __label__ | ||
|  | 	LEQ                    // <= | ||
|  | 	LONG                   // long | ||
|  | 	LONGCHARCONST          // L'a' | ||
|  | 	LONGSTRINGLITERAL      // L"foo" | ||
|  | 	LSH                    // << | ||
|  | 	LSHASSIGN              // <<= | ||
|  | 	MODASSIGN              // %= | ||
|  | 	MULASSIGN              // *= | ||
|  | 	NEQ                    // != | ||
|  | 	NORETURN               // _Noreturn | ||
|  | 	ORASSIGN               // |= | ||
|  | 	OROR                   // || | ||
|  | 	PPNUMBER               // .32e. | ||
|  | 	PPPASTE                // ## | ||
|  | 	PRAGMASTDC             // __pragma_stdc | ||
|  | 	REAL                   // __real__ | ||
|  | 	REGISTER               // register | ||
|  | 	RESTRICT               // restrict | ||
|  | 	RETURN                 // return | ||
|  | 	RSH                    // >> | ||
|  | 	RSHASSIGN              // >>= | ||
|  | 	SAT                    // _Sat | ||
|  | 	SHORT                  // short | ||
|  | 	SIGNED                 // signed | ||
|  | 	SIZEOF                 // sizeof | ||
|  | 	STATIC                 // static | ||
|  | 	STRINGLITERAL          // "foo" | ||
|  | 	STRUCT                 // struct | ||
|  | 	SUBASSIGN              // -= | ||
|  | 	SWITCH                 // switch | ||
|  | 	THREADLOCAL            // _Thread_local | ||
|  | 	TYPEDEF                // typedef | ||
|  | 	TYPEDEFNAME            // int_t in typedef int int_t; | ||
|  | 	TYPEOF                 // typeof | ||
|  | 	UNION                  // union | ||
|  | 	UNSIGNED               // unsigned | ||
|  | 	VOID                   // void | ||
|  | 	VOLATILE               // volatile | ||
|  | 	WHILE                  // while | ||
|  | 	XORASSIGN              // ^= | ||
|  | 
 | ||
|  | 	lastTok | ||
|  | ) | ||
|  | 
 | ||
|  | var ( | ||
|  | 	tokNames = map[rune]StringID{ | ||
|  | 		ACCUM:                  dict.sid("ACCUM"), | ||
|  | 		ADDASSIGN:              dict.sid("ADDASSIGN"), | ||
|  | 		ALIGNAS:                dict.sid("ALIGNAS"), | ||
|  | 		ALIGNOF:                dict.sid("ALIGNOF"), | ||
|  | 		ANDAND:                 dict.sid("ANDAND"), | ||
|  | 		ANDASSIGN:              dict.sid("ANDASSIGN"), | ||
|  | 		ARROW:                  dict.sid("ARROW"), | ||
|  | 		ASM:                    dict.sid("ASM"), | ||
|  | 		ATOMIC:                 dict.sid("ATOMIC"), | ||
|  | 		ATTRIBUTE:              dict.sid("ATTRIBUTE"), | ||
|  | 		AUTO:                   dict.sid("AUTO"), | ||
|  | 		BOOL:                   dict.sid("BOOL"), | ||
|  | 		BREAK:                  dict.sid("BREAK"), | ||
|  | 		BUILTINCHOOSEEXPR:      dict.sid("BUILTINCHOOSEEXPR"), | ||
|  | 		BUILTINTYPESCOMPATIBLE: dict.sid("BUILTINTYPESCOMPATIBLE"), | ||
|  | 		CASE:                   dict.sid("CASE"), | ||
|  | 		CHAR:                   dict.sid("CHAR"), | ||
|  | 		CHARCONST:              dict.sid("CHARCONST"), | ||
|  | 		COMPLEX:                dict.sid("COMPLEX"), | ||
|  | 		CONST:                  dict.sid("CONST"), | ||
|  | 		CONTINUE:               dict.sid("CONTINUE"), | ||
|  | 		DDD:                    dict.sid("DDD"), | ||
|  | 		DEC:                    dict.sid("DEC"), | ||
|  | 		DECIMAL128:             dict.sid("DECIMAL128"), | ||
|  | 		DECIMAL32:              dict.sid("DECIMAL32"), | ||
|  | 		DECIMAL64:              dict.sid("DECIMAL64"), | ||
|  | 		DEFAULT:                dict.sid("DEFAULT"), | ||
|  | 		DIVASSIGN:              dict.sid("DIVASSIGN"), | ||
|  | 		DO:                     dict.sid("DO"), | ||
|  | 		DOUBLE:                 dict.sid("DOUBLE"), | ||
|  | 		ELSE:                   dict.sid("ELSE"), | ||
|  | 		ENUM:                   dict.sid("ENUM"), | ||
|  | 		ENUMCONST:              dict.sid("ENUMCONST"), | ||
|  | 		EQ:                     dict.sid("EQ"), | ||
|  | 		EXTERN:                 dict.sid("EXTERN"), | ||
|  | 		FLOAT128:               dict.sid("FLOAT128"), | ||
|  | 		FLOAT16:                dict.sid("FLOAT16"), | ||
|  | 		FLOAT32:                dict.sid("FLOAT32"), | ||
|  | 		FLOAT32X:               dict.sid("FLOAT32X"), | ||
|  | 		FLOAT64:                dict.sid("FLOAT64"), | ||
|  | 		FLOAT64X:               dict.sid("FLOAT64X"), | ||
|  | 		FLOAT80:                dict.sid("FLOAT80"), | ||
|  | 		FLOAT:                  dict.sid("FLOAT"), | ||
|  | 		FLOATCONST:             dict.sid("FLOATCONST"), | ||
|  | 		FOR:                    dict.sid("FOR"), | ||
|  | 		FRACT:                  dict.sid("FRACT"), | ||
|  | 		GEQ:                    dict.sid("GEQ"), | ||
|  | 		GOTO:                   dict.sid("GOTO"), | ||
|  | 		IDENTIFIER:             dict.sid("IDENTIFIER"), | ||
|  | 		IF:                     dict.sid("IF"), | ||
|  | 		IMAG:                   dict.sid("IMAG"), | ||
|  | 		INC:                    dict.sid("INC"), | ||
|  | 		INLINE:                 dict.sid("INLINE"), | ||
|  | 		INT8:                   dict.sid("INT8"), | ||
|  | 		INT16:                  dict.sid("INT16"), | ||
|  | 		INT32:                  dict.sid("INT32"), | ||
|  | 		INT64:                  dict.sid("INT64"), | ||
|  | 		INT128:                 dict.sid("INT128"), | ||
|  | 		INT:                    dict.sid("INT"), | ||
|  | 		INTCONST:               dict.sid("INTCONST"), | ||
|  | 		LABEL:                  dict.sid("LABEL"), | ||
|  | 		LEQ:                    dict.sid("LEQ"), | ||
|  | 		LONG:                   dict.sid("LONG"), | ||
|  | 		LONGCHARCONST:          dict.sid("LONGCHARCONST"), | ||
|  | 		LONGSTRINGLITERAL:      dict.sid("LONGSTRINGLITERAL"), | ||
|  | 		LSH:                    dict.sid("LSH"), | ||
|  | 		LSHASSIGN:              dict.sid("LSHASSIGN"), | ||
|  | 		MODASSIGN:              dict.sid("MODASSIGN"), | ||
|  | 		MULASSIGN:              dict.sid("MULASSIGN"), | ||
|  | 		NEQ:                    dict.sid("NEQ"), | ||
|  | 		NORETURN:               dict.sid("NORETURN"), | ||
|  | 		ORASSIGN:               dict.sid("ORASSIGN"), | ||
|  | 		OROR:                   dict.sid("OROR"), | ||
|  | 		PPNUMBER:               dict.sid("PPNUMBER"), | ||
|  | 		PPPASTE:                dict.sid("PPPASTE"), | ||
|  | 		PRAGMASTDC:             dict.sid("PPPRAGMASTDC"), | ||
|  | 		REAL:                   dict.sid("REAL"), | ||
|  | 		REGISTER:               dict.sid("REGISTER"), | ||
|  | 		RESTRICT:               dict.sid("RESTRICT"), | ||
|  | 		RETURN:                 dict.sid("RETURN"), | ||
|  | 		RSH:                    dict.sid("RSH"), | ||
|  | 		RSHASSIGN:              dict.sid("RSHASSIGN"), | ||
|  | 		SAT:                    dict.sid("SAT"), | ||
|  | 		SHORT:                  dict.sid("SHORT"), | ||
|  | 		SIGNED:                 dict.sid("SIGNED"), | ||
|  | 		SIZEOF:                 dict.sid("SIZEOF"), | ||
|  | 		STATIC:                 dict.sid("STATIC"), | ||
|  | 		STRINGLITERAL:          dict.sid("STRINGLITERAL"), | ||
|  | 		STRUCT:                 dict.sid("STRUCT"), | ||
|  | 		SUBASSIGN:              dict.sid("SUBASSIGN"), | ||
|  | 		SWITCH:                 dict.sid("SWITCH"), | ||
|  | 		THREADLOCAL:            dict.sid("THREADLOCAL"), | ||
|  | 		TYPEDEF:                dict.sid("TYPEDEF"), | ||
|  | 		TYPEDEFNAME:            dict.sid("TYPEDEFNAME"), | ||
|  | 		TYPEOF:                 dict.sid("TYPEOF"), | ||
|  | 		UNION:                  dict.sid("UNION"), | ||
|  | 		UNSIGNED:               dict.sid("UNSIGNED"), | ||
|  | 		VOID:                   dict.sid("VOID"), | ||
|  | 		VOLATILE:               dict.sid("VOLATILE"), | ||
|  | 		WHILE:                  dict.sid("WHILE"), | ||
|  | 		XORASSIGN:              dict.sid("XORASSIGN"), | ||
|  | 	} | ||
|  | 
 | ||
|  | 	keywords = map[StringID]rune{ | ||
|  | 
 | ||
|  | 		// [0], 6.4.1 | ||
|  | 		dict.sid("auto"):     AUTO, | ||
|  | 		dict.sid("break"):    BREAK, | ||
|  | 		dict.sid("case"):     CASE, | ||
|  | 		dict.sid("char"):     CHAR, | ||
|  | 		dict.sid("const"):    CONST, | ||
|  | 		dict.sid("continue"): CONTINUE, | ||
|  | 		dict.sid("default"):  DEFAULT, | ||
|  | 		dict.sid("do"):       DO, | ||
|  | 		dict.sid("double"):   DOUBLE, | ||
|  | 		dict.sid("else"):     ELSE, | ||
|  | 		dict.sid("enum"):     ENUM, | ||
|  | 		dict.sid("extern"):   EXTERN, | ||
|  | 		dict.sid("float"):    FLOAT, | ||
|  | 		dict.sid("for"):      FOR, | ||
|  | 		dict.sid("goto"):     GOTO, | ||
|  | 		dict.sid("if"):       IF, | ||
|  | 		dict.sid("inline"):   INLINE, | ||
|  | 		dict.sid("int"):      INT, | ||
|  | 		dict.sid("long"):     LONG, | ||
|  | 		dict.sid("register"): REGISTER, | ||
|  | 		dict.sid("restrict"): RESTRICT, | ||
|  | 		dict.sid("return"):   RETURN, | ||
|  | 		dict.sid("short"):    SHORT, | ||
|  | 		dict.sid("signed"):   SIGNED, | ||
|  | 		dict.sid("sizeof"):   SIZEOF, | ||
|  | 		dict.sid("static"):   STATIC, | ||
|  | 		dict.sid("struct"):   STRUCT, | ||
|  | 		dict.sid("switch"):   SWITCH, | ||
|  | 		dict.sid("typedef"):  TYPEDEF, | ||
|  | 		dict.sid("union"):    UNION, | ||
|  | 		dict.sid("unsigned"): UNSIGNED, | ||
|  | 		dict.sid("void"):     VOID, | ||
|  | 		dict.sid("volatile"): VOLATILE, | ||
|  | 		dict.sid("while"):    WHILE, | ||
|  | 
 | ||
|  | 		dict.sid("_Alignas"):      ALIGNAS, | ||
|  | 		dict.sid("_Alignof"):      ALIGNOF, | ||
|  | 		dict.sid("_Atomic"):       ATOMIC, | ||
|  | 		dict.sid("_Bool"):         BOOL, | ||
|  | 		dict.sid("_Complex"):      COMPLEX, | ||
|  | 		dict.sid("_Noreturn"):     NORETURN, | ||
|  | 		dict.sid("_Thread_local"): THREADLOCAL, | ||
|  | 		dict.sid("__alignof"):     ALIGNOF, | ||
|  | 		dict.sid("__alignof__"):   ALIGNOF, | ||
|  | 		dict.sid("__asm"):         ASM, | ||
|  | 		dict.sid("__asm__"):       ASM, | ||
|  | 		dict.sid("__attribute"):   ATTRIBUTE, | ||
|  | 		dict.sid("__attribute__"): ATTRIBUTE, | ||
|  | 		dict.sid("__complex"):     COMPLEX, | ||
|  | 		dict.sid("__complex__"):   COMPLEX, | ||
|  | 		dict.sid("__const"):       CONST, | ||
|  | 		dict.sid("__inline"):      INLINE, | ||
|  | 		dict.sid("__inline__"):    INLINE, | ||
|  | 		dict.sid("__int16"):       INT16, | ||
|  | 		dict.sid("__int32"):       INT32, | ||
|  | 		dict.sid("__int64"):       INT64, | ||
|  | 		dict.sid("__int8"):        INT8, | ||
|  | 		dict.sid("__pragma_stdc"): PRAGMASTDC, | ||
|  | 		dict.sid("__restrict"):    RESTRICT, | ||
|  | 		dict.sid("__restrict__"):  RESTRICT, | ||
|  | 		dict.sid("__signed"):      SIGNED, | ||
|  | 		dict.sid("__signed__"):    SIGNED, | ||
|  | 		dict.sid("__thread"):      THREADLOCAL, | ||
|  | 		dict.sid("__typeof"):      TYPEOF, | ||
|  | 		dict.sid("__typeof__"):    TYPEOF, | ||
|  | 		dict.sid("__volatile"):    VOLATILE, | ||
|  | 		dict.sid("__volatile__"):  VOLATILE, | ||
|  | 		dict.sid("typeof"):        TYPEOF, | ||
|  | 	} | ||
|  | 
 | ||
|  | 	gccKeywords = map[StringID]rune{ | ||
|  | 		dict.sid("_Accum"):                       ACCUM, | ||
|  | 		dict.sid("_Decimal128"):                  DECIMAL128, | ||
|  | 		dict.sid("_Decimal32"):                   DECIMAL32, | ||
|  | 		dict.sid("_Decimal64"):                   DECIMAL64, | ||
|  | 		dict.sid("_Float128"):                    FLOAT128, | ||
|  | 		dict.sid("_Float16"):                     FLOAT16, | ||
|  | 		dict.sid("_Float32"):                     FLOAT32, | ||
|  | 		dict.sid("_Float32x"):                    FLOAT32X, | ||
|  | 		dict.sid("_Float64"):                     FLOAT64, | ||
|  | 		dict.sid("_Float64x"):                    FLOAT64X, | ||
|  | 		dict.sid("_Fract"):                       FRACT, | ||
|  | 		dict.sid("_Sat"):                         SAT, | ||
|  | 		dict.sid("__builtin_choose_expr"):        BUILTINCHOOSEEXPR, | ||
|  | 		dict.sid("__builtin_types_compatible_p"): BUILTINTYPESCOMPATIBLE, | ||
|  | 		dict.sid("__float80"):                    FLOAT80, | ||
|  | 		dict.sid("__fp16"):                       FLOAT16, | ||
|  | 		dict.sid("__imag"):                       IMAG, | ||
|  | 		dict.sid("__imag__"):                     IMAG, | ||
|  | 		dict.sid("__int128"):                     INT128, | ||
|  | 		dict.sid("__label__"):                    LABEL, | ||
|  | 		dict.sid("__real"):                       REAL, | ||
|  | 		dict.sid("__real__"):                     REAL, | ||
|  | 	} | ||
|  | ) | ||
|  | 
 | ||
|  | func init() { | ||
|  | 	for r := rune(0xe001); r < lastTok; r++ { | ||
|  | 		if _, ok := tokNames[r]; !ok { | ||
|  | 			panic(internalError()) | ||
|  | 		} | ||
|  | 	} | ||
|  | 	for k, v := range keywords { | ||
|  | 		gccKeywords[k] = v | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | func tokName(r rune) string { | ||
|  | 	switch { | ||
|  | 	case r < 0: | ||
|  | 		return "<EOF>" | ||
|  | 	case r >= unicodePrivateAreaFirst && r <= unicodePrivateAreaLast: | ||
|  | 		return tokNames[r].String() | ||
|  | 	default: | ||
|  | 		return fmt.Sprintf("%+q", r) | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | type parser struct { | ||
|  | 	block        *CompoundStatement | ||
|  | 	ctx          *context | ||
|  | 	currFn       *FunctionDefinition | ||
|  | 	declScope    Scope | ||
|  | 	fileScope    Scope | ||
|  | 	hash         *maphash.Hash | ||
|  | 	in           chan *[]Token | ||
|  | 	inBuf        []Token | ||
|  | 	inBufp       *[]Token | ||
|  | 	key          sharedFunctionDefinitionKey | ||
|  | 	prev         Token | ||
|  | 	resolveScope Scope | ||
|  | 	resolvedIn   Scope // Typedef name | ||
|  | 	scopes       int | ||
|  | 	sepLen       int | ||
|  | 	seps         []StringID | ||
|  | 	strcatLen    int | ||
|  | 	strcats      []StringID | ||
|  | 	switches     int | ||
|  | 
 | ||
|  | 	tok Token | ||
|  | 
 | ||
|  | 	closed             bool | ||
|  | 	errored            bool | ||
|  | 	ignoreKeywords     bool | ||
|  | 	typedefNameEnabled bool | ||
|  | } | ||
|  | 
 | ||
|  | func newParser(ctx *context, in chan *[]Token) *parser { | ||
|  | 	s := Scope{} | ||
|  | 	var hash *maphash.Hash | ||
|  | 	if s := ctx.cfg.SharedFunctionDefinitions; s != nil { | ||
|  | 		hash = &s.hash | ||
|  | 	} | ||
|  | 	return &parser{ | ||
|  | 		ctx:          ctx, | ||
|  | 		declScope:    s, | ||
|  | 		fileScope:    s, | ||
|  | 		hash:         hash, | ||
|  | 		in:           in, | ||
|  | 		resolveScope: s, | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | func (p *parser) openScope(skip bool) { | ||
|  | 	p.scopes++ | ||
|  | 	p.declScope = p.declScope.new() | ||
|  | 	if skip { | ||
|  | 		p.declScope[scopeSkip] = nil | ||
|  | 	} | ||
|  | 	p.resolveScope = p.declScope | ||
|  | 	// var a []string | ||
|  | 	// for s := p.declScope; s != nil; s = s.Parent() { | ||
|  | 	// 	a = append(a, fmt.Sprintf("%p", s)) | ||
|  | 	// } | ||
|  | 	// trc("openScope(%v) %p: %v", skip, p.declScope, strings.Join(a, " ")) | ||
|  | } | ||
|  | 
 | ||
|  | func (p *parser) closeScope() { | ||
|  | 	// declScope := p.declScope | ||
|  | 	p.declScope = p.declScope.Parent() | ||
|  | 	p.resolveScope = p.declScope | ||
|  | 	p.scopes-- | ||
|  | 	// var a []string | ||
|  | 	// for s := p.declScope; s != nil; s = s.Parent() { | ||
|  | 	// 	a = append(a, fmt.Sprintf("%p", s)) | ||
|  | 	// } | ||
|  | 	// trc("%p.closeScope %v", declScope, strings.Join(a, " ")) | ||
|  | } | ||
|  | 
 | ||
|  | func (p *parser) err0(consume bool, msg string, args ...interface{}) { | ||
|  | 	if panicOnParserError { //TODOOK | ||
|  | 		s := fmt.Sprintf("FAIL: "+msg, args...) | ||
|  | 		panic(fmt.Sprintf("%s\n%s: ", s, PrettyString(p.tok))) //TODOOK | ||
|  | 	} | ||
|  | 	// s := fmt.Sprintf("FAIL: "+p.tok.Position().String()+": "+msg, args...) | ||
|  | 	// caller("%s: %s: ", s, PrettyString(p.tok)) | ||
|  | 	p.errored = true | ||
|  | 	if consume { | ||
|  | 		p.tok.Rune = 0 | ||
|  | 	} | ||
|  | 	if p.ctx.err(p.tok.Position(), "`%s`: "+msg, append([]interface{}{p.tok}, args...)...) { | ||
|  | 		p.closed = true | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | func (p *parser) err(msg string, args ...interface{}) { p.err0(true, msg, args...) } | ||
|  | 
 | ||
|  | func (p *parser) rune() rune { | ||
|  | 	if p.tok.Rune == 0 { | ||
|  | 		p.next() | ||
|  | 	} | ||
|  | 	return p.tok.Rune | ||
|  | } | ||
|  | 
 | ||
|  | func (p *parser) shift() (r Token) { | ||
|  | 	if p.tok.Rune == 0 { | ||
|  | 		p.next() | ||
|  | 	} | ||
|  | 	r = p.tok | ||
|  | 	p.tok.Rune = 0 | ||
|  | 	// dbg("", shift(r)) | ||
|  | 	return r | ||
|  | } | ||
|  | 
 | ||
|  | func (p *parser) unget(toks ...Token) { //TODO injected __func__ has two trailing semicolons, why? | ||
|  | 	p.inBuf = append(toks, p.inBuf...) | ||
|  | 	// fmt.Printf("unget %q\n", tokStr(toks, "|")) //TODO- | ||
|  | } | ||
|  | 
 | ||
|  | func (p *parser) peek(handleTypedefname bool) rune { | ||
|  | 	if p.closed { | ||
|  | 		return -1 | ||
|  | 	} | ||
|  | 
 | ||
|  | 	if len(p.inBuf) == 0 { | ||
|  | 		if p.inBufp != nil { | ||
|  | 			tokenPool.Put(p.inBufp) | ||
|  | 		} | ||
|  | 		var ok bool | ||
|  | 		if p.inBufp, ok = <-p.in; !ok { | ||
|  | 			// dbg("parser: EOF") | ||
|  | 			return -1 | ||
|  | 		} | ||
|  | 
 | ||
|  | 		p.inBuf = *p.inBufp | ||
|  | 		// dbg("parser receives: %q", tokStr(p.inBuf, "|")) | ||
|  | 		// fmt.Printf("parser receives %v: %q\n", p.inBuf[0].Position(), tokStr(p.inBuf, "|")) //TODO- | ||
|  | 	} | ||
|  | 	tok := p.inBuf[0] | ||
|  | 	r := tok.Rune | ||
|  | 	if r == IDENTIFIER { | ||
|  | 		if x, ok := p.ctx.keywords[p.inBuf[0].Value]; ok && !p.ignoreKeywords { | ||
|  | 			return x | ||
|  | 		} | ||
|  | 
 | ||
|  | 		if handleTypedefname { | ||
|  | 			nm := tok.Value | ||
|  | 			seq := tok.seq | ||
|  | 			for s := p.resolveScope; s != nil; s = s.Parent() { | ||
|  | 				for _, v := range s[nm] { | ||
|  | 					switch x := v.(type) { | ||
|  | 					case *Declarator: | ||
|  | 						if !x.isVisible(seq) { | ||
|  | 							continue | ||
|  | 						} | ||
|  | 
 | ||
|  | 						if x.IsTypedefName && p.peek(false) != ':' { | ||
|  | 							return TYPEDEFNAME | ||
|  | 						} | ||
|  | 
 | ||
|  | 						return IDENTIFIER | ||
|  | 					case *Enumerator: | ||
|  | 						return IDENTIFIER | ||
|  | 					case *EnumSpecifier, *StructOrUnionSpecifier, *StructDeclarator, *LabeledStatement: | ||
|  | 						// nop | ||
|  | 					default: | ||
|  | 						panic(internalErrorf("%T", x)) | ||
|  | 					} | ||
|  | 				} | ||
|  | 			} | ||
|  | 		} | ||
|  | 	} | ||
|  | 	return r | ||
|  | } | ||
|  | 
 | ||
|  | func (p *parser) next() { | ||
|  | 	if p.closed { | ||
|  | 		// dbg("parser: EOF") | ||
|  | 		p.tok.Rune = -1 | ||
|  | 		return | ||
|  | 	} | ||
|  | 
 | ||
|  | more: | ||
|  | 	if len(p.inBuf) == 0 { | ||
|  | 		if p.inBufp != nil { | ||
|  | 			tokenPool.Put(p.inBufp) | ||
|  | 		} | ||
|  | 		var ok bool | ||
|  | 		if p.inBufp, ok = <-p.in; !ok { | ||
|  | 			// dbg("parser: EOF") | ||
|  | 			p.closed = true | ||
|  | 			p.tok.Rune = -1 | ||
|  | 			return | ||
|  | 		} | ||
|  | 
 | ||
|  | 		p.inBuf = *p.inBufp | ||
|  | 		// dbg("parser receives: %q", tokStr(p.inBuf, "|")) | ||
|  | 		// fmt.Printf("parser receives %v: %q\n", p.inBuf[0].Position(), tokStr(p.inBuf, "|")) //TODO- | ||
|  | 	} | ||
|  | 	p.tok = p.inBuf[0] | ||
|  | 	switch p.tok.Rune { | ||
|  | 	case STRINGLITERAL, LONGSTRINGLITERAL: | ||
|  | 		switch p.prev.Rune { | ||
|  | 		case STRINGLITERAL, LONGSTRINGLITERAL: | ||
|  | 			p.strcatLen += len(p.tok.Value.String()) | ||
|  | 			p.strcats = append(p.strcats, p.tok.Value) | ||
|  | 			p.sepLen += len(p.tok.Sep.String()) | ||
|  | 			p.seps = append(p.seps, p.tok.Sep) | ||
|  | 			p.inBuf = p.inBuf[1:] | ||
|  | 			goto more | ||
|  | 		default: | ||
|  | 			p.strcatLen = len(p.tok.Value.String()) | ||
|  | 			p.strcats = []StringID{p.tok.Value} | ||
|  | 			p.sepLen = len(p.tok.Sep.String()) | ||
|  | 			p.seps = []StringID{p.tok.Sep} | ||
|  | 			p.prev = p.tok | ||
|  | 			p.inBuf = p.inBuf[1:] | ||
|  | 			goto more | ||
|  | 		} | ||
|  | 	default: | ||
|  | 		switch p.prev.Rune { | ||
|  | 		case STRINGLITERAL, LONGSTRINGLITERAL: | ||
|  | 			p.tok = p.prev | ||
|  | 			var b bytes.Buffer | ||
|  | 			b.Grow(p.strcatLen) | ||
|  | 			for _, v := range p.strcats { | ||
|  | 				b.WriteString(v.String()) | ||
|  | 			} | ||
|  | 			p.tok.Value = dict.id(b.Bytes()) | ||
|  | 			b.Reset() | ||
|  | 			b.Grow(p.sepLen) | ||
|  | 			for _, v := range p.seps { | ||
|  | 				b.WriteString(v.String()) | ||
|  | 			} | ||
|  | 			p.tok.Sep = dict.id(b.Bytes()) | ||
|  | 			p.prev.Rune = 0 | ||
|  | 		default: | ||
|  | 			p.inBuf = p.inBuf[1:] | ||
|  | 		} | ||
|  | 	} | ||
|  | 	p.resolvedIn = nil | ||
|  | out: | ||
|  | 	switch p.tok.Rune { | ||
|  | 	case IDENTIFIER: | ||
|  | 		nm := p.tok.Value | ||
|  | 		if x, ok := p.ctx.keywords[nm]; ok && !p.ignoreKeywords { | ||
|  | 			p.tok.Rune = x | ||
|  | 			break | ||
|  | 		} | ||
|  | 
 | ||
|  | 		if p.typedefNameEnabled { | ||
|  | 			seq := p.tok.seq | ||
|  | 			// dbg("checking for typedefname in scope %p", p.resolveScope) | ||
|  | 			for s := p.resolveScope; s != nil; s = s.Parent() { | ||
|  | 				// dbg("scope %p", s) | ||
|  | 				for _, v := range s[nm] { | ||
|  | 					// dbg("%v: %T", nm, v) | ||
|  | 					switch x := v.(type) { | ||
|  | 					case *Declarator: | ||
|  | 						if !x.isVisible(seq) { | ||
|  | 							continue | ||
|  | 						} | ||
|  | 
 | ||
|  | 						// dbg("", x.isVisible(pos), x.IsTypedefName) | ||
|  | 						if x.IsTypedefName && p.peek(false) != ':' { | ||
|  | 							p.tok.Rune = TYPEDEFNAME | ||
|  | 							p.resolvedIn = s | ||
|  | 						} | ||
|  | 
 | ||
|  | 						p.typedefNameEnabled = false | ||
|  | 						break out | ||
|  | 					case *Enumerator: | ||
|  | 						if x.isVisible(seq) { | ||
|  | 							break out | ||
|  | 						} | ||
|  | 					case *EnumSpecifier, *StructOrUnionSpecifier, *StructDeclarator, *LabeledStatement: | ||
|  | 						// nop | ||
|  | 					default: | ||
|  | 						panic(internalError()) | ||
|  | 					} | ||
|  | 				} | ||
|  | 			} | ||
|  | 		} | ||
|  | 	case PPNUMBER: | ||
|  | 		switch s := p.tok.Value.String(); { | ||
|  | 		case strings.ContainsAny(s, ".+-ijpIJP"): | ||
|  | 			p.tok.Rune = FLOATCONST | ||
|  | 		case strings.HasPrefix(s, "0x") || strings.HasPrefix(s, "0X"): | ||
|  | 			p.tok.Rune = INTCONST | ||
|  | 		case strings.ContainsAny(s, "Ee"): | ||
|  | 			p.tok.Rune = FLOATCONST | ||
|  | 		default: | ||
|  | 			p.tok.Rune = INTCONST | ||
|  | 		} | ||
|  | 	} | ||
|  | 	if p.ctx.cfg.SharedFunctionDefinitions != nil { | ||
|  | 		p.hashTok() | ||
|  | 	} | ||
|  | 	// dbg("parser.next p.tok %v", PrettyString(p.tok)) | ||
|  | 	// fmt.Printf("%s%s/* %s */", p.tok.Sep, p.tok.Value, tokName(p.tok.Rune)) //TODO- | ||
|  | } | ||
|  | 
 | ||
|  | func (p *parser) hashTok() { | ||
|  | 	n := p.tok.Rune | ||
|  | 	for i := 0; i < 4; i++ { | ||
|  | 		p.hash.WriteByte(byte(n)) | ||
|  | 		n >>= 8 | ||
|  | 	} | ||
|  | 	n = int32(p.tok.Value) | ||
|  | 	for i := 0; i < 4; i++ { | ||
|  | 		p.hash.WriteByte(byte(n)) | ||
|  | 		n >>= 8 | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | // [0], 6.5.1 Primary expressions | ||
|  | // | ||
|  | //  primary-expression: | ||
|  | // 	identifier | ||
|  | // 	constant | ||
|  | // 	string-literal | ||
|  | // 	( expression ) | ||
|  | // 	( compound-statement ) | ||
|  | func (p *parser) primaryExpression() *PrimaryExpression { | ||
|  | 	var kind PrimaryExpressionCase | ||
|  | 	var resolvedIn Scope | ||
|  | 	var resolvedTo Node | ||
|  | out: | ||
|  | 	switch p.rune() { | ||
|  | 	case IDENTIFIER: | ||
|  | 		kind = PrimaryExpressionIdent | ||
|  | 		nm := p.tok.Value | ||
|  | 		seq := p.tok.seq | ||
|  | 		for s := p.resolveScope; s != nil; s = s.Parent() { | ||
|  | 			for _, v := range s[nm] { | ||
|  | 				switch x := v.(type) { | ||
|  | 				case *Enumerator: | ||
|  | 					if x.isVisible(seq) { | ||
|  | 						resolvedIn = s | ||
|  | 						resolvedTo = x | ||
|  | 						p.tok.Rune = ENUMCONST | ||
|  | 						kind = PrimaryExpressionEnum | ||
|  | 						break out | ||
|  | 					} | ||
|  | 				case *Declarator: | ||
|  | 					if x.IsTypedefName || !x.isVisible(seq) { | ||
|  | 						continue | ||
|  | 					} | ||
|  | 
 | ||
|  | 					resolvedIn = s | ||
|  | 					resolvedTo = x | ||
|  | 					break out | ||
|  | 				case *EnumSpecifier, *StructOrUnionSpecifier, *StructDeclarator, *LabeledStatement: | ||
|  | 					// nop | ||
|  | 				default: | ||
|  | 					panic(internalError()) | ||
|  | 				} | ||
|  | 			} | ||
|  | 		} | ||
|  | 
 | ||
|  | 		if !p.ctx.cfg.ignoreUndefinedIdentifiers && p.ctx.cfg.RejectLateBinding { | ||
|  | 			p.err0(false, "front-end: undefined: %s", nm) | ||
|  | 		} | ||
|  | 	case INTCONST: | ||
|  | 		kind = PrimaryExpressionInt | ||
|  | 	case FLOATCONST: | ||
|  | 		kind = PrimaryExpressionFloat | ||
|  | 	case ENUMCONST: | ||
|  | 		kind = PrimaryExpressionEnum | ||
|  | 	case CHARCONST: | ||
|  | 		kind = PrimaryExpressionChar | ||
|  | 	case LONGCHARCONST: | ||
|  | 		kind = PrimaryExpressionLChar | ||
|  | 	case STRINGLITERAL: | ||
|  | 		kind = PrimaryExpressionString | ||
|  | 	case LONGSTRINGLITERAL: | ||
|  | 		kind = PrimaryExpressionLString | ||
|  | 	case '(': | ||
|  | 		t := p.shift() | ||
|  | 		switch p.peek(false) { | ||
|  | 		case '{': | ||
|  | 			if p.ctx.cfg.RejectStatementExpressions { | ||
|  | 				p.err0(false, "statement expressions not allowed") | ||
|  | 			} | ||
|  | 			s := p.compoundStatement(nil, nil) | ||
|  | 			var t2 Token | ||
|  | 			switch p.rune() { | ||
|  | 			case ')': | ||
|  | 				t2 = p.shift() | ||
|  | 			default: | ||
|  | 				p.err("expected )") | ||
|  | 			} | ||
|  | 			return &PrimaryExpression{Case: PrimaryExpressionStmt, Token: t, CompoundStatement: s, Token2: t2, lexicalScope: p.declScope} | ||
|  | 		default: | ||
|  | 			e := p.expression() | ||
|  | 			var t2 Token | ||
|  | 			switch p.rune() { | ||
|  | 			case ')': | ||
|  | 				t2 = p.shift() | ||
|  | 			default: | ||
|  | 				p.err("expected )") | ||
|  | 			} | ||
|  | 			return &PrimaryExpression{Case: PrimaryExpressionExpr, Token: t, Expression: e, Token2: t2, lexicalScope: p.declScope} | ||
|  | 		} | ||
|  | 	default: | ||
|  | 		p.err("expected primary-expression") | ||
|  | 		return nil | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return &PrimaryExpression{Case: kind, Token: p.shift(), lexicalScope: p.declScope, resolvedIn: resolvedIn, resolvedTo: resolvedTo} | ||
|  | } | ||
|  | 
 | ||
|  | // [0], 6.5.2 Postfix operators | ||
|  | // | ||
|  | //  postfix-expression: | ||
|  | // 	primary-expression | ||
|  | // 	postfix-expression [ expression ] | ||
|  | // 	postfix-expression ( argument-expression-list_opt ) | ||
|  | // 	postfix-expression . identifier | ||
|  | // 	postfix-expression -> identifier | ||
|  | // 	postfix-expression ++ | ||
|  | // 	postfix-expression -- | ||
|  | // 	( type-name ) { initializer-list } | ||
|  | // 	( type-name ) { initializer-list , } | ||
|  | // 	__builtin_types_compatible_p ( type-name , type-name ) | ||
|  | func (p *parser) postfixExpression(typ *TypeName) (r *PostfixExpression) { | ||
|  | 	var t, t2, t3, t4, t5 Token | ||
|  | out: | ||
|  | 	switch { | ||
|  | 	case typ != nil: | ||
|  | 		switch p.rune() { | ||
|  | 		case '{': | ||
|  | 			t3 = p.shift() | ||
|  | 		default: | ||
|  | 			p.err("expected {") | ||
|  | 			return nil | ||
|  | 		} | ||
|  | 
 | ||
|  | 		var list *InitializerList | ||
|  | 		switch p.rune() { | ||
|  | 		case '}': | ||
|  | 			if p.ctx.cfg.RejectEmptyInitializerList { | ||
|  | 				p.err0(false, "expected initializer-list") | ||
|  | 			} | ||
|  | 		default: | ||
|  | 			list = p.initializerList(nil) | ||
|  | 			if p.rune() == ',' { | ||
|  | 				t4 = p.shift() | ||
|  | 			} | ||
|  | 		} | ||
|  | 		switch p.rune() { | ||
|  | 		case '}': | ||
|  | 			t5 = p.shift() | ||
|  | 		default: | ||
|  | 			p.err("expected }") | ||
|  | 		} | ||
|  | 		r = &PostfixExpression{Case: PostfixExpressionComplit, Token: t, TypeName: typ, Token2: t2, Token3: t3, InitializerList: list, Token4: t4, Token5: t5} | ||
|  | 		break out | ||
|  | 	default: | ||
|  | 		switch p.rune() { | ||
|  | 		case BUILTINCHOOSEEXPR: | ||
|  | 			t = p.shift() | ||
|  | 			switch p.rune() { | ||
|  | 			case '(': | ||
|  | 				t2 = p.shift() | ||
|  | 			default: | ||
|  | 				p.err("expected (") | ||
|  | 			} | ||
|  | 			expr1 := p.assignmentExpression() | ||
|  | 			switch p.rune() { | ||
|  | 			case ',': | ||
|  | 				t3 = p.shift() | ||
|  | 			default: | ||
|  | 				p.err("expected ,") | ||
|  | 			} | ||
|  | 			expr2 := p.assignmentExpression() | ||
|  | 			switch p.rune() { | ||
|  | 			case ',': | ||
|  | 				t4 = p.shift() | ||
|  | 			default: | ||
|  | 				p.err("expected ,") | ||
|  | 			} | ||
|  | 			expr3 := p.assignmentExpression() | ||
|  | 			switch p.rune() { | ||
|  | 			case ')': | ||
|  | 				t5 = p.shift() | ||
|  | 			default: | ||
|  | 				p.err("expected )") | ||
|  | 			} | ||
|  | 			return &PostfixExpression{Case: PostfixExpressionChooseExpr, Token: t, Token2: t2, Token3: t3, Token4: t4, Token5: t5, AssignmentExpression: expr1, AssignmentExpression2: expr2, AssignmentExpression3: expr3} | ||
|  | 		case BUILTINTYPESCOMPATIBLE: | ||
|  | 			t = p.shift() | ||
|  | 			switch p.rune() { | ||
|  | 			case '(': | ||
|  | 				t2 = p.shift() | ||
|  | 			default: | ||
|  | 				p.err("expected (") | ||
|  | 			} | ||
|  | 			typ := p.typeName() | ||
|  | 			switch p.rune() { | ||
|  | 			case ',': | ||
|  | 				t3 = p.shift() | ||
|  | 			default: | ||
|  | 				p.err("expected ,") | ||
|  | 			} | ||
|  | 			typ2 := p.typeName() | ||
|  | 			switch p.rune() { | ||
|  | 			case ')': | ||
|  | 				t4 = p.shift() | ||
|  | 			default: | ||
|  | 				p.err("expected )") | ||
|  | 			} | ||
|  | 			return &PostfixExpression{Case: PostfixExpressionTypeCmp, Token: t, Token2: t2, TypeName: typ, Token3: t3, TypeName2: typ2, Token4: t4} | ||
|  | 		case '(': | ||
|  | 			switch p.peek(true) { | ||
|  | 			case VOID, CHAR, SHORT, INT, INT8, INT16, INT32, INT64, INT128, LONG, FLOAT, FLOAT16, FLOAT80, FLOAT32, FLOAT32X, FLOAT64, FLOAT64X, FLOAT128, DECIMAL32, DECIMAL64, DECIMAL128, FRACT, SAT, ACCUM, DOUBLE, SIGNED, UNSIGNED, BOOL, COMPLEX, STRUCT, UNION, ENUM, TYPEDEFNAME, TYPEOF, ATOMIC, | ||
|  | 				ATTRIBUTE, CONST, RESTRICT, VOLATILE: | ||
|  | 				p.typedefNameEnabled = true | ||
|  | 				t = p.shift() | ||
|  | 				typ := p.typeName() | ||
|  | 				p.typedefNameEnabled = false | ||
|  | 				switch p.rune() { | ||
|  | 				case ')': | ||
|  | 					t2 = p.shift() | ||
|  | 				default: | ||
|  | 					p.err("expected )") | ||
|  | 				} | ||
|  | 				switch p.rune() { | ||
|  | 				case '{': | ||
|  | 					t3 = p.shift() | ||
|  | 				default: | ||
|  | 					p.err("expected {") | ||
|  | 				} | ||
|  | 				var list *InitializerList | ||
|  | 				switch p.rune() { | ||
|  | 				case '}': | ||
|  | 					if p.ctx.cfg.RejectEmptyInitializerList { | ||
|  | 						p.err0(false, "expected initializer-list") | ||
|  | 					} | ||
|  | 				default: | ||
|  | 					list = p.initializerList(nil) | ||
|  | 					if p.rune() == ',' { | ||
|  | 						t4 = p.shift() | ||
|  | 					} | ||
|  | 				} | ||
|  | 				switch p.rune() { | ||
|  | 				case '}': | ||
|  | 					t5 = p.shift() | ||
|  | 				default: | ||
|  | 					p.err("expected }") | ||
|  | 				} | ||
|  | 				r = &PostfixExpression{Case: PostfixExpressionComplit, Token: t, TypeName: typ, Token2: t2, Token3: t3, InitializerList: list, Token4: t4, Token5: t5} | ||
|  | 				break out | ||
|  | 			} | ||
|  | 
 | ||
|  | 			fallthrough | ||
|  | 		default: | ||
|  | 			pe := p.primaryExpression() | ||
|  | 			if pe == nil { | ||
|  | 				return nil | ||
|  | 			} | ||
|  | 
 | ||
|  | 			r = &PostfixExpression{Case: PostfixExpressionPrimary, PrimaryExpression: pe} | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	for { | ||
|  | 		switch p.rune() { | ||
|  | 		case '[': | ||
|  | 			t = p.shift() | ||
|  | 			e := p.expression() | ||
|  | 			switch p.rune() { | ||
|  | 			case ']': | ||
|  | 				t2 = p.shift() | ||
|  | 			default: | ||
|  | 				p.err("expected ]") | ||
|  | 			} | ||
|  | 			r = &PostfixExpression{Case: PostfixExpressionIndex, PostfixExpression: r, Token: t, Expression: e, Token2: t2} | ||
|  | 		case '(': | ||
|  | 			t = p.shift() | ||
|  | 			list := p.argumentExpressionListOpt() | ||
|  | 			switch p.rune() { | ||
|  | 			case ')': | ||
|  | 				t2 = p.shift() | ||
|  | 			default: | ||
|  | 				p.err("expected )") | ||
|  | 			} | ||
|  | 			r = &PostfixExpression{Case: PostfixExpressionCall, PostfixExpression: r, Token: t, ArgumentExpressionList: list, Token2: t2} | ||
|  | 		case '.': | ||
|  | 			t = p.shift() | ||
|  | 			switch p.rune() { | ||
|  | 			case IDENTIFIER: | ||
|  | 				t2 = p.shift() | ||
|  | 			default: | ||
|  | 				p.err("expected identifier") | ||
|  | 			} | ||
|  | 			r = &PostfixExpression{Case: PostfixExpressionSelect, PostfixExpression: r, Token: t, Token2: t2} | ||
|  | 		case ARROW: | ||
|  | 			t = p.shift() | ||
|  | 			switch p.rune() { | ||
|  | 			case IDENTIFIER: | ||
|  | 				t2 = p.shift() | ||
|  | 			default: | ||
|  | 				p.err("expected identifier") | ||
|  | 			} | ||
|  | 			r = &PostfixExpression{Case: PostfixExpressionPSelect, PostfixExpression: r, Token: t, Token2: t2} | ||
|  | 		case INC: | ||
|  | 			r = &PostfixExpression{Case: PostfixExpressionInc, PostfixExpression: r, Token: p.shift()} | ||
|  | 		case DEC: | ||
|  | 			r = &PostfixExpression{Case: PostfixExpressionDec, PostfixExpression: r, Token: p.shift()} | ||
|  | 		default: | ||
|  | 			return r | ||
|  | 		} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | //  argument-expression-list: | ||
|  | // 	assignment-expression | ||
|  | // 	argument-expression-list , assignment-expression | ||
|  | func (p *parser) argumentExpressionListOpt() (r *ArgumentExpressionList) { | ||
|  | 	if p.rune() == ')' { | ||
|  | 		return nil | ||
|  | 	} | ||
|  | 
 | ||
|  | 	e := p.assignmentExpression() | ||
|  | 	if e == nil { | ||
|  | 		return nil | ||
|  | 	} | ||
|  | 
 | ||
|  | 	r = &ArgumentExpressionList{AssignmentExpression: e} | ||
|  | 	for prev := r; ; prev = prev.ArgumentExpressionList { | ||
|  | 		switch p.rune() { | ||
|  | 		case ',': | ||
|  | 			t := p.shift() | ||
|  | 			prev.ArgumentExpressionList = &ArgumentExpressionList{Token: t, AssignmentExpression: p.assignmentExpression()} | ||
|  | 		case ')': | ||
|  | 			return r | ||
|  | 		default: | ||
|  | 			p.err("expected , or )") | ||
|  | 			return r | ||
|  | 		} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | // [0], 6.5.3 Unary operators | ||
|  | // | ||
|  | //  unary-expression: | ||
|  | // 	postfix-expression | ||
|  | // 	++ unary-expression | ||
|  | // 	-- unary-expression | ||
|  | // 	unary-operator cast-expression | ||
|  | // 	sizeof unary-expression | ||
|  | // 	sizeof ( type-name ) | ||
|  | // 	&& identifier | ||
|  | // 	_Alignof unary-expression | ||
|  | // 	_Alignof ( type-name ) | ||
|  | // 	__imag__ unary-expression | ||
|  | // 	__real__ unary-expression | ||
|  | // | ||
|  | //  unary-operator: one of | ||
|  | // 	& * + - ~ ! | ||
|  | func (p *parser) unaryExpression(typ *TypeName) *UnaryExpression { | ||
|  | 	if typ != nil { | ||
|  | 		return &UnaryExpression{Case: UnaryExpressionPostfix, PostfixExpression: p.postfixExpression(typ), lexicalScope: p.declScope} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	var kind UnaryExpressionCase | ||
|  | 	var t, t2, t3 Token | ||
|  | 	switch p.rune() { | ||
|  | 	case INC: | ||
|  | 		t = p.shift() | ||
|  | 		return &UnaryExpression{Case: UnaryExpressionInc, Token: t, UnaryExpression: p.unaryExpression(nil), lexicalScope: p.declScope} | ||
|  | 	case DEC: | ||
|  | 		t = p.shift() | ||
|  | 		return &UnaryExpression{Case: UnaryExpressionDec, Token: t, UnaryExpression: p.unaryExpression(nil), lexicalScope: p.declScope} | ||
|  | 	case '&': | ||
|  | 		kind = UnaryExpressionAddrof | ||
|  | 	case '*': | ||
|  | 		kind = UnaryExpressionDeref | ||
|  | 	case '+': | ||
|  | 		kind = UnaryExpressionPlus | ||
|  | 	case '-': | ||
|  | 		kind = UnaryExpressionMinus | ||
|  | 	case '~': | ||
|  | 		kind = UnaryExpressionCpl | ||
|  | 	case '!': | ||
|  | 		kind = UnaryExpressionNot | ||
|  | 	case SIZEOF: | ||
|  | 		t = p.shift() | ||
|  | 		switch p.rune() { | ||
|  | 		case '(': | ||
|  | 			switch p.peek(true) { | ||
|  | 			case VOID, CHAR, SHORT, INT, INT8, INT16, INT32, INT64, INT128, LONG, FLOAT, FLOAT16, FLOAT80, FLOAT32, FLOAT32X, FLOAT64, FLOAT64X, FLOAT128, DECIMAL32, DECIMAL64, DECIMAL128, FRACT, SAT, ACCUM, DOUBLE, SIGNED, UNSIGNED, BOOL, COMPLEX, STRUCT, UNION, ENUM, TYPEDEFNAME, TYPEOF, ATOMIC, | ||
|  | 				ATTRIBUTE, CONST, RESTRICT, VOLATILE: | ||
|  | 				p.typedefNameEnabled = true | ||
|  | 				t2 = p.shift() | ||
|  | 				typ := p.typeName() | ||
|  | 				p.typedefNameEnabled = false | ||
|  | 				switch p.rune() { | ||
|  | 				case ')': | ||
|  | 					t3 = p.shift() | ||
|  | 				default: | ||
|  | 					p.err("expected )") | ||
|  | 				} | ||
|  | 				if p.peek(false) == '{' { | ||
|  | 					return &UnaryExpression{Case: UnaryExpressionSizeofExpr, Token: t, UnaryExpression: p.unaryExpression(typ), lexicalScope: p.declScope} | ||
|  | 				} | ||
|  | 
 | ||
|  | 				return &UnaryExpression{Case: UnaryExpressionSizeofType, Token: t, Token2: t2, TypeName: typ, Token3: t3, lexicalScope: p.declScope} | ||
|  | 			} | ||
|  | 
 | ||
|  | 			fallthrough | ||
|  | 		default: | ||
|  | 			return &UnaryExpression{Case: UnaryExpressionSizeofExpr, Token: t, UnaryExpression: p.unaryExpression(nil), lexicalScope: p.declScope} | ||
|  | 		} | ||
|  | 	case ANDAND: | ||
|  | 		t = p.shift() | ||
|  | 		var t2 Token | ||
|  | 		switch p.rune() { | ||
|  | 		case IDENTIFIER: | ||
|  | 			t2 = p.shift() | ||
|  | 		default: | ||
|  | 			p.err("expected identifier") | ||
|  | 		} | ||
|  | 		return &UnaryExpression{Case: UnaryExpressionLabelAddr, Token: t, Token2: t2, lexicalScope: p.declScope} | ||
|  | 	case ALIGNOF: | ||
|  | 		t = p.shift() | ||
|  | 		switch p.rune() { | ||
|  | 		case '(': | ||
|  | 			switch p.peek(true) { | ||
|  | 			case VOID, CHAR, SHORT, INT, INT8, INT16, INT32, INT64, INT128, LONG, FLOAT, FLOAT16, FLOAT80, FLOAT32, FLOAT32X, FLOAT64, FLOAT64X, FLOAT128, DECIMAL32, DECIMAL64, DECIMAL128, FRACT, SAT, ACCUM, DOUBLE, SIGNED, UNSIGNED, BOOL, COMPLEX, STRUCT, UNION, ENUM, TYPEDEFNAME, TYPEOF, ATOMIC, | ||
|  | 				ATTRIBUTE, CONST, RESTRICT, VOLATILE, | ||
|  | 				ALIGNAS: | ||
|  | 				t2 = p.shift() | ||
|  | 				typ := p.typeName() | ||
|  | 				switch p.rune() { | ||
|  | 				case ')': | ||
|  | 					t3 = p.shift() | ||
|  | 				default: | ||
|  | 					p.err("expected )") | ||
|  | 				} | ||
|  | 				return &UnaryExpression{Case: UnaryExpressionAlignofType, Token: t, Token2: t2, TypeName: typ, Token3: t2, lexicalScope: p.declScope} | ||
|  | 			default: | ||
|  | 				return &UnaryExpression{Case: UnaryExpressionAlignofExpr, Token: t, UnaryExpression: p.unaryExpression(nil), lexicalScope: p.declScope} | ||
|  | 			} | ||
|  | 		default: | ||
|  | 			return &UnaryExpression{Case: UnaryExpressionAlignofExpr, Token: t, UnaryExpression: p.unaryExpression(nil), lexicalScope: p.declScope} | ||
|  | 		} | ||
|  | 	case IMAG: | ||
|  | 		t = p.shift() | ||
|  | 		return &UnaryExpression{Case: UnaryExpressionImag, Token: t, UnaryExpression: p.unaryExpression(nil), lexicalScope: p.declScope} | ||
|  | 	case REAL: | ||
|  | 		t = p.shift() | ||
|  | 		return &UnaryExpression{Case: UnaryExpressionReal, Token: t, UnaryExpression: p.unaryExpression(nil), lexicalScope: p.declScope} | ||
|  | 	default: | ||
|  | 		return &UnaryExpression{Case: UnaryExpressionPostfix, PostfixExpression: p.postfixExpression(nil), lexicalScope: p.declScope} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	t = p.shift() | ||
|  | 	return &UnaryExpression{Case: kind, Token: t, CastExpression: p.castExpression(), lexicalScope: p.declScope} | ||
|  | } | ||
|  | 
 | ||
|  | // [0], 6.5.4 Cast operators | ||
|  | // | ||
|  | //  cast-expression: | ||
|  | // 	unary-expression | ||
|  | // 	( type-name ) cast-expression | ||
|  | func (p *parser) castExpression() *CastExpression { | ||
|  | 	var t, t2 Token | ||
|  | 	switch p.rune() { | ||
|  | 	case '(': | ||
|  | 		switch p.peek(true) { | ||
|  | 		case VOID, CHAR, SHORT, INT, INT8, INT16, INT32, INT64, INT128, LONG, FLOAT, FLOAT16, FLOAT80, FLOAT32, FLOAT32X, FLOAT64, FLOAT64X, FLOAT128, DECIMAL32, DECIMAL64, DECIMAL128, FRACT, SAT, ACCUM, DOUBLE, SIGNED, UNSIGNED, BOOL, COMPLEX, STRUCT, UNION, ENUM, TYPEDEFNAME, TYPEOF, ATOMIC, | ||
|  | 			ATTRIBUTE, CONST, RESTRICT, VOLATILE: | ||
|  | 			p.typedefNameEnabled = true | ||
|  | 			t = p.shift() | ||
|  | 			typ := p.typeName() | ||
|  | 			p.typedefNameEnabled = false | ||
|  | 			switch p.rune() { | ||
|  | 			case ')': | ||
|  | 				t2 = p.shift() | ||
|  | 			default: | ||
|  | 				p.err("expected )") | ||
|  | 			} | ||
|  | 			if p.peek(false) == '{' { | ||
|  | 				return &CastExpression{Case: CastExpressionUnary, UnaryExpression: p.unaryExpression(typ)} | ||
|  | 			} | ||
|  | 
 | ||
|  | 			return &CastExpression{Case: CastExpressionCast, Token: t, TypeName: typ, Token2: t2, CastExpression: p.castExpression()} | ||
|  | 		} | ||
|  | 
 | ||
|  | 		fallthrough | ||
|  | 	default: | ||
|  | 		return &CastExpression{Case: CastExpressionUnary, UnaryExpression: p.unaryExpression(nil)} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | // [0], 6.5.5 Multiplicative operators | ||
|  | // | ||
|  | //  multiplicative-expression: | ||
|  | // 	cast-expression | ||
|  | // 	multiplicative-expression * cast-expression | ||
|  | // 	multiplicative-expression / cast-expression | ||
|  | // 	multiplicative-expression % cast-expression | ||
|  | func (p *parser) multiplicativeExpression() (r *MultiplicativeExpression) { | ||
|  | 	r = &MultiplicativeExpression{Case: MultiplicativeExpressionCast, CastExpression: p.castExpression()} | ||
|  | 	for { | ||
|  | 		var kind MultiplicativeExpressionCase | ||
|  | 		switch p.rune() { | ||
|  | 		case '*': | ||
|  | 			kind = MultiplicativeExpressionMul | ||
|  | 		case '/': | ||
|  | 			kind = MultiplicativeExpressionDiv | ||
|  | 		case '%': | ||
|  | 			kind = MultiplicativeExpressionMod | ||
|  | 		default: | ||
|  | 			return r | ||
|  | 		} | ||
|  | 
 | ||
|  | 		t := p.shift() | ||
|  | 		r = &MultiplicativeExpression{Case: kind, MultiplicativeExpression: r, Token: t, CastExpression: p.castExpression()} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | // [0], 6.5.6 Additive operators | ||
|  | // | ||
|  | //  additive-expression: | ||
|  | // 	multiplicative-expression | ||
|  | // 	additive-expression + multiplicative-expression | ||
|  | // 	additive-expression - multiplicative-expression | ||
|  | func (p *parser) additiveExpression() (r *AdditiveExpression) { | ||
|  | 	r = &AdditiveExpression{Case: AdditiveExpressionMul, MultiplicativeExpression: p.multiplicativeExpression()} | ||
|  | 	for { | ||
|  | 		var kind AdditiveExpressionCase | ||
|  | 		switch p.rune() { | ||
|  | 		case '+': | ||
|  | 			kind = AdditiveExpressionAdd | ||
|  | 		case '-': | ||
|  | 			kind = AdditiveExpressionSub | ||
|  | 		default: | ||
|  | 			return r | ||
|  | 		} | ||
|  | 
 | ||
|  | 		t := p.shift() | ||
|  | 		r = &AdditiveExpression{Case: kind, AdditiveExpression: r, Token: t, MultiplicativeExpression: p.multiplicativeExpression(), lexicalScope: p.declScope} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | // [0], 6.5.7 Bitwise shift operators | ||
|  | // | ||
|  | //  shift-expression: | ||
|  | // 	additive-expression | ||
|  | // 	shift-expression << additive-expression | ||
|  | // 	shift-expression >> additive-expression | ||
|  | func (p *parser) shiftExpression() (r *ShiftExpression) { | ||
|  | 	r = &ShiftExpression{Case: ShiftExpressionAdd, AdditiveExpression: p.additiveExpression()} | ||
|  | 	for { | ||
|  | 		var kind ShiftExpressionCase | ||
|  | 		switch p.rune() { | ||
|  | 		case LSH: | ||
|  | 			kind = ShiftExpressionLsh | ||
|  | 		case RSH: | ||
|  | 			kind = ShiftExpressionRsh | ||
|  | 		default: | ||
|  | 			return r | ||
|  | 		} | ||
|  | 
 | ||
|  | 		t := p.shift() | ||
|  | 		r = &ShiftExpression{Case: kind, ShiftExpression: r, Token: t, AdditiveExpression: p.additiveExpression()} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | // [0], 6.5.8 Relational operators | ||
|  | // | ||
|  | //  relational-expression: | ||
|  | // 	shift-expression | ||
|  | // 	relational-expression <  shift-expression | ||
|  | // 	relational-expression >  shift-expression | ||
|  | // 	relational-expression <= shift-expression | ||
|  | // 	relational-expression >= shift-expression | ||
|  | func (p *parser) relationalExpression() (r *RelationalExpression) { | ||
|  | 	r = &RelationalExpression{Case: RelationalExpressionShift, ShiftExpression: p.shiftExpression()} | ||
|  | 	for { | ||
|  | 		var kind RelationalExpressionCase | ||
|  | 		switch p.rune() { | ||
|  | 		case '<': | ||
|  | 			kind = RelationalExpressionLt | ||
|  | 		case '>': | ||
|  | 			kind = RelationalExpressionGt | ||
|  | 		case LEQ: | ||
|  | 			kind = RelationalExpressionLeq | ||
|  | 		case GEQ: | ||
|  | 			kind = RelationalExpressionGeq | ||
|  | 		default: | ||
|  | 			return r | ||
|  | 		} | ||
|  | 
 | ||
|  | 		t := p.shift() | ||
|  | 		r = &RelationalExpression{Case: kind, RelationalExpression: r, Token: t, ShiftExpression: p.shiftExpression()} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | // [0], 6.5.9 Equality operators | ||
|  | // | ||
|  | //  equality-expression: | ||
|  | // 	relational-expression | ||
|  | // 	equality-expression == relational-expression | ||
|  | // 	equality-expression != relational-expression | ||
|  | func (p *parser) equalityExpression() (r *EqualityExpression) { | ||
|  | 	r = &EqualityExpression{Case: EqualityExpressionRel, RelationalExpression: p.relationalExpression()} | ||
|  | 	for { | ||
|  | 		var kind EqualityExpressionCase | ||
|  | 		switch p.rune() { | ||
|  | 		case EQ: | ||
|  | 			kind = EqualityExpressionEq | ||
|  | 		case NEQ: | ||
|  | 			kind = EqualityExpressionNeq | ||
|  | 		default: | ||
|  | 			return r | ||
|  | 		} | ||
|  | 
 | ||
|  | 		t := p.shift() | ||
|  | 		r = &EqualityExpression{Case: kind, EqualityExpression: r, Token: t, RelationalExpression: p.relationalExpression()} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | // [0], 6.5.10 Bitwise AND operator | ||
|  | // | ||
|  | //  AND-expression: | ||
|  | // 	equality-expression | ||
|  | // 	AND-expression & equality-expression | ||
|  | func (p *parser) andExpression() (r *AndExpression) { | ||
|  | 	r = &AndExpression{Case: AndExpressionEq, EqualityExpression: p.equalityExpression()} | ||
|  | 	for { | ||
|  | 		switch p.rune() { | ||
|  | 		case '&': | ||
|  | 			t := p.shift() | ||
|  | 			r = &AndExpression{Case: AndExpressionAnd, AndExpression: r, Token: t, EqualityExpression: p.equalityExpression()} | ||
|  | 		default: | ||
|  | 			return r | ||
|  | 		} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | // [0], 6.5.11 Bitwise exclusive OR operator | ||
|  | // | ||
|  | //  exclusive-OR-expression: | ||
|  | // 	AND-expression | ||
|  | // 	exclusive-OR-expression ^ AND-expression | ||
|  | func (p *parser) exclusiveOrExpression() (r *ExclusiveOrExpression) { | ||
|  | 	r = &ExclusiveOrExpression{Case: ExclusiveOrExpressionAnd, AndExpression: p.andExpression()} | ||
|  | 	for { | ||
|  | 		switch p.rune() { | ||
|  | 		case '^': | ||
|  | 			t := p.shift() | ||
|  | 			r = &ExclusiveOrExpression{Case: ExclusiveOrExpressionXor, ExclusiveOrExpression: r, Token: t, AndExpression: p.andExpression()} | ||
|  | 		default: | ||
|  | 			return r | ||
|  | 		} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | // [0], 6.5.12 Bitwise inclusive OR operator | ||
|  | // | ||
|  | //  inclusive-OR-expression: | ||
|  | // 	exclusive-OR-expression | ||
|  | // 	inclusive-OR-expression | exclusive-OR-expression | ||
|  | func (p *parser) inclusiveOrExpression() (r *InclusiveOrExpression) { | ||
|  | 	r = &InclusiveOrExpression{Case: InclusiveOrExpressionXor, ExclusiveOrExpression: p.exclusiveOrExpression()} | ||
|  | 	for { | ||
|  | 		switch p.rune() { | ||
|  | 		case '|': | ||
|  | 			t := p.shift() | ||
|  | 			r = &InclusiveOrExpression{Case: InclusiveOrExpressionOr, InclusiveOrExpression: r, Token: t, ExclusiveOrExpression: p.exclusiveOrExpression()} | ||
|  | 		default: | ||
|  | 			return r | ||
|  | 		} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | // [0], 6.5.13 Logical AND operator | ||
|  | // | ||
|  | //  logical-AND-expression: | ||
|  | // 	inclusive-OR-expression | ||
|  | // 	logical-AND-expression && inclusive-OR-expression | ||
|  | func (p *parser) logicalAndExpression() (r *LogicalAndExpression) { | ||
|  | 	r = &LogicalAndExpression{Case: LogicalAndExpressionOr, InclusiveOrExpression: p.inclusiveOrExpression()} | ||
|  | 	for { | ||
|  | 		switch p.rune() { | ||
|  | 		case ANDAND: | ||
|  | 			t := p.shift() | ||
|  | 			r = &LogicalAndExpression{Case: LogicalAndExpressionLAnd, LogicalAndExpression: r, Token: t, InclusiveOrExpression: p.inclusiveOrExpression()} | ||
|  | 		default: | ||
|  | 			return r | ||
|  | 		} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | // [0], 6.5.14 Logical OR operator | ||
|  | // | ||
|  | //  logical-OR-expression: | ||
|  | // 	logical-AND-expression | ||
|  | // 	logical-OR-expression || logical-AND-expression | ||
|  | func (p *parser) logicalOrExpression() (r *LogicalOrExpression) { | ||
|  | 	r = &LogicalOrExpression{Case: LogicalOrExpressionLAnd, LogicalAndExpression: p.logicalAndExpression()} | ||
|  | 	for { | ||
|  | 		switch p.rune() { | ||
|  | 		case OROR: | ||
|  | 			t := p.shift() | ||
|  | 			r = &LogicalOrExpression{Case: LogicalOrExpressionLOr, LogicalOrExpression: r, Token: t, LogicalAndExpression: p.logicalAndExpression()} | ||
|  | 		default: | ||
|  | 			return r | ||
|  | 		} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | // [0], 6.5.15 Conditional operator | ||
|  | // | ||
|  | //  conditional-expression: | ||
|  | // 	logical-OR-expression | ||
|  | // 	logical-OR-expression ? expression : conditional-expression | ||
|  | func (p *parser) conditionalExpression() (r *ConditionalExpression) { | ||
|  | 	lo := p.logicalOrExpression() | ||
|  | 	var t, t2 Token | ||
|  | 	switch p.rune() { | ||
|  | 	case '?': | ||
|  | 		t = p.shift() | ||
|  | 		var e *Expression | ||
|  | 		switch p.rune() { | ||
|  | 		case ':': | ||
|  | 			if p.ctx.cfg.RejectMissingConditionalExpr { | ||
|  | 				p.err("expected expression") | ||
|  | 			} | ||
|  | 		default: | ||
|  | 			e = p.expression() | ||
|  | 		} | ||
|  | 		switch p.rune() { | ||
|  | 		case ':': | ||
|  | 			t2 = p.shift() | ||
|  | 		default: | ||
|  | 			p.err("expected :") | ||
|  | 		} | ||
|  | 		return &ConditionalExpression{Case: ConditionalExpressionCond, LogicalOrExpression: lo, Token: t, Expression: e, Token2: t2, ConditionalExpression: p.conditionalExpression()} | ||
|  | 	default: | ||
|  | 		return &ConditionalExpression{Case: ConditionalExpressionLOr, LogicalOrExpression: lo} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | // [0], 6.5.16 Assignment operators | ||
|  | // | ||
|  | //  assignment-expression: | ||
|  | // 	conditional-expression | ||
|  | // 	unary-expression assignment-operator assignment-expression | ||
|  | // | ||
|  | //  assignment-operator: one of | ||
|  | // 	= *= /= %= += -= <<= >>= &= ^= |= | ||
|  | func (p *parser) assignmentExpression() (r *AssignmentExpression) { | ||
|  | 	ce := p.conditionalExpression() | ||
|  | 	if ce == nil || ce.Case != ConditionalExpressionLOr { | ||
|  | 		return &AssignmentExpression{Case: AssignmentExpressionCond, ConditionalExpression: ce, lexicalScope: p.declScope} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	loe := ce.LogicalOrExpression | ||
|  | 	if loe == nil || loe.Case != LogicalOrExpressionLAnd { | ||
|  | 		return &AssignmentExpression{Case: AssignmentExpressionCond, ConditionalExpression: ce, lexicalScope: p.declScope} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	lae := loe.LogicalAndExpression | ||
|  | 	if lae == nil || lae.Case != LogicalAndExpressionOr { | ||
|  | 		return &AssignmentExpression{Case: AssignmentExpressionCond, ConditionalExpression: ce, lexicalScope: p.declScope} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	ioe := lae.InclusiveOrExpression | ||
|  | 	if ioe == nil || ioe.Case != InclusiveOrExpressionXor { | ||
|  | 		return &AssignmentExpression{Case: AssignmentExpressionCond, ConditionalExpression: ce, lexicalScope: p.declScope} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	eoe := ioe.ExclusiveOrExpression | ||
|  | 	if eoe == nil || eoe.Case != ExclusiveOrExpressionAnd { | ||
|  | 		return &AssignmentExpression{Case: AssignmentExpressionCond, ConditionalExpression: ce, lexicalScope: p.declScope} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	ae := eoe.AndExpression | ||
|  | 	if ae == nil || ae.Case != AndExpressionEq { | ||
|  | 		return &AssignmentExpression{Case: AssignmentExpressionCond, ConditionalExpression: ce, lexicalScope: p.declScope} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	ee := ae.EqualityExpression | ||
|  | 	if ee == nil || ee.Case != EqualityExpressionRel { | ||
|  | 		return &AssignmentExpression{Case: AssignmentExpressionCond, ConditionalExpression: ce, lexicalScope: p.declScope} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	re := ee.RelationalExpression | ||
|  | 	if re == nil || re.Case != RelationalExpressionShift { | ||
|  | 		return &AssignmentExpression{Case: AssignmentExpressionCond, ConditionalExpression: ce, lexicalScope: p.declScope} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	se := re.ShiftExpression | ||
|  | 	if se == nil || se.Case != ShiftExpressionAdd { | ||
|  | 		return &AssignmentExpression{Case: AssignmentExpressionCond, ConditionalExpression: ce, lexicalScope: p.declScope} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	adde := se.AdditiveExpression | ||
|  | 	if adde == nil || adde.Case != AdditiveExpressionMul { | ||
|  | 		return &AssignmentExpression{Case: AssignmentExpressionCond, ConditionalExpression: ce, lexicalScope: p.declScope} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	me := adde.MultiplicativeExpression | ||
|  | 	if me == nil || me.Case != MultiplicativeExpressionCast { | ||
|  | 		return &AssignmentExpression{Case: AssignmentExpressionCond, ConditionalExpression: ce, lexicalScope: p.declScope} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	cast := me.CastExpression | ||
|  | 	if cast == nil || cast.Case != CastExpressionUnary { | ||
|  | 		return &AssignmentExpression{Case: AssignmentExpressionCond, ConditionalExpression: ce, lexicalScope: p.declScope} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	var kind AssignmentExpressionCase | ||
|  | 	switch p.rune() { | ||
|  | 	case '=': | ||
|  | 		kind = AssignmentExpressionAssign | ||
|  | 	case MULASSIGN: | ||
|  | 		kind = AssignmentExpressionMul | ||
|  | 	case DIVASSIGN: | ||
|  | 		kind = AssignmentExpressionDiv | ||
|  | 	case MODASSIGN: | ||
|  | 		kind = AssignmentExpressionMod | ||
|  | 	case ADDASSIGN: | ||
|  | 		kind = AssignmentExpressionAdd | ||
|  | 	case SUBASSIGN: | ||
|  | 		kind = AssignmentExpressionSub | ||
|  | 	case LSHASSIGN: | ||
|  | 		kind = AssignmentExpressionLsh | ||
|  | 	case RSHASSIGN: | ||
|  | 		kind = AssignmentExpressionRsh | ||
|  | 	case ANDASSIGN: | ||
|  | 		kind = AssignmentExpressionAnd | ||
|  | 	case XORASSIGN: | ||
|  | 		kind = AssignmentExpressionXor | ||
|  | 	case ORASSIGN: | ||
|  | 		kind = AssignmentExpressionOr | ||
|  | 	default: | ||
|  | 		return &AssignmentExpression{Case: AssignmentExpressionCond, ConditionalExpression: ce, lexicalScope: p.declScope} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	t := p.shift() | ||
|  | 	return &AssignmentExpression{Case: kind, UnaryExpression: cast.UnaryExpression, Token: t, AssignmentExpression: p.assignmentExpression(), lexicalScope: p.declScope} | ||
|  | } | ||
|  | 
 | ||
|  | // [0], 6.5.17 Comma operator | ||
|  | // | ||
|  | //  expression: | ||
|  | // 	assignment-expression | ||
|  | // 	expression , assignment-expression | ||
|  | func (p *parser) expression() (r *Expression) { | ||
|  | 	r = &Expression{Case: ExpressionAssign, AssignmentExpression: p.assignmentExpression()} | ||
|  | 	for { | ||
|  | 		switch p.rune() { | ||
|  | 		case ',': | ||
|  | 			t := p.shift() | ||
|  | 			r = &Expression{Case: ExpressionComma, Expression: r, Token: t, AssignmentExpression: p.assignmentExpression()} | ||
|  | 		default: | ||
|  | 			return r | ||
|  | 		} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | // [0], 6.6 Constant expressions | ||
|  | // | ||
|  | //  constant-expression: | ||
|  | // 	conditional-expression | ||
|  | func (p *parser) constantExpression() (r *ConstantExpression) { | ||
|  | 	return &ConstantExpression{ConditionalExpression: p.conditionalExpression()} | ||
|  | } | ||
|  | 
 | ||
|  | // [0], 6.7 Declarations | ||
|  | // | ||
|  | //  declaration: | ||
|  | // 	declaration-specifiers init-declarator-list_opt attribute-specifier-list_opt ; | ||
|  | func (p *parser) declaration(ds *DeclarationSpecifiers, d *Declarator) (r *Declaration) { | ||
|  | 	defer func() { | ||
|  | 		if cs := p.block; cs != nil && r != nil { | ||
|  | 			cs.declarations = append(cs.declarations, r) | ||
|  | 		} | ||
|  | 	}() | ||
|  | 
 | ||
|  | 	if ds == nil { | ||
|  | 		ds = p.declarationSpecifiers(nil, nil) | ||
|  | 	} | ||
|  | 	if ds == noDeclSpecs { | ||
|  | 		ds = nil | ||
|  | 	} | ||
|  | 	if d == nil { | ||
|  | 		switch p.rune() { | ||
|  | 		case ';': | ||
|  | 			p.typedefNameEnabled = true | ||
|  | 			return &Declaration{DeclarationSpecifiers: ds, Token: p.shift()} | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	list := p.initDeclaratorList(d, ds.typedef()) | ||
|  | 	p.typedefNameEnabled = true | ||
|  | 	var t Token | ||
|  | 	switch p.rune() { | ||
|  | 	case ';': | ||
|  | 		t = p.shift() | ||
|  | 	default: | ||
|  | 		p.err("expected ;") | ||
|  | 	} | ||
|  | 	return &Declaration{DeclarationSpecifiers: ds, InitDeclaratorList: list, Token: t} | ||
|  | } | ||
|  | 
 | ||
|  | //  declaration-specifiers: | ||
|  | // 	storage-class-specifier declaration-specifiers_opt | ||
|  | // 	type-specifier declaration-specifiers_opt | ||
|  | // 	type-qualifier declaration-specifiers_opt | ||
|  | // 	function-specifier declaration-specifiers_opt | ||
|  | //	alignment-specifier declaration-specifiers_opt | ||
|  | //	attribute-specifier declaration-specifiers_opt | ||
|  | func (p *parser) declarationSpecifiers(extern, inline *bool) (r *DeclarationSpecifiers) { | ||
|  | 	switch p.rune() { | ||
|  | 	case TYPEDEF, EXTERN, STATIC, AUTO, REGISTER, THREADLOCAL: | ||
|  | 		if extern != nil && p.rune() == EXTERN { | ||
|  | 			*extern = true | ||
|  | 		} | ||
|  | 		r = &DeclarationSpecifiers{Case: DeclarationSpecifiersStorage, StorageClassSpecifier: p.storageClassSpecifier()} | ||
|  | 		if r.StorageClassSpecifier.Case == StorageClassSpecifierTypedef { | ||
|  | 			r.class = fTypedef | ||
|  | 		} | ||
|  | 	case VOID, CHAR, SHORT, INT, INT8, INT16, INT32, INT64, INT128, LONG, FLOAT, FLOAT16, FLOAT80, FLOAT32, FLOAT32X, FLOAT64, FLOAT64X, FLOAT128, DECIMAL32, DECIMAL64, DECIMAL128, FRACT, SAT, ACCUM, DOUBLE, SIGNED, UNSIGNED, BOOL, COMPLEX, STRUCT, UNION, ENUM, TYPEDEFNAME, TYPEOF: | ||
|  | 		r = &DeclarationSpecifiers{Case: DeclarationSpecifiersTypeSpec, TypeSpecifier: p.typeSpecifier()} | ||
|  | 	case CONST, RESTRICT, VOLATILE: | ||
|  | 		r = &DeclarationSpecifiers{Case: DeclarationSpecifiersTypeQual, TypeQualifier: p.typeQualifier()} | ||
|  | 	case INLINE, NORETURN: | ||
|  | 		r = &DeclarationSpecifiers{Case: DeclarationSpecifiersFunc, FunctionSpecifier: p.functionSpecifier(inline)} | ||
|  | 	case ALIGNAS: | ||
|  | 		r = &DeclarationSpecifiers{Case: DeclarationSpecifiersAlignSpec, AlignmentSpecifier: p.alignmentSpecifier()} | ||
|  | 	case ATOMIC: | ||
|  | 		switch p.peek(false) { | ||
|  | 		case '(': | ||
|  | 			r = &DeclarationSpecifiers{Case: DeclarationSpecifiersTypeSpec, TypeSpecifier: p.typeSpecifier()} | ||
|  | 		default: | ||
|  | 			r = &DeclarationSpecifiers{Case: DeclarationSpecifiersTypeQual, TypeQualifier: p.typeQualifier()} | ||
|  | 		} | ||
|  | 	case ATTRIBUTE: | ||
|  | 		r = &DeclarationSpecifiers{Case: DeclarationSpecifiersAttribute, AttributeSpecifier: p.attributeSpecifier()} | ||
|  | 	default: | ||
|  | 		p.err("expected declaration-specifiers") | ||
|  | 		return nil | ||
|  | 	} | ||
|  | 	r0 := r | ||
|  | 	for prev := r; ; prev = prev.DeclarationSpecifiers { | ||
|  | 		switch p.rune() { | ||
|  | 		case TYPEDEF, EXTERN, STATIC, AUTO, REGISTER, THREADLOCAL: | ||
|  | 			if extern != nil && p.rune() == EXTERN { | ||
|  | 				*extern = true | ||
|  | 			} | ||
|  | 			prev.DeclarationSpecifiers = &DeclarationSpecifiers{Case: DeclarationSpecifiersStorage, StorageClassSpecifier: p.storageClassSpecifier()} | ||
|  | 			if prev.DeclarationSpecifiers.StorageClassSpecifier.Case == StorageClassSpecifierTypedef { | ||
|  | 				r0.class |= fTypedef | ||
|  | 			} | ||
|  | 		case VOID, CHAR, SHORT, INT, INT8, INT16, INT32, INT64, INT128, LONG, FLOAT, FLOAT16, FLOAT80, FLOAT32, FLOAT32X, FLOAT64, FLOAT64X, FLOAT128, DECIMAL32, DECIMAL64, DECIMAL128, FRACT, SAT, ACCUM, DOUBLE, SIGNED, UNSIGNED, BOOL, COMPLEX, STRUCT, UNION, ENUM, TYPEDEFNAME, TYPEOF: | ||
|  | 			prev.DeclarationSpecifiers = &DeclarationSpecifiers{Case: DeclarationSpecifiersTypeSpec, TypeSpecifier: p.typeSpecifier()} | ||
|  | 		case CONST, RESTRICT, VOLATILE: | ||
|  | 			prev.DeclarationSpecifiers = &DeclarationSpecifiers{Case: DeclarationSpecifiersTypeQual, TypeQualifier: p.typeQualifier()} | ||
|  | 		case INLINE, NORETURN: | ||
|  | 			prev.DeclarationSpecifiers = &DeclarationSpecifiers{Case: DeclarationSpecifiersFunc, FunctionSpecifier: p.functionSpecifier(inline)} | ||
|  | 		case ALIGNAS: | ||
|  | 			prev.DeclarationSpecifiers = &DeclarationSpecifiers{Case: DeclarationSpecifiersAlignSpec, AlignmentSpecifier: p.alignmentSpecifier()} | ||
|  | 		case ATOMIC: | ||
|  | 			switch p.peek(false) { | ||
|  | 			case '(': | ||
|  | 				prev.DeclarationSpecifiers = &DeclarationSpecifiers{Case: DeclarationSpecifiersTypeSpec, TypeSpecifier: p.typeSpecifier()} | ||
|  | 			default: | ||
|  | 				prev.DeclarationSpecifiers = &DeclarationSpecifiers{Case: DeclarationSpecifiersTypeQual, TypeQualifier: p.typeQualifier()} | ||
|  | 			} | ||
|  | 		case ATTRIBUTE: | ||
|  | 			prev.DeclarationSpecifiers = &DeclarationSpecifiers{Case: DeclarationSpecifiersAttribute, AttributeSpecifier: p.attributeSpecifier()} | ||
|  | 		default: | ||
|  | 			return r | ||
|  | 		} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | //  init-declarator-list: | ||
|  | // 	init-declarator | ||
|  | // 	init-declarator-list , attribute-specifier-list_opt init-declarator | ||
|  | func (p *parser) initDeclaratorList(d *Declarator, isTypedefName bool) (r *InitDeclaratorList) { | ||
|  | 	r = &InitDeclaratorList{InitDeclarator: p.initDeclarator(d, isTypedefName)} | ||
|  | 	for prev := r; ; prev = prev.InitDeclaratorList { | ||
|  | 		switch p.rune() { | ||
|  | 		case ',': | ||
|  | 			t := p.shift() | ||
|  | 			attr := p.attributeSpecifierListOpt() | ||
|  | 			// if attr != nil { | ||
|  | 			// 	trc("%v: ATTRS", attr.Position()) | ||
|  | 			// } | ||
|  | 			prev.InitDeclaratorList = &InitDeclaratorList{Token: t, AttributeSpecifierList: attr, InitDeclarator: p.initDeclarator(nil, isTypedefName)} | ||
|  | 		default: | ||
|  | 			return r | ||
|  | 		} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | func (p *parser) attributeSpecifierListOpt() (r *AttributeSpecifierList) { | ||
|  | 	if p.rune() == ATTRIBUTE { | ||
|  | 		r = p.attributeSpecifierList() | ||
|  | 	} | ||
|  | 	return r | ||
|  | } | ||
|  | 
 | ||
|  | //  init-declarator: | ||
|  | // 	declarator attribute-specifier-list_opt | ||
|  | // 	declarator attribute-specifier-list_opt = initializer | ||
|  | func (p *parser) initDeclarator(d *Declarator, isTypedefName bool) *InitDeclarator { | ||
|  | 	if d == nil { | ||
|  | 		d = p.declarator(true, isTypedefName, nil) | ||
|  | 	} | ||
|  | 	attr := p.attributeSpecifierListOpt() | ||
|  | 	// if attr != nil { | ||
|  | 	// 	trc("%v: ATTRS", attr.Position()) | ||
|  | 	// } | ||
|  | 	switch p.rune() { | ||
|  | 	case '=': | ||
|  | 		t := p.shift() | ||
|  | 		return &InitDeclarator{Case: InitDeclaratorInit, Declarator: d, AttributeSpecifierList: attr, Token: t, Initializer: p.initializer(nil)} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return &InitDeclarator{Case: InitDeclaratorDecl, Declarator: d, AttributeSpecifierList: attr} | ||
|  | } | ||
|  | 
 | ||
|  | // [0], 6.7.1 Storage-class specifiers | ||
|  | // | ||
|  | //  storage-class-specifier: | ||
|  | // 	typedef | ||
|  | // 	extern | ||
|  | // 	static | ||
|  | // 	auto | ||
|  | // 	register | ||
|  | func (p *parser) storageClassSpecifier() *StorageClassSpecifier { | ||
|  | 	var kind StorageClassSpecifierCase | ||
|  | 	switch p.rune() { | ||
|  | 	case TYPEDEF: | ||
|  | 		kind = StorageClassSpecifierTypedef | ||
|  | 	case EXTERN: | ||
|  | 		kind = StorageClassSpecifierExtern | ||
|  | 	case STATIC: | ||
|  | 		kind = StorageClassSpecifierStatic | ||
|  | 	case AUTO: | ||
|  | 		kind = StorageClassSpecifierAuto | ||
|  | 	case REGISTER: | ||
|  | 		kind = StorageClassSpecifierRegister | ||
|  | 	case THREADLOCAL: | ||
|  | 		kind = StorageClassSpecifierThreadLocal | ||
|  | 	default: | ||
|  | 		p.err("expected storage-class-specifier") | ||
|  | 		return nil | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return &StorageClassSpecifier{Case: kind, Token: p.shift()} | ||
|  | } | ||
|  | 
 | ||
|  | // [0], 6.7.2 Type specifiers | ||
|  | // | ||
|  | //  type-specifier: | ||
|  | // 	void | ||
|  | // 	char | ||
|  | // 	short | ||
|  | // 	int | ||
|  | // 	long | ||
|  | // 	float | ||
|  | // 	__fp16 | ||
|  | // 	__float80 | ||
|  | // 	double | ||
|  | // 	signed | ||
|  | // 	unsigned | ||
|  | // 	_Bool | ||
|  | // 	_Complex | ||
|  | // 	_Float128 | ||
|  | // 	struct-or-union-specifier | ||
|  | // 	enum-specifier | ||
|  | // 	typedef-name | ||
|  | // 	typeof ( expression ) | ||
|  | // 	typeof ( type-name ) | ||
|  | //	atomic-type-specifier | ||
|  | //	_Frac | ||
|  | //	_Sat | ||
|  | //	_Accum | ||
|  | // 	_Float32 | ||
|  | func (p *parser) typeSpecifier() *TypeSpecifier { | ||
|  | 	var kind TypeSpecifierCase | ||
|  | 	switch p.rune() { | ||
|  | 	case VOID: | ||
|  | 		kind = TypeSpecifierVoid | ||
|  | 	case CHAR: | ||
|  | 		kind = TypeSpecifierChar | ||
|  | 	case SHORT: | ||
|  | 		kind = TypeSpecifierShort | ||
|  | 	case INT: | ||
|  | 		kind = TypeSpecifierInt | ||
|  | 	case INT8: | ||
|  | 		kind = TypeSpecifierInt8 | ||
|  | 	case INT16: | ||
|  | 		kind = TypeSpecifierInt16 | ||
|  | 	case INT32: | ||
|  | 		kind = TypeSpecifierInt32 | ||
|  | 	case INT64: | ||
|  | 		kind = TypeSpecifierInt64 | ||
|  | 	case INT128: | ||
|  | 		kind = TypeSpecifierInt128 | ||
|  | 	case LONG: | ||
|  | 		kind = TypeSpecifierLong | ||
|  | 	case FLOAT: | ||
|  | 		kind = TypeSpecifierFloat | ||
|  | 	case FLOAT16: | ||
|  | 		kind = TypeSpecifierFloat16 | ||
|  | 	case FLOAT80: | ||
|  | 		kind = TypeSpecifierFloat80 | ||
|  | 	case FLOAT32: | ||
|  | 		kind = TypeSpecifierFloat32 | ||
|  | 	case FLOAT32X: | ||
|  | 		kind = TypeSpecifierFloat32x | ||
|  | 	case FLOAT64: | ||
|  | 		kind = TypeSpecifierFloat64 | ||
|  | 	case FLOAT64X: | ||
|  | 		kind = TypeSpecifierFloat64x | ||
|  | 	case FLOAT128: | ||
|  | 		kind = TypeSpecifierFloat128 | ||
|  | 	case DECIMAL32: | ||
|  | 		kind = TypeSpecifierDecimal32 | ||
|  | 	case DECIMAL64: | ||
|  | 		kind = TypeSpecifierDecimal64 | ||
|  | 	case DECIMAL128: | ||
|  | 		kind = TypeSpecifierDecimal128 | ||
|  | 	case DOUBLE: | ||
|  | 		kind = TypeSpecifierDouble | ||
|  | 	case SIGNED: | ||
|  | 		kind = TypeSpecifierSigned | ||
|  | 	case UNSIGNED: | ||
|  | 		kind = TypeSpecifierUnsigned | ||
|  | 	case BOOL: | ||
|  | 		kind = TypeSpecifierBool | ||
|  | 	case COMPLEX: | ||
|  | 		kind = TypeSpecifierComplex | ||
|  | 	case FRACT: | ||
|  | 		kind = TypeSpecifierFract | ||
|  | 	case SAT: | ||
|  | 		kind = TypeSpecifierSat | ||
|  | 	case ACCUM: | ||
|  | 		kind = TypeSpecifierAccum | ||
|  | 	case TYPEDEFNAME: | ||
|  | 		kind = TypeSpecifierTypedefName | ||
|  | 	case STRUCT, UNION: | ||
|  | 		r := &TypeSpecifier{Case: TypeSpecifierStructOrUnion, StructOrUnionSpecifier: p.structOrUnionSpecifier()} | ||
|  | 		p.typedefNameEnabled = false | ||
|  | 		return r | ||
|  | 	case ENUM: | ||
|  | 		r := &TypeSpecifier{Case: TypeSpecifierEnum, EnumSpecifier: p.enumSpecifier()} | ||
|  | 		p.typedefNameEnabled = false | ||
|  | 		return r | ||
|  | 	case TYPEOF: | ||
|  | 		var t, t2, t3 Token | ||
|  | 		t = p.shift() | ||
|  | 		switch p.rune() { | ||
|  | 		case '(': | ||
|  | 			t2 = p.shift() | ||
|  | 		default: | ||
|  | 			p.err("expected (") | ||
|  | 		} | ||
|  | 		switch p.rune() { | ||
|  | 		case VOID, CHAR, SHORT, INT, INT8, INT16, INT32, INT64, INT128, LONG, FLOAT, FLOAT16, FLOAT80, FLOAT32, FLOAT32X, FLOAT64, FLOAT64X, FLOAT128, DECIMAL32, DECIMAL64, DECIMAL128, FRACT, SAT, ACCUM, DOUBLE, SIGNED, UNSIGNED, BOOL, COMPLEX, STRUCT, UNION, ENUM, TYPEDEFNAME, TYPEOF, ATOMIC, | ||
|  | 			ATTRIBUTE, CONST, RESTRICT, VOLATILE, | ||
|  | 			ALIGNAS: | ||
|  | 			typ := p.typeName() | ||
|  | 			switch p.rune() { | ||
|  | 			case ')': | ||
|  | 				t3 = p.shift() | ||
|  | 			default: | ||
|  | 				p.err("expected )") | ||
|  | 			} | ||
|  | 			return &TypeSpecifier{Case: TypeSpecifierTypeofType, Token: t, Token2: t2, TypeName: typ, Token3: t3} | ||
|  | 		default: | ||
|  | 			e := p.expression() | ||
|  | 			switch p.rune() { | ||
|  | 			case ')': | ||
|  | 				t3 = p.shift() | ||
|  | 			default: | ||
|  | 				p.err("expected )") | ||
|  | 			} | ||
|  | 			return &TypeSpecifier{Case: TypeSpecifierTypeofExpr, Token: t, Token2: t2, Expression: e, Token3: t3} | ||
|  | 		} | ||
|  | 	case ATOMIC: | ||
|  | 		return &TypeSpecifier{Case: TypeSpecifierAtomic, AtomicTypeSpecifier: p.atomicTypeSpecifier()} | ||
|  | 	default: | ||
|  | 		p.err("expected type-specifier") | ||
|  | 		return nil | ||
|  | 	} | ||
|  | 
 | ||
|  | 	p.typedefNameEnabled = false | ||
|  | 	return &TypeSpecifier{Case: kind, Token: p.shift(), resolvedIn: p.resolvedIn} | ||
|  | } | ||
|  | 
 | ||
|  | // [0], 6.7.2.1 Structure and union specifiers | ||
|  | // | ||
|  | //  struct-or-union-specifier: | ||
|  | // 	struct-or-union attribute-specifier-list_opt identifier_opt { struct-declaration-list } | ||
|  | // 	struct-or-union attribute-specifier-list_opt identifier | ||
|  | func (p *parser) structOrUnionSpecifier() *StructOrUnionSpecifier { | ||
|  | 	switch p.rune() { | ||
|  | 	case STRUCT, UNION: | ||
|  | 	default: | ||
|  | 		p.err("expected struct-or-union-specifier") | ||
|  | 		return nil | ||
|  | 	} | ||
|  | 
 | ||
|  | 	sou := p.structOrUnion() | ||
|  | 	attr := p.attributeSpecifierListOpt() | ||
|  | 	// if attr != nil { | ||
|  | 	// 	trc("%v: ATTRS", attr.Position()) | ||
|  | 	// } | ||
|  | 	var t, t2, t3 Token | ||
|  | 	switch p.rune() { | ||
|  | 	case IDENTIFIER: | ||
|  | 		t = p.shift() | ||
|  | 		if p.rune() != '{' { | ||
|  | 			return &StructOrUnionSpecifier{Case: StructOrUnionSpecifierTag, StructOrUnion: sou, AttributeSpecifierList: attr, Token: t, lexicalScope: p.declScope} | ||
|  | 		} | ||
|  | 
 | ||
|  | 		fallthrough | ||
|  | 	case '{': | ||
|  | 		maxAlign := p.ctx.maxAlign | ||
|  | 		p.openScope(true) | ||
|  | 		p.typedefNameEnabled = true | ||
|  | 		p.resolveScope = p.declScope.Parent() | ||
|  | 		t2 = p.shift() | ||
|  | 		var list *StructDeclarationList | ||
|  | 		switch p.peek(false) { | ||
|  | 		case '}': | ||
|  | 			if p.ctx.cfg.RejectEmptyStructs { | ||
|  | 				p.err("expected struct-declarator-list") | ||
|  | 			} | ||
|  | 		default: | ||
|  | 			list = p.structDeclarationList() | ||
|  | 		} | ||
|  | 		p.closeScope() | ||
|  | 		switch p.rune() { | ||
|  | 		case '}': | ||
|  | 			t3 = p.shift() | ||
|  | 		default: | ||
|  | 			p.err("expected }") | ||
|  | 		} | ||
|  | 		r := &StructOrUnionSpecifier{Case: StructOrUnionSpecifierDef, StructOrUnion: sou, AttributeSpecifierList: attr, Token: t, Token2: t2, StructDeclarationList: list, Token3: t3, lexicalScope: p.declScope, maxAlign: maxAlign} | ||
|  | 		if t.Value != 0 { | ||
|  | 			p.declScope.declare(t.Value, r) | ||
|  | 		} | ||
|  | 		return r | ||
|  | 	default: | ||
|  | 		p.err("expected identifier or {") | ||
|  | 		return nil | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | //  struct-or-union: | ||
|  | // 	struct | ||
|  | // 	union | ||
|  | func (p *parser) structOrUnion() *StructOrUnion { | ||
|  | 	var kind StructOrUnionCase | ||
|  | 	switch p.rune() { | ||
|  | 	case STRUCT: | ||
|  | 		kind = StructOrUnionStruct | ||
|  | 	case UNION: | ||
|  | 		kind = StructOrUnionUnion | ||
|  | 	default: | ||
|  | 		p.err("expected struct-or-union") | ||
|  | 		return nil | ||
|  | 	} | ||
|  | 
 | ||
|  | 	p.typedefNameEnabled = false | ||
|  | 	return &StructOrUnion{Case: kind, Token: p.shift()} | ||
|  | } | ||
|  | 
 | ||
|  | //  struct-declaration-list: | ||
|  | // 	struct-declaration | ||
|  | // 	struct-declaration-list struct-declaration | ||
|  | func (p *parser) structDeclarationList() (r *StructDeclarationList) { | ||
|  | 	r = &StructDeclarationList{StructDeclaration: p.structDeclaration()} | ||
|  | 	for prev := r; ; prev = prev.StructDeclarationList { | ||
|  | 		switch p.rune() { | ||
|  | 		case VOID, CHAR, SHORT, INT, INT8, INT16, INT32, INT64, INT128, LONG, FLOAT, FLOAT16, FLOAT80, FLOAT32, FLOAT32X, FLOAT64, FLOAT64X, FLOAT128, DECIMAL32, DECIMAL64, DECIMAL128, FRACT, SAT, ACCUM, DOUBLE, SIGNED, UNSIGNED, BOOL, COMPLEX, STRUCT, UNION, ENUM, TYPEDEFNAME, TYPEOF, ATOMIC, | ||
|  | 			ATTRIBUTE, CONST, RESTRICT, VOLATILE, | ||
|  | 			ALIGNAS: | ||
|  | 			prev.StructDeclarationList = &StructDeclarationList{StructDeclaration: p.structDeclaration()} | ||
|  | 		case ';': | ||
|  | 			p.shift() | ||
|  | 			if p.ctx.cfg.RejectEmptyFields { | ||
|  | 				p.err("expected struct-declaration") | ||
|  | 			} | ||
|  | 		default: | ||
|  | 			return r | ||
|  | 		} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | //  struct-declaration: | ||
|  | // 	specifier-qualifier-list struct-declarator-list ; | ||
|  | func (p *parser) structDeclaration() (r *StructDeclaration) { | ||
|  | 	if p.rune() == ';' { | ||
|  | 		if p.ctx.cfg.RejectEmptyStructDeclaration { | ||
|  | 			p.err("expected struct-declaration") | ||
|  | 		} | ||
|  | 		return &StructDeclaration{Empty: true, Token: p.shift()} | ||
|  | 	} | ||
|  | 	sql := p.specifierQualifierList() | ||
|  | 	r = &StructDeclaration{SpecifierQualifierList: sql} | ||
|  | 	switch p.rune() { | ||
|  | 	case ';': | ||
|  | 		if p.ctx.cfg.RejectAnonymousFields { | ||
|  | 			p.err("expected struct-declarator") | ||
|  | 		} | ||
|  | 	default: | ||
|  | 		r.StructDeclaratorList = p.structDeclaratorList(r) | ||
|  | 	} | ||
|  | 	var t Token | ||
|  | 	p.typedefNameEnabled = true | ||
|  | 	switch p.rune() { | ||
|  | 	case '}': | ||
|  | 		if p.ctx.cfg.RejectMissingFinalStructFieldSemicolon { | ||
|  | 			p.err0(false, "expected ;") | ||
|  | 		} | ||
|  | 	case ';': | ||
|  | 		t = p.shift() | ||
|  | 	default: | ||
|  | 		p.err("expected ;") | ||
|  | 	} | ||
|  | 	r.Token = t | ||
|  | 	return r | ||
|  | } | ||
|  | 
 | ||
|  | //  specifier-qualifier-list: | ||
|  | // 	type-specifier specifier-qualifier-list_opt | ||
|  | // 	type-qualifier specifier-qualifier-list_opt | ||
|  | // 	alignment-specifier-qualifier-list_opt | ||
|  | func (p *parser) specifierQualifierList() (r *SpecifierQualifierList) { | ||
|  | 	switch p.rune() { | ||
|  | 	case VOID, CHAR, SHORT, INT, INT8, INT16, INT32, INT64, INT128, LONG, FLOAT, FLOAT16, FLOAT80, FLOAT32, FLOAT32X, FLOAT64, FLOAT64X, FLOAT128, DECIMAL32, DECIMAL64, DECIMAL128, FRACT, SAT, ACCUM, DOUBLE, SIGNED, UNSIGNED, BOOL, COMPLEX, STRUCT, UNION, ENUM, TYPEDEFNAME, TYPEOF: | ||
|  | 		r = &SpecifierQualifierList{Case: SpecifierQualifierListTypeSpec, TypeSpecifier: p.typeSpecifier()} | ||
|  | 	case CONST, RESTRICT, VOLATILE: | ||
|  | 		r = &SpecifierQualifierList{Case: SpecifierQualifierListTypeQual, TypeQualifier: p.typeQualifier()} | ||
|  | 	case ALIGNAS: | ||
|  | 		r = &SpecifierQualifierList{Case: SpecifierQualifierListAlignSpec, AlignmentSpecifier: p.alignmentSpecifier()} | ||
|  | 	case ATOMIC: | ||
|  | 		switch p.peek(false) { | ||
|  | 		case '(': | ||
|  | 			r = &SpecifierQualifierList{Case: SpecifierQualifierListTypeSpec, TypeSpecifier: p.typeSpecifier()} | ||
|  | 		default: | ||
|  | 			r = &SpecifierQualifierList{Case: SpecifierQualifierListTypeQual, TypeQualifier: p.typeQualifier()} | ||
|  | 		} | ||
|  | 	case ATTRIBUTE: | ||
|  | 		r = &SpecifierQualifierList{Case: SpecifierQualifierListAttribute, AttributeSpecifier: p.attributeSpecifier()} | ||
|  | 	default: | ||
|  | 		p.err("expected specifier-qualifier-list: %s", tokName(p.rune())) | ||
|  | 		return nil | ||
|  | 	} | ||
|  | 	for prev := r; ; prev = prev.SpecifierQualifierList { | ||
|  | 		switch p.rune() { | ||
|  | 		case VOID, CHAR, SHORT, INT, INT8, INT16, INT32, INT64, INT128, LONG, FLOAT, FLOAT16, FLOAT80, FLOAT32, FLOAT32X, FLOAT64, FLOAT64X, FLOAT128, DECIMAL32, DECIMAL64, DECIMAL128, FRACT, SAT, ACCUM, DOUBLE, SIGNED, UNSIGNED, BOOL, COMPLEX, STRUCT, UNION, ENUM, TYPEDEFNAME, TYPEOF: | ||
|  | 			prev.SpecifierQualifierList = &SpecifierQualifierList{Case: SpecifierQualifierListTypeSpec, TypeSpecifier: p.typeSpecifier()} | ||
|  | 		case CONST, RESTRICT, VOLATILE: | ||
|  | 			prev.SpecifierQualifierList = &SpecifierQualifierList{Case: SpecifierQualifierListTypeQual, TypeQualifier: p.typeQualifier()} | ||
|  | 		case ALIGNAS: | ||
|  | 			prev.SpecifierQualifierList = &SpecifierQualifierList{Case: SpecifierQualifierListAlignSpec, AlignmentSpecifier: p.alignmentSpecifier()} | ||
|  | 		case ATOMIC: | ||
|  | 			switch p.peek(false) { | ||
|  | 			case '(': | ||
|  | 				prev.SpecifierQualifierList = &SpecifierQualifierList{Case: SpecifierQualifierListTypeSpec, TypeSpecifier: p.typeSpecifier()} | ||
|  | 			default: | ||
|  | 				prev.SpecifierQualifierList = &SpecifierQualifierList{Case: SpecifierQualifierListTypeQual, TypeQualifier: p.typeQualifier()} | ||
|  | 			} | ||
|  | 		case ATTRIBUTE: | ||
|  | 			prev.SpecifierQualifierList = &SpecifierQualifierList{Case: SpecifierQualifierListAttribute, AttributeSpecifier: p.attributeSpecifier()} | ||
|  | 		default: | ||
|  | 			return r | ||
|  | 		} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | //  struct-declarator-list: | ||
|  | // 	struct-declarator | ||
|  | // 	struct-declarator-list , struct-declarator | ||
|  | func (p *parser) structDeclaratorList(decl *StructDeclaration) (r *StructDeclaratorList) { | ||
|  | 	r = &StructDeclaratorList{StructDeclarator: p.structDeclarator(decl)} | ||
|  | 	for prev := r; ; prev = prev.StructDeclaratorList { | ||
|  | 		switch p.rune() { | ||
|  | 		case ',': | ||
|  | 			t := p.shift() | ||
|  | 			prev.StructDeclaratorList = &StructDeclaratorList{Token: t, StructDeclarator: p.structDeclarator(decl)} | ||
|  | 		default: | ||
|  | 			return r | ||
|  | 		} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | //  struct-declarator: | ||
|  | // 	declarator | ||
|  | // 	declarator_opt : constant-expression attribute-specifier-list_opt | ||
|  | func (p *parser) structDeclarator(decl *StructDeclaration) (r *StructDeclarator) { | ||
|  | 	var d *Declarator | ||
|  | 	if p.rune() != ':' { | ||
|  | 		d = p.declarator(false, false, nil) | ||
|  | 	} | ||
|  | 
 | ||
|  | 	switch p.rune() { | ||
|  | 	case ':': | ||
|  | 		t := p.shift() | ||
|  | 		r = &StructDeclarator{Case: StructDeclaratorBitField, Declarator: d, Token: t, ConstantExpression: p.constantExpression(), decl: decl} | ||
|  | 		r.AttributeSpecifierList = p.attributeSpecifierListOpt() | ||
|  | 		// if r.AttributeSpecifierList != nil { | ||
|  | 		// 	trc("%v: ATTRS", r.AttributeSpecifierList.Position()) | ||
|  | 		// } | ||
|  | 	default: | ||
|  | 		r = &StructDeclarator{Case: StructDeclaratorDecl, Declarator: d, decl: decl} | ||
|  | 	} | ||
|  | 	if d != nil { | ||
|  | 		p.declScope.declare(d.Name(), r) | ||
|  | 	} | ||
|  | 	return r | ||
|  | } | ||
|  | 
 | ||
|  | // [0], 6.7.2.2 Enumeration specifiers | ||
|  | // | ||
|  | //  enum-specifier: | ||
|  | // 	enum attribute-specifier-list_opt identifier_opt { enumerator-list } | ||
|  | // 	enum attribute-specifier-list_opt identifier_opt { enumerator-list , } | ||
|  | // 	enum attribute-specifier-list_opt identifier | ||
|  | func (p *parser) enumSpecifier() *EnumSpecifier { | ||
|  | 	if p.rune() != ENUM { | ||
|  | 		p.err("expected enum") | ||
|  | 		return nil | ||
|  | 	} | ||
|  | 
 | ||
|  | 	var t, t2, t3, t4, t5 Token | ||
|  | 	p.typedefNameEnabled = false | ||
|  | 	t = p.shift() | ||
|  | 	attr := p.attributeSpecifierListOpt() | ||
|  | 	// if attr != nil { | ||
|  | 	// 	trc("%v: ATTRS", attr.Position()) | ||
|  | 	// } | ||
|  | 	if p.rune() == IDENTIFIER { | ||
|  | 		t2 = p.shift() | ||
|  | 		if p.rune() != '{' { | ||
|  | 			return &EnumSpecifier{Case: EnumSpecifierTag, AttributeSpecifierList: attr, Token: t, Token2: t2, lexicalScope: p.declScope} | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	if p.rune() != '{' { | ||
|  | 		p.err("expected identifier or {") | ||
|  | 		return nil | ||
|  | 	} | ||
|  | 
 | ||
|  | 	p.typedefNameEnabled = false | ||
|  | 	t3 = p.shift() | ||
|  | 	list := p.enumeratorList() | ||
|  | 	if p.rune() == ',' { | ||
|  | 		t4 = p.shift() | ||
|  | 	} | ||
|  | 
 | ||
|  | 	switch p.rune() { | ||
|  | 	case '}': | ||
|  | 		t5 = p.shift() | ||
|  | 	default: | ||
|  | 		p.err("expected }") | ||
|  | 	} | ||
|  | 	r := &EnumSpecifier{Case: EnumSpecifierDef, AttributeSpecifierList: attr, Token: t, Token2: t2, Token3: t3, EnumeratorList: list, Token4: t4, Token5: t5, lexicalScope: p.declScope} | ||
|  | 	if t2.Value != 0 { | ||
|  | 		p.declScope.declare(t2.Value, r) | ||
|  | 	} | ||
|  | 	return r | ||
|  | } | ||
|  | 
 | ||
|  | //  enumerator-list: | ||
|  | // 	enumerator | ||
|  | // 	enumerator-list , enumerator | ||
|  | func (p *parser) enumeratorList() *EnumeratorList { | ||
|  | 	r := &EnumeratorList{Enumerator: p.enumerator()} | ||
|  | 	for prev := r; ; prev = prev.EnumeratorList { | ||
|  | 		switch p.rune() { | ||
|  | 		case ',': | ||
|  | 			if p.peek(false) == '}' { | ||
|  | 				return r | ||
|  | 			} | ||
|  | 
 | ||
|  | 			t := p.shift() | ||
|  | 			prev.EnumeratorList = &EnumeratorList{Token: t, Enumerator: p.enumerator()} | ||
|  | 		default: | ||
|  | 			return r | ||
|  | 		} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | //  enumerator: | ||
|  | // 	enumeration-constant attribute-specifier-list_opt | ||
|  | // 	enumeration-constant attribute-specifier-list_opt = constant-expression | ||
|  | func (p *parser) enumerator() (r *Enumerator) { | ||
|  | 	if p.rune() != IDENTIFIER { | ||
|  | 		p.err("expected enumeration-constant") | ||
|  | 		return nil | ||
|  | 	} | ||
|  | 
 | ||
|  | 	t := p.shift() | ||
|  | 	attr := p.attributeSpecifierListOpt() | ||
|  | 	// if attr != nil { | ||
|  | 	// 	trc("%v: ATTRS", attr.Position()) | ||
|  | 	// } | ||
|  | 	if p.rune() != '=' { | ||
|  | 		r = &Enumerator{Case: EnumeratorIdent, Token: t, AttributeSpecifierList: attr, lexicalScope: p.declScope} | ||
|  | 		p.declScope.declare(t.Value, r) | ||
|  | 		return r | ||
|  | 	} | ||
|  | 
 | ||
|  | 	t2 := p.shift() | ||
|  | 	r = &Enumerator{Case: EnumeratorExpr, Token: t, AttributeSpecifierList: attr, Token2: t2, ConstantExpression: p.constantExpression(), lexicalScope: p.declScope} | ||
|  | 	p.declScope.declare(t.Value, r) | ||
|  | 	return r | ||
|  | } | ||
|  | 
 | ||
|  | // [2], 6.7.2.4 Atomic type specifiers | ||
|  | // | ||
|  | //  atomic-type-specifier: | ||
|  | // 	_Atomic ( type-name ) | ||
|  | func (p *parser) atomicTypeSpecifier() *AtomicTypeSpecifier { | ||
|  | 	if p.rune() != ATOMIC { | ||
|  | 		p.err("expected _Atomic") | ||
|  | 		return nil | ||
|  | 	} | ||
|  | 
 | ||
|  | 	t := p.shift() | ||
|  | 	var t2, t3 Token | ||
|  | 	switch p.rune() { | ||
|  | 	case '(': | ||
|  | 		t2 = p.shift() | ||
|  | 	default: | ||
|  | 		p.err("expected (") | ||
|  | 	} | ||
|  | 	typ := p.typeName() | ||
|  | 	switch p.rune() { | ||
|  | 	case ')': | ||
|  | 		t3 = p.shift() | ||
|  | 	default: | ||
|  | 		p.err("expected )") | ||
|  | 	} | ||
|  | 	return &AtomicTypeSpecifier{Token: t, Token2: t2, TypeName: typ, Token3: t3} | ||
|  | } | ||
|  | 
 | ||
|  | // [0], 6.7.3 Type qualifiers | ||
|  | // | ||
|  | //  type-qualifier: | ||
|  | // 	const | ||
|  | // 	restrict | ||
|  | // 	volatile | ||
|  | // 	_Atomic | ||
|  | func (p *parser) typeQualifier() *TypeQualifier { | ||
|  | 	switch p.rune() { | ||
|  | 	case CONST: | ||
|  | 		return &TypeQualifier{Case: TypeQualifierConst, Token: p.shift()} | ||
|  | 	case RESTRICT: | ||
|  | 		return &TypeQualifier{Case: TypeQualifierRestrict, Token: p.shift()} | ||
|  | 	case VOLATILE: | ||
|  | 		return &TypeQualifier{Case: TypeQualifierVolatile, Token: p.shift()} | ||
|  | 	case ATOMIC: | ||
|  | 		return &TypeQualifier{Case: TypeQualifierAtomic, Token: p.shift()} | ||
|  | 	default: | ||
|  | 		p.err("expected type-qualifier") | ||
|  | 		return nil | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | // [0], 6.7.4 Function specifiers | ||
|  | // | ||
|  | //  function-specifier: | ||
|  | // 	inline | ||
|  | // 	_Noreturn | ||
|  | func (p *parser) functionSpecifier(inline *bool) *FunctionSpecifier { | ||
|  | 	switch p.rune() { | ||
|  | 	case INLINE: | ||
|  | 		if inline != nil { | ||
|  | 			*inline = true | ||
|  | 		} | ||
|  | 		return &FunctionSpecifier{Case: FunctionSpecifierInline, Token: p.shift()} | ||
|  | 	case NORETURN: | ||
|  | 		return &FunctionSpecifier{Case: FunctionSpecifierNoreturn, Token: p.shift()} | ||
|  | 	default: | ||
|  | 		p.err("expected function-specifier") | ||
|  | 		return nil | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | // [0], 6.7.5 Declarators | ||
|  | // | ||
|  | //  declarator: | ||
|  | // 	pointer_opt direct-declarator attribute-specifier-list_opt | ||
|  | func (p *parser) declarator(declare, isTypedefName bool, ptr *Pointer) *Declarator { | ||
|  | 	if ptr == nil && (p.rune() == '*' || p.rune() == '^') { | ||
|  | 		ptr = p.pointer() | ||
|  | 	} | ||
|  | 	r := &Declarator{IsTypedefName: isTypedefName, Pointer: ptr, DirectDeclarator: p.directDeclarator(nil)} | ||
|  | 	r.AttributeSpecifierList = p.attributeSpecifierListOpt() | ||
|  | 	// if r.AttributeSpecifierList != nil { | ||
|  | 	// 	trc("%v: ATTRS", r.AttributeSpecifierList.Position()) | ||
|  | 	// } | ||
|  | 	if declare { | ||
|  | 		p.declScope.declare(r.Name(), r) | ||
|  | 	} | ||
|  | 	return r | ||
|  | } | ||
|  | 
 | ||
|  | // [2], 6.7.5 Alignment specifier | ||
|  | // | ||
|  | // alignment-specifier: | ||
|  | // 	_Alignas ( type-name ) | ||
|  | // 	_Alignas ( constant-expression ) | ||
|  | func (p *parser) alignmentSpecifier() *AlignmentSpecifier { | ||
|  | 	if p.rune() != ALIGNAS { | ||
|  | 		p.err("expected _Alignas") | ||
|  | 		return nil | ||
|  | 	} | ||
|  | 
 | ||
|  | 	t := p.shift() | ||
|  | 	var t2, t3 Token | ||
|  | 	switch p.rune() { | ||
|  | 	case '(': | ||
|  | 		t2 = p.shift() | ||
|  | 	default: | ||
|  | 		p.err("expected (") | ||
|  | 	} | ||
|  | 	switch p.rune() { | ||
|  | 	case VOID, CHAR, SHORT, INT, INT8, INT16, INT32, INT64, INT128, LONG, FLOAT, FLOAT16, FLOAT80, FLOAT32, FLOAT32X, FLOAT64, FLOAT64X, FLOAT128, DECIMAL32, DECIMAL64, DECIMAL128, FRACT, SAT, ACCUM, DOUBLE, SIGNED, UNSIGNED, BOOL, COMPLEX, STRUCT, UNION, ENUM, TYPEDEFNAME, TYPEOF, ATOMIC, | ||
|  | 		ATTRIBUTE, CONST, RESTRICT, VOLATILE, | ||
|  | 		ALIGNAS: | ||
|  | 		typ := p.typeName() | ||
|  | 		switch p.rune() { | ||
|  | 		case ')': | ||
|  | 			t3 = p.shift() | ||
|  | 		default: | ||
|  | 			p.err("expected )") | ||
|  | 		} | ||
|  | 		return &AlignmentSpecifier{Case: AlignmentSpecifierAlignasType, Token: t, Token2: t2, TypeName: typ, Token3: t3} | ||
|  | 	default: | ||
|  | 		e := p.constantExpression() | ||
|  | 		switch p.rune() { | ||
|  | 		case ')': | ||
|  | 			t3 = p.shift() | ||
|  | 		default: | ||
|  | 			p.err("expected )") | ||
|  | 		} | ||
|  | 		return &AlignmentSpecifier{Case: AlignmentSpecifierAlignasExpr, Token: t, Token2: t2, ConstantExpression: e, Token3: t3} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | //  direct-declarator: | ||
|  | // 	identifier asm_opt | ||
|  | // 	( attribute-specifier-list_opt declarator ) | ||
|  | // 	direct-declarator [ type-qualifier-list_opt assignment-expression_opt ] | ||
|  | // 	direct-declarator [ static type-qualifier-list_opt assignment-expression ] | ||
|  | // 	direct-declarator [ type-qualifier-list static assignment-expression ] | ||
|  | // 	direct-declarator [ type-qualifier-list_opt * ] | ||
|  | // 	direct-declarator ( parameter-type-list ) | ||
|  | // 	direct-declarator ( identifier-list_opt ) | ||
|  | func (p *parser) directDeclarator(d *DirectDeclarator) (r *DirectDeclarator) { | ||
|  | 	switch { | ||
|  | 	case d != nil: | ||
|  | 		r = d | ||
|  | 	default: | ||
|  | 		switch p.rune() { | ||
|  | 		case IDENTIFIER: | ||
|  | 			t := p.shift() | ||
|  | 			var a *Asm | ||
|  | 			if p.rune() == ASM { | ||
|  | 				a = p.asm() | ||
|  | 			} | ||
|  | 			r = &DirectDeclarator{Case: DirectDeclaratorIdent, Token: t, Asm: a, lexicalScope: p.declScope} | ||
|  | 		case '(': | ||
|  | 			t := p.shift() | ||
|  | 			attr := p.attributeSpecifierListOpt() | ||
|  | 			// if attr != nil { | ||
|  | 			// 	trc("%v: ATTRS", attr.Position()) | ||
|  | 			// } | ||
|  | 			d := p.declarator(false, false, nil) | ||
|  | 			var t2 Token | ||
|  | 			switch p.rune() { | ||
|  | 			case ')': | ||
|  | 				t2 = p.shift() | ||
|  | 			default: | ||
|  | 				p.err("expected )") | ||
|  | 			} | ||
|  | 			r = &DirectDeclarator{Case: DirectDeclaratorDecl, Token: t, AttributeSpecifierList: attr, Declarator: d, Token2: t2, lexicalScope: p.declScope} | ||
|  | 		default: | ||
|  | 			p.err("expected direct-declarator") | ||
|  | 			return nil | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	var t, t2, t3 Token | ||
|  | 	for { | ||
|  | 		var e *AssignmentExpression | ||
|  | 		switch p.rune() { | ||
|  | 		case '[': | ||
|  | 			t = p.shift() | ||
|  | 			switch p.rune() { | ||
|  | 			case ']': | ||
|  | 				t2 = p.shift() | ||
|  | 				r = &DirectDeclarator{Case: DirectDeclaratorArr, DirectDeclarator: r, Token: t, Token2: t2, lexicalScope: p.declScope} | ||
|  | 			case ATTRIBUTE, CONST, RESTRICT, VOLATILE, ATOMIC: // type-qualifier | ||
|  | 				list := p.typeQualifierList() | ||
|  | 				switch p.rune() { | ||
|  | 				case STATIC: | ||
|  | 					t2 = p.shift() | ||
|  | 					e = p.assignmentExpression() | ||
|  | 					switch p.rune() { | ||
|  | 					case ']': | ||
|  | 						t3 = p.shift() | ||
|  | 					default: | ||
|  | 						p.err("expected ]") | ||
|  | 					} | ||
|  | 					r = &DirectDeclarator{Case: DirectDeclaratorArrStatic, DirectDeclarator: r, Token: t, TypeQualifiers: list, Token2: t2, AssignmentExpression: e, Token3: t3, lexicalScope: p.declScope} | ||
|  | 				case ']': | ||
|  | 					r = &DirectDeclarator{Case: DirectDeclaratorArr, DirectDeclarator: r, Token: t, TypeQualifiers: list, Token2: p.shift(), lexicalScope: p.declScope} | ||
|  | 				case '*': | ||
|  | 					switch p.peek(false) { | ||
|  | 					case ']': | ||
|  | 						t2 = p.shift() | ||
|  | 						r = &DirectDeclarator{Case: DirectDeclaratorStar, DirectDeclarator: r, Token: t, TypeQualifiers: list, Token2: t2, Token3: p.shift(), lexicalScope: p.declScope} | ||
|  | 					default: | ||
|  | 						e = p.assignmentExpression() | ||
|  | 						switch p.rune() { | ||
|  | 						case ']': | ||
|  | 							t2 = p.shift() | ||
|  | 						default: | ||
|  | 							p.err("expected ]") | ||
|  | 						} | ||
|  | 						r = &DirectDeclarator{Case: DirectDeclaratorArr, DirectDeclarator: r, Token: t, TypeQualifiers: list, AssignmentExpression: e, Token2: t2, lexicalScope: p.declScope} | ||
|  | 					} | ||
|  | 				default: | ||
|  | 					e = p.assignmentExpression() | ||
|  | 					switch p.rune() { | ||
|  | 					case ']': | ||
|  | 						t2 = p.shift() | ||
|  | 					default: | ||
|  | 						p.err("expected ]") | ||
|  | 					} | ||
|  | 					r = &DirectDeclarator{Case: DirectDeclaratorArr, DirectDeclarator: r, Token: t, TypeQualifiers: list, AssignmentExpression: e, Token2: t2, lexicalScope: p.declScope} | ||
|  | 				} | ||
|  | 			case STATIC: | ||
|  | 				t2 := p.shift() | ||
|  | 				var list *TypeQualifiers | ||
|  | 				switch p.peek(false) { | ||
|  | 				case ATTRIBUTE, CONST, RESTRICT, VOLATILE, ATOMIC: | ||
|  | 					list = p.typeQualifierList() | ||
|  | 				} | ||
|  | 				e := p.assignmentExpression() | ||
|  | 				switch p.rune() { | ||
|  | 				case ']': | ||
|  | 					t3 = p.shift() | ||
|  | 				default: | ||
|  | 					p.err("expected ]") | ||
|  | 				} | ||
|  | 				r = &DirectDeclarator{Case: DirectDeclaratorStaticArr, DirectDeclarator: r, Token: t, Token2: t2, TypeQualifiers: list, AssignmentExpression: e, Token3: t3, lexicalScope: p.declScope} | ||
|  | 			case '*': | ||
|  | 				if p.peek(false) == ']' { | ||
|  | 					t2 = p.shift() | ||
|  | 					r = &DirectDeclarator{Case: DirectDeclaratorStar, DirectDeclarator: r, Token: t, Token2: t2, Token3: p.shift(), lexicalScope: p.declScope} | ||
|  | 					break | ||
|  | 				} | ||
|  | 
 | ||
|  | 				fallthrough | ||
|  | 			default: | ||
|  | 				e = p.assignmentExpression() | ||
|  | 				switch p.rune() { | ||
|  | 				case ']': | ||
|  | 					t2 = p.shift() | ||
|  | 				default: | ||
|  | 					p.err("expected ]") | ||
|  | 				} | ||
|  | 				r = &DirectDeclarator{Case: DirectDeclaratorArr, DirectDeclarator: r, Token: t, AssignmentExpression: e, Token2: t2, lexicalScope: p.declScope} | ||
|  | 			} | ||
|  | 		case '(': | ||
|  | 			p.openScope(false) | ||
|  | 			p.typedefNameEnabled = true | ||
|  | 			t = p.shift() | ||
|  | 			paramScope := p.declScope | ||
|  | 			switch p.rune() { | ||
|  | 			case IDENTIFIER: | ||
|  | 				list := p.identifierList() | ||
|  | 				p.closeScope() | ||
|  | 				p.typedefNameEnabled = true | ||
|  | 				switch p.rune() { | ||
|  | 				case ')': | ||
|  | 					t2 = p.shift() | ||
|  | 				default: | ||
|  | 					p.err("expected )") | ||
|  | 				} | ||
|  | 				r = &DirectDeclarator{Case: DirectDeclaratorFuncIdent, DirectDeclarator: r, Token: t, IdentifierList: list, Token2: t2, paramScope: paramScope, lexicalScope: p.declScope} | ||
|  | 			case ')': | ||
|  | 				p.closeScope() | ||
|  | 				p.typedefNameEnabled = true | ||
|  | 				r = &DirectDeclarator{Case: DirectDeclaratorFuncIdent, DirectDeclarator: r, Token: t, Token2: p.shift(), paramScope: paramScope, lexicalScope: p.declScope} | ||
|  | 			default: | ||
|  | 				list := p.parameterTypeList() | ||
|  | 				p.closeScope() | ||
|  | 				p.typedefNameEnabled = true | ||
|  | 				switch p.rune() { | ||
|  | 				case ')': | ||
|  | 					t2 = p.shift() | ||
|  | 				default: | ||
|  | 					p.err("expected )") | ||
|  | 				} | ||
|  | 				r = &DirectDeclarator{Case: DirectDeclaratorFuncParam, DirectDeclarator: r, Token: t, ParameterTypeList: list, Token2: t2, paramScope: paramScope, lexicalScope: p.declScope} | ||
|  | 			} | ||
|  | 		default: | ||
|  | 			return r | ||
|  | 		} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | //  pointer: | ||
|  | // 	* type-qualifier-list_opt | ||
|  | // 	* type-qualifier-list_opt pointer | ||
|  | //      ^ type-qualifier-list_opt | ||
|  | func (p *parser) pointer() (r *Pointer) { | ||
|  | 	if p.rune() == '^' { | ||
|  | 		t := p.shift() | ||
|  | 		var list *TypeQualifiers | ||
|  | 		switch p.rune() { | ||
|  | 		case ATTRIBUTE, CONST, RESTRICT, VOLATILE, ATOMIC: | ||
|  | 			list = p.typeQualifierList() | ||
|  | 		} | ||
|  | 
 | ||
|  | 		return &Pointer{Case: PointerBlock, Token: t, TypeQualifiers: list} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	if p.rune() != '*' { | ||
|  | 		p.err("expected * or ^") | ||
|  | 		return nil | ||
|  | 	} | ||
|  | 
 | ||
|  | 	t := p.shift() | ||
|  | 	var list *TypeQualifiers | ||
|  | 	switch p.rune() { | ||
|  | 	case ATTRIBUTE, CONST, RESTRICT, VOLATILE, ATOMIC: | ||
|  | 		list = p.typeQualifierList() | ||
|  | 	} | ||
|  | 
 | ||
|  | 	switch p.rune() { | ||
|  | 	case '*': | ||
|  | 		return &Pointer{Case: PointerPtr, Token: t, TypeQualifiers: list, Pointer: p.pointer()} | ||
|  | 	default: | ||
|  | 		return &Pointer{Case: PointerTypeQual, Token: t, TypeQualifiers: list} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | //  type-qualifier-list: | ||
|  | // 	type-qualifier | ||
|  | // 	attribute-specifier | ||
|  | // 	type-qualifier-list type-qualifier | ||
|  | // 	type-qualifier-list attribute-specifier | ||
|  | func (p *parser) typeQualifierList() (r *TypeQualifiers) { | ||
|  | 	switch p.rune() { | ||
|  | 	case ATTRIBUTE: | ||
|  | 		r = &TypeQualifiers{Case: TypeQualifiersAttribute, AttributeSpecifier: p.attributeSpecifier()} | ||
|  | 	default: | ||
|  | 		r = &TypeQualifiers{Case: TypeQualifiersTypeQual, TypeQualifier: p.typeQualifier()} | ||
|  | 	} | ||
|  | 	for prev := r; ; prev = prev.TypeQualifiers { | ||
|  | 		switch p.rune() { | ||
|  | 		case ATTRIBUTE: | ||
|  | 			prev.TypeQualifiers = &TypeQualifiers{Case: TypeQualifiersAttribute, AttributeSpecifier: p.attributeSpecifier()} | ||
|  | 		case CONST, RESTRICT, VOLATILE, ATOMIC: | ||
|  | 			prev.TypeQualifiers = &TypeQualifiers{TypeQualifier: p.typeQualifier()} | ||
|  | 		default: | ||
|  | 			return r | ||
|  | 		} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | //  parameter-type-list: | ||
|  | // 	parameter-list | ||
|  | // 	parameter-list , ... | ||
|  | func (p *parser) parameterTypeList() *ParameterTypeList { | ||
|  | 	list := p.parameterList() | ||
|  | 	switch p.rune() { | ||
|  | 	case ',': | ||
|  | 		t := p.shift() | ||
|  | 		var t2 Token | ||
|  | 		switch p.rune() { | ||
|  | 		case DDD: | ||
|  | 			t2 = p.shift() | ||
|  | 		default: | ||
|  | 			p.err("expected ...") | ||
|  | 		} | ||
|  | 		return &ParameterTypeList{Case: ParameterTypeListVar, ParameterList: list, Token: t, Token2: t2} | ||
|  | 	default: | ||
|  | 		return &ParameterTypeList{Case: ParameterTypeListList, ParameterList: list} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | //  parameter-list: | ||
|  | // 	parameter-declaration | ||
|  | // 	parameter-list , parameter-declaration | ||
|  | func (p *parser) parameterList() (r *ParameterList) { | ||
|  | 	r = &ParameterList{ParameterDeclaration: p.parameterDeclaration()} | ||
|  | 	for prev := r; ; prev = prev.ParameterList { | ||
|  | 		switch p.rune() { | ||
|  | 		case ';': | ||
|  | 			if p.ctx.cfg.RejectParamSemicolon { | ||
|  | 				p.err0(false, "expected ,") | ||
|  | 			} | ||
|  | 			fallthrough | ||
|  | 		case ',': | ||
|  | 			if p.peek(false) == DDD { | ||
|  | 				return r | ||
|  | 			} | ||
|  | 
 | ||
|  | 			p.typedefNameEnabled = true | ||
|  | 			t := p.shift() | ||
|  | 			prev.ParameterList = &ParameterList{Token: t, ParameterDeclaration: p.parameterDeclaration()} | ||
|  | 		default: | ||
|  | 			return r | ||
|  | 		} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | //  parameter-declaration: | ||
|  | // 	declaration-specifiers declarator attribute-specifier-list_opt | ||
|  | // 	declaration-specifiers abstract-declarator_opt | ||
|  | func (p *parser) parameterDeclaration() *ParameterDeclaration { | ||
|  | 	ds := p.declarationSpecifiers(nil, nil) | ||
|  | 	switch p.rune() { | ||
|  | 	case ',', ')': | ||
|  | 		r := &ParameterDeclaration{Case: ParameterDeclarationAbstract, DeclarationSpecifiers: ds} | ||
|  | 		return r | ||
|  | 	default: | ||
|  | 		switch x := p.declaratorOrAbstractDeclarator(ds.typedef()).(type) { | ||
|  | 		case *AbstractDeclarator: | ||
|  | 			return &ParameterDeclaration{Case: ParameterDeclarationAbstract, DeclarationSpecifiers: ds, AbstractDeclarator: x} | ||
|  | 		case *Declarator: | ||
|  | 			p.declScope.declare(x.Name(), x) | ||
|  | 			attr := p.attributeSpecifierListOpt() | ||
|  | 			// if attr != nil { | ||
|  | 			// 	trc("%v: ATTRS", attr.Position()) | ||
|  | 			// } | ||
|  | 			return &ParameterDeclaration{Case: ParameterDeclarationDecl, DeclarationSpecifiers: ds, Declarator: x, AttributeSpecifierList: attr} | ||
|  | 		default: | ||
|  | 			panic(internalError()) | ||
|  | 		} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | func (p *parser) declaratorOrAbstractDeclarator(isTypedefName bool) (r Node) { | ||
|  | 	var ptr *Pointer | ||
|  | 	switch p.rune() { | ||
|  | 	case '*', '^': | ||
|  | 		ptr = p.pointer() | ||
|  | 	} | ||
|  | 	switch p.rune() { | ||
|  | 	case IDENTIFIER: | ||
|  | 		return p.declarator(false, isTypedefName, ptr) | ||
|  | 	case '[': | ||
|  | 		return p.abstractDeclarator(ptr) | ||
|  | 	case '(': | ||
|  | 		switch p.peek(true) { | ||
|  | 		case ')': | ||
|  | 			t := p.shift() | ||
|  | 			t2 := p.shift() | ||
|  | 			return &AbstractDeclarator{ | ||
|  | 				Case:    AbstractDeclaratorDecl, | ||
|  | 				Pointer: ptr, | ||
|  | 				DirectAbstractDeclarator: p.directAbstractDeclarator( | ||
|  | 					&DirectAbstractDeclarator{ | ||
|  | 						Case:   DirectAbstractDeclaratorFunc, | ||
|  | 						Token:  t, | ||
|  | 						Token2: t2, | ||
|  | 					}, | ||
|  | 				), | ||
|  | 			} | ||
|  | 		case TYPEDEF, EXTERN, STATIC, AUTO, REGISTER, THREADLOCAL, | ||
|  | 			VOID, CHAR, SHORT, INT, INT8, INT16, INT32, INT64, INT128, LONG, FLOAT, FLOAT16, FLOAT80, FLOAT32, FLOAT32X, FLOAT64, FLOAT64X, FLOAT128, DECIMAL32, DECIMAL64, DECIMAL128, FRACT, SAT, ACCUM, DOUBLE, SIGNED, UNSIGNED, BOOL, COMPLEX, STRUCT, UNION, ENUM, TYPEDEFNAME, TYPEOF, ATOMIC, | ||
|  | 			CONST, RESTRICT, VOLATILE, | ||
|  | 			INLINE, NORETURN, ATTRIBUTE, | ||
|  | 			ALIGNAS: | ||
|  | 			p.openScope(false) | ||
|  | 			paramScope := p.declScope | ||
|  | 			p.typedefNameEnabled = true | ||
|  | 			t := p.shift() | ||
|  | 			list := p.parameterTypeList() | ||
|  | 			p.closeScope() | ||
|  | 			p.typedefNameEnabled = true | ||
|  | 			var t2 Token | ||
|  | 			switch p.rune() { | ||
|  | 			case ')': | ||
|  | 				t2 = p.shift() | ||
|  | 			default: | ||
|  | 				p.err("expected )") | ||
|  | 			} | ||
|  | 			return &AbstractDeclarator{ | ||
|  | 				Case:    AbstractDeclaratorDecl, | ||
|  | 				Pointer: ptr, | ||
|  | 				DirectAbstractDeclarator: p.directAbstractDeclarator( | ||
|  | 					&DirectAbstractDeclarator{ | ||
|  | 						Case:              DirectAbstractDeclaratorFunc, | ||
|  | 						Token:             t, | ||
|  | 						ParameterTypeList: list, | ||
|  | 						Token2:            t2, | ||
|  | 						paramScope:        paramScope, | ||
|  | 					}, | ||
|  | 				), | ||
|  | 			} | ||
|  | 		} | ||
|  | 
 | ||
|  | 		t := p.shift() | ||
|  | 		switch x := p.declaratorOrAbstractDeclarator(isTypedefName).(type) { | ||
|  | 		case *AbstractDeclarator: | ||
|  | 			var t2 Token | ||
|  | 			switch p.rune() { | ||
|  | 			case ')': | ||
|  | 				t2 = p.shift() | ||
|  | 			default: | ||
|  | 				p.err("expected )") | ||
|  | 			} | ||
|  | 			return &AbstractDeclarator{ | ||
|  | 				Case:    AbstractDeclaratorDecl, | ||
|  | 				Pointer: ptr, | ||
|  | 				DirectAbstractDeclarator: p.directAbstractDeclarator( | ||
|  | 					&DirectAbstractDeclarator{ | ||
|  | 						Case:               DirectAbstractDeclaratorDecl, | ||
|  | 						Token:              t, | ||
|  | 						AbstractDeclarator: x, | ||
|  | 						Token2:             t2, | ||
|  | 					}, | ||
|  | 				), | ||
|  | 			} | ||
|  | 		case *Declarator: | ||
|  | 			var t2 Token | ||
|  | 			switch p.rune() { | ||
|  | 			case ')': | ||
|  | 				t2 = p.shift() | ||
|  | 			default: | ||
|  | 				p.err("expected )") | ||
|  | 			} | ||
|  | 			return &Declarator{ | ||
|  | 				Pointer: ptr, | ||
|  | 				DirectDeclarator: p.directDeclarator( | ||
|  | 					&DirectDeclarator{ | ||
|  | 						Case:       DirectDeclaratorDecl, | ||
|  | 						Token:      t, | ||
|  | 						Declarator: x, | ||
|  | 						Token2:     t2, | ||
|  | 					}, | ||
|  | 				), | ||
|  | 			} | ||
|  | 		default: | ||
|  | 			panic(internalError()) | ||
|  | 		} | ||
|  | 	case ')', ',': | ||
|  | 		return p.abstractDeclarator(ptr) | ||
|  | 	default: | ||
|  | 		p.err("unexpected %s", p.tok.Value) | ||
|  | 		return p.abstractDeclarator(ptr) | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | //  identifier-list: | ||
|  | // 	identifier | ||
|  | // 	identifier-list , identifier | ||
|  | func (p *parser) identifierList() (r *IdentifierList) { | ||
|  | 	switch p.rune() { | ||
|  | 	case IDENTIFIER: | ||
|  | 		r = &IdentifierList{Token: p.shift(), lexicalScope: p.declScope} | ||
|  | 	default: | ||
|  | 		p.err("expected identifier") | ||
|  | 		return nil | ||
|  | 	} | ||
|  | 
 | ||
|  | 	for prev := r; p.rune() == ','; prev = prev.IdentifierList { | ||
|  | 		t := p.shift() | ||
|  | 		var t2 Token | ||
|  | 		switch p.rune() { | ||
|  | 		case IDENTIFIER: | ||
|  | 			t2 = p.shift() | ||
|  | 		default: | ||
|  | 			p.err("expected identifier") | ||
|  | 		} | ||
|  | 		prev.IdentifierList = &IdentifierList{Token: t, Token2: t2, lexicalScope: p.declScope} | ||
|  | 	} | ||
|  | 	return r | ||
|  | } | ||
|  | 
 | ||
|  | // [0], 6.7.6 Type names | ||
|  | // | ||
|  | //  type-name: | ||
|  | // 	specifier-qualifier-list abstract-declarator_opt | ||
|  | func (p *parser) typeName() *TypeName { | ||
|  | 	p.typedefNameEnabled = true | ||
|  | 	list := p.specifierQualifierList() | ||
|  | 	switch p.rune() { | ||
|  | 	case ')', ',': | ||
|  | 		return &TypeName{SpecifierQualifierList: list} | ||
|  | 	case '*', '(', '[': | ||
|  | 		return &TypeName{SpecifierQualifierList: list, AbstractDeclarator: p.abstractDeclarator(nil)} | ||
|  | 	default: | ||
|  | 		p.err("expected ) or * or ( or [ or ,") | ||
|  | 		return &TypeName{SpecifierQualifierList: list} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | //  abstract-declarator: | ||
|  | // 	pointer | ||
|  | // 	pointer_opt direct-abstract-declarator | ||
|  | func (p *parser) abstractDeclarator(ptr *Pointer) *AbstractDeclarator { | ||
|  | 	if ptr == nil && (p.rune() == '*' || p.rune() == '^') { | ||
|  | 		ptr = p.pointer() | ||
|  | 	} | ||
|  | 	switch p.rune() { | ||
|  | 	case '[', '(': | ||
|  | 		return &AbstractDeclarator{Case: AbstractDeclaratorDecl, Pointer: ptr, DirectAbstractDeclarator: p.directAbstractDeclarator(nil)} | ||
|  | 	default: | ||
|  | 		return &AbstractDeclarator{Case: AbstractDeclaratorPtr, Pointer: ptr} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | //  direct-abstract-declarator: | ||
|  | // 	( abstract-declarator ) | ||
|  | // 	direct-abstract-declarator_opt [ type-qualifier-list_opt assignment-expression_opt ] | ||
|  | // 	direct-abstract-declarator_opt [ static type-qualifier-list_opt assignment-expression ] | ||
|  | // 	direct-abstract-declarator_opt [ type-qualifier-list static assignment-expression ] | ||
|  | // 	direct-abstract-declarator_opt [ * ] | ||
|  | // 	direct-abstract-declarator_opt ( parameter-type-list_opt ) | ||
|  | func (p *parser) directAbstractDeclarator(d *DirectAbstractDeclarator) (r *DirectAbstractDeclarator) { | ||
|  | 	var t, t2, t3 Token | ||
|  | 	switch { | ||
|  | 	case d != nil: | ||
|  | 		r = d | ||
|  | 	default: | ||
|  | 		switch p.rune() { | ||
|  | 		case '[': | ||
|  | 			t = p.shift() | ||
|  | 			switch p.rune() { | ||
|  | 			case '*': | ||
|  | 				t2 = p.shift() | ||
|  | 				switch p.rune() { | ||
|  | 				case ']': | ||
|  | 					t3 = p.shift() | ||
|  | 				default: | ||
|  | 					p.err("expected ]") | ||
|  | 				} | ||
|  | 				r = &DirectAbstractDeclarator{Case: DirectAbstractDeclaratorArrStar, Token: t, Token2: t2, Token3: t3} | ||
|  | 			case ATTRIBUTE, CONST, RESTRICT, VOLATILE, ATOMIC: | ||
|  | 				list := p.typeQualifierList() | ||
|  | 				switch p.rune() { | ||
|  | 				case STATIC: | ||
|  | 					t2 = p.shift() | ||
|  | 					e := p.assignmentExpression() | ||
|  | 					switch p.rune() { | ||
|  | 					case ']': | ||
|  | 						t3 = p.shift() | ||
|  | 					default: | ||
|  | 						p.err("expected ]") | ||
|  | 					} | ||
|  | 					r = &DirectAbstractDeclarator{Case: DirectAbstractDeclaratorArrStatic, Token: t, TypeQualifiers: list, Token2: t2, AssignmentExpression: e, Token3: t3} | ||
|  | 				default: | ||
|  | 					e := p.assignmentExpression() | ||
|  | 					switch p.rune() { | ||
|  | 					case ']': | ||
|  | 						t2 = p.shift() | ||
|  | 					default: | ||
|  | 						p.err("expected ]") | ||
|  | 					} | ||
|  | 					r = &DirectAbstractDeclarator{Case: DirectAbstractDeclaratorArr, Token: t, TypeQualifiers: list, AssignmentExpression: e, Token2: t2} | ||
|  | 				} | ||
|  | 			case STATIC: | ||
|  | 				t2 = p.shift() | ||
|  | 				var list *TypeQualifiers | ||
|  | 				switch p.rune() { | ||
|  | 				case ATTRIBUTE, CONST, RESTRICT, VOLATILE, ATOMIC: | ||
|  | 					list = p.typeQualifierList() | ||
|  | 				} | ||
|  | 				e := p.assignmentExpression() | ||
|  | 				switch p.rune() { | ||
|  | 				case ']': | ||
|  | 					t3 = p.shift() | ||
|  | 				default: | ||
|  | 					p.err("expected ]") | ||
|  | 				} | ||
|  | 				r = &DirectAbstractDeclarator{Case: DirectAbstractDeclaratorStaticArr, Token: t, Token2: t2, TypeQualifiers: list, AssignmentExpression: e, Token3: t3} | ||
|  | 			case ']': | ||
|  | 				r = &DirectAbstractDeclarator{Case: DirectAbstractDeclaratorArr, Token: t, Token2: p.shift()} | ||
|  | 			default: | ||
|  | 				e := p.assignmentExpression() | ||
|  | 				switch p.rune() { | ||
|  | 				case ']': | ||
|  | 					t2 = p.shift() | ||
|  | 				default: | ||
|  | 					p.err("expected ]") | ||
|  | 				} | ||
|  | 				r = &DirectAbstractDeclarator{Case: DirectAbstractDeclaratorArr, Token: t, AssignmentExpression: e, Token2: t2} | ||
|  | 			} | ||
|  | 		case '(': | ||
|  | 			switch p.peek(true) { | ||
|  | 			case ')': | ||
|  | 				t := p.shift() | ||
|  | 				r = &DirectAbstractDeclarator{Case: DirectAbstractDeclaratorFunc, Token: t, Token2: p.shift()} | ||
|  | 			case VOID, CHAR, SHORT, INT, INT8, INT16, INT32, INT64, INT128, LONG, FLOAT, FLOAT16, FLOAT80, FLOAT32, FLOAT32X, FLOAT64, FLOAT64X, FLOAT128, DECIMAL32, DECIMAL64, DECIMAL128, FRACT, SAT, ACCUM, DOUBLE, SIGNED, UNSIGNED, BOOL, COMPLEX, STRUCT, UNION, ENUM, TYPEDEFNAME, TYPEOF, ATOMIC, | ||
|  | 				ATTRIBUTE, CONST, RESTRICT, VOLATILE, | ||
|  | 				ALIGNAS: | ||
|  | 				p.openScope(false) | ||
|  | 				paramScope := p.declScope | ||
|  | 				p.typedefNameEnabled = true | ||
|  | 				t = p.shift() | ||
|  | 				list := p.parameterTypeList() | ||
|  | 				p.closeScope() | ||
|  | 				p.typedefNameEnabled = true | ||
|  | 				switch p.rune() { | ||
|  | 				case ')': | ||
|  | 					t2 = p.shift() | ||
|  | 				default: | ||
|  | 					p.err("expected )") | ||
|  | 				} | ||
|  | 				r = &DirectAbstractDeclarator{Case: DirectAbstractDeclaratorFunc, Token: t, ParameterTypeList: list, Token2: t2, paramScope: paramScope} | ||
|  | 			default: | ||
|  | 				p.openScope(false) | ||
|  | 				paramScope := p.declScope | ||
|  | 				p.typedefNameEnabled = true | ||
|  | 				t = p.shift() | ||
|  | 				d := p.abstractDeclarator(nil) | ||
|  | 				p.closeScope() | ||
|  | 				p.typedefNameEnabled = true | ||
|  | 				switch p.rune() { | ||
|  | 				case ')': | ||
|  | 					t2 = p.shift() | ||
|  | 				default: | ||
|  | 					p.err("expected )") | ||
|  | 				} | ||
|  | 				r = &DirectAbstractDeclarator{Case: DirectAbstractDeclaratorDecl, Token: t, AbstractDeclarator: d, Token2: t2, paramScope: paramScope} | ||
|  | 			} | ||
|  | 		default: | ||
|  | 			panic(internalError()) | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	for { | ||
|  | 		switch p.rune() { | ||
|  | 		case '(': | ||
|  | 			if p.peek(false) == ')' { | ||
|  | 				t = p.shift() | ||
|  | 				r = &DirectAbstractDeclarator{Case: DirectAbstractDeclaratorFunc, DirectAbstractDeclarator: r, Token: t, Token2: p.shift()} | ||
|  | 				break | ||
|  | 			} | ||
|  | 
 | ||
|  | 			p.openScope(false) | ||
|  | 			p.typedefNameEnabled = true | ||
|  | 			t = p.shift() | ||
|  | 			paramScope := p.declScope | ||
|  | 			list := p.parameterTypeList() | ||
|  | 			p.closeScope() | ||
|  | 			p.typedefNameEnabled = true | ||
|  | 			switch p.rune() { | ||
|  | 			case ')': | ||
|  | 				t2 = p.shift() | ||
|  | 			default: | ||
|  | 				p.err("expected )") | ||
|  | 			} | ||
|  | 			r = &DirectAbstractDeclarator{Case: DirectAbstractDeclaratorFunc, DirectAbstractDeclarator: r, Token: t, ParameterTypeList: list, Token2: t2, paramScope: paramScope} | ||
|  | 		case '[': | ||
|  | 			t = p.shift() | ||
|  | 			switch p.rune() { | ||
|  | 			case '*': | ||
|  | 				t2 = p.shift() | ||
|  | 				switch p.rune() { | ||
|  | 				case ']': | ||
|  | 					t3 = p.shift() | ||
|  | 				default: | ||
|  | 					p.err("expected ]") | ||
|  | 				} | ||
|  | 				r = &DirectAbstractDeclarator{Case: DirectAbstractDeclaratorArrStar, DirectAbstractDeclarator: r, Token: t, Token2: t2, Token3: t3} | ||
|  | 			case ATTRIBUTE, CONST, RESTRICT, VOLATILE, ATOMIC: | ||
|  | 				list := p.typeQualifierList() | ||
|  | 				switch p.rune() { | ||
|  | 				case STATIC: | ||
|  | 					t2 = p.shift() | ||
|  | 					e := p.assignmentExpression() | ||
|  | 					switch p.rune() { | ||
|  | 					case ']': | ||
|  | 						t3 = p.shift() | ||
|  | 					default: | ||
|  | 						p.err("expected ]") | ||
|  | 					} | ||
|  | 					r = &DirectAbstractDeclarator{Case: DirectAbstractDeclaratorArrStatic, DirectAbstractDeclarator: r, Token: t, TypeQualifiers: list, Token2: t2, AssignmentExpression: e, Token3: t3} | ||
|  | 				default: | ||
|  | 					e := p.assignmentExpression() | ||
|  | 					switch p.rune() { | ||
|  | 					case ']': | ||
|  | 						t2 = p.shift() | ||
|  | 					default: | ||
|  | 						p.err("expected ]") | ||
|  | 					} | ||
|  | 					r = &DirectAbstractDeclarator{Case: DirectAbstractDeclaratorArr, DirectAbstractDeclarator: r, Token: t, TypeQualifiers: list, AssignmentExpression: e, Token2: t2} | ||
|  | 				} | ||
|  | 			case STATIC: | ||
|  | 				t2 = p.shift() | ||
|  | 				var list *TypeQualifiers | ||
|  | 				switch p.rune() { | ||
|  | 				case ATTRIBUTE, CONST, RESTRICT, VOLATILE, ATOMIC: | ||
|  | 					list = p.typeQualifierList() | ||
|  | 				} | ||
|  | 				e := p.assignmentExpression() | ||
|  | 				switch p.rune() { | ||
|  | 				case ']': | ||
|  | 					t3 = p.shift() | ||
|  | 				default: | ||
|  | 					p.err("expected ]") | ||
|  | 				} | ||
|  | 				r = &DirectAbstractDeclarator{Case: DirectAbstractDeclaratorStaticArr, DirectAbstractDeclarator: r, Token: t, Token2: t2, TypeQualifiers: list, AssignmentExpression: e, Token3: t3} | ||
|  | 			case ']': | ||
|  | 				r = &DirectAbstractDeclarator{Case: DirectAbstractDeclaratorArr, DirectAbstractDeclarator: r, Token: t, Token2: p.shift()} | ||
|  | 			default: | ||
|  | 				e := p.assignmentExpression() | ||
|  | 				switch p.rune() { | ||
|  | 				case ']': | ||
|  | 					t2 = p.shift() | ||
|  | 				default: | ||
|  | 					p.err("expected ]") | ||
|  | 				} | ||
|  | 				r = &DirectAbstractDeclarator{Case: DirectAbstractDeclaratorArr, DirectAbstractDeclarator: r, Token: t, AssignmentExpression: e, Token2: t2} | ||
|  | 			} | ||
|  | 		default: | ||
|  | 			return r | ||
|  | 		} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | // [0], 6.7.8 Initialization | ||
|  | // | ||
|  | //  initializer: | ||
|  | // 	assignment-expression | ||
|  | // 	{ initializer-list } | ||
|  | // 	{ initializer-list , } | ||
|  | func (p *parser) initializer(parent *Initializer) *Initializer { | ||
|  | 	switch p.rune() { | ||
|  | 	case '{': | ||
|  | 		t := p.shift() | ||
|  | 		if p.peek(false) == '}' { | ||
|  | 			if p.ctx.cfg.RejectEmptyInitializerList { | ||
|  | 				p.err("expected initializer-list") | ||
|  | 			} | ||
|  | 			return &Initializer{Case: InitializerInitList, Token: t, Token3: p.shift()} | ||
|  | 		} | ||
|  | 
 | ||
|  | 		r := &Initializer{Case: InitializerInitList, Token: t, parent: parent} | ||
|  | 		r.InitializerList = p.initializerList(r) | ||
|  | 		if p.rune() == ',' { | ||
|  | 			r.Token2 = p.shift() | ||
|  | 		} | ||
|  | 		switch p.rune() { | ||
|  | 		case '}': | ||
|  | 			r.Token3 = p.shift() | ||
|  | 		default: | ||
|  | 			p.err("expected }") | ||
|  | 		} | ||
|  | 		return r | ||
|  | 	default: | ||
|  | 		return &Initializer{Case: InitializerExpr, AssignmentExpression: p.assignmentExpression(), parent: parent} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | //  initializer-list: | ||
|  | // 	designation_opt initializer | ||
|  | // 	initializer-list , designation_opt initializer | ||
|  | func (p *parser) initializerList(parent *Initializer) (r *InitializerList) { | ||
|  | 	var d *Designation | ||
|  | 	switch p.rune() { | ||
|  | 	case '[', '.': | ||
|  | 		d = p.designation() | ||
|  | 	case IDENTIFIER: | ||
|  | 		if p.peek(false) == ':' { | ||
|  | 			d = p.designation() | ||
|  | 		} | ||
|  | 	} | ||
|  | 	r = &InitializerList{Designation: d, Initializer: p.initializer(parent)} | ||
|  | 	for prev := r; ; prev = prev.InitializerList { | ||
|  | 		switch p.rune() { | ||
|  | 		case ',': | ||
|  | 			t := p.tok | ||
|  | 			prev.Initializer.trailingComma = &t | ||
|  | 			if p.peek(false) == '}' { | ||
|  | 				return r | ||
|  | 			} | ||
|  | 
 | ||
|  | 			t = p.shift() | ||
|  | 			d = nil | ||
|  | 			switch p.rune() { | ||
|  | 			case '[', '.': | ||
|  | 				d = p.designation() | ||
|  | 			case IDENTIFIER: | ||
|  | 				if p.peek(false) == ':' { | ||
|  | 					d = p.designation() | ||
|  | 				} | ||
|  | 			} | ||
|  | 			prev.InitializerList = &InitializerList{Token: t, Designation: d, Initializer: p.initializer(parent)} | ||
|  | 		default: | ||
|  | 			return r | ||
|  | 		} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | //  designation: | ||
|  | // 	designator-list = | ||
|  | func (p *parser) designation() *Designation { | ||
|  | 	var t Token | ||
|  | 	list, colon := p.designatorList() | ||
|  | 	if !colon { | ||
|  | 		switch p.rune() { | ||
|  | 		case '=': | ||
|  | 			t = p.shift() | ||
|  | 		default: | ||
|  | 			p.err("expected =") | ||
|  | 		} | ||
|  | 	} | ||
|  | 	return &Designation{DesignatorList: list, Token: t} | ||
|  | } | ||
|  | 
 | ||
|  | //  designator-list: | ||
|  | // 	designator | ||
|  | // 	designator-list designator | ||
|  | func (p *parser) designatorList() (r *DesignatorList, colon bool) { | ||
|  | 	d, isCol := p.designator(true) | ||
|  | 	if isCol { | ||
|  | 		return &DesignatorList{Designator: d}, true | ||
|  | 	} | ||
|  | 
 | ||
|  | 	r = &DesignatorList{Designator: d} | ||
|  | 	for prev := r; ; prev = prev.DesignatorList { | ||
|  | 		switch p.rune() { | ||
|  | 		case '[', '.': | ||
|  | 			d, _ = p.designator(false) | ||
|  | 			prev.DesignatorList = &DesignatorList{Designator: d} | ||
|  | 		default: | ||
|  | 			return r, false | ||
|  | 		} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | //  designator: | ||
|  | // 	[ constant-expression ] | ||
|  | // 	. identifier | ||
|  | //	identifier : | ||
|  | func (p *parser) designator(acceptCol bool) (*Designator, bool) { | ||
|  | 	var t, t2 Token | ||
|  | 	switch p.rune() { | ||
|  | 	case '[': | ||
|  | 		t = p.shift() | ||
|  | 		e := p.constantExpression() | ||
|  | 		switch p.rune() { | ||
|  | 		case ']': | ||
|  | 			t2 = p.shift() | ||
|  | 		default: | ||
|  | 			p.err("expected ]") | ||
|  | 		} | ||
|  | 		return &Designator{Case: DesignatorIndex, Token: t, ConstantExpression: e, Token2: t2, lexicalScope: p.declScope}, false | ||
|  | 	case '.': | ||
|  | 		t = p.shift() | ||
|  | 		switch p.rune() { | ||
|  | 		case IDENTIFIER: | ||
|  | 			t2 = p.shift() | ||
|  | 		default: | ||
|  | 			p.err("expected identifier") | ||
|  | 		} | ||
|  | 		return &Designator{Case: DesignatorField, Token: t, Token2: t2, lexicalScope: p.declScope}, false | ||
|  | 	case IDENTIFIER: | ||
|  | 		if acceptCol && p.peek(false) == ':' { | ||
|  | 			t = p.shift() | ||
|  | 			return &Designator{Case: DesignatorField2, Token: t, Token2: p.shift(), lexicalScope: p.declScope}, true | ||
|  | 		} | ||
|  | 
 | ||
|  | 		p.err("expected designator") | ||
|  | 		return nil, false | ||
|  | 	default: | ||
|  | 		p.err("expected [ or .") | ||
|  | 		return nil, false | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | // [0], 6.8 Statements and blocks | ||
|  | // | ||
|  | //  statement: | ||
|  | // 	labeled-statement | ||
|  | // 	compound-statement | ||
|  | // 	expression-statement | ||
|  | // 	selection-statement | ||
|  | // 	iteration-statement | ||
|  | // 	jump-statement | ||
|  | //	asm-statement | ||
|  | func (p *parser) statement() (r *Statement) { | ||
|  | 	var r0 *Statement | ||
|  | 	var prevLS, ls *LabeledStatement | ||
|  | 
 | ||
|  | 	defer func() { | ||
|  | 		if ls != nil { | ||
|  | 			ls.Statement = r | ||
|  | 			r = r0 | ||
|  | 		} | ||
|  | 	}() | ||
|  | 
 | ||
|  | 	for { | ||
|  | 		switch p.rune() { | ||
|  | 		case IDENTIFIER: | ||
|  | 			switch { | ||
|  | 			case p.peek(false) == ':': | ||
|  | 				ls = p.labeledStatement() | ||
|  | 			default: | ||
|  | 				return &Statement{Case: StatementExpr, ExpressionStatement: p.expressionStatement()} | ||
|  | 			} | ||
|  | 		case '{': | ||
|  | 			return &Statement{Case: StatementCompound, CompoundStatement: p.compoundStatement(nil, nil)} | ||
|  | 		case IF, SWITCH: | ||
|  | 			return &Statement{Case: StatementSelection, SelectionStatement: p.selectionStatement()} | ||
|  | 		case WHILE, DO, FOR: | ||
|  | 			return &Statement{Case: StatementIteration, IterationStatement: p.iterationStatement()} | ||
|  | 		case GOTO, BREAK, CONTINUE, RETURN: | ||
|  | 			return &Statement{Case: StatementJump, JumpStatement: p.jumpStatement()} | ||
|  | 		case CASE, DEFAULT: | ||
|  | 			ls = p.labeledStatement() | ||
|  | 		case ASM: | ||
|  | 			return &Statement{Case: StatementAsm, AsmStatement: p.asmStatement()} | ||
|  | 		default: | ||
|  | 			return &Statement{Case: StatementExpr, ExpressionStatement: p.expressionStatement()} | ||
|  | 		} | ||
|  | 
 | ||
|  | 		switch { | ||
|  | 		case r0 == nil: | ||
|  | 			r0 = &Statement{Case: StatementLabeled, LabeledStatement: ls} | ||
|  | 		default: | ||
|  | 			prevLS.Statement = &Statement{Case: StatementLabeled, LabeledStatement: ls} | ||
|  | 		} | ||
|  | 		prevLS = ls | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | // [0], 6.8.1 Labeled statements | ||
|  | // | ||
|  | //  labeled-statement: | ||
|  | // 	identifier : statement | ||
|  | // 	case constant-expression : statement | ||
|  | // 	case constant-expression ... constant-expression : statement | ||
|  | // 	default : statement | ||
|  | func (p *parser) labeledStatement() (r *LabeledStatement) { | ||
|  | 	defer func() { | ||
|  | 		if r != nil { | ||
|  | 			p.block.labeledStmts = append(p.block.labeledStmts, r) | ||
|  | 		} | ||
|  | 	}() | ||
|  | 
 | ||
|  | 	var t, t2, t3 Token | ||
|  | 	switch p.rune() { | ||
|  | 	case IDENTIFIER: | ||
|  | 		t = p.shift() | ||
|  | 		switch p.rune() { | ||
|  | 		case ':': | ||
|  | 			t2 = p.shift() | ||
|  | 		default: | ||
|  | 			p.err("expected :") | ||
|  | 			return nil | ||
|  | 		} | ||
|  | 
 | ||
|  | 		attr := p.attributeSpecifierListOpt() | ||
|  | 		// if attr != nil { | ||
|  | 		// 	trc("%v: ATTRS", attr.Position()) | ||
|  | 		// } | ||
|  | 		p.block.hasLabel() | ||
|  | 		r = &LabeledStatement{ | ||
|  | 			Case: LabeledStatementLabel, Token: t, Token2: t2, AttributeSpecifierList: attr, | ||
|  | 			lexicalScope: p.declScope, block: p.block, | ||
|  | 		} | ||
|  | 		p.declScope.declare(t.Value, r) | ||
|  | 		return r | ||
|  | 	case CASE: | ||
|  | 		if p.switches == 0 { | ||
|  | 			p.err("case label not within a switch statement") | ||
|  | 		} | ||
|  | 		t = p.shift() | ||
|  | 		e := p.constantExpression() | ||
|  | 		switch p.rune() { | ||
|  | 		case DDD: | ||
|  | 			if p.ctx.cfg.RejectCaseRange { | ||
|  | 				p.err0(false, "expected :") | ||
|  | 			} | ||
|  | 			t2 = p.shift() | ||
|  | 			e2 := p.constantExpression() | ||
|  | 			switch p.rune() { | ||
|  | 			case ':': | ||
|  | 				t3 = p.shift() | ||
|  | 			default: | ||
|  | 				p.err("expected :") | ||
|  | 			} | ||
|  | 			return &LabeledStatement{ | ||
|  | 				Case: LabeledStatementRange, Token: t, ConstantExpression: e, | ||
|  | 				Token2: t2, ConstantExpression2: e2, Token3: t3, | ||
|  | 				lexicalScope: p.declScope, block: p.block, | ||
|  | 			} | ||
|  | 		case ':': | ||
|  | 			t2 = p.shift() | ||
|  | 		default: | ||
|  | 			p.err("expected :") | ||
|  | 		} | ||
|  | 		return &LabeledStatement{ | ||
|  | 			Case: LabeledStatementCaseLabel, Token: t, ConstantExpression: e, | ||
|  | 			Token2: t2, lexicalScope: p.declScope, block: p.block, | ||
|  | 		} | ||
|  | 	case DEFAULT: | ||
|  | 		if p.switches == 0 { | ||
|  | 			p.err("'deafult' label not within a switch statement") | ||
|  | 		} | ||
|  | 		t = p.shift() | ||
|  | 		switch p.rune() { | ||
|  | 		case ':': | ||
|  | 			t2 = p.shift() | ||
|  | 		default: | ||
|  | 			p.err("expected :") | ||
|  | 		} | ||
|  | 		return &LabeledStatement{ | ||
|  | 			Case: LabeledStatementDefault, Token: t, Token2: t2, | ||
|  | 			lexicalScope: p.declScope, block: p.block, | ||
|  | 		} | ||
|  | 	default: | ||
|  | 		p.err("expected labeled-statement") | ||
|  | 		return &LabeledStatement{} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | // [0], 6.8.2 Compound statement | ||
|  | // | ||
|  | //  compound-statement: | ||
|  | // 	{ block-item-list_opt } | ||
|  | func (p *parser) compoundStatement(s Scope, inject []Token) (r *CompoundStatement) { | ||
|  | 	if p.rune() != '{' { | ||
|  | 		p.err("expected {") | ||
|  | 		return nil | ||
|  | 	} | ||
|  | 
 | ||
|  | 	r = &CompoundStatement{parent: p.block} | ||
|  | 	if fn := p.currFn; fn != nil { | ||
|  | 		fn.compoundStatements = append(fn.compoundStatements, r) | ||
|  | 	} | ||
|  | 	sv := p.block | ||
|  | 	if sv != nil { | ||
|  | 		sv.children = append(sv.children, r) | ||
|  | 	} | ||
|  | 	p.block = r | ||
|  | 	switch { | ||
|  | 	case s != nil: | ||
|  | 		p.declScope = s | ||
|  | 		p.resolveScope = s | ||
|  | 		p.scopes++ | ||
|  | 		// var a []string | ||
|  | 		// for s := p.declScope; s != nil; s = s.Parent() { | ||
|  | 		// 	a = append(a, fmt.Sprintf("%p", s)) | ||
|  | 		// } | ||
|  | 		// dbg("using func scope %p: %v", s, strings.Join(a, " ")) | ||
|  | 	default: | ||
|  | 		p.openScope(false) | ||
|  | 	} | ||
|  | 	s = p.declScope | ||
|  | 	p.typedefNameEnabled = true | ||
|  | 	t := p.shift() | ||
|  | 	if len(inject) != 0 { | ||
|  | 		p.unget(inject...) | ||
|  | 	} | ||
|  | 	list := p.blockItemList() | ||
|  | 	var t2 Token | ||
|  | 	p.closeScope() | ||
|  | 	p.typedefNameEnabled = true | ||
|  | 	switch p.rune() { | ||
|  | 	case '}': | ||
|  | 		t2 = p.shift() | ||
|  | 	default: | ||
|  | 		p.err("expected }") | ||
|  | 	} | ||
|  | 	r.Token = t | ||
|  | 	r.BlockItemList = list | ||
|  | 	r.Token2 = t2 | ||
|  | 	r.scope = s | ||
|  | 	p.block = sv | ||
|  | 	return r | ||
|  | } | ||
|  | 
 | ||
|  | //  block-item-list: | ||
|  | // 	block-item | ||
|  | // 	block-item-list block-item | ||
|  | func (p *parser) blockItemList() (r *BlockItemList) { | ||
|  | 	var prev *BlockItemList | ||
|  | 	for p.rune() != '}' && p.rune() > 0 { | ||
|  | 		n := &BlockItemList{BlockItem: p.blockItem()} | ||
|  | 		if r == nil { | ||
|  | 			r = n | ||
|  | 			prev = r | ||
|  | 			continue | ||
|  | 		} | ||
|  | 
 | ||
|  | 		prev.BlockItemList = n | ||
|  | 		prev = n | ||
|  | 	} | ||
|  | 	return r | ||
|  | } | ||
|  | 
 | ||
|  | //  block-item: | ||
|  | // 	declaration | ||
|  | // 	statement | ||
|  | // 	label-declaration | ||
|  | // 	declaration-specifiers declarator compound-statement | ||
|  | func (p *parser) blockItem() *BlockItem { | ||
|  | 	switch p.rune() { | ||
|  | 	case | ||
|  | 		TYPEDEF, EXTERN, STATIC, AUTO, REGISTER, THREADLOCAL, | ||
|  | 		VOID, CHAR, SHORT, INT, INT8, INT16, INT32, INT64, INT128, LONG, FLOAT, FLOAT16, FLOAT80, FLOAT32, FLOAT32X, FLOAT64, FLOAT64X, FLOAT128, DECIMAL32, DECIMAL64, DECIMAL128, FRACT, SAT, ACCUM, DOUBLE, SIGNED, UNSIGNED, BOOL, COMPLEX, STRUCT, UNION, ENUM, TYPEDEFNAME, TYPEOF, ATOMIC, | ||
|  | 		CONST, RESTRICT, VOLATILE, | ||
|  | 		ALIGNAS, | ||
|  | 		INLINE, NORETURN, ATTRIBUTE: | ||
|  | 		ds := p.declarationSpecifiers(nil, nil) | ||
|  | 		switch p.rune() { | ||
|  | 		case ';': | ||
|  | 			r := &BlockItem{Case: BlockItemDecl, Declaration: p.declaration(ds, nil)} | ||
|  | 			p.typedefNameEnabled = true | ||
|  | 			return r | ||
|  | 		} | ||
|  | 
 | ||
|  | 		d := p.declarator(true, ds.typedef(), nil) | ||
|  | 		switch p.rune() { | ||
|  | 		case '{': | ||
|  | 			if p.ctx.cfg.RejectNestedFunctionDefinitions { | ||
|  | 				p.err0(false, "nested functions not allowed") | ||
|  | 			} | ||
|  | 			r := &BlockItem{Case: BlockItemFuncDef, DeclarationSpecifiers: ds, Declarator: d, CompoundStatement: p.compoundStatement(d.ParamScope(), p.fn(d.Name()))} | ||
|  | 			p.typedefNameEnabled = true | ||
|  | 			return r | ||
|  | 		default: | ||
|  | 			r := &BlockItem{Case: BlockItemDecl, Declaration: p.declaration(ds, d)} | ||
|  | 			return r | ||
|  | 		} | ||
|  | 	case LABEL: | ||
|  | 		p.block.hasLabel() | ||
|  | 		return &BlockItem{Case: BlockItemLabel, LabelDeclaration: p.labelDeclaration()} | ||
|  | 	case PRAGMASTDC: | ||
|  | 		return &BlockItem{Case: BlockItemPragma, PragmaSTDC: p.pragmaSTDC()} | ||
|  | 	default: | ||
|  | 		return &BlockItem{Case: BlockItemStmt, Statement: p.statement()} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | //  label-declaration | ||
|  | // 	__label__ identifier-list ; | ||
|  | func (p *parser) labelDeclaration() *LabelDeclaration { | ||
|  | 	if p.rune() != LABEL { | ||
|  | 		p.err("expected __label__") | ||
|  | 		return nil | ||
|  | 	} | ||
|  | 
 | ||
|  | 	t := p.shift() | ||
|  | 	list := p.identifierList() | ||
|  | 	p.typedefNameEnabled = true | ||
|  | 	var t2 Token | ||
|  | 	switch p.rune() { | ||
|  | 	case ';': | ||
|  | 		t2 = p.shift() | ||
|  | 	default: | ||
|  | 		p.err("expected ;") | ||
|  | 	} | ||
|  | 	return &LabelDeclaration{Token: t, IdentifierList: list, Token2: t2} | ||
|  | } | ||
|  | 
 | ||
|  | // [0], 6.8.3 Expression and null statements | ||
|  | // | ||
|  | //  expression-statement: | ||
|  | // 	expression_opt attribute-specifier-list_opt; | ||
|  | func (p *parser) expressionStatement() *ExpressionStatement { | ||
|  | 	switch p.rune() { | ||
|  | 	case '}': | ||
|  | 		p.typedefNameEnabled = true | ||
|  | 		return &ExpressionStatement{} | ||
|  | 	case ';': | ||
|  | 		p.typedefNameEnabled = true | ||
|  | 		return &ExpressionStatement{Token: p.shift()} | ||
|  | 	case ATTRIBUTE: | ||
|  | 		p.typedefNameEnabled = true | ||
|  | 		attr := p.attributeSpecifierList() | ||
|  | 		// if attr != nil { | ||
|  | 		// 	trc("%v: ATTRS", attr.Position()) | ||
|  | 		// } | ||
|  | 		var t Token | ||
|  | 		switch p.rune() { | ||
|  | 		case ';': | ||
|  | 			t = p.shift() | ||
|  | 		default: | ||
|  | 			p.err("expected ;") | ||
|  | 		} | ||
|  | 		return &ExpressionStatement{AttributeSpecifierList: attr, Token: t} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	e := p.expression() | ||
|  | 	var t Token | ||
|  | 	p.typedefNameEnabled = true | ||
|  | 	attr := p.attributeSpecifierListOpt() | ||
|  | 	// if attr != nil { | ||
|  | 	// 	trc("%v: ATTRS", attr.Position()) | ||
|  | 	// } | ||
|  | 	switch p.rune() { | ||
|  | 	case ';': | ||
|  | 		t = p.shift() | ||
|  | 	default: | ||
|  | 		p.err("expected ;") | ||
|  | 	} | ||
|  | 	return &ExpressionStatement{Expression: e, AttributeSpecifierList: attr, Token: t} | ||
|  | } | ||
|  | 
 | ||
|  | // [0], 6.8.4 Selection statements | ||
|  | // | ||
|  | //  selection-statement: | ||
|  | //  	if ( expression ) statement | ||
|  | //  	if ( expression ) statement else statement | ||
|  | //  	switch ( expression ) statement | ||
|  | func (p *parser) selectionStatement() *SelectionStatement { | ||
|  | 	var t, t2, t3, t4 Token | ||
|  | 	switch p.rune() { | ||
|  | 	case IF: | ||
|  | 		p.openScope(false) | ||
|  | 		t = p.shift() | ||
|  | 		switch p.rune() { | ||
|  | 		case '(': | ||
|  | 			t2 = p.shift() | ||
|  | 		default: | ||
|  | 			p.err("expected (") | ||
|  | 		} | ||
|  | 		e := p.expression() | ||
|  | 		switch p.rune() { | ||
|  | 		case ')': | ||
|  | 			t3 = p.shift() | ||
|  | 		default: | ||
|  | 			p.err("expected )") | ||
|  | 		} | ||
|  | 		p.openScope(false) | ||
|  | 		s := p.statement() | ||
|  | 		if p.peek(false) != ELSE { | ||
|  | 			r := &SelectionStatement{Case: SelectionStatementIf, Token: t, Token2: t2, Expression: e, Token3: t3, Statement: s} | ||
|  | 			p.closeScope() | ||
|  | 			p.closeScope() | ||
|  | 			return r | ||
|  | 		} | ||
|  | 
 | ||
|  | 		p.closeScope() | ||
|  | 		p.openScope(false) | ||
|  | 		t4 = p.shift() | ||
|  | 		r := &SelectionStatement{Case: SelectionStatementIfElse, Token: t, Token2: t2, Expression: e, Token3: t3, Statement: s, Token4: t4, Statement2: p.statement()} | ||
|  | 		p.closeScope() | ||
|  | 		p.closeScope() | ||
|  | 		return r | ||
|  | 	case SWITCH: | ||
|  | 		p.switches++ | ||
|  | 		p.openScope(false) | ||
|  | 		t = p.shift() | ||
|  | 		switch p.rune() { | ||
|  | 		case '(': | ||
|  | 			t2 = p.shift() | ||
|  | 		default: | ||
|  | 			p.err("expected (") | ||
|  | 		} | ||
|  | 		e := p.expression() | ||
|  | 		switch p.rune() { | ||
|  | 		case ')': | ||
|  | 			t3 = p.shift() | ||
|  | 		default: | ||
|  | 			p.err("expected )") | ||
|  | 		} | ||
|  | 		p.openScope(false) | ||
|  | 		s := p.statement() | ||
|  | 		p.closeScope() | ||
|  | 		p.closeScope() | ||
|  | 		p.switches-- | ||
|  | 		return &SelectionStatement{Case: SelectionStatementSwitch, Token: t, Token2: t2, Expression: e, Token3: t3, Statement: s} | ||
|  | 	default: | ||
|  | 		p.err("expected selection-statement") | ||
|  | 		return nil | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | // [0], 6.8.5 Iteration statements | ||
|  | // | ||
|  | //  iteration-statement: | ||
|  | // 	while ( expression ) statement | ||
|  | // 	do statement while ( expression ) ; | ||
|  | // 	for ( expression_opt ; expression_opt ; expression_opt ) statement | ||
|  | // 	for ( declaration expression_opt ; expression_opt ) statement | ||
|  | func (p *parser) iterationStatement() (r *IterationStatement) { | ||
|  | 	var t, t2, t3, t4, t5 Token | ||
|  | 	var e, e2, e3 *Expression | ||
|  | 	switch p.rune() { | ||
|  | 	case WHILE: | ||
|  | 		p.openScope(false) | ||
|  | 		t = p.shift() | ||
|  | 		if p.rune() != '(' { | ||
|  | 			p.err("expected (") | ||
|  | 			p.closeScope() | ||
|  | 			return nil | ||
|  | 		} | ||
|  | 
 | ||
|  | 		t2 = p.shift() | ||
|  | 		e = p.expression() | ||
|  | 		switch p.rune() { | ||
|  | 		case ')': | ||
|  | 			t3 = p.shift() | ||
|  | 		default: | ||
|  | 			p.err("expected )") | ||
|  | 		} | ||
|  | 		p.openScope(false) | ||
|  | 		r = &IterationStatement{Case: IterationStatementWhile, Token: t, Token2: t2, Expression: e, Token3: t3, Statement: p.statement()} | ||
|  | 		p.closeScope() | ||
|  | 		p.closeScope() | ||
|  | 		return r | ||
|  | 	case DO: | ||
|  | 		t := p.shift() | ||
|  | 		p.openScope(false) | ||
|  | 		p.openScope(false) | ||
|  | 		s := p.statement() | ||
|  | 		p.closeScope() | ||
|  | 		switch p.rune() { | ||
|  | 		case WHILE: | ||
|  | 			t2 = p.shift() | ||
|  | 		default: | ||
|  | 			p.err("expected while") | ||
|  | 			p.closeScope() | ||
|  | 			return nil | ||
|  | 		} | ||
|  | 
 | ||
|  | 		if p.rune() != '(' { | ||
|  | 			p.err("expected (") | ||
|  | 			p.closeScope() | ||
|  | 			return nil | ||
|  | 		} | ||
|  | 
 | ||
|  | 		t3 = p.shift() | ||
|  | 		e = p.expression() | ||
|  | 		switch p.rune() { | ||
|  | 		case ')': | ||
|  | 			t4 = p.shift() | ||
|  | 		default: | ||
|  | 			p.err("expected )") | ||
|  | 		} | ||
|  | 		p.typedefNameEnabled = true | ||
|  | 		switch p.rune() { | ||
|  | 		case ';': | ||
|  | 			t5 = p.shift() | ||
|  | 		default: | ||
|  | 			p.err("expected ;") | ||
|  | 		} | ||
|  | 		r = &IterationStatement{Case: IterationStatementDo, Token: t, Statement: s, Token2: t2, Token3: t3, Expression: e, Token4: t4, Token5: t5} | ||
|  | 		p.closeScope() | ||
|  | 		return r | ||
|  | 	case FOR: | ||
|  | 		p.openScope(false) | ||
|  | 		t = p.shift() | ||
|  | 		if p.rune() != '(' { | ||
|  | 			p.err("expected (") | ||
|  | 			p.closeScope() | ||
|  | 			return nil | ||
|  | 		} | ||
|  | 
 | ||
|  | 		t2 = p.shift() | ||
|  | 		var d *Declaration | ||
|  | 		switch p.rune() { | ||
|  | 		case TYPEDEF, EXTERN, STATIC, AUTO, REGISTER, THREADLOCAL, | ||
|  | 			VOID, CHAR, SHORT, INT, INT8, INT16, INT32, INT64, INT128, LONG, FLOAT, FLOAT16, FLOAT80, FLOAT32, FLOAT32X, FLOAT64, FLOAT64X, FLOAT128, DECIMAL32, DECIMAL64, DECIMAL128, FRACT, SAT, ACCUM, DOUBLE, SIGNED, UNSIGNED, BOOL, COMPLEX, STRUCT, UNION, ENUM, TYPEDEFNAME, TYPEOF, ATOMIC, | ||
|  | 			CONST, RESTRICT, VOLATILE, | ||
|  | 			ALIGNAS, | ||
|  | 			INLINE, NORETURN, ATTRIBUTE: | ||
|  | 			d = p.declaration(nil, nil) | ||
|  | 			if p.rune() != ';' { | ||
|  | 				e = p.expression() | ||
|  | 			} | ||
|  | 			switch p.rune() { | ||
|  | 			case ';': | ||
|  | 				t3 = p.shift() | ||
|  | 			default: | ||
|  | 				p.err("expected ;") | ||
|  | 			} | ||
|  | 			if p.rune() != ')' { | ||
|  | 				e2 = p.expression() | ||
|  | 			} | ||
|  | 			switch p.rune() { | ||
|  | 			case ')': | ||
|  | 				t4 = p.shift() | ||
|  | 			default: | ||
|  | 				p.err("expected )") | ||
|  | 			} | ||
|  | 			p.openScope(false) | ||
|  | 			r = &IterationStatement{Case: IterationStatementForDecl, Token: t, Token2: t2, Declaration: d, Expression: e, Token3: t3, Expression2: e2, Token4: t4, Statement: p.statement()} | ||
|  | 			p.closeScope() | ||
|  | 			p.closeScope() | ||
|  | 			return r | ||
|  | 		default: | ||
|  | 			if p.rune() != ';' { | ||
|  | 				e = p.expression() | ||
|  | 			} | ||
|  | 			switch p.rune() { | ||
|  | 			case ';': | ||
|  | 				t3 = p.shift() | ||
|  | 			default: | ||
|  | 				p.err("expected ;") | ||
|  | 			} | ||
|  | 			if p.rune() != ';' { | ||
|  | 				e2 = p.expression() | ||
|  | 			} | ||
|  | 			switch p.rune() { | ||
|  | 			case ';': | ||
|  | 				t4 = p.shift() | ||
|  | 			default: | ||
|  | 				p.err("expected ;") | ||
|  | 			} | ||
|  | 			if p.rune() != ')' { | ||
|  | 				e3 = p.expression() | ||
|  | 			} | ||
|  | 			switch p.rune() { | ||
|  | 			case ')': | ||
|  | 				t5 = p.shift() | ||
|  | 			default: | ||
|  | 				p.err("expected )") | ||
|  | 			} | ||
|  | 			p.openScope(false) | ||
|  | 			r = &IterationStatement{Case: IterationStatementFor, Token: t, Token2: t2, Expression: e, Token3: t3, Expression2: e2, Token4: t4, Expression3: e3, Token5: t5, Statement: p.statement()} | ||
|  | 			p.closeScope() | ||
|  | 			p.closeScope() | ||
|  | 			return r | ||
|  | 		} | ||
|  | 	default: | ||
|  | 		p.err("expected iteration-statement") | ||
|  | 		return nil | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | // [0], 6.8.6 Jump statements | ||
|  | // | ||
|  | //  jump-statement: | ||
|  | // 	goto identifier ; | ||
|  | // 	goto * expression ; | ||
|  | // 	continue ; | ||
|  | // 	break ; | ||
|  | // 	return expression_opt ; | ||
|  | func (p *parser) jumpStatement() *JumpStatement { | ||
|  | 	var t, t2, t3 Token | ||
|  | 	var kind JumpStatementCase | ||
|  | 	switch p.rune() { | ||
|  | 	case GOTO: | ||
|  | 		p.typedefNameEnabled = false | ||
|  | 		t = p.shift() | ||
|  | 		switch p.rune() { | ||
|  | 		case IDENTIFIER: | ||
|  | 			t2 = p.shift() | ||
|  | 		case '*': | ||
|  | 			t2 = p.shift() | ||
|  | 			p.typedefNameEnabled = true | ||
|  | 			e := p.expression() | ||
|  | 			switch p.rune() { | ||
|  | 			case ';': | ||
|  | 				t3 = p.shift() | ||
|  | 			default: | ||
|  | 				p.err("expected ;") | ||
|  | 			} | ||
|  | 			return &JumpStatement{Case: JumpStatementGotoExpr, Token: t, Token2: t2, Expression: e, Token3: t3, lexicalScope: p.declScope} | ||
|  | 		default: | ||
|  | 			p.err("expected identifier or *") | ||
|  | 		} | ||
|  | 		p.typedefNameEnabled = true | ||
|  | 		switch p.rune() { | ||
|  | 		case ';': | ||
|  | 			t3 = p.shift() | ||
|  | 		default: | ||
|  | 			p.err("expected ;") | ||
|  | 		} | ||
|  | 		return &JumpStatement{Case: JumpStatementGoto, Token: t, Token2: t2, Token3: t3, lexicalScope: p.declScope} | ||
|  | 	case CONTINUE: | ||
|  | 		kind = JumpStatementContinue | ||
|  | 	case BREAK: | ||
|  | 		kind = JumpStatementBreak | ||
|  | 	case RETURN: | ||
|  | 		t = p.shift() | ||
|  | 		var e *Expression | ||
|  | 		if p.rune() != ';' { | ||
|  | 			e = p.expression() | ||
|  | 		} | ||
|  | 		p.typedefNameEnabled = true | ||
|  | 		switch p.rune() { | ||
|  | 		case ';': | ||
|  | 			t2 = p.shift() | ||
|  | 		default: | ||
|  | 			p.err("expected ;") | ||
|  | 		} | ||
|  | 		return &JumpStatement{Case: JumpStatementReturn, Token: t, Expression: e, Token2: t2, lexicalScope: p.declScope} | ||
|  | 	default: | ||
|  | 		p.err("expected jump-statement") | ||
|  | 		return nil | ||
|  | 	} | ||
|  | 
 | ||
|  | 	t = p.shift() | ||
|  | 	p.typedefNameEnabled = true | ||
|  | 	switch p.rune() { | ||
|  | 	case ';': | ||
|  | 		t2 = p.shift() | ||
|  | 	default: | ||
|  | 		p.err("expected ;") | ||
|  | 	} | ||
|  | 	return &JumpStatement{Case: kind, Token: t, Token2: t2, lexicalScope: p.declScope} | ||
|  | } | ||
|  | 
 | ||
|  | // [0], 6.9 External definitions | ||
|  | // | ||
|  | //  translation-unit: | ||
|  | // 	external-declaration | ||
|  | // 	translation-unit external-declaration | ||
|  | func (p *parser) translationUnit() (r *TranslationUnit) { | ||
|  | 	p.typedefNameEnabled = true | ||
|  | 	var prev *TranslationUnit | ||
|  | 	for p.rune() >= 0 { | ||
|  | 		ed := p.externalDeclaration() | ||
|  | 		if ed == nil { | ||
|  | 			continue | ||
|  | 		} | ||
|  | 
 | ||
|  | 		t := &TranslationUnit{ExternalDeclaration: ed} | ||
|  | 		switch { | ||
|  | 		case r == nil: | ||
|  | 			r = t | ||
|  | 		default: | ||
|  | 			prev.TranslationUnit = t | ||
|  | 		} | ||
|  | 		prev = t | ||
|  | 	} | ||
|  | 	if r != nil { | ||
|  | 		return r | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return &TranslationUnit{} | ||
|  | } | ||
|  | 
 | ||
|  | //  external-declaration: | ||
|  | // 	function-definition | ||
|  | // 	declaration | ||
|  | // 	asm-function-definition | ||
|  | // 	; | ||
|  | func (p *parser) externalDeclaration() *ExternalDeclaration { | ||
|  | 	var ds *DeclarationSpecifiers | ||
|  | 	var inline, extern bool | ||
|  | 	if p.ctx.cfg.SharedFunctionDefinitions != nil { | ||
|  | 		p.rune() | ||
|  | 		p.hash.Reset() | ||
|  | 		p.key = sharedFunctionDefinitionKey{pos: dict.sid(p.tok.Position().String())} | ||
|  | 		p.hashTok() | ||
|  | 	} | ||
|  | 	switch p.rune() { | ||
|  | 	case TYPEDEF, EXTERN, STATIC, AUTO, REGISTER, THREADLOCAL, | ||
|  | 		VOID, CHAR, SHORT, INT, INT8, INT16, INT32, INT64, INT128, LONG, FLOAT, FLOAT16, FLOAT80, FLOAT32, FLOAT32X, FLOAT64, FLOAT64X, FLOAT128, DECIMAL32, DECIMAL64, DECIMAL128, FRACT, SAT, ACCUM, DOUBLE, SIGNED, UNSIGNED, BOOL, COMPLEX, STRUCT, UNION, ENUM, TYPEDEFNAME, TYPEOF, ATOMIC, | ||
|  | 		CONST, RESTRICT, VOLATILE, | ||
|  | 		INLINE, NORETURN, ATTRIBUTE, | ||
|  | 		ALIGNAS: | ||
|  | 		ds = p.declarationSpecifiers(&extern, &inline) | ||
|  | 	case ';': | ||
|  | 		if p.ctx.cfg.RejectEmptyDeclarations { | ||
|  | 			p.err("expected external-declaration") | ||
|  | 			return nil | ||
|  | 		} | ||
|  | 
 | ||
|  | 		return &ExternalDeclaration{Case: ExternalDeclarationEmpty, Token: p.shift()} | ||
|  | 	case ASM: | ||
|  | 		return &ExternalDeclaration{Case: ExternalDeclarationAsmStmt, AsmStatement: p.asmStatement()} | ||
|  | 	case PRAGMASTDC: | ||
|  | 		return &ExternalDeclaration{Case: ExternalDeclarationPragma, PragmaSTDC: p.pragmaSTDC()} | ||
|  | 	default: | ||
|  | 		if p.ctx.cfg.RejectMissingDeclarationSpecifiers { | ||
|  | 			p.err("expected declaration-specifiers") | ||
|  | 		} | ||
|  | 	} | ||
|  | 	if p.rune() == ';' { | ||
|  | 		return &ExternalDeclaration{Case: ExternalDeclarationDecl, Declaration: p.declaration(ds, nil)} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	p.rune() | ||
|  | 	d := p.declarator(false, ds.typedef(), nil) | ||
|  | 	p.declScope.declare(d.Name(), d) | ||
|  | 	switch p.rune() { | ||
|  | 	case ',', ';', '=', ATTRIBUTE: | ||
|  | 		if ds == nil { | ||
|  | 			ds = noDeclSpecs | ||
|  | 		} | ||
|  | 		r := &ExternalDeclaration{Case: ExternalDeclarationDecl, Declaration: p.declaration(ds, d)} | ||
|  | 		return r | ||
|  | 	case ASM: | ||
|  | 		return &ExternalDeclaration{Case: ExternalDeclarationAsm, AsmFunctionDefinition: p.asmFunctionDefinition(ds, d)} | ||
|  | 	default: | ||
|  | 		fd := p.functionDefinition(ds, d) | ||
|  | 		if sfd := p.ctx.cfg.SharedFunctionDefinitions; sfd != nil { | ||
|  | 			p.key.nm = d.Name() | ||
|  | 			p.key.hash = p.hash.Sum64() | ||
|  | 			if ex := sfd.m[p.key]; ex != nil { | ||
|  | 				sfd.M[ex] = struct{}{} | ||
|  | 				d := ex.Declarator | ||
|  | 				p.declScope.declare(d.Name(), d) | ||
|  | 				r := &ExternalDeclaration{Case: ExternalDeclarationFuncDef, FunctionDefinition: ex} | ||
|  | 				return r | ||
|  | 			} | ||
|  | 
 | ||
|  | 			sfd.m[p.key] = fd | ||
|  | 		} | ||
|  | 
 | ||
|  | 		r := &ExternalDeclaration{Case: ExternalDeclarationFuncDef, FunctionDefinition: fd} | ||
|  | 		return r | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | func (p *parser) pragmaSTDC() *PragmaSTDC { | ||
|  | 	if p.rune() != PRAGMASTDC { | ||
|  | 		p.err("expected __pragma_stdc") | ||
|  | 	} | ||
|  | 
 | ||
|  | 	t := p.shift()  // _Pragma | ||
|  | 	t2 := p.shift() // STDC | ||
|  | 	t3 := p.shift() // FOO | ||
|  | 	t4 := p.shift() // Bar | ||
|  | 	return &PragmaSTDC{Token: t, Token2: t2, Token3: t3, Token4: t4} | ||
|  | } | ||
|  | 
 | ||
|  | // [0], 6.9.1 Function definitions | ||
|  | // | ||
|  | //  function-definition: | ||
|  | // 	declaration-specifiers declarator declaration-list_opt compound-statement | ||
|  | func (p *parser) functionDefinition(ds *DeclarationSpecifiers, d *Declarator) (r *FunctionDefinition) { | ||
|  | 	var list *DeclarationList | ||
|  | 	s := d.ParamScope() | ||
|  | 	switch { | ||
|  | 	case p.rune() != '{': // As in: int f(i) int i; { return i; } | ||
|  | 		list = p.declarationList(s) | ||
|  | 	case d.DirectDeclarator != nil && d.DirectDeclarator.Case == DirectDeclaratorFuncIdent: // As in: int f(i) { return i; } | ||
|  | 		d.DirectDeclarator.idListNoDeclList = true | ||
|  | 		for n := d.DirectDeclarator.IdentifierList; n != nil; n = n.IdentifierList { | ||
|  | 			tok := n.Token2 | ||
|  | 			if tok.Value == 0 { | ||
|  | 				tok = n.Token | ||
|  | 			} | ||
|  | 			d := &Declarator{ | ||
|  | 				IsParameter: true, | ||
|  | 				DirectDeclarator: &DirectDeclarator{ | ||
|  | 					Case:  DirectDeclaratorIdent, | ||
|  | 					Token: tok, | ||
|  | 				}, | ||
|  | 			} | ||
|  | 			s.declare(tok.Value, d) | ||
|  | 			if p.ctx.cfg.RejectMissingDeclarationSpecifiers { | ||
|  | 				p.ctx.errNode(&tok, "expected declaration-specifiers") | ||
|  | 			} | ||
|  | 		} | ||
|  | 	} | ||
|  | 	p.block = nil | ||
|  | 	r = &FunctionDefinition{DeclarationSpecifiers: ds, Declarator: d, DeclarationList: list} | ||
|  | 	sv := p.currFn | ||
|  | 	p.currFn = r | ||
|  | 	r.CompoundStatement = p.compoundStatement(d.ParamScope(), p.fn(d.Name())) | ||
|  | 	p.currFn = sv | ||
|  | 	return r | ||
|  | } | ||
|  | 
 | ||
|  | func (p *parser) fn(nm StringID) (r []Token) { | ||
|  | 	if p.ctx.cfg.PreprocessOnly { | ||
|  | 		return nil | ||
|  | 	} | ||
|  | 
 | ||
|  | 	pos := p.tok.Position() | ||
|  | 	toks := []Token{ | ||
|  | 		{Rune: STATIC, Value: idStatic, Src: idStatic}, | ||
|  | 		{Rune: CONST, Value: idConst, Src: idConst}, | ||
|  | 		{Rune: CHAR, Value: idChar, Src: idChar}, | ||
|  | 		{Rune: IDENTIFIER, Value: idFunc, Src: idFunc}, | ||
|  | 		{Rune: '[', Value: idLBracket, Src: idLBracket}, | ||
|  | 		{Rune: ']', Value: idRBracket, Src: idRBracket}, | ||
|  | 		{Rune: '=', Value: idEq, Src: idEq}, | ||
|  | 		{Rune: STRINGLITERAL, Value: nm, Src: nm}, | ||
|  | 		{Rune: ';', Value: idSemicolon, Src: idSemicolon}, | ||
|  | 	} | ||
|  | 	if p.ctx.cfg.InjectTracingCode { | ||
|  | 		id := dict.sid(fmt.Sprintf("%s:%s\n", pos, nm.String())) | ||
|  | 		toks = append(toks, []Token{ | ||
|  | 			{Rune: IDENTIFIER, Value: idFprintf, Src: idFprintf}, | ||
|  | 			{Rune: '(', Value: idLParen, Src: idLParen}, | ||
|  | 			{Rune: IDENTIFIER, Value: idStderr, Src: idStderr}, | ||
|  | 			{Rune: ',', Value: idComma, Src: idComma}, | ||
|  | 			{Rune: STRINGLITERAL, Value: id, Src: id}, | ||
|  | 			{Rune: ')', Value: idRParen, Src: idRParen}, | ||
|  | 			{Rune: ';', Value: idSemicolon, Src: idSemicolon}, | ||
|  | 			{Rune: IDENTIFIER, Value: idFFlush, Src: idFFlush}, | ||
|  | 			{Rune: '(', Value: idLParen, Src: idLParen}, | ||
|  | 			{Rune: IDENTIFIER, Value: idStderr, Src: idStderr}, | ||
|  | 			{Rune: ')', Value: idRParen, Src: idRParen}, | ||
|  | 			{Rune: ';', Value: idSemicolon, Src: idSemicolon}, | ||
|  | 		}...) | ||
|  | 	} | ||
|  | 	for _, v := range toks { | ||
|  | 		v.file = p.tok.file | ||
|  | 		v.pos = p.tok.pos | ||
|  | 		v.seq = p.tok.seq | ||
|  | 		r = append(r, v) | ||
|  | 	} | ||
|  | 	return r | ||
|  | } | ||
|  | 
 | ||
|  | //  declaration-list: | ||
|  | // 	declaration | ||
|  | // 	declaration-list declaration | ||
|  | func (p *parser) declarationList(s Scope) (r *DeclarationList) { | ||
|  | 	p.declScope = s | ||
|  | 	p.resolveScope = s | ||
|  | 	switch ch := p.rune(); ch { | ||
|  | 	case TYPEDEF, EXTERN, STATIC, AUTO, REGISTER, THREADLOCAL, | ||
|  | 		VOID, CHAR, SHORT, INT, INT8, INT16, INT32, INT64, INT128, LONG, FLOAT, FLOAT16, FLOAT80, FLOAT32, FLOAT32X, FLOAT64, FLOAT64X, FLOAT128, DECIMAL32, DECIMAL64, DECIMAL128, FRACT, SAT, ACCUM, DOUBLE, SIGNED, UNSIGNED, BOOL, COMPLEX, STRUCT, UNION, ENUM, TYPEDEFNAME, TYPEOF, ATOMIC, | ||
|  | 		CONST, RESTRICT, VOLATILE, | ||
|  | 		ALIGNAS, | ||
|  | 		INLINE, NORETURN, ATTRIBUTE: | ||
|  | 		r = &DeclarationList{Declaration: p.declaration(nil, nil)} | ||
|  | 	default: | ||
|  | 		p.err("expected declaration: %s", tokName(ch)) | ||
|  | 		return nil | ||
|  | 	} | ||
|  | 
 | ||
|  | 	for prev := r; ; prev = prev.DeclarationList { | ||
|  | 		switch p.rune() { | ||
|  | 		case TYPEDEF, EXTERN, STATIC, AUTO, REGISTER, THREADLOCAL, | ||
|  | 			VOID, CHAR, SHORT, INT, INT8, INT16, INT32, INT64, INT128, LONG, FLOAT, FLOAT16, FLOAT80, FLOAT32, FLOAT32X, FLOAT64, FLOAT64X, FLOAT128, DECIMAL32, DECIMAL64, DECIMAL128, FRACT, SAT, ACCUM, DOUBLE, SIGNED, UNSIGNED, BOOL, COMPLEX, STRUCT, UNION, ENUM, TYPEDEFNAME, TYPEOF, ATOMIC, | ||
|  | 			CONST, RESTRICT, VOLATILE, | ||
|  | 			ALIGNAS, | ||
|  | 			INLINE, NORETURN, ATTRIBUTE: | ||
|  | 			prev.DeclarationList = &DeclarationList{Declaration: p.declaration(nil, nil)} | ||
|  | 		default: | ||
|  | 			return r | ||
|  | 		} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | // ----------------------------------------------------------------- Extensions | ||
|  | 
 | ||
|  | //  asm-function-definition: | ||
|  | // 	declaration-specifiers declarator asm-statement | ||
|  | func (p *parser) asmFunctionDefinition(ds *DeclarationSpecifiers, d *Declarator) *AsmFunctionDefinition { | ||
|  | 	return &AsmFunctionDefinition{DeclarationSpecifiers: ds, Declarator: d, AsmStatement: p.asmStatement()} | ||
|  | } | ||
|  | 
 | ||
|  | //  asm-statement: | ||
|  | //  	asm attribute-specifier-list_opt ; | ||
|  | func (p *parser) asmStatement() *AsmStatement { | ||
|  | 	a := p.asm() | ||
|  | 	attr := p.attributeSpecifierListOpt() | ||
|  | 	// if attr != nil { | ||
|  | 	// 	trc("%v: ATTRS", attr.Position()) | ||
|  | 	// } | ||
|  | 	var t Token | ||
|  | 	switch p.rune() { | ||
|  | 	case ';': | ||
|  | 		p.typedefNameEnabled = true | ||
|  | 		t = p.shift() | ||
|  | 	default: | ||
|  | 		p.err("expected ';'") | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return &AsmStatement{Asm: a, AttributeSpecifierList: attr, Token: t} | ||
|  | } | ||
|  | 
 | ||
|  | //  asm: | ||
|  | // 	asm asm-qualifier-list_opt ( string-literal asm-arg-list_opt ) | ||
|  | func (p *parser) asm() *Asm { | ||
|  | 	var t, t2, t3, t4 Token | ||
|  | 	switch p.rune() { | ||
|  | 	case ASM: | ||
|  | 		t = p.shift() | ||
|  | 	default: | ||
|  | 		p.err("expected asm") | ||
|  | 	} | ||
|  | 
 | ||
|  | 	var qlist *AsmQualifierList | ||
|  | 	switch p.rune() { | ||
|  | 	case VOLATILE, INLINE, GOTO: | ||
|  | 		qlist = p.asmQualifierList() | ||
|  | 	} | ||
|  | 
 | ||
|  | 	switch p.rune() { | ||
|  | 	case '(': | ||
|  | 		t2 = p.shift() | ||
|  | 	default: | ||
|  | 		p.err("expected (") | ||
|  | 	} | ||
|  | 
 | ||
|  | 	switch p.rune() { | ||
|  | 	case STRINGLITERAL: | ||
|  | 		t3 = p.shift() | ||
|  | 	default: | ||
|  | 		p.err("expected string-literal") | ||
|  | 	} | ||
|  | 
 | ||
|  | 	var argList *AsmArgList | ||
|  | 	switch p.rune() { | ||
|  | 	case ':': | ||
|  | 		argList = p.asmArgList() | ||
|  | 	} | ||
|  | 
 | ||
|  | 	switch p.rune() { | ||
|  | 	case ')': | ||
|  | 		t4 = p.shift() | ||
|  | 	default: | ||
|  | 		p.err("expected )") | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return &Asm{Token: t, AsmQualifierList: qlist, Token2: t2, Token3: t3, AsmArgList: argList, Token4: t4} | ||
|  | } | ||
|  | 
 | ||
|  | //  asm-qualifier-list: | ||
|  | // 	asm-qualifier | ||
|  | // 	asm-qualifier-list asm-qualifier | ||
|  | func (p *parser) asmQualifierList() (r *AsmQualifierList) { | ||
|  | 	switch p.rune() { | ||
|  | 	case VOLATILE, INLINE, GOTO: | ||
|  | 		r = &AsmQualifierList{AsmQualifier: p.asmQualifier()} | ||
|  | 	default: | ||
|  | 		p.err("expected asm-qualifier-list") | ||
|  | 		return nil | ||
|  | 	} | ||
|  | 
 | ||
|  | 	for prev := r; ; prev = prev.AsmQualifierList { | ||
|  | 		switch p.rune() { | ||
|  | 		case VOLATILE, INLINE, GOTO: | ||
|  | 			prev.AsmQualifierList = &AsmQualifierList{AsmQualifier: p.asmQualifier()} | ||
|  | 		default: | ||
|  | 			return r | ||
|  | 		} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | //  asm-qualifier: | ||
|  | // 	volatile | ||
|  | //  	inline | ||
|  | // 	goto" | ||
|  | func (p *parser) asmQualifier() *AsmQualifier { | ||
|  | 	switch p.rune() { | ||
|  | 	case VOLATILE: | ||
|  | 		return &AsmQualifier{Case: AsmQualifierVolatile, Token: p.shift()} | ||
|  | 	case INLINE: | ||
|  | 		return &AsmQualifier{Case: AsmQualifierInline, Token: p.shift()} | ||
|  | 	case GOTO: | ||
|  | 		return &AsmQualifier{Case: AsmQualifierGoto, Token: p.shift()} | ||
|  | 	default: | ||
|  | 		p.err("expected asm-qualifier") | ||
|  | 		return nil | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | //  asm-arg-list: | ||
|  | // 	: ExpressionListOpt | ||
|  | // 	asm-arg-list : expression-list_opt | ||
|  | func (p *parser) asmArgList() (r *AsmArgList) { | ||
|  | 	if p.rune() != ':' { | ||
|  | 		p.err("expected :") | ||
|  | 		return nil | ||
|  | 	} | ||
|  | 
 | ||
|  | 	t := p.shift() | ||
|  | 	var list *AsmExpressionList | ||
|  | 	switch p.rune() { | ||
|  | 	case ':', ')': | ||
|  | 	default: | ||
|  | 		list = p.asmExpressionList() | ||
|  | 	} | ||
|  | 	r = &AsmArgList{Token: t, AsmExpressionList: list} | ||
|  | 	for prev := r; p.rune() == ':'; prev = prev.AsmArgList { | ||
|  | 		t := p.shift() | ||
|  | 		switch p.rune() { | ||
|  | 		case ':', ')': | ||
|  | 		default: | ||
|  | 			list = p.asmExpressionList() | ||
|  | 		} | ||
|  | 		prev.AsmArgList = &AsmArgList{Token: t, AsmExpressionList: list} | ||
|  | 	} | ||
|  | 	return r | ||
|  | } | ||
|  | 
 | ||
|  | //  asm-expression-list: | ||
|  | // 	asm-index_opt assignment-expression | ||
|  | // 	asm-expression-list , asm-index_opt assignment-expression | ||
|  | func (p *parser) asmExpressionList() (r *AsmExpressionList) { | ||
|  | 	var x *AsmIndex | ||
|  | 	if p.rune() == '[' { | ||
|  | 		x = p.asmIndex() | ||
|  | 	} | ||
|  | 
 | ||
|  | 	r = &AsmExpressionList{AsmIndex: x, AssignmentExpression: p.assignmentExpression()} | ||
|  | 	for prev := r; p.rune() == ','; prev = prev.AsmExpressionList { | ||
|  | 		t := p.shift() | ||
|  | 		if p.rune() == '[' { | ||
|  | 			x = p.asmIndex() | ||
|  | 		} | ||
|  | 		prev.AsmExpressionList = &AsmExpressionList{Token: t, AsmIndex: x, AssignmentExpression: p.assignmentExpression()} | ||
|  | 	} | ||
|  | 	return r | ||
|  | } | ||
|  | 
 | ||
|  | //  asm-index: | ||
|  | // 	[ expression ] | ||
|  | func (p *parser) asmIndex() *AsmIndex { | ||
|  | 	if p.rune() != '[' { | ||
|  | 		p.err("expected [") | ||
|  | 		return nil | ||
|  | 	} | ||
|  | 
 | ||
|  | 	t := p.shift() | ||
|  | 	e := p.expression() | ||
|  | 	var t2 Token | ||
|  | 	switch p.rune() { | ||
|  | 	case ']': | ||
|  | 		t2 = p.shift() | ||
|  | 	default: | ||
|  | 		p.err("expected ]") | ||
|  | 	} | ||
|  | 	return &AsmIndex{Token: t, Expression: e, Token2: t2} | ||
|  | } | ||
|  | 
 | ||
|  | //  attribute-specifier-list: | ||
|  | // 	attribute-specifier | ||
|  | // 	attribute-specifier-list attribute-specifier | ||
|  | func (p *parser) attributeSpecifierList() (r *AttributeSpecifierList) { | ||
|  | 	if p.rune() != ATTRIBUTE { | ||
|  | 		p.err("expected __attribute__") | ||
|  | 		return nil | ||
|  | 	} | ||
|  | 
 | ||
|  | 	r = &AttributeSpecifierList{AttributeSpecifier: p.attributeSpecifier()} | ||
|  | 	for prev := r; p.rune() == ATTRIBUTE; prev = r.AttributeSpecifierList { | ||
|  | 		prev.AttributeSpecifierList = &AttributeSpecifierList{AttributeSpecifier: p.attributeSpecifier()} | ||
|  | 	} | ||
|  | 	return r | ||
|  | } | ||
|  | 
 | ||
|  | //  attribute-specifier: | ||
|  | // 	__attribute__ (( attribute-value-list_opt )) | ||
|  | func (p *parser) attributeSpecifier() (r *AttributeSpecifier) { | ||
|  | 	if p.rune() != ATTRIBUTE { | ||
|  | 		p.err("expected __attribute__") | ||
|  | 		return nil | ||
|  | 	} | ||
|  | 
 | ||
|  | 	en := p.typedefNameEnabled | ||
|  | 	t := p.shift() | ||
|  | 	var t2, t3, t4, t5 Token | ||
|  | 	p.ignoreKeywords = true | ||
|  | 	switch p.rune() { | ||
|  | 	case '(': | ||
|  | 		t2 = p.shift() | ||
|  | 	default: | ||
|  | 		p.err("expected (") | ||
|  | 	} | ||
|  | 	switch p.rune() { | ||
|  | 	case '(': | ||
|  | 		t3 = p.shift() | ||
|  | 	default: | ||
|  | 		p.err("expected (") | ||
|  | 	} | ||
|  | 	var list *AttributeValueList | ||
|  | 	if p.rune() != ')' { | ||
|  | 		list = p.attributeValueList() | ||
|  | 	} | ||
|  | 	p.ignoreKeywords = false | ||
|  | 	p.typedefNameEnabled = en | ||
|  | 	switch p.rune() { | ||
|  | 	case ')': | ||
|  | 		t4 = p.shift() | ||
|  | 	default: | ||
|  | 		p.err("expected )") | ||
|  | 	} | ||
|  | 	switch p.rune() { | ||
|  | 	case ')': | ||
|  | 		t5 = p.shift() | ||
|  | 	default: | ||
|  | 		p.err("expected )") | ||
|  | 	} | ||
|  | 	return &AttributeSpecifier{Token: t, Token2: t2, Token3: t3, AttributeValueList: list, Token4: t4, Token5: t5} | ||
|  | } | ||
|  | 
 | ||
|  | //  attribute-value-list: | ||
|  | // 	attribute-value | ||
|  | // 	attribute-value-list , attribute-value | ||
|  | func (p *parser) attributeValueList() (r *AttributeValueList) { | ||
|  | 	r = &AttributeValueList{AttributeValue: p.attributeValue()} | ||
|  | 	for prev := r; p.rune() == ','; prev = prev.AttributeValueList { | ||
|  | 		t := p.shift() | ||
|  | 		prev.AttributeValueList = &AttributeValueList{Token: t, AttributeValue: p.attributeValue()} | ||
|  | 	} | ||
|  | 	return r | ||
|  | } | ||
|  | 
 | ||
|  | //  attribute-value: | ||
|  | // 	identifier | ||
|  | // 	identifier ( expression-list_opt ) | ||
|  | func (p *parser) attributeValue() *AttributeValue { | ||
|  | 	if p.rune() != IDENTIFIER { | ||
|  | 		p.err("expected identifier") | ||
|  | 		return nil | ||
|  | 	} | ||
|  | 
 | ||
|  | 	t := p.shift() | ||
|  | 	if p.rune() != '(' { | ||
|  | 		return &AttributeValue{Case: AttributeValueIdent, Token: t, lexicalScope: p.declScope} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	p.ignoreKeywords = false | ||
|  | 	t2 := p.shift() | ||
|  | 	var list *ExpressionList | ||
|  | 	if p.rune() != ')' { | ||
|  | 		list = p.expressionList() | ||
|  | 	} | ||
|  | 	p.ignoreKeywords = true | ||
|  | 	var t3 Token | ||
|  | 	switch p.rune() { | ||
|  | 	case ')': | ||
|  | 		t3 = p.shift() | ||
|  | 	default: | ||
|  | 		p.err("expected )") | ||
|  | 	} | ||
|  | 	return &AttributeValue{Case: AttributeValueExpr, Token: t, Token2: t2, ExpressionList: list, Token3: t3, lexicalScope: p.declScope} | ||
|  | } | ||
|  | 
 | ||
|  | //  expression-list: | ||
|  | // 	assignment-expression | ||
|  | // 	expression-list , assignment-expression | ||
|  | func (p *parser) expressionList() (r *ExpressionList) { | ||
|  | 	r = &ExpressionList{AssignmentExpression: p.assignmentExpression()} | ||
|  | 	for prev := r; p.rune() == ','; prev = prev.ExpressionList { | ||
|  | 		t := p.shift() | ||
|  | 		prev.ExpressionList = &ExpressionList{Token: t, AssignmentExpression: p.assignmentExpression()} | ||
|  | 	} | ||
|  | 	return r | ||
|  | } |