packages feed

cimple-0.0.1: src/Language/Cimple/Parser.y

{
module Language.Cimple.Parser where

import           Language.Cimple.AST    (AssignOp (..), BinaryOp (..),
                                         LiteralType (..), Node (..),
                                         Scope (..), UnaryOp (..))
import           Language.Cimple.Lexer  (Alex, AlexPosn, Lexeme (..), alexError,
                                         alexMonadScan)
import           Language.Cimple.Tokens (LexemeClass (..))
}

-- Conflict between (static) FunctionDecl and (static) ConstDecl.
%expect 2

%name parseCimple
%error {parseError}
%lexer {lexwrap} {L _ Eof _}
%monad {Alex}
%tokentype {Lexeme String}
%token
    ID_CONST			{ L _ IdConst			_ }
    ID_FUNC_TYPE		{ L _ IdFuncType		_ }
    ID_STD_TYPE			{ L _ IdStdType			_ }
    ID_SUE_TYPE			{ L _ IdSueType			_ }
    ID_TYVAR			{ L _ IdTyVar			_ }
    ID_VAR			{ L _ IdVar			_ }
    bitmask			{ L _ KwBitmask			_ }
    break			{ L _ KwBreak			_ }
    case			{ L _ KwCase			_ }
    class			{ L _ KwClass			_ }
    const			{ L _ KwConst			_ }
    continue			{ L _ KwContinue		_ }
    default			{ L _ KwDefault			_ }
    do				{ L _ KwDo			_ }
    else			{ L _ KwElse			_ }
    enum			{ L _ KwEnum			_ }
    'error'			{ L _ KwError			_ }
    event			{ L _ KwEvent			_ }
    extern			{ L _ KwExtern			_ }
    for				{ L _ KwFor			_ }
    goto			{ L _ KwGoto			_ }
    if				{ L _ KwIf			_ }
    namespace			{ L _ KwNamespace		_ }
    return			{ L _ KwReturn			_ }
    sizeof			{ L _ KwSizeof			_ }
    static			{ L _ KwStatic			_ }
    struct			{ L _ KwStruct			_ }
    switch			{ L _ KwSwitch			_ }
    this			{ L _ KwThis			_ }
    typedef			{ L _ KwTypedef			_ }
    union			{ L _ KwUnion			_ }
    VLA				{ L _ KwVla			_ }
    void			{ L _ KwVoid			_ }
    while			{ L _ KwWhile			_ }
    with			{ L _ KwWith			_ }
    LIT_CHAR			{ L _ LitChar			_ }
    LIT_FALSE			{ L _ LitFalse			_ }
    LIT_TRUE			{ L _ LitTrue			_ }
    LIT_INTEGER			{ L _ LitInteger		_ }
    LIT_STRING			{ L _ LitString			_ }
    LIT_SYS_INCLUDE		{ L _ LitSysInclude		_ }
    '&'				{ L _ PctAmpersand		_ }
    '&&'			{ L _ PctAmpersandAmpersand	_ }
    '&='			{ L _ PctAmpersandEq		_ }
    '->'			{ L _ PctArrow			_ }
    '*'				{ L _ PctAsterisk		_ }
    '*='			{ L _ PctAsteriskEq		_ }
    '^'				{ L _ PctCaret			_ }
    '^='			{ L _ PctCaretEq		_ }
    ':'				{ L _ PctColon			_ }
    ','				{ L _ PctComma			_ }
    '!'				{ L _ PctEMark			_ }
    '!='			{ L _ PctEMarkEq		_ }
    '='				{ L _ PctEq			_ }
    '=='			{ L _ PctEqEq			_ }
    '>'				{ L _ PctGreater		_ }
    '>='			{ L _ PctGreaterEq		_ }
    '>>'			{ L _ PctGreaterGreater		_ }
    '>>='			{ L _ PctGreaterGreaterEq	_ }
    '{'				{ L _ PctLBrace			_ }
    '['				{ L _ PctLBrack			_ }
    '<'				{ L _ PctLess			_ }
    '<='			{ L _ PctLessEq			_ }
    '<<'			{ L _ PctLessLess		_ }
    '<<='			{ L _ PctLessLessEq		_ }
    '('				{ L _ PctLParen			_ }
    '-'				{ L _ PctMinus			_ }
    '-='			{ L _ PctMinusEq		_ }
    '--'			{ L _ PctMinusMinus		_ }
    '%'				{ L _ PctPercent		_ }
    '%='			{ L _ PctPercentEq		_ }
    '.'				{ L _ PctPeriod			_ }
    '...'			{ L _ PctEllipsis		_ }
    '|'				{ L _ PctPipe			_ }
    '|='			{ L _ PctPipeEq			_ }
    '||'			{ L _ PctPipePipe		_ }
    '+'				{ L _ PctPlus			_ }
    '+='			{ L _ PctPlusEq			_ }
    '++'			{ L _ PctPlusPlus		_ }
    '?'				{ L _ PctQMark			_ }
    '}'				{ L _ PctRBrace			_ }
    ']'				{ L _ PctRBrack			_ }
    ')'				{ L _ PctRParen			_ }
    ';'				{ L _ PctSemicolon		_ }
    '/'				{ L _ PctSlash			_ }
    '/='			{ L _ PctSlashEq		_ }
    '~'				{ L _ PctTilde			_ }
    'defined'			{ L _ PpDefined			_ }
    '#define'			{ L _ PpDefine			_ }
    '#elif'			{ L _ PpElif			_ }
    '#else'			{ L _ PpElse			_ }
    '#endif'			{ L _ PpEndif			_ }
    '#error'			{ L _ PpError			_ }
    '#if'			{ L _ PpIf			_ }
    '#ifdef'			{ L _ PpIfdef			_ }
    '#ifndef'			{ L _ PpIfndef			_ }
    '#include'			{ L _ PpInclude			_ }
    '#undef'			{ L _ PpUndef			_ }
    '\n'			{ L _ PpNewline			_ }
    '/**/'			{ L _ CmtBlock			_ }
    '/*'			{ L _ CmtStart			_ }
    '*/'			{ L _ CmtEnd			_ }
    'Copyright'			{ L _ CmtSpdxCopyright		_ }
    'License'			{ L _ CmtSpdxLicense		_ }
    COMMENT_CODE		{ L _ CmtCode			_ }
    COMMENT_WORD		{ L _ CmtWord			_ }
    COMMENT_REF			{ L _ CmtRef			_ }

%left ','
%right '=' '+=' '-=' '*=' '/=' '%=' '<<=' '>>=' '&=' '^=' '|='
%right '?' ':'
%left '||'
%left '&&'
%left '|'
%left '^'
%left '&'
%left '!=' '=='
%left '<' '<=' '>' '>='
%left '<<' '>>'
%left '+' '-'
%left '*' '/' '%'
%right CAST ADDRESS NEG DEREF sizeof '!' '~' '++' '--'
%left '->' '.' '(' '['

%%

TranslationUnit :: { [StringNode] }
TranslationUnit
:	ToplevelDecls							{ reverse $1 }

ToplevelDecls :: { [StringNode] }
ToplevelDecls
:	ToplevelDecl							{ [$1] }
|	ToplevelDecls ToplevelDecl					{ $2 : $1 }

ToplevelDecl :: { StringNode }
ToplevelDecl
:	PreprocIfdef(ToplevelDecls)					{ $1 }
|	PreprocIf(ToplevelDecls)					{ $1 }
|	PreprocInclude							{ $1 }
|	PreprocDefine							{ $1 }
|	PreprocUndef							{ $1 }
|	PreprocError							{ $1 }
|	ExternC								{ $1 }
|	TypedefDecl							{ $1 }
|	AggregateDecl							{ $1 }
|	EnumDecl							{ $1 }
|	FunctionDecl							{ $1 }
|	ConstDecl							{ $1 }
|	Comment								{ $1 }
|	Namespace							{ $1 }
|	Event								{ $1 }
|	ErrorDecl							{ $1 }

Namespace :: { StringNode }
Namespace
:	NamespaceDeclarator						{ $1 Global }
|	static NamespaceDeclarator					{ $2 Static }

NamespaceDeclarator :: { Scope -> StringNode }
NamespaceDeclarator
:	class ID_SUE_TYPE TypeParams '{' ToplevelDecls '}'		{ \s -> Class s $2 $3 $5 }
|	namespace IdVar '{' ToplevelDecls '}'				{ \s -> Namespace s $2 $4 }

TypeParams :: { [StringNode] }
TypeParams
:									{ [] }
|	'<' ID_TYVAR '>'						{ [TyVar $2] }

Event :: { StringNode }
Event
:	event IdVar       '{' EventType '}'				{ Event $2 $4 }
|	event IdVar const '{' EventType '}'				{ Event $2 $5 }

EventType :: { StringNode }
EventType
:	Comment typedef void EventParams ';'				{ Commented $1 $4 }

EventParams :: { StringNode }
EventParams
:	FunctionParamList						{ EventParams $1 }

ErrorDecl :: { StringNode }
ErrorDecl
:	'error' for IdVar EnumeratorList				{ ErrorDecl $3 $4 }

Comment :: { StringNode }
Comment
:	'/*' CommentBody '*/'						{ Comment (reverse $2) }
|	'/**/'								{ CommentBlock $1 }

CommentBody :: { [StringNode] }
CommentBody
:	CommentWord							{ [$1] }
|	CommentBody CommentWord						{ $2 : $1 }

CommentWord :: { StringNode }
CommentWord
:	COMMENT_WORD							{ CommentWord $1 }
|	COMMENT_REF							{ CommentWord $1 }
|	COMMENT_CODE							{ CommentWord $1 }
|	LIT_INTEGER							{ CommentWord $1 }
|	LIT_STRING							{ CommentWord $1 }
|	'Copyright'							{ CommentWord $1 }
|	'License'							{ CommentWord $1 }
|	'.'								{ CommentWord $1 }
|	'?'								{ CommentWord $1 }
|	'!'								{ CommentWord $1 }
|	','								{ CommentWord $1 }
|	';'								{ CommentWord $1 }
|	':'								{ CommentWord $1 }
|	'('								{ CommentWord $1 }
|	')'								{ CommentWord $1 }
|	'<'								{ CommentWord $1 }
|	'>'								{ CommentWord $1 }
|	'/'								{ CommentWord $1 }
|	'+'								{ CommentWord $1 }
|	'-'								{ CommentWord $1 }
|	'='								{ CommentWord $1 }
|	'\n'								{ CommentWord $1 }

PreprocIfdef(decls)
:	'#ifdef' ID_CONST decls PreprocElse(decls) '#endif'		{ PreprocIfdef $2 $3 $4 }
|	'#ifndef' ID_CONST decls PreprocElse(decls) '#endif'		{ PreprocIfndef $2 $3 $4 }

PreprocIf(decls)
:	'#if' ConstExpr '\n' decls PreprocElse(decls) '#endif'		{ PreprocIf $2 $4 $5 }

PreprocElse(decls)
:									{ PreprocElse [] }
|	'#else' decls							{ PreprocElse $2 }
|	'#elif' ConstExpr '\n' decls PreprocElse(decls)			{ PreprocElif $2 $4 $5 }

PreprocError :: { StringNode }
PreprocError
:	'#error' LIT_STRING						{ PreprocError $2 }

PreprocInclude :: { StringNode }
PreprocInclude
:	'#include' LIT_STRING						{ PreprocInclude $2 }
|	'#include' LIT_SYS_INCLUDE					{ PreprocInclude $2 }

PreprocDefine :: { StringNode }
PreprocDefine
:	'#define' ID_CONST '\n'						{ PreprocDefine $2 }
|	'#define' ID_CONST ConstExpr '\n'				{ PreprocDefineConst $2 $3 }
|	'#define' ID_CONST MacroParamList MacroBody '\n'		{ PreprocDefineMacro $2 $3 $4 }

PreprocUndef :: { StringNode }
PreprocUndef
:	'#undef' ID_CONST						{ PreprocUndef $2 }

ConstExpr :: { StringNode }
ConstExpr
:	LiteralExpr							{ $1 }
|	'defined' '(' ID_CONST ')'					{ PreprocDefined $3 }
|	PureExpr(ConstExpr)						{ $1 }

MacroParamList :: { [StringNode] }
MacroParamList
:	'(' ')'								{ [] }
|	'(' MacroParams ')'						{ reverse $2 }
|	'(' MacroParams ',' '...' ')'					{ reverse $ Ellipsis : $2 }

MacroParams :: { [StringNode] }
MacroParams
:	MacroParam							{ [$1] }
|	MacroParams ',' MacroParam					{ $3 : $1 }

MacroParam :: { StringNode }
MacroParam
:	IdVar								{ MacroParam $1 }

MacroBody :: { StringNode }
MacroBody
:	do CompoundStmt while '(' LIT_INTEGER ')'			{% macroBodyStmt $2 $5 }
|	FunctionCall							{ MacroBodyFunCall $1 }

ExternC :: { StringNode }
ExternC
:	'#ifdef' ID_CONST
	extern LIT_STRING '{'
	'#endif'
	ToplevelDecls
	'#ifdef' ID_CONST
	'}'
	'#endif'							{% externC $2 $4 $7 $9 }

Stmts :: { [StringNode] }
Stmts
:	Stmt								{ [$1] }
|	Stmts Stmt							{ $2 : $1 }

Stmt :: { StringNode }
Stmt
:	PreprocIfdef(Stmts)						{ $1 }
|	PreprocIf(Stmts)						{ $1 }
|	PreprocDefine Stmts PreprocUndef				{ PreprocScopedDefine $1 $2 $3 }
|	LabelStmt							{ $1 }
|	DeclStmt							{ $1 }
|	CompoundStmt							{ CompoundStmt $1 }
|	IfStmt								{ $1 }
|	ForStmt								{ $1 }
|	WhileStmt							{ $1 }
|	DoWhileStmt							{ $1 }
|	AssignExpr ';'							{ $1 }
|	ExprStmt ';'							{ $1 }
|	FunctionCall ';'						{ $1 }
|	break ';'							{ Break }
|	goto ID_CONST ';'						{ Goto $2 }
|	continue ';'							{ Continue }
|	return ';'							{ Return Nothing }
|	return Expr ';'							{ Return (Just $2) }
|	switch '(' Expr ')' CompoundStmt				{ Switch $3 $5 }
|	Comment								{ $1 }

IfStmt :: { StringNode }
IfStmt
:	if '(' Expr ')' CompoundStmt					{ IfStmt $3 $5 Nothing }
|	if '(' Expr ')' CompoundStmt else IfStmt			{ IfStmt $3 $5 (Just $7) }
|	if '(' Expr ')' CompoundStmt else CompoundStmt			{ IfStmt $3 $5 (Just (CompoundStmt $7)) }

ForStmt :: { StringNode }
ForStmt
:	for '(' ForInit Opt(Expr) ';' Opt(ForNext) ')' CompoundStmt	{ ForStmt $3 $4 $6 $8 }

ForInit :: { Maybe (StringNode) }
ForInit
:	';'								{ Nothing }
|	AssignExpr ';'							{ Just $1 }
|	SingleVarDecl							{ Just $1 }

ForNext :: { StringNode }
ForNext
:	ExprStmt							{ $1 }
|	AssignExpr							{ $1 }

Opt(x)
:									{ Nothing }
|	x								{ Just $1 }

WhileStmt :: { StringNode }
WhileStmt
:	while '(' Expr ')' CompoundStmt					{ WhileStmt $3 $5 }

DoWhileStmt :: { StringNode }
DoWhileStmt
:	do CompoundStmt while '(' Expr ')' ';'				{ DoWhileStmt $2 $5 }

LabelStmt :: { StringNode }
LabelStmt
:	case Expr ':' Stmt						{ Case $2 $4 }
|	default ':' Stmt						{ Default $3 }
|	ID_CONST ':' Stmt						{ Label $1 $3 }

DeclStmt :: { StringNode }
DeclStmt
:	VarDecl								{ $1 }
|	VLA '(' Type ',' IdVar ',' Expr ')' ';'				{ VLA $3 $5 $7 }

SingleVarDecl :: { StringNode }
SingleVarDecl
:	QualType Declarator ';'						{ VarDecl $1 [$2] }

VarDecl :: { StringNode }
VarDecl
:	QualType Declarators ';'					{ VarDecl $1 (reverse $2) }

Declarators :: { [StringNode] }
Declarators
:	Declarator							{ [$1] }
|	Declarators ',' Declarator					{ $3 : $1 }

Declarator :: { StringNode }
Declarator
:	DeclSpec '=' InitialiserExpr					{ Declarator $1 (Just $3) }
|	DeclSpec							{ Declarator $1 Nothing }

InitialiserExpr :: { StringNode }
InitialiserExpr
:	InitialiserList							{ InitialiserList $1 }
|	Expr								{ $1 }

DeclSpec :: { StringNode }
DeclSpec
:	IdVar								{ DeclSpecVar $1 }
|	DeclSpec '[' ']'						{ DeclSpecArray $1 Nothing }
|	DeclSpec '[' Expr ']'						{ DeclSpecArray $1 (Just $3) }

IdVar :: { Lexeme String }
IdVar
:	ID_VAR								{ $1 }
|	default								{ $1 }
|	'error'								{ $1 }

InitialiserList :: { [StringNode] }
InitialiserList
:	'{' Initialisers '}'						{ reverse $2 }
|	'{' Initialisers ',' '}'					{ reverse $2 }

Initialisers :: { [StringNode] }
Initialisers
:	Initialiser							{ [$1] }
|	Initialisers ',' Initialiser					{ $3 : $1 }

Initialiser :: { StringNode }
Initialiser
:	Expr								{ $1 }
|	InitialiserList							{ InitialiserList $1 }

CompoundStmt :: { [StringNode] }
CompoundStmt
:	'{' Stmts '}'							{ $2 }

PureExpr(x)
:	x '!=' x							{ BinaryExpr $1 BopNe $3 }
|	x '==' x							{ BinaryExpr $1 BopEq $3 }
|	x '||' x							{ BinaryExpr $1 BopOr $3 }
|	x '^' x								{ BinaryExpr $1 BopBitXor $3 }
|	x '|' x								{ BinaryExpr $1 BopBitOr $3 }
|	x '&&' x							{ BinaryExpr $1 BopAnd $3 }
|	x '&' x								{ BinaryExpr $1 BopBitAnd $3 }
|	x '/' x								{ BinaryExpr $1 BopDiv $3 }
|	x '*' x								{ BinaryExpr $1 BopMul $3 }
|	x '%' x								{ BinaryExpr $1 BopMod $3 }
|	x '+' x								{ BinaryExpr $1 BopPlus $3 }
|	x '-' x								{ BinaryExpr $1 BopMinus $3 }
|	x '<' x								{ BinaryExpr $1 BopLt $3 }
|	x '<=' x							{ BinaryExpr $1 BopLe $3 }
|	x '<<' x							{ BinaryExpr $1 BopLsh $3 }
|	x '>' x								{ BinaryExpr $1 BopGt $3 }
|	x '>=' x							{ BinaryExpr $1 BopGe $3 }
|	x '>>' x							{ BinaryExpr $1 BopRsh $3 }
|	x '?' x ':' x							{ TernaryExpr $1 $3 $5 }
|	'(' x ')'							{ ParenExpr $2 }
|	'!' x								{ UnaryExpr UopNot $2 }
|	'~' x								{ UnaryExpr UopNeg $2 }
|	'-' x %prec NEG							{ UnaryExpr UopMinus $2 }
|	'&' x %prec ADDRESS						{ UnaryExpr UopAddress $2 }
|	'(' QualType ')' x %prec CAST					{ CastExpr $2 $4 }
|	sizeof '(' x ')'						{ SizeofExpr $3 }
|	sizeof '(' Type ')'						{ SizeofExpr $3 }

LiteralExpr :: { StringNode }
LiteralExpr
:	LIT_CHAR							{ LiteralExpr Char $1 }
|	LIT_INTEGER							{ LiteralExpr Int $1 }
|	LIT_FALSE							{ LiteralExpr Bool $1 }
|	LIT_TRUE							{ LiteralExpr Bool $1 }
|	LIT_STRING							{ LiteralExpr String $1 }
|	ID_CONST							{ LiteralExpr ConstId $1 }

Expr :: { StringNode }
Expr
:	LhsExpr								{ $1 }
|	ExprStmt							{ $1 }
|	LiteralExpr							{ $1 }
|	FunctionCall							{ $1 }
|	PureExpr(Expr)							{ $1 }

AssignExpr :: { StringNode }
AssignExpr
:	LhsExpr AssignOperator Expr					{ AssignExpr $1 $2 $3 }

AssignOperator :: { AssignOp }
AssignOperator
:	'='								{ AopEq      }
|	'*='								{ AopMul     }
|	'/='								{ AopDiv     }
|	'+='								{ AopPlus    }
|	'-='								{ AopMinus   }
|	'&='								{ AopBitAnd  }
|	'|='								{ AopBitOr   }
|	'^='								{ AopBitXor  }
|	'%='								{ AopMod     }
|	'<<='								{ AopLsh     }
|	'>>='								{ AopRsh     }

ExprStmt :: { StringNode }
ExprStmt
:	'++' Expr							{ UnaryExpr UopIncr $2 }
|	'--' Expr							{ UnaryExpr UopDecr $2 }

LhsExpr :: { StringNode }
LhsExpr
:	IdVar								{ VarExpr $1 }
|	'*' LhsExpr %prec DEREF						{ UnaryExpr UopDeref $2 }
|	LhsExpr '.' IdVar						{ MemberAccess $1 $3 }
|	LhsExpr '->' IdVar						{ PointerAccess $1 $3 }
|	LhsExpr '[' Expr ']'						{ ArrayAccess $1 $3 }

FunctionCall :: { StringNode }
FunctionCall
:	Expr ArgList							{ FunctionCall $1 $2 }

ArgList :: { [StringNode] }
ArgList
:	'(' ')'								{ [] }
|	'(' Args ')'							{ reverse $2 }

Args :: { [StringNode] }
Args
:	Arg								{ [$1] }
|	Args ',' Arg							{ $3 : $1 }

Arg :: { StringNode }
Arg
:	Expr								{ $1 }
|	Comment Expr							{ CommentExpr $1 $2 }

EnumDecl :: { StringNode }
EnumDecl
:	enum class ID_SUE_TYPE EnumeratorList				{ EnumClass $3 $4 }
|	enum       ID_SUE_TYPE EnumeratorList				{ EnumConsts (Just $2) $3 }
|	enum                   EnumeratorList ';'			{ EnumConsts Nothing $2 }
|	typedef enum ID_SUE_TYPE EnumeratorList ID_SUE_TYPE ';'		{ EnumDecl $3 $4 $5 }
|	bitmask ID_SUE_TYPE EnumeratorList				{ EnumDecl $2 $3 $2 }

EnumeratorList :: { [StringNode] }
EnumeratorList
:	'{' Enumerators '}'						{ $2 }

Enumerators :: { [StringNode] }
Enumerators
:	Enumerator							{ [$1] }
|	Enumerators Enumerator						{ $2 : $1 }

Enumerator :: { StringNode }
Enumerator
:	EnumeratorName ','						{ Enumerator $1 Nothing }
|	EnumeratorName '=' ConstExpr ','				{ Enumerator $1 (Just $3) }
|	namespace ID_CONST '{' Enumerators '}'				{ Namespace Global $2 $4 }
|	Comment								{ $1 }

EnumeratorName :: { Lexeme String }
EnumeratorName
:	ID_CONST							{ $1 }
|	ID_SUE_TYPE							{ $1 }

AggregateDecl :: { StringNode }
AggregateDecl
:	AggregateType ';'						{ $1 }
|	class ID_SUE_TYPE TypeParams ';'				{ ClassForward $2 $3 }
|	typedef AggregateType ID_SUE_TYPE ';'				{ Typedef $2 $3 }

AggregateType :: { StringNode }
AggregateType
:	struct ID_SUE_TYPE '{' MemberDecls '}'				{ Struct $2 $4 }
|	struct this '{' MemberDecls '}'					{ Struct $2 $4 }
|	union ID_SUE_TYPE '{' MemberDecls '}'				{ Union $2 $4 }

MemberDecls :: { [StringNode] }
MemberDecls
:	MemberDecl							{ [$1] }
|	MemberDecls MemberDecl						{ $2 : $1 }

MemberDecl :: { StringNode }
MemberDecl
:	QualType DeclSpec ';'						{ MemberDecl $1 $2 Nothing }
|	QualType DeclSpec ':' LIT_INTEGER ';'				{ MemberDecl $1 $2 (Just $4) }
|	namespace IdVar '{' MemberDecls '}'				{ Namespace Global $2 $4 }
|	PreprocIfdef(MemberDecls)					{ $1 }
|	Comment								{ $1 }

TypedefDecl :: { StringNode }
TypedefDecl
:	typedef QualType ID_SUE_TYPE ';'				{ Typedef $2 $3 }
|	typedef FunctionPrototype(ID_FUNC_TYPE) ';'			{ TypedefFunction $2 }

QualType :: { StringNode }
QualType
:	Type								{ $1 }
|	const Type							{ TyConst $2 }

Type :: { StringNode }
Type
:	LeafType							{ $1 }
|	Type '*'							{ TyPointer $1 }
|	Type const							{ TyConst $1 }

LeafType :: { StringNode }
LeafType
:	struct ID_SUE_TYPE						{ TyStruct $2 }
|	void								{ TyStd $1 }
|	this								{ TyStd $1 }
|	ID_FUNC_TYPE							{ TyFunc $1 }
|	ID_STD_TYPE							{ TyStd $1 }
|	ID_SUE_TYPE							{ TyUserDefined $1 }
|	ID_TYVAR							{ TyVar $1 }

FunctionDecl :: { StringNode }
FunctionDecl
:	FunctionDeclarator						{ $1 Global }
|	static FunctionDeclarator					{ $2 Static }

FunctionDeclarator :: { Scope -> StringNode }
FunctionDeclarator
:	FunctionPrototype(IdVar) WithError				{ \s -> FunctionDecl s $1 $2 }
|	FunctionPrototype(IdVar) CompoundStmt				{ \s -> FunctionDefn s $1 $2 }
|	QualType DeclSpec '{' Accessors '}'				{ \s -> Property $1 $2 $4 }

Accessors :: { [StringNode] }
Accessors
:	Accessor							{ [$1] }
|	Accessors Accessor						{ $2 : $1 }

Accessor :: { StringNode }
Accessor
:	IdVar FunctionParamList WithError				{ Accessor $1 $2 $3 }
|	Comment								{ $1 }

WithError :: { Maybe StringNode }
WithError
:	';'								{ Nothing }
|	with 'error' EnumeratorList					{ Just (ErrorList $3) }
|	with 'error' for IdVar ';'					{ Just (ErrorFor $4) }

FunctionPrototype(id)
:	QualType id FunctionParamList					{ FunctionPrototype $1 $2 $3 }
|	QualType id FunctionParamList const				{ FunctionPrototype $1 $2 $3 }

FunctionParamList :: { [StringNode] }
FunctionParamList
:	'(' ')'								{ [] }
|	'(' void ')'							{ [TyStd $2] }
|	'(' FunctionParams ')'						{ reverse $2 }
|	'(' FunctionParams ',' '...' ')'				{ reverse $ Ellipsis : $2 }

FunctionParams :: { [StringNode] }
FunctionParams
:	FunctionParam							{ [$1] }
|	FunctionParams ',' FunctionParam				{ $3 : $1 }

FunctionParam :: { StringNode }
FunctionParam
:	QualType DeclSpec						{ FunctionParam $1 $2 }

ConstDecl :: { StringNode }
ConstDecl
:	extern const LeafType ID_VAR ';'				{ ConstDecl $3 $4 }
|	const LeafType ID_VAR '=' InitialiserExpr ';'			{ ConstDefn Global $2 $3 $5 }
|	static const LeafType ID_VAR '=' InitialiserExpr ';'		{ ConstDefn Static $3 $4 $6 }

{
type StringNode = Node (Lexeme String)

parseError :: Show text => Lexeme text -> Alex a
parseError token = alexError $ "Parse error near token: " <> show token

lexwrap :: (Lexeme String -> Alex a) -> Alex a
lexwrap = (alexMonadScan >>=)

externC
    :: Lexeme String
    -> Lexeme String
    -> [StringNode]
    -> Lexeme String
    -> Alex StringNode
externC (L _ _ "__cplusplus") (L _ _ "\"C\"") decls (L _ _ "__cplusplus") =
    return $ ExternC decls
externC _ lang _ _ =
    alexError $ show lang
        <> ": extern \"C\" declaration invalid (did you spell __cplusplus right?)"

macroBodyStmt
    :: [StringNode]
    -> Lexeme String
    -> Alex StringNode
macroBodyStmt decls (L _ _ "0") =
    return $ MacroBodyStmt decls
macroBodyStmt _ cond =
    alexError $ show cond
        <> ": macro do-while body must end in 'while (0)'"
}