// Code generated by yy. DO NOT EDIT.

%{
// Copyright 2016 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.

// Based on [0], 6.10. Substantial portions of expression AST size
// optimizations are from [2], license of which follows.

// ----------------------------------------------------------------------------

// Copyright 2013 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This grammar is derived from the C grammar in the 'ansitize'
// program, which carried this notice:
// 
// Copyright (c) 2006 Russ Cox, 
// 	Massachusetts Institute of Technology
// 
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated
// documentation files (the "Software"), to deal in the
// Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute,
// sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// 
// The above copyright notice and this permission notice shall
// be included in all copies or substantial portions of the
// Software.
// 
// The software is provided "as is", without warranty of any
// kind, express or implied, including but not limited to the
// warranties of merchantability, fitness for a particular
// purpose and noninfringement.  In no event shall the authors
// or copyright holders be liable for any claim, damages or
// other liability, whether in an action of contract, tort or
// otherwise, arising from, out of or in connection with the
// software or the use or other dealings in the software.

package cc

import (
	"fmt"

	"modernc.org/xc"
	"modernc.org/golex/lex"
)
%}

%union {
	Token     xc.Token
	groupPart Node
	node      Node
	toks      PPTokenList
}

%token	<Token>
	'!'
	'%'
	'&'
	'('
	')'
	'*'
	'+'
	','
	'-'
	'.'
	'/'
	':'
	';'
	'<'
	'='
	'>'
	'?'
	'['
	'\n'
	']'
	'^'
	'{'
	'|'
	'}'
	'~'
	ADDASSIGN                    "+="
	ALIGNOF                      "_Alignof"
	ANDAND                       "&&"
	ANDASSIGN                    "&="
	ARROW                        "->"
	ASM                          "asm"
	AUTO                         "auto"
	BOOL                         "_Bool"
	BREAK                        "break"
	CASE                         "case"
	CAST
	CHAR                         "char"
	CHARCONST                    "character constant"
	COMPLEX                      "_Complex"
	CONST                        "const"
	CONSTANT_EXPRESSION 1048577  "constant expression prefix"
	CONTINUE                     "continue"
	DDD                          "..."
	DEC                          "--"
	DEFAULT                      "default"
	DIVASSIGN                    "/="
	DO                           "do"
	DOUBLE                       "double"
	ELSE                         "else"
	ENUM                         "enum"
	EQ                           "=="
	EXTERN                       "extern"
	FLOAT                        "float"
	FLOATCONST                   "floating-point constant"
	FOR                          "for"
	GEQ                          ">="
	GOTO                         "goto"
	IDENTIFIER                   "identifier"
	IDENTIFIER_LPAREN            "identifier immediatelly followed by '('"
	IDENTIFIER_NONREPL           "non replaceable identifier"
	IF                           "if"
	INC                          "++"
	INLINE                       "inline"
	INT                          "int"
	INTCONST                     "integer constant"
	LEQ                          "<="
	LONG                         "long"
	LONGCHARCONST                "long character constant"
	LONGSTRINGLITERAL            "long string constant"
	LSH                          "<<"
	LSHASSIGN                    "<<="
	MODASSIGN                    "%="
	MULASSIGN                    "*="
	NEQ                          "!="
	NOELSE
	NORETURN                     "_Noreturn"
	NOSEMI
	ORASSIGN                     "|="
	OROR                         "||"
	PPDEFINE                     "#define"
	PPELIF                       "#elif"
	PPELSE                       "#else"
	PPENDIF                      "#endif"
	PPERROR                      "#error"
	PPHASH_NL                    "#"
	PPHEADER_NAME                "header name"
	PPIF                         "#if"
	PPIFDEF                      "#ifdef"
	PPIFNDEF                     "#ifndef"
	PPINCLUDE                    "#include"
	PPINCLUDE_NEXT               "#include_next"
	PPLINE                       "#line"
	PPNONDIRECTIVE               "#foo"
	PPNUMBER                     "preprocessing number"
	PPOTHER                      "ppother"
	PPPASTE                      "##"
	PPPRAGMA                     "#pragma"
	PPUNDEF                      "#undef"
	PREPROCESSING_FILE 1048576   "preprocessing file prefix"
	REGISTER                     "register"
	RESTRICT                     "restrict"
	RETURN                       "return"
	RSH                          ">>"
	RSHASSIGN                    ">>="
	SHORT                        "short"
	SIGNED                       "signed"
	SIZEOF                       "sizeof"
	STATIC                       "static"
	STATIC_ASSERT                "_Static_assert"
	STRINGLITERAL                "string literal"
	STRUCT                       "struct"
	SUBASSIGN                    "-="
	SWITCH                       "switch"
	TRANSLATION_UNIT 1048578     "translation unit prefix"
	TYPEDEF                      "typedef"
	TYPEDEFNAME                  "typedefname"
	TYPEOF                       "typeof"
	UNARY
	UNION                        "union"
	UNSIGNED                     "unsigned"
	VOID                         "void"
	VOLATILE                     "volatile"
	WHILE                        "while"
	XORASSIGN                    "^="

%type	<groupPart>
	GroupPart                    "group part"

%type	<node>
	AbstractDeclarator           "abstract declarator"
	AbstractDeclaratorOpt        "optional abstract declarator"
	ArgumentExpressionList       "argument expression list"
	ArgumentExpressionListOpt    "optional argument expression list"
	AssemblerInstructions        "assembler instructions"
	AssemblerOperand             "assembler operand"
	AssemblerOperands            "assembler operands"
	AssemblerStatement           "assembler statement"
	AssemblerSymbolicNameOpt     "optional assembler symbolic name"
	BasicAssemblerStatement      "basic assembler statement"
	BlockItem                    "block item"
	BlockItemList                "block item list"
	BlockItemListOpt             "optional block item list"
	Clobbers                     "clobbers"
	CommaOpt                     "optional comma"
	CompoundStatement            "compound statement"
	ConstantExpression           "constant expression"
	ControlLine                  "control line"
	Declaration                  "declaration"
	DeclarationList              "declaration list"
	DeclarationListOpt           "optional declaration list"
	DeclarationSpecifiers        "declaration specifiers"
	DeclarationSpecifiersOpt     "optional declaration specifiers"
	Declarator                   "declarator"
	DeclaratorOpt                "optional declarator"
	Designation                  "designation"
	DesignationOpt               "optional designation"
	Designator                   "designator"
	DesignatorList               "designator list"
	DirectAbstractDeclarator     "direct abstract declarator"
	DirectAbstractDeclaratorOpt  "optional direct abstract declarator"
	DirectDeclarator             "direct declarator"
	ElifGroup                    "elif group"
	ElifGroupList                "elif group list"
	ElifGroupListOpt             "optional elif group list"
	ElseGroup                    "else group"
	ElseGroupOpt                 "optional else group"
	EndifLine                    "endif line"
	EnumSpecifier                "enum specifier"
	EnumerationConstant          "enumearation constant"
	Enumerator                   "enumerator"
	EnumeratorList               "enumerator list"
	Expression                   "expression"
	ExpressionList               "expression list"
	ExpressionListOpt            "optional expression list"
	ExpressionOpt                "optional expression"
	ExpressionStatement          "expression statement"
	ExternalDeclaration          "external declaration"
	FunctionBody                 "function body"
	FunctionDefinition           "function definition"
	FunctionSpecifier            "function specifier"
	GroupList                    "group list"
	GroupListOpt                 "optional group list"
	IdentifierList               "identifier list"
	IdentifierListOpt            "optional identifier list"
	IdentifierOpt                "optional identifier"
	IfGroup                      "if group"
	IfSection                    "if section"
	InitDeclarator               "init declarator"
	InitDeclaratorList           "init declarator list"
	InitDeclaratorListOpt        "optional init declarator list"
	Initializer                  "initializer"
	InitializerList              "initializer list"
	IterationStatement           "iteration statement"
	JumpStatement                "jump statement"
	LabeledStatement             "labeled statement"
	PPTokens
	ParameterDeclaration         "parameter declaration"
	ParameterList                "parameter list"
	ParameterTypeList            "parameter type list"
	ParameterTypeListOpt         "optional parameter type list"
	Pointer                      "pointer"
	PointerOpt                   "optional pointer"
	PreprocessingFile            "preprocessing file"
	SelectionStatement           "selection statement"
	SpecifierQualifierList       "specifier qualifier list"
	SpecifierQualifierListOpt    "optional specifier qualifier list"
	Start
	Statement                    "statement"
	StaticAssertDeclaration      "static assert declaration"
	StorageClassSpecifier        "storage class specifier"
	StructDeclaration            "struct declaration"
	StructDeclarationList        "struct declaration list"
	StructDeclarator             "struct declarator"
	StructDeclaratorList         "struct declarator list"
	StructOrUnion                "struct-or-union"
	StructOrUnionSpecifier       "struct-or-union specifier"
	TranslationUnit              "translation unit"
	TypeName                     "type name"
	TypeQualifier                "type qualifier"
	TypeQualifierList            "type qualifier list"
	TypeQualifierListOpt         "optional type qualifier list"
	TypeSpecifier                "type specifier"
	VolatileOpt                  "optional volatile"

%type	<toks>
	PPTokenList                  "token list"
	PPTokenListOpt               "optional token list"
	ReplacementList              "replacement list"
	TextLine                     "text line"

%precedence	NOSEMI
%precedence	';'
%precedence	NOELSE
%precedence	ELSE
%right	'=' ADDASSIGN ANDASSIGN DIVASSIGN LSHASSIGN MODASSIGN MULASSIGN ORASSIGN RSHASSIGN SUBASSIGN XORASSIGN
%right	':' '?'
%left	OROR
%left	ANDAND
%left	'|'
%left	'^'
%left	'&'
%left	EQ NEQ
%left	'<' '>' GEQ LEQ
%left	LSH RSH
%left	'+' '-'
%left	'%' '*' '/'
%precedence	CAST
%left	'!' '~' SIZEOF UNARY
%right	'(' '.' '[' ARROW DEC INC

%start Start

%%

Start:
	PREPROCESSING_FILE
	{
		lx := yylex.(*lexer)
		lx.preprocessingFile = nil
	}
	PreprocessingFile
	{
		lx := yylex.(*lexer)
		lx.preprocessingFile = $3.(*PreprocessingFile)
	}
|	CONSTANT_EXPRESSION
	{
		lx := yylex.(*lexer)
		lx.constantExpression = nil
	}
	ConstantExpression
	{
		lx := yylex.(*lexer)
		lx.constantExpression = $3.(*ConstantExpression)
	}
|	TRANSLATION_UNIT
	{
		lx := yylex.(*lexer)
		lx.translationUnit = nil
	}
	TranslationUnit
	{
		lx := yylex.(*lexer)
		if lx.report.Errors(false) == nil && lx.scope.kind != ScopeFile {
			panic("internal error")
		}

		lx.translationUnit = $3.(*TranslationUnit).reverse()
		lx.translationUnit.Declarations = lx.scope
	}

EnumerationConstant:
	IDENTIFIER
	{
		$$ = &EnumerationConstant{
			Token:  $1,
		}
	}

ArgumentExpressionList:
	Expression
	{
		$$ = &ArgumentExpressionList{
			Expression:  $1.(*Expression),
		}
	}
|	ArgumentExpressionList ',' Expression
	{
		$$ = &ArgumentExpressionList{
			Case:                    1,
			ArgumentExpressionList:  $1.(*ArgumentExpressionList),
			Token:                   $2,
			Expression:              $3.(*Expression),
		}
	}

ArgumentExpressionListOpt:
	/* empty */
	{
		$$ = (*ArgumentExpressionListOpt)(nil)
		}
|	ArgumentExpressionList
	{
		$$ = &ArgumentExpressionListOpt{
			ArgumentExpressionList:  $1.(*ArgumentExpressionList).reverse(),
		}
	}

Expression:
	IDENTIFIER %prec NOSEMI
	{
		lx := yylex.(*lexer)
		lhs := &Expression{
			Token:  $1,
		}
		$$ = lhs
		lhs.scope = lx.scope
	}
|	CHARCONST
	{
		$$ = &Expression{
			Case:   1,
			Token:  $1,
		}
	}
|	FLOATCONST
	{
		$$ = &Expression{
			Case:   2,
			Token:  $1,
		}
	}
|	INTCONST
	{
		$$ = &Expression{
			Case:   3,
			Token:  $1,
		}
	}
|	LONGCHARCONST
	{
		$$ = &Expression{
			Case:   4,
			Token:  $1,
		}
	}
|	LONGSTRINGLITERAL
	{
		$$ = &Expression{
			Case:   5,
			Token:  $1,
		}
	}
|	STRINGLITERAL
	{
		$$ = &Expression{
			Case:   6,
			Token:  $1,
		}
	}
|	'(' ExpressionList ')'
	{
		$$ = &Expression{
			Case:            7,
			Token:           $1,
			ExpressionList:  $2.(*ExpressionList).reverse(),
			Token2:          $3,
		}
	}
|	Expression '[' ExpressionList ']'
	{
		$$ = &Expression{
			Case:            8,
			Expression:      $1.(*Expression),
			Token:           $2,
			ExpressionList:  $3.(*ExpressionList).reverse(),
			Token2:          $4,
		}
	}
|	Expression '(' ArgumentExpressionListOpt ')'
	{
		lx := yylex.(*lexer)
		lhs := &Expression{
			Case:                       9,
			Expression:                 $1.(*Expression),
			Token:                      $2,
			ArgumentExpressionListOpt:  $3.(*ArgumentExpressionListOpt),
			Token2:                     $4,
		}
		$$ = lhs
		o := lhs.ArgumentExpressionListOpt
		if o == nil {
			break
		}

		if lhs.Expression.Case == 0 { // IDENTIFIER
			if lx.tweaks.enableBuiltinConstantP &&lhs.Expression.Token.Val == idBuiltinConstantP {
				break
			}

			b := lhs.Expression.scope.Lookup(NSIdentifiers, lhs.Expression.Token.Val)
			if b.Node == nil && lx.tweaks.enableImplicitFuncDef {
				for l := o.ArgumentExpressionList; l != nil; l = l.ArgumentExpressionList {
					l.Expression.eval(lx)
				}
				break
			}
		}

		lhs.Expression.eval(lx)
		for l := o.ArgumentExpressionList; l != nil; l = l.ArgumentExpressionList {
			l.Expression.eval(lx)
		}
	}
|	Expression '.' IDENTIFIER
	{
		$$ = &Expression{
			Case:        10,
			Expression:  $1.(*Expression),
			Token:       $2,
			Token2:      $3,
		}
	}
|	Expression "->" IDENTIFIER
	{
		$$ = &Expression{
			Case:        11,
			Expression:  $1.(*Expression),
			Token:       $2,
			Token2:      $3,
		}
	}
|	Expression "++"
	{
		$$ = &Expression{
			Case:        12,
			Expression:  $1.(*Expression),
			Token:       $2,
		}
	}
|	Expression "--"
	{
		$$ = &Expression{
			Case:        13,
			Expression:  $1.(*Expression),
			Token:       $2,
		}
	}
|	'(' TypeName ')' '{' InitializerList CommaOpt '}'
	{
		$$ = &Expression{
			Case:             14,
			Token:            $1,
			TypeName:         $2.(*TypeName),
			Token2:           $3,
			Token3:           $4,
			InitializerList:  $5.(*InitializerList).reverse(),
			CommaOpt:         $6.(*CommaOpt),
			Token4:           $7,
		}
	}
|	"++" Expression
	{
		$$ = &Expression{
			Case:        15,
			Token:       $1,
			Expression:  $2.(*Expression),
		}
	}
|	"--" Expression
	{
		$$ = &Expression{
			Case:        16,
			Token:       $1,
			Expression:  $2.(*Expression),
		}
	}
|	'&' Expression %prec UNARY
	{
		$$ = &Expression{
			Case:        17,
			Token:       $1,
			Expression:  $2.(*Expression),
		}
	}
|	'*' Expression %prec UNARY
	{
		$$ = &Expression{
			Case:        18,
			Token:       $1,
			Expression:  $2.(*Expression),
		}
	}
|	'+' Expression %prec UNARY
	{
		$$ = &Expression{
			Case:        19,
			Token:       $1,
			Expression:  $2.(*Expression),
		}
	}
|	'-' Expression %prec UNARY
	{
		$$ = &Expression{
			Case:        20,
			Token:       $1,
			Expression:  $2.(*Expression),
		}
	}
|	'~' Expression
	{
		$$ = &Expression{
			Case:        21,
			Token:       $1,
			Expression:  $2.(*Expression),
		}
	}
|	'!' Expression
	{
		$$ = &Expression{
			Case:        22,
			Token:       $1,
			Expression:  $2.(*Expression),
		}
	}
|	"sizeof" Expression
	{
		$$ = &Expression{
			Case:        23,
			Token:       $1,
			Expression:  $2.(*Expression),
		}
	}
|	"sizeof" '(' TypeName ')' %prec SIZEOF
	{
		$$ = &Expression{
			Case:      24,
			Token:     $1,
			Token2:    $2,
			TypeName:  $3.(*TypeName),
			Token3:    $4,
		}
	}
|	'(' TypeName ')' Expression %prec CAST
	{
		$$ = &Expression{
			Case:        25,
			Token:       $1,
			TypeName:    $2.(*TypeName),
			Token2:      $3,
			Expression:  $4.(*Expression),
		}
	}
|	Expression '*' Expression
	{
		$$ = &Expression{
			Case:         26,
			Expression:   $1.(*Expression),
			Token:        $2,
			Expression2:  $3.(*Expression),
		}
	}
|	Expression '/' Expression
	{
		$$ = &Expression{
			Case:         27,
			Expression:   $1.(*Expression),
			Token:        $2,
			Expression2:  $3.(*Expression),
		}
	}
|	Expression '%' Expression
	{
		$$ = &Expression{
			Case:         28,
			Expression:   $1.(*Expression),
			Token:        $2,
			Expression2:  $3.(*Expression),
		}
	}
|	Expression '+' Expression
	{
		$$ = &Expression{
			Case:         29,
			Expression:   $1.(*Expression),
			Token:        $2,
			Expression2:  $3.(*Expression),
		}
	}
|	Expression '-' Expression
	{
		$$ = &Expression{
			Case:         30,
			Expression:   $1.(*Expression),
			Token:        $2,
			Expression2:  $3.(*Expression),
		}
	}
|	Expression "<<" Expression
	{
		$$ = &Expression{
			Case:         31,
			Expression:   $1.(*Expression),
			Token:        $2,
			Expression2:  $3.(*Expression),
		}
	}
|	Expression ">>" Expression
	{
		$$ = &Expression{
			Case:         32,
			Expression:   $1.(*Expression),
			Token:        $2,
			Expression2:  $3.(*Expression),
		}
	}
|	Expression '<' Expression
	{
		$$ = &Expression{
			Case:         33,
			Expression:   $1.(*Expression),
			Token:        $2,
			Expression2:  $3.(*Expression),
		}
	}
|	Expression '>' Expression
	{
		$$ = &Expression{
			Case:         34,
			Expression:   $1.(*Expression),
			Token:        $2,
			Expression2:  $3.(*Expression),
		}
	}
|	Expression "<=" Expression
	{
		$$ = &Expression{
			Case:         35,
			Expression:   $1.(*Expression),
			Token:        $2,
			Expression2:  $3.(*Expression),
		}
	}
|	Expression ">=" Expression
	{
		$$ = &Expression{
			Case:         36,
			Expression:   $1.(*Expression),
			Token:        $2,
			Expression2:  $3.(*Expression),
		}
	}
|	Expression "==" Expression
	{
		$$ = &Expression{
			Case:         37,
			Expression:   $1.(*Expression),
			Token:        $2,
			Expression2:  $3.(*Expression),
		}
	}
|	Expression "!=" Expression
	{
		$$ = &Expression{
			Case:         38,
			Expression:   $1.(*Expression),
			Token:        $2,
			Expression2:  $3.(*Expression),
		}
	}
|	Expression '&' Expression
	{
		$$ = &Expression{
			Case:         39,
			Expression:   $1.(*Expression),
			Token:        $2,
			Expression2:  $3.(*Expression),
		}
	}
|	Expression '^' Expression
	{
		$$ = &Expression{
			Case:         40,
			Expression:   $1.(*Expression),
			Token:        $2,
			Expression2:  $3.(*Expression),
		}
	}
|	Expression '|' Expression
	{
		$$ = &Expression{
			Case:         41,
			Expression:   $1.(*Expression),
			Token:        $2,
			Expression2:  $3.(*Expression),
		}
	}
|	Expression "&&" Expression
	{
		$$ = &Expression{
			Case:         42,
			Expression:   $1.(*Expression),
			Token:        $2,
			Expression2:  $3.(*Expression),
		}
	}
|	Expression "||" Expression
	{
		$$ = &Expression{
			Case:         43,
			Expression:   $1.(*Expression),
			Token:        $2,
			Expression2:  $3.(*Expression),
		}
	}
|	Expression '?' ExpressionList ':' Expression
	{
		$$ = &Expression{
			Case:            44,
			Expression:      $1.(*Expression),
			Token:           $2,
			ExpressionList:  $3.(*ExpressionList).reverse(),
			Token2:          $4,
			Expression2:     $5.(*Expression),
		}
	}
|	Expression '=' Expression
	{
		$$ = &Expression{
			Case:         45,
			Expression:   $1.(*Expression),
			Token:        $2,
			Expression2:  $3.(*Expression),
		}
	}
|	Expression "*=" Expression
	{
		$$ = &Expression{
			Case:         46,
			Expression:   $1.(*Expression),
			Token:        $2,
			Expression2:  $3.(*Expression),
		}
	}
|	Expression "/=" Expression
	{
		$$ = &Expression{
			Case:         47,
			Expression:   $1.(*Expression),
			Token:        $2,
			Expression2:  $3.(*Expression),
		}
	}
|	Expression "%=" Expression
	{
		$$ = &Expression{
			Case:         48,
			Expression:   $1.(*Expression),
			Token:        $2,
			Expression2:  $3.(*Expression),
		}
	}
|	Expression "+=" Expression
	{
		$$ = &Expression{
			Case:         49,
			Expression:   $1.(*Expression),
			Token:        $2,
			Expression2:  $3.(*Expression),
		}
	}
|	Expression "-=" Expression
	{
		$$ = &Expression{
			Case:         50,
			Expression:   $1.(*Expression),
			Token:        $2,
			Expression2:  $3.(*Expression),
		}
	}
|	Expression "<<=" Expression
	{
		$$ = &Expression{
			Case:         51,
			Expression:   $1.(*Expression),
			Token:        $2,
			Expression2:  $3.(*Expression),
		}
	}
|	Expression ">>=" Expression
	{
		$$ = &Expression{
			Case:         52,
			Expression:   $1.(*Expression),
			Token:        $2,
			Expression2:  $3.(*Expression),
		}
	}
|	Expression "&=" Expression
	{
		$$ = &Expression{
			Case:         53,
			Expression:   $1.(*Expression),
			Token:        $2,
			Expression2:  $3.(*Expression),
		}
	}
|	Expression "^=" Expression
	{
		$$ = &Expression{
			Case:         54,
			Expression:   $1.(*Expression),
			Token:        $2,
			Expression2:  $3.(*Expression),
		}
	}
|	Expression "|=" Expression
	{
		$$ = &Expression{
			Case:         55,
			Expression:   $1.(*Expression),
			Token:        $2,
			Expression2:  $3.(*Expression),
		}
	}
|	"_Alignof" '(' TypeName ')'
	{
		$$ = &Expression{
			Case:      56,
			Token:     $1,
			Token2:    $2,
			TypeName:  $3.(*TypeName),
			Token3:    $4,
		}
	}
|	'(' CompoundStatement ')'
	{
		$$ = &Expression{
			Case:               57,
			Token:              $1,
			CompoundStatement:  $2.(*CompoundStatement),
			Token2:             $3,
		}
	}
|	"&&" IDENTIFIER
	{
		lx := yylex.(*lexer)
		lhs := &Expression{
			Case:    58,
			Token:   $1,
			Token2:  $2,
		}
		$$ = lhs
		if !lx.tweaks.enableComputedGotos {
			lx.report.Err(lhs.Pos(), "computed gotos not enabled")
		}
	}
|	Expression '?' ':' Expression
	{
		lx := yylex.(*lexer)
		lhs := &Expression{
			Case:         59,
			Expression:   $1.(*Expression),
			Token:        $2,
			Token2:       $3,
			Expression2:  $4.(*Expression),
		}
		$$ = lhs
		if !lx.tweaks.enableOmitConditionalOperand {
			lx.report.Err(lhs.Pos(), "omitting conditional operand not enabled")
		}
	}

ExpressionOpt:
	/* empty */
	{
		$$ = (*ExpressionOpt)(nil)
		}
|	Expression
	{
		lx := yylex.(*lexer)
		lhs := &ExpressionOpt{
			Expression:  $1.(*Expression),
		}
		$$ = lhs
		lhs.Expression.eval(lx)
	}

ExpressionList:
	Expression
	{
		$$ = &ExpressionList{
			Expression:  $1.(*Expression),
		}
	}
|	ExpressionList ',' Expression
	{
		$$ = &ExpressionList{
			Case:            1,
			ExpressionList:  $1.(*ExpressionList),
			Token:           $2,
			Expression:      $3.(*Expression),
		}
	}

ExpressionListOpt:
	/* empty */
	{
		$$ = (*ExpressionListOpt)(nil)
		}
|	ExpressionList
	{
		lx := yylex.(*lexer)
		lhs := &ExpressionListOpt{
			ExpressionList:  $1.(*ExpressionList).reverse(),
		}
		$$ = lhs
		lhs.ExpressionList.eval(lx)
	}

ConstantExpression:
	{
		lx := yylex.(*lexer)
		lx.constExprToks = []xc.Token{lx.last}
	}
	Expression
	{
		lx := yylex.(*lexer)
		lhs := &ConstantExpression{
			Expression:  $2.(*Expression),
		}
		$$ = lhs
		lhs.Value, lhs.Type = lhs.Expression.eval(lx)
		if lhs.Value == nil {
			lx.report.Err(lhs.Pos(), "not a constant expression")
		}
		l := lx.constExprToks
		lhs.toks = l[:len(l)-1]
		lx.constExprToks = nil
	}

Declaration:
	DeclarationSpecifiers InitDeclaratorListOpt ';'
	{
		lx := yylex.(*lexer)
		lhs := &Declaration{
			DeclarationSpecifiers:  $1.(*DeclarationSpecifiers),
			InitDeclaratorListOpt:  $2.(*InitDeclaratorListOpt),
			Token:                  $3,
		}
		$$ = lhs
		ts0 := lhs.DeclarationSpecifiers.typeSpecifiers()
		if ts0 == 0 && lx.tweaks.enableImplicitIntType {
			lhs.DeclarationSpecifiers.typeSpecifier = tsEncode(tsInt)
		}
		ts := tsDecode(lhs.DeclarationSpecifiers.typeSpecifiers())
		ok := false
		for _, v := range ts {
			if v == tsStructSpecifier || v == tsUnionSpecifier {
				ok = true
				break
			}
		}
		if ok {
			s := lhs.DeclarationSpecifiers
			d := &Declarator{specifier: s}
			dd := &DirectDeclarator{
				Token: xc.Token{Char: lex.NewChar(lhs.Pos(), 0)},
				declarator: d,
				idScope: lx.scope,
				specifier: s,
			}
			d.DirectDeclarator = dd
			d.setFull(lx)
			for l := lhs.DeclarationSpecifiers; l != nil; {
				ts := l.TypeSpecifier
				if ts != nil && ts.Case == 11 && ts.StructOrUnionSpecifier.Case == 0 { // StructOrUnion IdentifierOpt '{' StructDeclarationList '}'
					ts.StructOrUnionSpecifier.declarator = d
					break
				}

				if o := l.DeclarationSpecifiersOpt; o != nil {
					l = o.DeclarationSpecifiers
					continue
				}

				break
			}
		}

		o := lhs.InitDeclaratorListOpt
		if o != nil {
			break
		}

		s := lhs.DeclarationSpecifiers
		d := &Declarator{specifier: s}
		dd := &DirectDeclarator{
			Token: xc.Token{Char: lex.NewChar(lhs.Pos(), 0)},
			declarator: d,
			idScope: lx.scope,
			specifier: s,
		}
		d.DirectDeclarator = dd
		d.setFull(lx)
		lhs.declarator = d
	}
|	StaticAssertDeclaration
	{
		$$ = &Declaration{
			Case:                     1,
			StaticAssertDeclaration:  $1.(*StaticAssertDeclaration),
		}
	}

DeclarationSpecifiers:
	StorageClassSpecifier DeclarationSpecifiersOpt
	{
		lx := yylex.(*lexer)
		lhs := &DeclarationSpecifiers{
			StorageClassSpecifier:     $1.(*StorageClassSpecifier),
			DeclarationSpecifiersOpt:  $2.(*DeclarationSpecifiersOpt),
		}
		$$ = lhs
		lx.scope.specifier = lhs
		a := lhs.StorageClassSpecifier
		b := lhs.DeclarationSpecifiersOpt
		if b == nil {
			lhs.attr = a.attr
			break
		}

		if a.attr&b.attr != 0 {
			lx.report.Err(a.Pos(), "invalid storage class specifier")
			break
		}

		lhs.attr = a.attr|b.attr
		lhs.typeSpecifier = b.typeSpecifier
		if lhs.StorageClassSpecifier.Case != 0 /* "typedef" */ && lhs.IsTypedef() {
			lx.report.Err(a.Pos(), "invalid storage class specifier")
		}
	}
|	TypeSpecifier DeclarationSpecifiersOpt
	{
		lx := yylex.(*lexer)
		lhs := &DeclarationSpecifiers{
			Case:                      1,
			TypeSpecifier:             $1.(*TypeSpecifier),
			DeclarationSpecifiersOpt:  $2.(*DeclarationSpecifiersOpt),
		}
		$$ = lhs
		lx.scope.specifier = lhs
		a := lhs.TypeSpecifier
		b := lhs.DeclarationSpecifiersOpt
		if b == nil {
			lhs.typeSpecifier = a.typeSpecifier
			break
		}

		lhs.attr = b.attr
		tsb := tsDecode(b.typeSpecifier)
		if len(tsb) == 1 && tsb[0] == tsTypedefName && lx.tweaks.allowCompatibleTypedefRedefinitions {
			tsb[0] = 0
		}
		ts := tsEncode(append(tsDecode(a.typeSpecifier), tsb...)...)
		if _, ok := tsValid[ts]; !ok {
			ts = tsEncode(tsInt)
			lx.report.Err(a.Pos(), "invalid type specifier")
		}
		lhs.typeSpecifier = ts
	}
|	TypeQualifier DeclarationSpecifiersOpt
	{
		lx := yylex.(*lexer)
		lhs := &DeclarationSpecifiers{
			Case:                      2,
			TypeQualifier:             $1.(*TypeQualifier),
			DeclarationSpecifiersOpt:  $2.(*DeclarationSpecifiersOpt),
		}
		$$ = lhs
		lx.scope.specifier = lhs
		a := lhs.TypeQualifier
		b := lhs.DeclarationSpecifiersOpt
		if b == nil {
			lhs.attr = a.attr
			break
		}
	
		if a.attr&b.attr != 0 {
			lx.report.Err(a.Pos(), "invalid type qualifier")
			break
		}

		lhs.attr = a.attr|b.attr
		lhs.typeSpecifier = b.typeSpecifier
		if lhs.IsTypedef() {
			lx.report.Err(a.Pos(), "invalid type qualifier")
		}
	}
|	FunctionSpecifier DeclarationSpecifiersOpt
	{
		lx := yylex.(*lexer)
		lhs := &DeclarationSpecifiers{
			Case:                      3,
			FunctionSpecifier:         $1.(*FunctionSpecifier),
			DeclarationSpecifiersOpt:  $2.(*DeclarationSpecifiersOpt),
		}
		$$ = lhs
		lx.scope.specifier = lhs
		a := lhs.FunctionSpecifier
		b := lhs.DeclarationSpecifiersOpt
		if b == nil {
			lhs.attr = a.attr
			break
		}
	
		if a.attr&b.attr != 0 {
			lx.report.Err(a.Pos(), "invalid function specifier")
			break
		}

		lhs.attr = a.attr|b.attr
		lhs.typeSpecifier = b.typeSpecifier
		if lhs.IsTypedef() {
			lx.report.Err(a.Pos(), "invalid function specifier")
		}
	}

DeclarationSpecifiersOpt:
	/* empty */
	{
		$$ = (*DeclarationSpecifiersOpt)(nil)
		}
|	DeclarationSpecifiers
	{
		lhs := &DeclarationSpecifiersOpt{
			DeclarationSpecifiers:  $1.(*DeclarationSpecifiers),
		}
		$$ = lhs
		lhs.attr = lhs.DeclarationSpecifiers.attr
		lhs.typeSpecifier = lhs.DeclarationSpecifiers.typeSpecifier
	}

InitDeclaratorList:
	InitDeclarator
	{
		$$ = &InitDeclaratorList{
			InitDeclarator:  $1.(*InitDeclarator),
		}
	}
|	InitDeclaratorList ',' InitDeclarator
	{
		$$ = &InitDeclaratorList{
			Case:                1,
			InitDeclaratorList:  $1.(*InitDeclaratorList),
			Token:               $2,
			InitDeclarator:      $3.(*InitDeclarator),
		}
	}

InitDeclaratorListOpt:
	/* empty */
	{
		$$ = (*InitDeclaratorListOpt)(nil)
		}
|	InitDeclaratorList
	{
		$$ = &InitDeclaratorListOpt{
			InitDeclaratorList:  $1.(*InitDeclaratorList).reverse(),
		}
	}

InitDeclarator:
	Declarator
	{
		lx := yylex.(*lexer)
		lhs := &InitDeclarator{
			Declarator:  $1.(*Declarator),
		}
		$$ = lhs
		lhs.Declarator.setFull(lx)
	}
|	Declarator
	{
		lx := yylex.(*lexer)
		d := $1.(*Declarator)
		d.setFull(lx)
	}
	'=' Initializer
	{
		lx := yylex.(*lexer)
		lhs := &InitDeclarator{
			Case:         1,
			Declarator:   $1.(*Declarator),
			Token:        $3,
			Initializer:  $4.(*Initializer),
		}
		$$ = lhs
		d := lhs.Declarator
		lhs.Initializer.typeCheck(&d.Type, d.Type, lhs.Declarator.specifier.IsStatic(), lx)
		if d.Type.Specifier().IsExtern() {
			id, _ := d.Identifier()
			lx.report.Err(d.Pos(), "'%s' initialized and declared 'extern'", dict.S(id))
		}
	}

StorageClassSpecifier:
	"typedef"
	{
		lhs := &StorageClassSpecifier{
			Token:  $1,
		}
		$$ = lhs
		lhs.attr = saTypedef
	}
|	"extern"
	{
		lhs := &StorageClassSpecifier{
			Case:   1,
			Token:  $1,
		}
		$$ = lhs
		lhs.attr = saExtern
	}
|	"static"
	{
		lhs := &StorageClassSpecifier{
			Case:   2,
			Token:  $1,
		}
		$$ = lhs
		lhs.attr = saStatic
	}
|	"auto"
	{
		lhs := &StorageClassSpecifier{
			Case:   3,
			Token:  $1,
		}
		$$ = lhs
		lhs.attr = saAuto
	}
|	"register"
	{
		lhs := &StorageClassSpecifier{
			Case:   4,
			Token:  $1,
		}
		$$ = lhs
		lhs.attr = saRegister
	}

TypeSpecifier:
	"void"
	{
		lhs := &TypeSpecifier{
			Token:  $1,
		}
		$$ = lhs
		lhs.typeSpecifier = tsEncode(tsVoid)
	}
|	"char"
	{
		lhs := &TypeSpecifier{
			Case:   1,
			Token:  $1,
		}
		$$ = lhs
		lhs.typeSpecifier = tsEncode(tsChar)
	}
|	"short"
	{
		lhs := &TypeSpecifier{
			Case:   2,
			Token:  $1,
		}
		$$ = lhs
		lhs.typeSpecifier = tsEncode(tsShort)
	}
|	"int"
	{
		lhs := &TypeSpecifier{
			Case:   3,
			Token:  $1,
		}
		$$ = lhs
		lhs.typeSpecifier = tsEncode(tsInt)
	}
|	"long"
	{
		lhs := &TypeSpecifier{
			Case:   4,
			Token:  $1,
		}
		$$ = lhs
		lhs.typeSpecifier = tsEncode(tsLong)
	}
|	"float"
	{
		lhs := &TypeSpecifier{
			Case:   5,
			Token:  $1,
		}
		$$ = lhs
		lhs.typeSpecifier = tsEncode(tsFloat)
	}
|	"double"
	{
		lhs := &TypeSpecifier{
			Case:   6,
			Token:  $1,
		}
		$$ = lhs
		lhs.typeSpecifier = tsEncode(tsDouble)
	}
|	"signed"
	{
		lhs := &TypeSpecifier{
			Case:   7,
			Token:  $1,
		}
		$$ = lhs
		lhs.typeSpecifier = tsEncode(tsSigned)
	}
|	"unsigned"
	{
		lhs := &TypeSpecifier{
			Case:   8,
			Token:  $1,
		}
		$$ = lhs
		lhs.typeSpecifier = tsEncode(tsUnsigned)
	}
|	"_Bool"
	{
		lhs := &TypeSpecifier{
			Case:   9,
			Token:  $1,
		}
		$$ = lhs
		lhs.typeSpecifier = tsEncode(tsBool)
	}
|	"_Complex"
	{
		lhs := &TypeSpecifier{
			Case:   10,
			Token:  $1,
		}
		$$ = lhs
		lhs.typeSpecifier = tsEncode(tsComplex)
	}
|	StructOrUnionSpecifier
	{
		lhs := &TypeSpecifier{
			Case:                    11,
			StructOrUnionSpecifier:  $1.(*StructOrUnionSpecifier),
		}
		$$ = lhs
		lhs.typeSpecifier = tsEncode(lhs.StructOrUnionSpecifier.typeSpecifiers())
	}
|	EnumSpecifier
	{
		lhs := &TypeSpecifier{
			Case:           12,
			EnumSpecifier:  $1.(*EnumSpecifier),
		}
		$$ = lhs
		lhs.typeSpecifier = tsEncode(tsEnumSpecifier)
	}
|	TYPEDEFNAME
	{
		lx := yylex.(*lexer)
		lhs := &TypeSpecifier{
			Case:   13,
			Token:  $1,
		}
		$$ = lhs
		lhs.typeSpecifier = tsEncode(tsTypedefName)
		_, lhs.scope = lx.scope.Lookup2(NSIdentifiers, lhs.Token.Val)
	}
|	"typeof" '(' Expression ')'
	{
		lx := yylex.(*lexer)
		lhs := &TypeSpecifier{
			Case:        14,
			Token:       $1,
			Token2:      $2,
			Expression:  $3.(*Expression),
			Token3:      $4,
		}
		$$ = lhs
		lhs.typeSpecifier = tsEncode(tsTypeof)
		_, lhs.Type = lhs.Expression.eval(lx)
	}
|	"typeof" '(' TypeName ')'
	{
		lhs := &TypeSpecifier{
			Case:      15,
			Token:     $1,
			Token2:    $2,
			TypeName:  $3.(*TypeName),
			Token3:    $4,
		}
		$$ = lhs
		lhs.typeSpecifier = tsEncode(tsTypeof)
		lhs.Type = undefined
		if t := lhs.TypeName.Type; t != nil {
			lhs.Type = t
		}
	}

StructOrUnionSpecifier:
	StructOrUnion IdentifierOpt '{'
	{
		lx := yylex.(*lexer)
		if o := $2.(*IdentifierOpt); o != nil {
			lx.scope.declareStructTag(o.Token, lx.report)
		}
		lx.pushScope(ScopeMembers)
		lx.scope.isUnion = $1.(*StructOrUnion).Case == 1 // "union"
		lx.scope.prevStructDeclarator = nil
	}
	StructDeclarationList '}'
	{
		lx := yylex.(*lexer)
		lhs := &StructOrUnionSpecifier{
			StructOrUnion:          $1.(*StructOrUnion),
			IdentifierOpt:          $2.(*IdentifierOpt),
			Token:                  $3,
			StructDeclarationList:  $5.(*StructDeclarationList).reverse(),
			Token2:                 $6,
		}
		$$ = lhs
		sc := lx.scope
		lhs.scope = sc
		if sc.bitOffset != 0 {
			finishBitField(lhs, lx)
		}

		i := 0
		var bt Type
		var d *Declarator
		for l := lhs.StructDeclarationList; l != nil; l = l.StructDeclarationList {
			for l := l.StructDeclaration.StructDeclaratorList; l != nil; l = l.StructDeclaratorList {
				switch sd := l.StructDeclarator; sd.Case {
				case 0: // Declarator
					d = sd.Declarator
				case 1: // DeclaratorOpt ':' ConstantExpression
					if o := sd.DeclaratorOpt; o != nil {
						x := o.Declarator
						if x.bitOffset == 0  {
							d = x
							bt = lx.scope.bitFieldTypes[i]
							i++
						}
						x.bitFieldType = bt
					}
				}
			}
		}
		lx.scope.bitFieldTypes = nil

		lhs.alignOf = sc.maxAlign
		switch {
		case sc.isUnion:
			lhs.sizeOf = align(sc.maxSize, sc.maxAlign)
		default:
			off := sc.offset
			lhs.sizeOf = align(sc.offset, sc.maxAlign)
			if d != nil {
				d.padding = lhs.sizeOf-off
			}
		}

		lx.popScope(lhs.Token2)
		if o := lhs.IdentifierOpt; o != nil {
			lx.scope.defineStructTag(o.Token, lhs, lx.report)
		}
	}
|	StructOrUnion IDENTIFIER
	{
		lx := yylex.(*lexer)
		lhs := &StructOrUnionSpecifier{
			Case:           1,
			StructOrUnion:  $1.(*StructOrUnion),
			Token:          $2,
		}
		$$ = lhs
		lx.scope.declareStructTag(lhs.Token, lx.report)
		lhs.scope = lx.scope
	}
|	StructOrUnion IdentifierOpt '{' '}'
	{
		lx := yylex.(*lexer)
		lhs := &StructOrUnionSpecifier{
			Case:           2,
			StructOrUnion:  $1.(*StructOrUnion),
			IdentifierOpt:  $2.(*IdentifierOpt),
			Token:          $3,
			Token2:         $4,
		}
		$$ = lhs
		if !lx.tweaks.enableEmptyStructs {
			lx.report.Err(lhs.Token.Pos(), "empty structs/unions not allowed")
		}
		if o := $2.(*IdentifierOpt); o != nil {
			lx.scope.declareStructTag(o.Token, lx.report)
		}
		lx.scope.isUnion = $1.(*StructOrUnion).Case == 1 // "union"
		lx.scope.prevStructDeclarator = nil
		lhs.alignOf = 1
		lhs.sizeOf = 0
		if o := lhs.IdentifierOpt; o != nil {
			lx.scope.defineStructTag(o.Token, lhs, lx.report)
		}
	}

StructOrUnion:
	"struct"
	{
		$$ = &StructOrUnion{
			Token:  $1,
		}
	}
|	"union"
	{
		$$ = &StructOrUnion{
			Case:   1,
			Token:  $1,
		}
	}

StructDeclarationList:
	StructDeclaration
	{
		$$ = &StructDeclarationList{
			StructDeclaration:  $1.(*StructDeclaration),
		}
	}
|	StructDeclarationList StructDeclaration
	{
		$$ = &StructDeclarationList{
			Case:                   1,
			StructDeclarationList:  $1.(*StructDeclarationList),
			StructDeclaration:      $2.(*StructDeclaration),
		}
	}

StructDeclaration:
	SpecifierQualifierList StructDeclaratorList ';'
	{
		lx := yylex.(*lexer)
		lhs := &StructDeclaration{
			SpecifierQualifierList:  $1.(*SpecifierQualifierList),
			StructDeclaratorList:    $2.(*StructDeclaratorList).reverse(),
			Token:                   $3,
		}
		$$ = lhs
		s := lhs.SpecifierQualifierList
		if k := s.kind(); k != Struct && k != Union {
			break
		}

		d := &Declarator{specifier: s}
		dd := &DirectDeclarator{
			Token: xc.Token{Char: lex.NewChar(lhs.Pos(), 0)},
			declarator: d,
			idScope: lx.scope,
			specifier: s,
		}
		d.DirectDeclarator = dd
		d.setFull(lx)
		for l := lhs.SpecifierQualifierList; l != nil; {
			ts := l.TypeSpecifier
			if ts != nil && ts.Case == 11 && ts.StructOrUnionSpecifier.Case == 0 { // StructOrUnion IdentifierOpt '{' StructDeclarationList '}'
				ts.StructOrUnionSpecifier.declarator = d
				break
			}

			if o := l.SpecifierQualifierListOpt; o != nil {
				l = o.SpecifierQualifierList
				continue
			}

			break
		}
	}
|	SpecifierQualifierList ';'
	{
		lx := yylex.(*lexer)
		lhs := &StructDeclaration{
			Case:                    1,
			SpecifierQualifierList:  $1.(*SpecifierQualifierList),
			Token:                   $2,
		}
		$$ = lhs
		s := lhs.SpecifierQualifierList
		if !lx.tweaks.enableAnonymousStructFields {
			lx.report.Err(lhs.Token.Pos(), "unnamed fields not allowed")
		} else if k := s.kind(); k != Struct && k != Union {
			lx.report.Err(lhs.Token.Pos(), "only unnamed structs and unions are allowed")
			break
		}

		d := &Declarator{specifier: s}
		dd := &DirectDeclarator{
			Token: xc.Token{Char: lex.NewChar(lhs.Pos(), 0)},
			declarator: d,
			idScope: lx.scope,
			specifier: s,
		}
		d.DirectDeclarator = dd
		d.setFull(lx)

		// we have no struct declarators to parse, so we have to create the case of one implicit declarator
		// because else the size of anonymous members is not included in the struct size!
		dummy := &StructDeclarator{Declarator: d}
		dummy.post(lx)

		for l := lhs.SpecifierQualifierList; l != nil; {
			ts := l.TypeSpecifier
			if ts != nil && ts.Case == 11 && ts.StructOrUnionSpecifier.Case == 0 { // StructOrUnion IdentifierOpt '{' StructDeclarationList '}'
				ts.StructOrUnionSpecifier.declarator = d
				break
			}

			if o := l.SpecifierQualifierListOpt; o != nil {
				l = o.SpecifierQualifierList
				continue
			}

			break
		}
	}
|	StaticAssertDeclaration
	{
		$$ = &StructDeclaration{
			Case:                     2,
			StaticAssertDeclaration:  $1.(*StaticAssertDeclaration),
		}
	}

SpecifierQualifierList:
	TypeSpecifier SpecifierQualifierListOpt
	{
		lx := yylex.(*lexer)
		lhs := &SpecifierQualifierList{
			TypeSpecifier:              $1.(*TypeSpecifier),
			SpecifierQualifierListOpt:  $2.(*SpecifierQualifierListOpt),
		}
		$$ = lhs
		lx.scope.specifier = lhs
		a := lhs.TypeSpecifier
		b := lhs.SpecifierQualifierListOpt
		if b == nil {
			lhs.typeSpecifier = a.typeSpecifier
			break
		}

		lhs.attr = b.attr
		ts := tsEncode(append(tsDecode(a.typeSpecifier), tsDecode(b.typeSpecifier)...)...)
		if _, ok := tsValid[ts]; !ok {
			lx.report.Err(a.Pos(), "invalid type specifier")
			break
		}

		lhs.typeSpecifier = ts
	}
|	TypeQualifier SpecifierQualifierListOpt
	{
		lx := yylex.(*lexer)
		lhs := &SpecifierQualifierList{
			Case:                       1,
			TypeQualifier:              $1.(*TypeQualifier),
			SpecifierQualifierListOpt:  $2.(*SpecifierQualifierListOpt),
		}
		$$ = lhs
		lx.scope.specifier = lhs
		a := lhs.TypeQualifier
		b := lhs.SpecifierQualifierListOpt
		if b == nil {
			lhs.attr = a.attr
			break
		}
	
		if a.attr&b.attr != 0 {
			lx.report.Err(a.Pos(), "invalid type qualifier")
			break
		}

		lhs.attr = a.attr|b.attr
		lhs.typeSpecifier = b.typeSpecifier
	}

SpecifierQualifierListOpt:
	/* empty */
	{
		$$ = (*SpecifierQualifierListOpt)(nil)
		}
|	SpecifierQualifierList
	{
		lhs := &SpecifierQualifierListOpt{
			SpecifierQualifierList:  $1.(*SpecifierQualifierList),
		}
		$$ = lhs
		lhs.attr = lhs.SpecifierQualifierList.attr
		lhs.typeSpecifier = lhs.SpecifierQualifierList.typeSpecifier
	}

StructDeclaratorList:
	StructDeclarator
	{
		$$ = &StructDeclaratorList{
			StructDeclarator:  $1.(*StructDeclarator),
		}
	}
|	StructDeclaratorList ',' StructDeclarator
	{
		$$ = &StructDeclaratorList{
			Case:                  1,
			StructDeclaratorList:  $1.(*StructDeclaratorList),
			Token:                 $2,
			StructDeclarator:      $3.(*StructDeclarator),
		}
	}

StructDeclarator:
	Declarator
	{
		lx := yylex.(*lexer)
		lhs := &StructDeclarator{
			Declarator:  $1.(*Declarator),
		}
		$$ = lhs
		lhs.Declarator.setFull(lx)
		lhs.post(lx)
	}
|	DeclaratorOpt ':' ConstantExpression
	{
		lx := yylex.(*lexer)
		lhs := &StructDeclarator{
			Case:                1,
			DeclaratorOpt:       $1.(*DeclaratorOpt),
			Token:               $2,
			ConstantExpression:  $3.(*ConstantExpression),
		}
		$$ = lhs
		m := lx.model
		e := lhs.ConstantExpression
		if e.Value == nil {
			e.Value, e.Type = m.value2(1, m.IntType)
		}
		if !IsIntType(e.Type) {
			lx.report.Err(e.Pos(), "bit field width not an integer (have '%s')", e.Type)
			e.Value, e.Type = m.value2(1, m.IntType)
		}
		if o := lhs.DeclaratorOpt; o != nil {
			o.Declarator.setFull(lx)
		}
		lhs.post(lx)
	}

CommaOpt:
	/* empty */
	{
		$$ = (*CommaOpt)(nil)
		}
|	','
	{
		$$ = &CommaOpt{
			Token:  $1,
		}
	}

EnumSpecifier:
	"enum" IdentifierOpt
	{
		lx := yylex.(*lexer)
		if o := $2.(*IdentifierOpt); o != nil {
			lx.scope.declareEnumTag(o.Token, lx.report)
		}
		lx.iota = 0
	}
	'{' EnumeratorList CommaOpt '}'
	{
		lx := yylex.(*lexer)
		lhs := &EnumSpecifier{
			Token:           $1,
			IdentifierOpt:   $2.(*IdentifierOpt),
			Token2:          $4,
			EnumeratorList:  $5.(*EnumeratorList).reverse(),
			CommaOpt:        $6.(*CommaOpt),
			Token3:          $7,
		}
		$$ = lhs
		if o := lhs.IdentifierOpt; o != nil {
			lx.scope.defineEnumTag(o.Token, lhs, lx.report)
		}
		if !lx.tweaks.enableUnsignedEnums {
			break
		}

		lhs.unsigned = true
	loop:
		for l := lhs.EnumeratorList; l != nil; l = l.EnumeratorList {
			switch e := l.Enumerator; x := e.Value.(type) {
			case int32:
				if x < 0 {
					lhs.unsigned = false
					break loop
				}
			case int64:
				if x < 0 {
					lhs.unsigned = false
					break loop
				}
			default:
				panic(fmt.Errorf("%s: TODO Enumerator.Value type %T", position(e.Pos()), x))
			}
		}
	}
|	"enum" IDENTIFIER
	{
		lx := yylex.(*lexer)
		lhs := &EnumSpecifier{
			Case:    1,
			Token:   $1,
			Token2:  $2,
		}
		$$ = lhs
		lx.scope.declareEnumTag(lhs.Token2, lx.report)
	}

EnumeratorList:
	Enumerator
	{
		$$ = &EnumeratorList{
			Enumerator:  $1.(*Enumerator),
		}
	}
|	EnumeratorList ',' Enumerator
	{
		$$ = &EnumeratorList{
			Case:            1,
			EnumeratorList:  $1.(*EnumeratorList),
			Token:           $2,
			Enumerator:      $3.(*Enumerator),
		}
	}

Enumerator:
	EnumerationConstant
	{
		lx := yylex.(*lexer)
		lhs := &Enumerator{
			EnumerationConstant:  $1.(*EnumerationConstant),
		}
		$$ = lhs
		m := lx.model
		v := m.MustConvert(lx.iota, m.IntType)
		lhs.Value = v
		lx.scope.defineEnumConst(lx, lhs.EnumerationConstant.Token, v)
	}
|	EnumerationConstant '=' ConstantExpression
	{
		lx := yylex.(*lexer)
		lhs := &Enumerator{
			Case:                 1,
			EnumerationConstant:  $1.(*EnumerationConstant),
			Token:                $2,
			ConstantExpression:   $3.(*ConstantExpression),
		}
		$$ = lhs
		m := lx.model
		e := lhs.ConstantExpression
		var v interface{}
		// [0], 6.7.2.2
		// The expression that defines the value of an enumeration
		// constant shall be an integer constant expression that has a
		// value representable as an int.
		switch {
		case !IsIntType(e.Type):
			lx.report.Err(e.Pos(), "not an integer constant expression (have '%s')", e.Type)
			v = m.MustConvert(int32(0), m.IntType)
		default:
			var ok bool
			if v, ok = m.enumValueToInt(e.Value); !ok {
				lx.report.Err(e.Pos(), "overflow in enumeration value: %v", e.Value)
			}
		}

		lhs.Value = v
		lx.scope.defineEnumConst(lx, lhs.EnumerationConstant.Token, v)
	}

TypeQualifier:
	"const"
	{
		lhs := &TypeQualifier{
			Token:  $1,
		}
		$$ = lhs
		lhs.attr = saConst
	}
|	"restrict"
	{
		lhs := &TypeQualifier{
			Case:   1,
			Token:  $1,
		}
		$$ = lhs
		lhs.attr = saRestrict
	}
|	"volatile"
	{
		lhs := &TypeQualifier{
			Case:   2,
			Token:  $1,
		}
		$$ = lhs
		lhs.attr = saVolatile
	}

FunctionSpecifier:
	"inline"
	{
		lhs := &FunctionSpecifier{
			Token:  $1,
		}
		$$ = lhs
		lhs.attr = saInline
	}
|	"_Noreturn"
	{
		lhs := &FunctionSpecifier{
			Case:   1,
			Token:  $1,
		}
		$$ = lhs
		lhs.attr = saNoreturn
	}

Declarator:
	PointerOpt DirectDeclarator
	{
		lx := yylex.(*lexer)
		lhs := &Declarator{
			PointerOpt:        $1.(*PointerOpt),
			DirectDeclarator:  $2.(*DirectDeclarator),
		}
		$$ = lhs
		lhs.specifier = lx.scope.specifier
		lhs.DirectDeclarator.declarator = lhs
	}

DeclaratorOpt:
	/* empty */
	{
		$$ = (*DeclaratorOpt)(nil)
		}
|	Declarator
	{
		$$ = &DeclaratorOpt{
			Declarator:  $1.(*Declarator),
		}
	}

DirectDeclarator:
	IDENTIFIER
	{
		lx := yylex.(*lexer)
		lhs := &DirectDeclarator{
			Token:  $1,
		}
		$$ = lhs
		lhs.specifier = lx.scope.specifier
		lx.scope.declareIdentifier(lhs.Token, lhs, lx.report)
		lhs.idScope = lx.scope
	}
|	'(' Declarator ')'
	{
		lhs := &DirectDeclarator{
			Case:        1,
			Token:       $1,
			Declarator:  $2.(*Declarator),
			Token2:      $3,
		}
		$$ = lhs
		lhs.Declarator.specifier = nil
		lhs.Declarator.DirectDeclarator.parent = lhs
	}
|	DirectDeclarator '[' TypeQualifierListOpt ExpressionOpt ']'
	{
		lx := yylex.(*lexer)
		lhs := &DirectDeclarator{
			Case:                  2,
			DirectDeclarator:      $1.(*DirectDeclarator),
			Token:                 $2,
			TypeQualifierListOpt:  $3.(*TypeQualifierListOpt),
			ExpressionOpt:         $4.(*ExpressionOpt),
			Token2:                $5,
		}
		$$ = lhs
		lhs.elements = -1
		if o := lhs.ExpressionOpt; o != nil {
			var err error
			if lhs.elements, err = elements(o.Expression.eval(lx)); err != nil {
				lx.report.Err(o.Expression.Pos(), "%s", err)
			}
			
		}
		lhs.DirectDeclarator.parent = lhs
	}
|	DirectDeclarator '[' "static" TypeQualifierListOpt Expression ']'
	{
		lx := yylex.(*lexer)
		lhs := &DirectDeclarator{
			Case:                  3,
			DirectDeclarator:      $1.(*DirectDeclarator),
			Token:                 $2,
			Token2:                $3,
			TypeQualifierListOpt:  $4.(*TypeQualifierListOpt),
			Expression:            $5.(*Expression),
			Token3:                $6,
		}
		$$ = lhs
		var err error
		if lhs.elements, err = elements(lhs.Expression.eval(lx)); err != nil {
			lx.report.Err(lhs.Expression.Pos(), "%s", err)
		}
		lhs.DirectDeclarator.parent = lhs
	}
|	DirectDeclarator '[' TypeQualifierList "static" Expression ']'
	{
		lx := yylex.(*lexer)
		lhs := &DirectDeclarator{
			Case:               4,
			DirectDeclarator:   $1.(*DirectDeclarator),
			Token:              $2,
			TypeQualifierList:  $3.(*TypeQualifierList).reverse(),
			Token2:             $4,
			Expression:         $5.(*Expression),
			Token3:             $6,
		}
		$$ = lhs
		var err error
		if lhs.elements, err = elements(lhs.Expression.eval(lx)); err != nil {
			lx.report.Err(lhs.Expression.Pos(), "%s", err)
		}
		lhs.DirectDeclarator.parent = lhs
	}
|	DirectDeclarator '[' TypeQualifierListOpt '*' ']'
	{
		lhs := &DirectDeclarator{
			Case:                  5,
			DirectDeclarator:      $1.(*DirectDeclarator),
			Token:                 $2,
			TypeQualifierListOpt:  $3.(*TypeQualifierListOpt),
			Token2:                $4,
			Token3:                $5,
		}
		$$ = lhs
		lhs.DirectDeclarator.parent = lhs
		lhs.elements = -1
	}
|	DirectDeclarator '('
	{
		lx := yylex.(*lexer)
		lx.pushScope(ScopeParams)
	}
	ParameterTypeList ')'
	{
		lx := yylex.(*lexer)
		lhs := &DirectDeclarator{
			Case:               6,
			DirectDeclarator:   $1.(*DirectDeclarator),
			Token:              $2,
			ParameterTypeList:  $4.(*ParameterTypeList),
			Token2:             $5,
		}
		$$ = lhs
		lhs.paramsScope, _ = lx.popScope(lhs.Token2)
		lhs.DirectDeclarator.parent = lhs
	}
|	DirectDeclarator '(' IdentifierListOpt ')'
	{
		lhs := &DirectDeclarator{
			Case:               7,
			DirectDeclarator:   $1.(*DirectDeclarator),
			Token:              $2,
			IdentifierListOpt:  $3.(*IdentifierListOpt),
			Token2:             $4,
		}
		$$ = lhs
		lhs.DirectDeclarator.parent = lhs
	}

Pointer:
	'*' TypeQualifierListOpt
	{
		$$ = &Pointer{
			Token:                 $1,
			TypeQualifierListOpt:  $2.(*TypeQualifierListOpt),
		}
	}
|	'*' TypeQualifierListOpt Pointer
	{
		$$ = &Pointer{
			Case:                  1,
			Token:                 $1,
			TypeQualifierListOpt:  $2.(*TypeQualifierListOpt),
			Pointer:               $3.(*Pointer),
		}
	}

PointerOpt:
	/* empty */
	{
		$$ = (*PointerOpt)(nil)
		}
|	Pointer
	{
		$$ = &PointerOpt{
			Pointer:  $1.(*Pointer),
		}
	}

TypeQualifierList:
	TypeQualifier
	{
		lhs := &TypeQualifierList{
			TypeQualifier:  $1.(*TypeQualifier),
		}
		$$ = lhs
		lhs.attr = lhs.TypeQualifier.attr
	}
|	TypeQualifierList TypeQualifier
	{
		lx := yylex.(*lexer)
		lhs := &TypeQualifierList{
			Case:               1,
			TypeQualifierList:  $1.(*TypeQualifierList),
			TypeQualifier:      $2.(*TypeQualifier),
		}
		$$ = lhs
		a := lhs.TypeQualifierList
		b := lhs.TypeQualifier
		if a.attr&b.attr != 0 {
			lx.report.Err(b.Pos(), "invalid type qualifier")
			break
		}

		lhs.attr = a.attr|b.attr
	}

TypeQualifierListOpt:
	/* empty */
	{
		$$ = (*TypeQualifierListOpt)(nil)
		}
|	TypeQualifierList
	{
		$$ = &TypeQualifierListOpt{
			TypeQualifierList:  $1.(*TypeQualifierList).reverse(),
		}
	}

ParameterTypeList:
	ParameterList
	{
		lhs := &ParameterTypeList{
			ParameterList:  $1.(*ParameterList).reverse(),
		}
		$$ = lhs
		lhs.post()
	}
|	ParameterList ',' "..."
	{
		lhs := &ParameterTypeList{
			Case:           1,
			ParameterList:  $1.(*ParameterList).reverse(),
			Token:          $2,
			Token2:         $3,
		}
		$$ = lhs
		lhs.post()
	}

ParameterTypeListOpt:
	/* empty */
	{
		$$ = (*ParameterTypeListOpt)(nil)
		}
|	ParameterTypeList
	{
		$$ = &ParameterTypeListOpt{
			ParameterTypeList:  $1.(*ParameterTypeList),
		}
	}

ParameterList:
	ParameterDeclaration
	{
		$$ = &ParameterList{
			ParameterDeclaration:  $1.(*ParameterDeclaration),
		}
	}
|	ParameterList ',' ParameterDeclaration
	{
		$$ = &ParameterList{
			Case:                  1,
			ParameterList:         $1.(*ParameterList),
			Token:                 $2,
			ParameterDeclaration:  $3.(*ParameterDeclaration),
		}
	}

ParameterDeclaration:
	DeclarationSpecifiers Declarator
	{
		lx := yylex.(*lexer)
		lhs := &ParameterDeclaration{
			DeclarationSpecifiers:  $1.(*DeclarationSpecifiers),
			Declarator:             $2.(*Declarator),
		}
		$$ = lhs
		lhs.Declarator.setFull(lx)
		lhs.declarator = lhs.Declarator
	}
|	DeclarationSpecifiers AbstractDeclaratorOpt
	{
		lx := yylex.(*lexer)
		lhs := &ParameterDeclaration{
			Case:                   1,
			DeclarationSpecifiers:  $1.(*DeclarationSpecifiers),
			AbstractDeclaratorOpt:  $2.(*AbstractDeclaratorOpt),
		}
		$$ = lhs
		if o := lhs.AbstractDeclaratorOpt; o != nil {
			lhs.declarator = o.AbstractDeclarator.declarator
			lhs.declarator.setFull(lx)
			break
		}

		d := &Declarator{
			specifier: lx.scope.specifier,
			DirectDeclarator: &DirectDeclarator{
				Case: 0, // IDENTIFIER
			},
		}
		d.DirectDeclarator.declarator = d
		lhs.declarator = d
		d.setFull(lx)
	}

IdentifierList:
	IDENTIFIER
	{
		$$ = &IdentifierList{
			Token:  $1,
		}
	}
|	IdentifierList ',' IDENTIFIER
	{
		$$ = &IdentifierList{
			Case:            1,
			IdentifierList:  $1.(*IdentifierList),
			Token:           $2,
			Token2:          $3,
		}
	}

IdentifierListOpt:
	/* empty */
	{
		$$ = (*IdentifierListOpt)(nil)
		}
|	IdentifierList
	{
		$$ = &IdentifierListOpt{
			IdentifierList:  $1.(*IdentifierList).reverse(),
		}
	}

IdentifierOpt:
	/* empty */
	{
		$$ = (*IdentifierOpt)(nil)
		}
|	IDENTIFIER
	{
		$$ = &IdentifierOpt{
			Token:  $1,
		}
	}

TypeName:
	{
		lx := yylex.(*lexer)
		lx.pushScope(ScopeBlock)
	}
	SpecifierQualifierList AbstractDeclaratorOpt
	{
		lx := yylex.(*lexer)
		lhs := &TypeName{
			SpecifierQualifierList:  $2.(*SpecifierQualifierList),
			AbstractDeclaratorOpt:   $3.(*AbstractDeclaratorOpt),
		}
		$$ = lhs
		if o := lhs.AbstractDeclaratorOpt; o != nil {
			lhs.declarator = o.AbstractDeclarator.declarator
		} else {
			d := &Declarator{
				specifier: lhs.SpecifierQualifierList,
				DirectDeclarator: &DirectDeclarator{
					Case: 0, // IDENTIFIER
					idScope: lx.scope,
				},
			}
			d.DirectDeclarator.declarator = d
			lhs.declarator = d
		}
		lhs.Type = lhs.declarator.setFull(lx)
		lhs.scope = lx.scope
		lx.popScope(xc.Token{})
	}

AbstractDeclarator:
	Pointer
	{
		lx := yylex.(*lexer)
		lhs := &AbstractDeclarator{
			Pointer:  $1.(*Pointer),
		}
		$$ = lhs
		d := &Declarator{
			specifier: lx.scope.specifier,
			PointerOpt: &PointerOpt {
				Pointer: lhs.Pointer,
			},
			DirectDeclarator: &DirectDeclarator{
				Case: 0, // IDENTIFIER
				idScope: lx.scope,
			},
		}
		d.DirectDeclarator.declarator = d
		lhs.declarator = d
	}
|	PointerOpt DirectAbstractDeclarator
	{
		lx := yylex.(*lexer)
		lhs := &AbstractDeclarator{
			Case:                      1,
			PointerOpt:                $1.(*PointerOpt),
			DirectAbstractDeclarator:  $2.(*DirectAbstractDeclarator),
		}
		$$ = lhs
		d := &Declarator{
			specifier: lx.scope.specifier,
			PointerOpt: lhs.PointerOpt,
			DirectDeclarator: lhs.DirectAbstractDeclarator.directDeclarator,
		}
		d.DirectDeclarator.declarator = d
		lhs.declarator = d
	}

AbstractDeclaratorOpt:
	/* empty */
	{
		$$ = (*AbstractDeclaratorOpt)(nil)
		}
|	AbstractDeclarator
	{
		$$ = &AbstractDeclaratorOpt{
			AbstractDeclarator:  $1.(*AbstractDeclarator),
		}
	}

DirectAbstractDeclarator:
	'(' AbstractDeclarator ')'
	{
		lhs := &DirectAbstractDeclarator{
			Token:               $1,
			AbstractDeclarator:  $2.(*AbstractDeclarator),
			Token2:              $3,
		}
		$$ = lhs
		lhs.AbstractDeclarator.declarator.specifier = nil
		lhs.directDeclarator = &DirectDeclarator{
			Case: 1, // '(' Declarator ')'
			Declarator: lhs.AbstractDeclarator.declarator,
		}
		lhs.AbstractDeclarator.declarator.DirectDeclarator.parent = lhs.directDeclarator
	}
|	DirectAbstractDeclaratorOpt '[' ExpressionOpt ']'
	{
		lx := yylex.(*lexer)
		lhs := &DirectAbstractDeclarator{
			Case:                         1,
			DirectAbstractDeclaratorOpt:  $1.(*DirectAbstractDeclaratorOpt),
			Token:                        $2,
			ExpressionOpt:                $3.(*ExpressionOpt),
			Token2:                       $4,
		}
		$$ = lhs
		nElements := -1
		if o := lhs.ExpressionOpt; o != nil {
			var err error
			if nElements, err = elements(o.Expression.eval(lx)); err != nil {
				lx.report.Err(o.Expression.Pos(), "%s", err)
			}
		}
		var dd *DirectDeclarator
		switch o := lhs.DirectAbstractDeclaratorOpt; {
		case o == nil:
			dd = &DirectDeclarator{
				Case: 0, // IDENTIFIER
			}
		default:
			dd = o.DirectAbstractDeclarator.directDeclarator
		}
		lhs.directDeclarator = &DirectDeclarator{
			Case: 2, // DirectDeclarator '[' TypeQualifierListOpt ExpressionOpt ']'
			DirectDeclarator: dd,
			ExpressionOpt: lhs.ExpressionOpt,
			elements: nElements,
		}
		dd.parent = lhs.directDeclarator
	}
|	DirectAbstractDeclaratorOpt '[' TypeQualifierList ExpressionOpt ']'
	{
		lx := yylex.(*lexer)
		lhs := &DirectAbstractDeclarator{
			Case:                         2,
			DirectAbstractDeclaratorOpt:  $1.(*DirectAbstractDeclaratorOpt),
			Token:                        $2,
			TypeQualifierList:            $3.(*TypeQualifierList).reverse(),
			ExpressionOpt:                $4.(*ExpressionOpt),
			Token2:                       $5,
		}
		$$ = lhs
		if o := lhs.ExpressionOpt; o != nil {
			o.Expression.eval(lx)
		}
		var dd *DirectDeclarator
		switch o := lhs.DirectAbstractDeclaratorOpt; {
		case o == nil:
			dd = &DirectDeclarator{
				Case: 0, // IDENTIFIER
			}
		default:
			dd = o.DirectAbstractDeclarator.directDeclarator
		}
		lhs.directDeclarator = &DirectDeclarator{
			Case: 2, // DirectDeclarator '[' TypeQualifierListOpt ExpressionOpt ']'
			DirectDeclarator: dd,
			TypeQualifierListOpt: &TypeQualifierListOpt{ lhs.TypeQualifierList },
			ExpressionOpt: lhs.ExpressionOpt,
		}
		dd.parent = lhs.directDeclarator
	}
|	DirectAbstractDeclaratorOpt '[' "static" TypeQualifierListOpt Expression ']'
	{
		lx := yylex.(*lexer)
		lhs := &DirectAbstractDeclarator{
			Case:                         3,
			DirectAbstractDeclaratorOpt:  $1.(*DirectAbstractDeclaratorOpt),
			Token:                        $2,
			Token2:                       $3,
			TypeQualifierListOpt:         $4.(*TypeQualifierListOpt),
			Expression:                   $5.(*Expression),
			Token3:                       $6,
		}
		$$ = lhs
		lhs.Expression.eval(lx)
		var dd *DirectDeclarator
		switch o := lhs.DirectAbstractDeclaratorOpt; {
		case o == nil:
			dd = &DirectDeclarator{
				Case: 0, // IDENTIFIER
			}
		default:
			dd = o.DirectAbstractDeclarator.directDeclarator
		}
		lhs.directDeclarator = &DirectDeclarator{
			Case: 2, // DirectDeclarator '[' "static" TypeQualifierListOpt Expression ']'
			DirectDeclarator: dd,
			TypeQualifierListOpt: lhs.TypeQualifierListOpt,
			Expression: lhs.Expression,
		}
		dd.parent = lhs.directDeclarator
	}
|	DirectAbstractDeclaratorOpt '[' TypeQualifierList "static" Expression ']'
	{
		lx := yylex.(*lexer)
		lhs := &DirectAbstractDeclarator{
			Case:                         4,
			DirectAbstractDeclaratorOpt:  $1.(*DirectAbstractDeclaratorOpt),
			Token:                        $2,
			TypeQualifierList:            $3.(*TypeQualifierList).reverse(),
			Token2:                       $4,
			Expression:                   $5.(*Expression),
			Token3:                       $6,
		}
		$$ = lhs
		lhs.Expression.eval(lx)
		var dd *DirectDeclarator
		switch o := lhs.DirectAbstractDeclaratorOpt; {
		case o == nil:
			dd = &DirectDeclarator{
				Case: 0, // IDENTIFIER
			}
		default:
			dd = o.DirectAbstractDeclarator.directDeclarator
		}
		lhs.directDeclarator = &DirectDeclarator{
			Case: 4, // DirectDeclarator '[' TypeQualifierList "static" Expression ']'
			DirectDeclarator: dd,
			TypeQualifierList: lhs.TypeQualifierList,
			Expression: lhs.Expression,
		}
		dd.parent = lhs.directDeclarator
	}
|	DirectAbstractDeclaratorOpt '[' '*' ']'
	{
		lhs := &DirectAbstractDeclarator{
			Case:                         5,
			DirectAbstractDeclaratorOpt:  $1.(*DirectAbstractDeclaratorOpt),
			Token:                        $2,
			Token2:                       $3,
			Token3:                       $4,
		}
		$$ = lhs
		var dd *DirectDeclarator
		switch o := lhs.DirectAbstractDeclaratorOpt; {
		case o == nil:
			dd = &DirectDeclarator{
				Case: 0, // IDENTIFIER
			}
		default:
			dd = o.DirectAbstractDeclarator.directDeclarator
		}
		lhs.directDeclarator = &DirectDeclarator{
			Case: 5, // DirectDeclarator '[' TypeQualifierListOpt '*' ']'
			DirectDeclarator: dd,
		}
		dd.parent = lhs.directDeclarator
	}
|	'('
	{
		lx := yylex.(*lexer)
		lx.pushScope(ScopeParams)
	}
	ParameterTypeListOpt ')'
	{
		lx := yylex.(*lexer)
		lhs := &DirectAbstractDeclarator{
			Case:                  6,
			Token:                 $1,
			ParameterTypeListOpt:  $3.(*ParameterTypeListOpt),
			Token2:                $4,
		}
		$$ = lhs
		lhs.paramsScope, _ = lx.popScope(lhs.Token2)
		switch o := lhs.ParameterTypeListOpt; {
		case o != nil:
			lhs.directDeclarator = &DirectDeclarator{
				Case: 6, // DirectDeclarator '(' ParameterTypeList ')'
				DirectDeclarator: &DirectDeclarator{
					Case: 0, // IDENTIFIER
				},
				ParameterTypeList: o.ParameterTypeList,
			}
		default:
			lhs.directDeclarator = &DirectDeclarator{
				Case: 7, // DirectDeclarator '(' IdentifierListOpt ')'
				DirectDeclarator: &DirectDeclarator{
					Case: 0, // IDENTIFIER
				},
			}
		}
		lhs.directDeclarator.DirectDeclarator.parent = lhs.directDeclarator
	}
|	DirectAbstractDeclarator '('
	{
		lx := yylex.(*lexer)
		lx.pushScope(ScopeParams)
	}
	ParameterTypeListOpt ')'
	{
		lx := yylex.(*lexer)
		lhs := &DirectAbstractDeclarator{
			Case:                      7,
			DirectAbstractDeclarator:  $1.(*DirectAbstractDeclarator),
			Token:                     $2,
			ParameterTypeListOpt:      $4.(*ParameterTypeListOpt),
			Token2:                    $5,
		}
		$$ = lhs
		lhs.paramsScope, _ = lx.popScope(lhs.Token2)
		switch o := lhs.ParameterTypeListOpt; {
		case o != nil:
			lhs.directDeclarator = &DirectDeclarator{
				Case: 6, // DirectDeclarator '(' ParameterTypeList ')'
				DirectDeclarator: lhs.DirectAbstractDeclarator.directDeclarator,
				ParameterTypeList: o.ParameterTypeList,
			}
		default:
			lhs.directDeclarator = &DirectDeclarator{
				Case: 7, // DirectDeclarator '(' IdentifierListOpt ')'
				DirectDeclarator: lhs.DirectAbstractDeclarator.directDeclarator,
			}
		}
		lhs.directDeclarator.DirectDeclarator.parent = lhs.directDeclarator
	}

DirectAbstractDeclaratorOpt:
	/* empty */
	{
		$$ = (*DirectAbstractDeclaratorOpt)(nil)
		}
|	DirectAbstractDeclarator
	{
		$$ = &DirectAbstractDeclaratorOpt{
			DirectAbstractDeclarator:  $1.(*DirectAbstractDeclarator),
		}
	}

Initializer:
	Expression
	{
		lx := yylex.(*lexer)
		lhs := &Initializer{
			Expression:  $1.(*Expression),
		}
		$$ = lhs
		lhs.Expression.eval(lx)
	}
|	'{' InitializerList CommaOpt '}'
	{
		$$ = &Initializer{
			Case:             1,
			Token:            $1,
			InitializerList:  $2.(*InitializerList).reverse(),
			CommaOpt:         $3.(*CommaOpt),
			Token2:           $4,
		}
	}
|	IDENTIFIER ':' Initializer
	{
		lx := yylex.(*lexer)
		lhs := &Initializer{
			Case:         2,
			Token:        $1,
			Token2:       $2,
			Initializer:  $3.(*Initializer),
		}
		$$ = lhs
		if !lx.tweaks.enableLegacyDesignators {
			lx.report.Err(lhs.Pos(), "legacy designators not enabled")
		}
	}

InitializerList:
	DesignationOpt Initializer
	{
		$$ = &InitializerList{
			DesignationOpt:  $1.(*DesignationOpt),
			Initializer:     $2.(*Initializer),
		}
	}
|	InitializerList ',' DesignationOpt Initializer
	{
		$$ = &InitializerList{
			Case:             1,
			InitializerList:  $1.(*InitializerList),
			Token:            $2,
			DesignationOpt:   $3.(*DesignationOpt),
			Initializer:      $4.(*Initializer),
		}
	}
|	/* empty */
	{
		$$ = (*InitializerList)(nil)
		}

Designation:
	DesignatorList '='
	{
		$$ = &Designation{
			DesignatorList:  $1.(*DesignatorList).reverse(),
			Token:           $2,
		}
	}

DesignationOpt:
	/* empty */
	{
		$$ = (*DesignationOpt)(nil)
		}
|	Designation
	{
		$$ = &DesignationOpt{
			Designation:  $1.(*Designation),
		}
	}

DesignatorList:
	Designator
	{
		$$ = &DesignatorList{
			Designator:  $1.(*Designator),
		}
	}
|	DesignatorList Designator
	{
		$$ = &DesignatorList{
			Case:            1,
			DesignatorList:  $1.(*DesignatorList),
			Designator:      $2.(*Designator),
		}
	}

Designator:
	'[' ConstantExpression ']'
	{
		$$ = &Designator{
			Token:               $1,
			ConstantExpression:  $2.(*ConstantExpression),
			Token2:              $3,
		}
	}
|	'.' IDENTIFIER
	{
		$$ = &Designator{
			Case:    1,
			Token:   $1,
			Token2:  $2,
		}
	}

Statement:
	LabeledStatement
	{
		$$ = &Statement{
			LabeledStatement:  $1.(*LabeledStatement),
		}
	}
|	CompoundStatement
	{
		$$ = &Statement{
			Case:               1,
			CompoundStatement:  $1.(*CompoundStatement),
		}
	}
|	ExpressionStatement
	{
		$$ = &Statement{
			Case:                 2,
			ExpressionStatement:  $1.(*ExpressionStatement),
		}
	}
|	SelectionStatement
	{
		$$ = &Statement{
			Case:                3,
			SelectionStatement:  $1.(*SelectionStatement),
		}
	}
|	IterationStatement
	{
		$$ = &Statement{
			Case:                4,
			IterationStatement:  $1.(*IterationStatement),
		}
	}
|	JumpStatement
	{
		$$ = &Statement{
			Case:           5,
			JumpStatement:  $1.(*JumpStatement),
		}
	}
|	AssemblerStatement
	{
		$$ = &Statement{
			Case:                6,
			AssemblerStatement:  $1.(*AssemblerStatement),
		}
	}

LabeledStatement:
	IDENTIFIER ':' Statement
	{
		$$ = &LabeledStatement{
			Token:      $1,
			Token2:     $2,
			Statement:  $3.(*Statement),
		}
	}
|	"case" ConstantExpression ':' Statement
	{
		$$ = &LabeledStatement{
			Case:                1,
			Token:               $1,
			ConstantExpression:  $2.(*ConstantExpression),
			Token2:              $3,
			Statement:           $4.(*Statement),
		}
	}
|	"default" ':' Statement
	{
		$$ = &LabeledStatement{
			Case:       2,
			Token:      $1,
			Token2:     $2,
			Statement:  $3.(*Statement),
		}
	}

CompoundStatement:
	'{'
	{
		lx := yylex.(*lexer)
		m := lx.scope.mergeScope
		lx.pushScope(ScopeBlock)
		if m != nil {
			lx.scope.merge(m)
		}
		lx.scope.mergeScope = nil
	}
	BlockItemListOpt '}'
	{
		lx := yylex.(*lexer)
		lhs := &CompoundStatement{
			Token:             $1,
			BlockItemListOpt:  $3.(*BlockItemListOpt),
			Token2:            $4,
		}
		$$ = lhs
		lhs.scope = lx.scope
		lx.popScope(lhs.Token2)
	}

BlockItemList:
	BlockItem
	{
		$$ = &BlockItemList{
			BlockItem:  $1.(*BlockItem),
		}
	}
|	BlockItemList BlockItem
	{
		$$ = &BlockItemList{
			Case:           1,
			BlockItemList:  $1.(*BlockItemList),
			BlockItem:      $2.(*BlockItem),
		}
	}

BlockItemListOpt:
	/* empty */
	{
		$$ = (*BlockItemListOpt)(nil)
		}
|	BlockItemList
	{
		$$ = &BlockItemListOpt{
			BlockItemList:  $1.(*BlockItemList).reverse(),
		}
	}

BlockItem:
	Declaration
	{
		$$ = &BlockItem{
			Declaration:  $1.(*Declaration),
		}
	}
|	Statement
	{
		$$ = &BlockItem{
			Case:       1,
			Statement:  $1.(*Statement),
		}
	}

ExpressionStatement:
	ExpressionListOpt ';'
	{
		$$ = &ExpressionStatement{
			ExpressionListOpt:  $1.(*ExpressionListOpt),
			Token:              $2,
		}
	}

SelectionStatement:
	"if" '(' ExpressionList ')' Statement %prec NOELSE
	{
		lx := yylex.(*lexer)
		lhs := &SelectionStatement{
			Token:           $1,
			Token2:          $2,
			ExpressionList:  $3.(*ExpressionList).reverse(),
			Token3:          $4,
			Statement:       $5.(*Statement),
		}
		$$ = lhs
		lhs.ExpressionList.eval(lx)
	}
|	"if" '(' ExpressionList ')' Statement "else" Statement
	{
		lx := yylex.(*lexer)
		lhs := &SelectionStatement{
			Case:            1,
			Token:           $1,
			Token2:          $2,
			ExpressionList:  $3.(*ExpressionList).reverse(),
			Token3:          $4,
			Statement:       $5.(*Statement),
			Token4:          $6,
			Statement2:      $7.(*Statement),
		}
		$$ = lhs
		lhs.ExpressionList.eval(lx)
	}
|	"switch" '(' ExpressionList ')' Statement
	{
		lx := yylex.(*lexer)
		lhs := &SelectionStatement{
			Case:            2,
			Token:           $1,
			Token2:          $2,
			ExpressionList:  $3.(*ExpressionList).reverse(),
			Token3:          $4,
			Statement:       $5.(*Statement),
		}
		$$ = lhs
		lhs.ExpressionList.eval(lx)
	}

IterationStatement:
	"while" '(' ExpressionList ')' Statement
	{
		lx := yylex.(*lexer)
		lhs := &IterationStatement{
			Token:           $1,
			Token2:          $2,
			ExpressionList:  $3.(*ExpressionList).reverse(),
			Token3:          $4,
			Statement:       $5.(*Statement),
		}
		$$ = lhs
		lhs.ExpressionList.eval(lx)
	}
|	"do" Statement "while" '(' ExpressionList ')' ';'
	{
		lx := yylex.(*lexer)
		lhs := &IterationStatement{
			Case:            1,
			Token:           $1,
			Statement:       $2.(*Statement),
			Token2:          $3,
			Token3:          $4,
			ExpressionList:  $5.(*ExpressionList).reverse(),
			Token4:          $6,
			Token5:          $7,
		}
		$$ = lhs
		lhs.ExpressionList.eval(lx)
	}
|	"for" '(' ExpressionListOpt ';' ExpressionListOpt ';' ExpressionListOpt ')' Statement
	{
		$$ = &IterationStatement{
			Case:                2,
			Token:               $1,
			Token2:              $2,
			ExpressionListOpt:   $3.(*ExpressionListOpt),
			Token3:              $4,
			ExpressionListOpt2:  $5.(*ExpressionListOpt),
			Token4:              $6,
			ExpressionListOpt3:  $7.(*ExpressionListOpt),
			Token5:              $8,
			Statement:           $9.(*Statement),
		}
	}
|	"for" '(' Declaration ExpressionListOpt ';' ExpressionListOpt ')' Statement
	{
		$$ = &IterationStatement{
			Case:                3,
			Token:               $1,
			Token2:              $2,
			Declaration:         $3.(*Declaration),
			ExpressionListOpt:   $4.(*ExpressionListOpt),
			Token3:              $5,
			ExpressionListOpt2:  $6.(*ExpressionListOpt),
			Token4:              $7,
			Statement:           $8.(*Statement),
		}
	}

JumpStatement:
	"goto" IDENTIFIER ';'
	{
		$$ = &JumpStatement{
			Token:   $1,
			Token2:  $2,
			Token3:  $3,
		}
	}
|	"continue" ';'
	{
		$$ = &JumpStatement{
			Case:    1,
			Token:   $1,
			Token2:  $2,
		}
	}
|	"break" ';'
	{
		$$ = &JumpStatement{
			Case:    2,
			Token:   $1,
			Token2:  $2,
		}
	}
|	"return" ExpressionListOpt ';'
	{
		$$ = &JumpStatement{
			Case:               3,
			Token:              $1,
			ExpressionListOpt:  $2.(*ExpressionListOpt),
			Token2:             $3,
		}
	}
|	"goto" Expression ';'
	{
		lx := yylex.(*lexer)
		lhs := &JumpStatement{
			Case:        4,
			Token:       $1,
			Expression:  $2.(*Expression),
			Token2:      $3,
		}
		$$ = lhs
		_, t := lhs.Expression.eval(lx)
		if t == nil {
			break
		}

		for t != nil && t.Kind() == Ptr {
			t = t.Element()
		}

		if t == nil || t.Kind() != Void {
			lx.report.Err(lhs.Pos(), "invalid computed goto argument type, have '%s'", t)
		}

		if !lx.tweaks.enableComputedGotos {
			lx.report.Err(lhs.Pos(), "computed gotos not enabled")
		}
	}

TranslationUnit:
	ExternalDeclaration
	{
		$$ = &TranslationUnit{
			ExternalDeclaration:  $1.(*ExternalDeclaration),
		}
	}
|	TranslationUnit ExternalDeclaration
	{
		$$ = &TranslationUnit{
			Case:                 1,
			TranslationUnit:      $1.(*TranslationUnit),
			ExternalDeclaration:  $2.(*ExternalDeclaration),
		}
	}

ExternalDeclaration:
	FunctionDefinition
	{
		$$ = &ExternalDeclaration{
			FunctionDefinition:  $1.(*FunctionDefinition),
		}
	}
|	Declaration
	{
		$$ = &ExternalDeclaration{
			Case:         1,
			Declaration:  $1.(*Declaration),
		}
	}
|	BasicAssemblerStatement ';'
	{
		$$ = &ExternalDeclaration{
			Case:                     2,
			BasicAssemblerStatement:  $1.(*BasicAssemblerStatement),
			Token:                    $2,
		}
	}
|	';'
	{
		lx := yylex.(*lexer)
		lhs := &ExternalDeclaration{
			Case:   3,
			Token:  $1,
		}
		$$ = lhs
		if !lx.tweaks.enableEmptyDeclarations {
			lx.report.Err(lhs.Pos(), "C++11 empty declarations are illegal in C99.")
		}
	}

FunctionDefinition:
	DeclarationSpecifiers Declarator DeclarationListOpt
	{
		lx := yylex.(*lexer)
		if ds := $1.(*DeclarationSpecifiers); ds.typeSpecifier == 0 {
			ds.typeSpecifier = tsEncode(tsInt)
			$2.(*Declarator).Type = lx.model.IntType
			if !lx.tweaks.enableOmitFuncRetType {
				lx.report.Err($2.Pos(), "missing function return type")
			}
		}
		var fd *FunctionDefinition
		fd.post(lx, $2.(*Declarator), $3.(*DeclarationListOpt))
	}
	FunctionBody
	{
		$$ = &FunctionDefinition{
			DeclarationSpecifiers:  $1.(*DeclarationSpecifiers),
			Declarator:             $2.(*Declarator),
			DeclarationListOpt:     $3.(*DeclarationListOpt),
			FunctionBody:           $5.(*FunctionBody),
		}
	}
|	{
		lx := yylex.(*lexer)
		lx.scope.specifier = &DeclarationSpecifiers{typeSpecifier: tsEncode(tsInt)}
	}
	Declarator DeclarationListOpt
	{
		lx := yylex.(*lexer)
		if !lx.tweaks.enableOmitFuncRetType {
			lx.report.Err($2.Pos(), "missing function return type")
		}
		var fd *FunctionDefinition
		fd.post(lx, $2.(*Declarator), $3.(*DeclarationListOpt))
	}
	FunctionBody
	{
		$$ = &FunctionDefinition{
			Case:                1,
			Declarator:          $2.(*Declarator),
			DeclarationListOpt:  $3.(*DeclarationListOpt),
			FunctionBody:        $5.(*FunctionBody),
		}
	}

FunctionBody:
	{
		lx := yylex.(*lexer)
		// Handle __func__, [0], 6.4.2.2.
		id, _ := lx.fnDeclarator.Identifier()
		lx.injectFunc = []xc.Token{
			{lex.Char{Rune: STATIC}, idStatic},
			{lex.Char{Rune: CONST}, idConst},
			{lex.Char{Rune: CHAR}, idChar},
			{lex.Char{Rune: IDENTIFIER}, idMagicFunc},
			{lex.Char{Rune: '['}, 0},
			{lex.Char{Rune: ']'}, 0},
			{lex.Char{Rune: '='}, 0},
			{lex.Char{Rune: STRINGLITERAL}, xc.Dict.SID(fmt.Sprintf("%q", xc.Dict.S(id)))},
			{lex.Char{Rune: ';'}, 0},
		}
	}
	CompoundStatement
	{
		lhs := &FunctionBody{
			CompoundStatement:  $2.(*CompoundStatement),
		}
		$$ = lhs
		lhs.scope = lhs.CompoundStatement.scope
	}
|	{
		lx := yylex.(*lexer)
		m := lx.scope.mergeScope
		lx.pushScope(ScopeBlock)
		if m != nil {
			lx.scope.merge(m)
		}
		lx.scope.mergeScope = nil
	}
	AssemblerStatement ';'
	{
		lx := yylex.(*lexer)
		lhs := &FunctionBody{
			Case:                1,
			AssemblerStatement:  $2.(*AssemblerStatement),
			Token:               $3,
		}
		$$ = lhs
		lhs.scope = lx.scope
		lx.popScope(lx.tokPrev)
	}

DeclarationList:
	Declaration
	{
		$$ = &DeclarationList{
			Declaration:  $1.(*Declaration),
		}
	}
|	DeclarationList Declaration
	{
		$$ = &DeclarationList{
			Case:             1,
			DeclarationList:  $1.(*DeclarationList),
			Declaration:      $2.(*Declaration),
		}
	}

DeclarationListOpt:
	/* empty */
	{
		$$ = (*DeclarationListOpt)(nil)
		}
|	{
		lx := yylex.(*lexer)
		lx.pushScope(ScopeParams)
	}
	DeclarationList
	{
		lx := yylex.(*lexer)
		lhs := &DeclarationListOpt{
			DeclarationList:  $2.(*DeclarationList).reverse(),
		}
		$$ = lhs
		lhs.paramsScope, _ = lx.popScopePos(lhs.Pos())
	}

AssemblerInstructions:
	STRINGLITERAL
	{
		$$ = &AssemblerInstructions{
			Token:  $1,
		}
	}
|	AssemblerInstructions STRINGLITERAL
	{
		$$ = &AssemblerInstructions{
			Case:                   1,
			AssemblerInstructions:  $1.(*AssemblerInstructions),
			Token:                  $2,
		}
	}

BasicAssemblerStatement:
	"asm" VolatileOpt '(' AssemblerInstructions ')'
	{
		$$ = &BasicAssemblerStatement{
			Token:                  $1,
			VolatileOpt:            $2.(*VolatileOpt),
			Token2:                 $3,
			AssemblerInstructions:  $4.(*AssemblerInstructions).reverse(),
			Token3:                 $5,
		}
	}

VolatileOpt:
	/* empty */
	{
		$$ = (*VolatileOpt)(nil)
		}
|	"volatile"
	{
		$$ = &VolatileOpt{
			Token:  $1,
		}
	}

AssemblerOperand:
	AssemblerSymbolicNameOpt STRINGLITERAL '(' Expression ')'
	{
		$$ = &AssemblerOperand{
			AssemblerSymbolicNameOpt:  $1.(*AssemblerSymbolicNameOpt),
			Token:                     $2,
			Token2:                    $3,
			Expression:                $4.(*Expression),
			Token3:                    $5,
		}
	}

AssemblerOperands:
	AssemblerOperand
	{
		$$ = &AssemblerOperands{
			AssemblerOperand:  $1.(*AssemblerOperand),
		}
	}
|	AssemblerOperands ',' AssemblerOperand
	{
		$$ = &AssemblerOperands{
			Case:               1,
			AssemblerOperands:  $1.(*AssemblerOperands),
			Token:              $2,
			AssemblerOperand:   $3.(*AssemblerOperand),
		}
	}

AssemblerSymbolicNameOpt:
	/* empty */
	{
		$$ = (*AssemblerSymbolicNameOpt)(nil)
		}
|	'[' IDENTIFIER ']'
	{
		$$ = &AssemblerSymbolicNameOpt{
			Token:   $1,
			Token2:  $2,
			Token3:  $3,
		}
	}

Clobbers:
	STRINGLITERAL
	{
		$$ = &Clobbers{
			Token:  $1,
		}
	}
|	Clobbers ',' STRINGLITERAL
	{
		$$ = &Clobbers{
			Case:      1,
			Clobbers:  $1.(*Clobbers),
			Token:     $2,
			Token2:    $3,
		}
	}

AssemblerStatement:
	BasicAssemblerStatement
	{
		$$ = &AssemblerStatement{
			BasicAssemblerStatement:  $1.(*BasicAssemblerStatement),
		}
	}
|	"asm" VolatileOpt '(' AssemblerInstructions ':' AssemblerOperands ')'
	{
		$$ = &AssemblerStatement{
			Case:                   1,
			Token:                  $1,
			VolatileOpt:            $2.(*VolatileOpt),
			Token2:                 $3,
			AssemblerInstructions:  $4.(*AssemblerInstructions).reverse(),
			Token3:                 $5,
			AssemblerOperands:      $6.(*AssemblerOperands).reverse(),
			Token4:                 $7,
		}
	}
|	"asm" VolatileOpt '(' AssemblerInstructions ':' AssemblerOperands ':' AssemblerOperands ')'
	{
		$$ = &AssemblerStatement{
			Case:                   2,
			Token:                  $1,
			VolatileOpt:            $2.(*VolatileOpt),
			Token2:                 $3,
			AssemblerInstructions:  $4.(*AssemblerInstructions).reverse(),
			Token3:                 $5,
			AssemblerOperands:      $6.(*AssemblerOperands).reverse(),
			Token4:                 $7,
			AssemblerOperands2:     $8.(*AssemblerOperands).reverse(),
			Token5:                 $9,
		}
	}
|	"asm" VolatileOpt '(' AssemblerInstructions ':' AssemblerOperands ':' AssemblerOperands ':' Clobbers ')'
	{
		$$ = &AssemblerStatement{
			Case:                   3,
			Token:                  $1,
			VolatileOpt:            $2.(*VolatileOpt),
			Token2:                 $3,
			AssemblerInstructions:  $4.(*AssemblerInstructions).reverse(),
			Token3:                 $5,
			AssemblerOperands:      $6.(*AssemblerOperands).reverse(),
			Token4:                 $7,
			AssemblerOperands2:     $8.(*AssemblerOperands).reverse(),
			Token5:                 $9,
			Clobbers:               $10.(*Clobbers).reverse(),
			Token6:                 $11,
		}
	}
|	"asm" VolatileOpt "goto" '(' AssemblerInstructions ':' ':' AssemblerOperands ':' Clobbers ':' IdentifierList ')'
	{
		$$ = &AssemblerStatement{
			Case:                   4,
			Token:                  $1,
			VolatileOpt:            $2.(*VolatileOpt),
			Token2:                 $3,
			Token3:                 $4,
			AssemblerInstructions:  $5.(*AssemblerInstructions).reverse(),
			Token4:                 $6,
			Token5:                 $7,
			AssemblerOperands:      $8.(*AssemblerOperands).reverse(),
			Token6:                 $9,
			Clobbers:               $10.(*Clobbers).reverse(),
			Token7:                 $11,
			IdentifierList:         $12.(*IdentifierList).reverse(),
			Token8:                 $13,
		}
	}
|	"asm" VolatileOpt '(' AssemblerInstructions ':' ')'
	{
		$$ = &AssemblerStatement{
			Case:                   5,
			Token:                  $1,
			VolatileOpt:            $2.(*VolatileOpt),
			Token2:                 $3,
			AssemblerInstructions:  $4.(*AssemblerInstructions).reverse(),
			Token3:                 $5,
			Token4:                 $6,
		}
	}
|	"asm" VolatileOpt '(' AssemblerInstructions ':' ':' AssemblerOperands ')'
	{
		$$ = &AssemblerStatement{
			Case:                   6,
			Token:                  $1,
			VolatileOpt:            $2.(*VolatileOpt),
			Token2:                 $3,
			AssemblerInstructions:  $4.(*AssemblerInstructions).reverse(),
			Token3:                 $5,
			Token4:                 $6,
			AssemblerOperands:      $7.(*AssemblerOperands).reverse(),
			Token5:                 $8,
		}
	}

StaticAssertDeclaration:
	"_Static_assert" '(' ConstantExpression ',' STRINGLITERAL ')' ';'
	{
		lx := yylex.(*lexer)
		lhs := &StaticAssertDeclaration{
			Token:               $1,
			Token2:              $2,
			ConstantExpression:  $3.(*ConstantExpression),
			Token3:              $4,
			Token4:              $5,
			Token5:              $6,
			Token6:              $7,
		}
		$$ = lhs
		ce := lhs.ConstantExpression
		if ce.Type == nil || ce.Type.Kind() == Undefined || ce.Value == nil || !IsIntType(ce.Type) {
			lx.report.Err(ce.Pos(), "invalid static assert expression (have '%v')", ce.Type)
			break
		}

		if !isNonZero(ce.Value) {
			lx.report.ErrTok(lhs.Token, "%s", lhs.Token4.S())
		}
	}

PreprocessingFile:
	GroupList
	{
		lx := yylex.(*lexer)
		lhs := &PreprocessingFile{
			GroupList:  $1.(*GroupList).reverse(),
		}
		$$ = lhs
		lhs.path = lx.file.Name()
	}

GroupList:
	GroupPart
	{
		$$ = &GroupList{
			GroupPart:  $1,
		}
	}
|	GroupList GroupPart
	{
		$$ = &GroupList{
			Case:       1,
			GroupList:  $1.(*GroupList),
			GroupPart:  $2,
		}
	}

GroupListOpt:
	/* empty */
	{
		$$ = (*GroupListOpt)(nil)
		}
|	GroupList
	{
		$$ = &GroupListOpt{
			GroupList:  $1.(*GroupList).reverse(),
		}
	}

GroupPart:
	ControlLine
	{
		$$ = $1.(Node)
	}
|	IfSection
	{
		$$ = $1.(Node)
	}
|	PPNONDIRECTIVE PPTokenList '\n'
	{
		$$ = $1
	}
|	TextLine
	{
		$$ = $1
	}

IfSection:
	IfGroup ElifGroupListOpt ElseGroupOpt EndifLine
	{
		$$ = &IfSection{
			IfGroup:           $1.(*IfGroup),
			ElifGroupListOpt:  $2.(*ElifGroupListOpt),
			ElseGroupOpt:      $3.(*ElseGroupOpt),
			EndifLine:         $4.(*EndifLine),
		}
	}

IfGroup:
	PPIF PPTokenList '\n' GroupListOpt
	{
		$$ = &IfGroup{
			Token:         $1,
			PPTokenList:   $2,
			Token2:        $3,
			GroupListOpt:  $4.(*GroupListOpt),
		}
	}
|	PPIFDEF IDENTIFIER '\n' GroupListOpt
	{
		$$ = &IfGroup{
			Case:          1,
			Token:         $1,
			Token2:        $2,
			Token3:        $3,
			GroupListOpt:  $4.(*GroupListOpt),
		}
	}
|	PPIFNDEF IDENTIFIER '\n' GroupListOpt
	{
		$$ = &IfGroup{
			Case:          2,
			Token:         $1,
			Token2:        $2,
			Token3:        $3,
			GroupListOpt:  $4.(*GroupListOpt),
		}
	}

ElifGroupList:
	ElifGroup
	{
		$$ = &ElifGroupList{
			ElifGroup:  $1.(*ElifGroup),
		}
	}
|	ElifGroupList ElifGroup
	{
		$$ = &ElifGroupList{
			Case:           1,
			ElifGroupList:  $1.(*ElifGroupList),
			ElifGroup:      $2.(*ElifGroup),
		}
	}

ElifGroupListOpt:
	/* empty */
	{
		$$ = (*ElifGroupListOpt)(nil)
		}
|	ElifGroupList
	{
		$$ = &ElifGroupListOpt{
			ElifGroupList:  $1.(*ElifGroupList).reverse(),
		}
	}

ElifGroup:
	PPELIF PPTokenList '\n' GroupListOpt
	{
		$$ = &ElifGroup{
			Token:         $1,
			PPTokenList:   $2,
			Token2:        $3,
			GroupListOpt:  $4.(*GroupListOpt),
		}
	}

ElseGroup:
	PPELSE '\n' GroupListOpt
	{
		$$ = &ElseGroup{
			Token:         $1,
			Token2:        $2,
			GroupListOpt:  $3.(*GroupListOpt),
		}
	}

ElseGroupOpt:
	/* empty */
	{
		$$ = (*ElseGroupOpt)(nil)
		}
|	ElseGroup
	{
		$$ = &ElseGroupOpt{
			ElseGroup:  $1.(*ElseGroup),
		}
	}

EndifLine:
	PPENDIF
	{
		$$ = &EndifLine{
			Token:  $1,
		}
	}

ControlLine:
	PPDEFINE IDENTIFIER ReplacementList
	{
		$$ = &ControlLine{
			Token:            $1,
			Token2:           $2,
			ReplacementList:  $3,
		}
	}
|	PPDEFINE IDENTIFIER_LPAREN "..." ')' ReplacementList
	{
		$$ = &ControlLine{
			Case:             1,
			Token:            $1,
			Token2:           $2,
			Token3:           $3,
			Token4:           $4,
			ReplacementList:  $5,
		}
	}
|	PPDEFINE IDENTIFIER_LPAREN IdentifierList ',' "..." ')' ReplacementList
	{
		$$ = &ControlLine{
			Case:             2,
			Token:            $1,
			Token2:           $2,
			IdentifierList:   $3.(*IdentifierList).reverse(),
			Token3:           $4,
			Token4:           $5,
			Token5:           $6,
			ReplacementList:  $7,
		}
	}
|	PPDEFINE IDENTIFIER_LPAREN IdentifierListOpt ')' ReplacementList
	{
		$$ = &ControlLine{
			Case:               3,
			Token:              $1,
			Token2:             $2,
			IdentifierListOpt:  $3.(*IdentifierListOpt),
			Token3:             $4,
			ReplacementList:    $5,
		}
	}
|	PPERROR PPTokenListOpt
	{
		$$ = &ControlLine{
			Case:            4,
			Token:           $1,
			PPTokenListOpt:  $2,
		}
	}
|	PPHASH_NL
	{
		$$ = &ControlLine{
			Case:   5,
			Token:  $1,
		}
	}
|	PPINCLUDE PPTokenList '\n'
	{
		$$ = &ControlLine{
			Case:         6,
			Token:        $1,
			PPTokenList:  $2,
			Token2:       $3,
		}
	}
|	PPLINE PPTokenList '\n'
	{
		$$ = &ControlLine{
			Case:         7,
			Token:        $1,
			PPTokenList:  $2,
			Token2:       $3,
		}
	}
|	PPPRAGMA PPTokenListOpt
	{
		$$ = &ControlLine{
			Case:            8,
			Token:           $1,
			PPTokenListOpt:  $2,
		}
	}
|	PPUNDEF IDENTIFIER '\n'
	{
		$$ = &ControlLine{
			Case:    9,
			Token:   $1,
			Token2:  $2,
			Token3:  $3,
		}
	}
|	PPDEFINE IDENTIFIER_LPAREN IdentifierList "..." ')' ReplacementList
	{
		lx := yylex.(*lexer)
		lhs := &ControlLine{
			Case:             10,
			Token:            $1,
			Token2:           $2,
			IdentifierList:   $3.(*IdentifierList).reverse(),
			Token3:           $4,
			Token4:           $5,
			ReplacementList:  $6,
		}
		$$ = lhs
		if !lx.tweaks.enableDefineOmitCommaBeforeDDD {
			lx.report.ErrTok(lhs.Token4, "missing comma before \"...\"")
		}
	}
|	PPDEFINE '\n'
	{
		lx := yylex.(*lexer)
		lhs := &ControlLine{
			Case:    11,
			Token:   $1,
			Token2:  $2,
		}
		$$ = lhs
		if !lx.tweaks.enableEmptyDefine {
			lx.report.ErrTok(lhs.Token2, "expected identifier")
		}
	}
|	PPUNDEF IDENTIFIER PPTokenList '\n'
	{
		lx := yylex.(*lexer)
		lhs := &ControlLine{
			Case:         12,
			Token:        $1,
			Token2:       $2,
			PPTokenList:  $3,
			Token3:       $4,
		}
		$$ = lhs
		toks := decodeTokens(lhs.PPTokenList, nil, false)
		if len(toks) == 0 {
			lhs.Case = 9 // PPUNDEF IDENTIFIER '\n' 
			break
		}

		lx.report.ErrTok(toks[0], "extra tokens after #undef argument")
	}
|	PPINCLUDE_NEXT PPTokenList '\n'
	{
		$$ = &ControlLine{
			Case:         13,
			Token:        $1,
			PPTokenList:  $2,
			Token2:       $3,
		}
	}

TextLine:
	PPTokenListOpt
	{
	}

ReplacementList:
	PPTokenListOpt
	{
	}

PPTokenList:
	PPTokens
	{
		lx := yylex.(*lexer)
		$$ = PPTokenList(dict.ID(lx.encBuf))
		lx.encBuf = lx.encBuf[:0]
		lx.encPos = 0
	}

PPTokenListOpt:
	'\n'
	{
		$$ = 0
	}
|	PPTokenList '\n'
	{
	}

PPTokens:
	PPOTHER
	{
	}
|	PPTokens PPOTHER
	{
	}
