qzdoom/src/zscript/zcc-parse.lemon

1020 lines
24 KiB
Text
Raw Normal View History

%include
{
#define NEW_AST_NODE(type,name) \
ZCC_##type *name = (ZCC_##type *)stat->SyntaxArena.Alloc(sizeof(ZCC_##type)); \
name->SiblingNext = name; \
name->SiblingPrev = name; \
name->NodeType = AST_##type
}
%token_prefix ZCC_
%token_type { ZCCToken }
%token_destructor {} // just to avoid a compiler warning
%name ZCCParse
%extra_argument { ZCCParseState *stat }
%syntax_error
{
FString unexpected, expecting;
int i;
int stateno = yypParser->yystack[yypParser->yyidx].stateno;
unexpected << "Unexpected " << ZCCTokenName(yymajor);
// Determine all the terminals that the parser would have accepted at this point
// (see yy_find_shift_action). This list can get quite long. Is it worthwhile to
// print it when not debugging the grammar, or would that be too confusing to
// the average user?
if (stateno < YY_SHIFT_MAX && (i = yy_shift_ofst[stateno])!=YY_SHIFT_USE_DFLT)
{
for (int j = 1; j < YYERRORSYMBOL; ++j)
{
int k = i + j;
if (k >= 0 && k < YY_SZ_ACTTAB && yy_lookahead[k] == j)
{
expecting << (expecting.IsEmpty() ? "Expecting " : " or ") << ZCCTokenName(j);
}
}
}
stat->sc.ScriptMessage("%s\n%s\n", unexpected.GetChars(), expecting.GetChars());
}
%parse_accept { stat->sc.ScriptMessage("input accepted\n"); }
%parse_failure { /**failed = true;*/ }
%nonassoc EQ MULEQ DIVEQ MODEQ ADDEQ SUBEQ LSHEQ RSHEQ ANDEQ OREQ XOREQ.
%right QUESTION COLON.
%left OROR.
%left ANDAND.
%left EQEQ NEQ APPROXEQ.
%left LT GT LTEQ GTEQ LTGTEQ IS.
%left DOTDOT.
%left OR. /* Note that this is like the Ruby precedence for these */
%left XOR. /* three operators and not the C precedence, since */
%left AND. /* they are higher priority than the comparisons. */
%left LSH RSH.
%left SUB ADD.
%left MUL DIV MOD CROSSPROD DOTPROD.
%left POW.
%right UNARY ADDADD SUBSUB.
%left DOT LPAREN LBRACKET.
%left SCOPE.
main ::= translation_unit. { stat->sc.ScriptMessage("Parse complete\n"); }
translation_unit ::= .
translation_unit ::= translation_unit external_declaration.
translation_unit ::= translation_unit EOF.
translation_unit ::= error.
external_declaration ::= class_definition.
/* Optional bits. */
opt_semicolon ::= .
opt_semicolon ::= SEMICOLON.
opt_comma ::= .
opt_comma ::= COMMA.
%type opt_expr{ZCC_Expression *}
opt_expr(X) ::= .
{
X = NULL;
}
opt_expr(X) ::= expr(A).
{
X = A;
}
/* A class definition. Can only occur at global scope. */
class_definition ::= class_start class_body.
{
/* stat->CurrClass = NULL;*/
}
class_start ::= CLASS IDENTIFIER class_ancestry class_flags.
%type class_ancestry {ENamedName}
class_ancestry(X) ::= . { X = NAME_Object; }
class_ancestry(X) ::= COLON IDENTIFIER(A). { X = ENamedName(A.Int); }
class_flags ::= .
class_flags ::= class_flags ABSTRACT.
class_flags ::= class_flags NATIVE.
class_flags ::= class_flags REPLACES IDENTIFIER.
class_body ::= SEMICOLON class_innards EOF.
class_body ::= LBRACE class_innards RBRACE.
class_innards ::= .
class_innards ::= class_innards class_member.
/* Classes can define variables, functions, enums, structs, states, constants, and defaults. */
class_member ::= declarator.
class_member ::= enum_def.
class_member ::= struct_def.
class_member ::= states_def.
class_member ::= default_def.
class_member ::= const_def.
/* Structs can define variables, enums, and structs. */
struct_def ::= STRUCT IDENTIFIER LBRACE struct_body RBRACE opt_semicolon.
struct_member ::= declarator_no_fun.
struct_member ::= enum_def.
/* Enumerators are lists of named integers. */
enum_def ::= ENUM IDENTIFIER enum_type LBRACE enum_list opt_comma RBRACE opt_semicolon.
enum_type ::= .
enum_type ::= COLON int_type.
enum_list ::= enumerator.
enum_list ::= enum_list COMMA enumerator.
enumerator ::= IDENTIFIER.
enumerator ::= IDENTIFIER EQ expr. /* Expression must be constant. */
/* States */
states_def ::= STATES scanner_mode LBRACE states_body RBRACE.
/* We use a special scanner mode to allow for sprite names and frame characters
* to not be quoted even if they contain special characters. The scanner_mode
* nonterminal is used to enter this mode. The scanner automatically leaves it
* upon pre-defined conditions. See the comments by FScanner::SetStateMode().
*
* Note that rules are reduced *after* one token of lookahead has been
* consumed, so this nonterminal must be placed one token before we want it to
* take effect. For example, in states_def above, the scanner mode will be
* set immediately after LBRACE is consumed, rather than immediately after
* STATES is consumed.
*/
scanner_mode ::= . { stat->sc.SetStateMode(true); }
states_body ::= .
states_body ::= error.
/*states_body ::= states_body LABELID.*/
states_body ::= states_body state_line.
states_body ::= states_body state_label.
states_body ::= states_body state_flow.
state_label ::= NWS(A) COLON.
{ Printf("Label %s\n", FName(ENamedName(A.Int)).GetChars()); }
state_flow ::= state_flow_type scanner_mode SEMICOLON.
state_flow_type ::= STOP.
state_flow_type ::= WAIT.
state_flow_type ::= FAIL.
state_flow_type ::= LOOP.
state_flow_type ::= GOTO dotted_identifier state_goto_offset.
state_goto_offset ::= .
state_goto_offset ::= PLUS expr. /* Must evaluate to an integer constant. */
state_line ::= NWS(A) NWS(B) expr state_opts state_action.
{ Printf("Sprite %s Frames %s\n", FName(ENamedName(A.Int)).GetChars(), FName(ENamedName(B.Int)).GetChars()); }
state_opts ::= .
state_opts ::= state_opts BRIGHT.
state_opts ::= state_opts OFFSET LPAREN expr COMMA expr RPAREN.
state_opts ::= state_opts LIGHT LPAREN light_list RPAREN.
light_list ::= STRCONST.
light_list ::= light_list COMMA STRCONST.
/* A state action can be either a compound statement or a single action function call. */
state_action ::= LBRACE statement_list scanner_mode RBRACE.
state_action ::= LBRACE error scanner_mode RBRACE.
state_action ::= state_call scanner_mode SEMICOLON.
state_call ::= .
state_call ::= IDENTIFIER state_call_parms.
state_call_parms ::= .
state_call_parms ::= LPAREN opt_expr_list RPAREN.
state_call_parms ::= LPAREN error RPAREN.
dotted_identifier ::= IDENTIFIER.
dotted_identifier ::= dotted_identifier DOT IDENTIFIER.
/* Definition of a default class instance. */
default_def ::= DEFAULT compound_statement.
/* Type names */
%type int_type {PType *}
%type type_name {PType *}
int_type(X) ::= SBYTE. { X = TypeSInt8; }
int_type(X) ::= BYTE. { X = TypeUInt8; }
int_type(X) ::= SHORT. { X = TypeSInt16; }
int_type(X) ::= USHORT. { X = TypeUInt16; }
int_type(X) ::= INT. { X = TypeSInt32; }
int_type(X) ::= UINT. { X = TypeUInt32; }
type_name(X) ::= BOOL. { /*FIXME*/ X = TypeBool; }
type_name(X) ::= int_type(A). { X = A; }
type_name(X) ::= FLOAT. { X = TypeFloat32; }
type_name(X) ::= DOUBLE. { X = TypeFloat64; }
type_name(X) ::= STRING. { X = TypeString; }
type_name(X) ::= VECTOR vector_size(A). { X = NewVector(A); }
type_name(X) ::= NAME. { X = TypeName; }
type_name(X) ::= IDENTIFIER. /* User-defined type (struct, enum, or class) */
{
// FIXME
X = NULL;
}
%type vector_size {unsigned int}
vector_size ::= .
vector_size(X) ::= LT INTCONST(A) GT. { X = A.Int; }
/* Type names can also be used as identifiers in contexts where type names
* are not normally allowed. */
%fallback IDENTIFIER
SBYTE BYTE SHORT USHORT INT UINT BOOL FLOAT DOUBLE STRING VECTOR NAME.
/* Aggregate types */
%type aggregate_type {PType *}
%type type {PType *}
%type type_or_array {PType *}
%type class_restrictor {PClass *}
aggregate_type ::= MAP LT type_or_array COMMA type_or_array GT. /* Hash table */
aggregate_type ::= ARRAY LT type_or_array GT. /* TArray<type> */
aggregate_type ::= CLASS class_restrictor. /* class<type> */
class_restrictor ::= .
class_restrictor ::= LT IDENTIFIER GT.
type(X) ::= type_name(A). { X = A; }
type(X) ::= aggregate_type(A). { X = A; }
type_or_array ::= type.
type_or_array ::= type array_size.
type_list ::= type_or_array. /* A comma-separated list of types */
type_list ::= type_list COMMA type_or_array.
type_list_or_void ::= VOID.
type_list_or_void ::= type_list.
%type array_size{ZCC_Expression *}
array_size(X) ::= LBRACKET opt_expr(A) RBRACKET.
{
if (A == NULL)
{
NEW_AST_NODE(Expression,nil);
X = nil;
}
else
{
X = A;
}
}
array_size(X) ::= array_size(A) LBRACKET opt_expr(B) RBRACKET.
{
if (B == NULL)
{
NEW_AST_NODE(Expression,nil);
A->AppendSibling(nil);
}
else
{
A->AppendSibling(B);
}
X = A;
}
declarator ::= decl_flags type_list_or_void variables_or_function. /* Multiple type names are only valid for functions. */
declarator_no_fun ::= decl_flags type variable_list.
variables_or_function ::= IDENTIFIER LPAREN func_params RPAREN func_const opt_func_body. /* Function */
variables_or_function ::= variable_list SEMICOLON.
variables_or_function ::= error SEMICOLON.
/*----- Variable Names -----*/
// They get the array size, because that makes it look more like C.
// I might still change my mind and stick array sizes with the rest
// of the type like C#.
%type variable_name{ZCC_VarName *}
%type variable_list{ZCC_VarName *}
variable_name(X) ::= IDENTIFIER(A).
{
NEW_AST_NODE(VarName,var);
var->Name = ENamedName(A.Int);
var->bIsArray = false;
var->ArraySize = 0;
X = var;
}
variable_name(X) ::= IDENTIFIER(A) array_size(B).
{
NEW_AST_NODE(VarName,var);
var->Name = ENamedName(A.Int);
var->bIsArray = false;
var->ArraySize = B;
X = var;
}
variable_list(X) ::= variable_name(A).
{
X = A;
}
variable_list(X) ::= variable_list(A) COMMA variable_name(B).
{
A->AppendSibling(B);
X = A;
}
decl_flags ::= .
decl_flags ::= decl_flags NATIVE.
decl_flags ::= decl_flags STATIC.
decl_flags ::= decl_flags PRIVATE.
decl_flags ::= decl_flags PROTECTED.
decl_flags ::= decl_flags LATENT.
decl_flags ::= decl_flags FINAL.
decl_flags ::= decl_flags META.
decl_flags ::= decl_flags ACTION.
decl_flags ::= decl_flags DEPRECATED LPAREN string_constant RPAREN.
func_const ::= .
func_const ::= CONST.
opt_func_body ::= SEMICOLON.
opt_func_body ::= function_body.
func_params ::= . /* empty */
func_params ::= VOID.
func_params ::= func_param_list.
func_param_list ::= func_param.
func_param_list ::= func_param COMMA func_param_list.
func_param ::= func_param_flags type variable_name.
func_param_flags ::= .
func_param_flags ::= func_param_flags IN.
func_param_flags ::= func_param_flags OUT.
func_param_flags ::= func_param_flags OPTIONAL.
struct_body ::= struct_member.
struct_body ::= struct_member struct_body.
/* Like UnrealScript, a constant's type is implied by its value's type. */
const_def ::= CONST IDENTIFIER EQ expr SEMICOLON.
/************ Expressions ************/
/* We use default to access a class's default instance. */
%fallback IDENTIFIER
DEFAULT.
%type expr{ZCC_Expression *}
%type primary{ZCC_Expression *}
%type unary_expr{ZCC_Expression *}
%type constant{ZCC_Expression *}
%include {
#define UNARY_EXPR(X,T) NEW_AST_NODE(ExprUnary, expr); expr->Operation = T; expr->Operand = X
#define BINARY_EXPR(X,Y,T) NEW_AST_NODE(ExprBinary, expr); expr->Operation = T; expr->Left = X; expr->Right = Y
}
/*----- Primary Expressions -----*/
primary(X) ::= IDENTIFIER(A).
{
NEW_AST_NODE(ExprID, expr);
expr->Operation = PEX_ID;
expr->Identifier = ENamedName(A.Int);
X = expr;
}
primary(X) ::= SUPER.
{
NEW_AST_NODE(Expression, expr);
expr->Operation = PEX_Super;
X = expr;
}
primary(X) ::= constant(A).
{
X = A;
}
primary(X) ::= SELF.
{
NEW_AST_NODE(Expression, expr);
expr->Operation = PEX_Self;
X = expr;
}
primary(X) ::= LPAREN expr(A) RPAREN.
{
X = A;
}
primary ::= LPAREN error RPAREN.
primary(X) ::= primary(A) LPAREN func_expr_list(B) RPAREN. [DOT] // Function call
{
NEW_AST_NODE(ExprFuncCall, expr);
expr->Operation = PEX_FuncCall;
expr->Function = A;
expr->Parameters = B;
X = expr;
}
primary(X) ::= primary(A) LBRACKET expr(B) RBRACKET. [DOT] // Array access
{
NEW_AST_NODE(ExprBinary, expr);
expr->Operation = PEX_ArrayAccess;
expr->Left = A;
expr->Right = B;
X = expr;
}
primary(X) ::= primary(A) DOT IDENTIFIER(B). // Member access
{
NEW_AST_NODE(ExprMemberAccess, expr);
expr->Operation = PEX_MemberAccess;
expr->Left = A;
expr->Right = ENamedName(B.Int);
X = expr;
}
primary(X) ::= primary(A) ADDADD. /* postfix++ */
{
UNARY_EXPR(A,PEX_PostInc);
X = expr;
}
primary(X) ::= primary(A) SUBSUB. /* postfix-- */
{
UNARY_EXPR(A,PEX_PostDec);
X = expr;
}
primary(X) ::= SCOPE primary(B).
{
BINARY_EXPR(NULL,B,PEX_Scope);
X = expr;
}
/*----- Unary Expressions -----*/
unary_expr(X) ::= primary(A).
{
X = A;
}
unary_expr(X) ::= SUB unary_expr(A). [UNARY]
{
UNARY_EXPR(A,PEX_Negate);
X = expr;
}
unary_expr(X) ::= ADD unary_expr(A). [UNARY]
{
// Even though this is really a no-op, we still need to make a node for
// it so we can type check that it is being applied to something numeric.
UNARY_EXPR(A,PEX_AntiNegate);
X = expr;
}
unary_expr(X) ::= SUBSUB unary_expr(A). [UNARY]
{
UNARY_EXPR(A,PEX_PreDec);
X = expr;
}
unary_expr(X) ::= ADDADD unary_expr(A). [UNARY]
{
UNARY_EXPR(A,PEX_PreInc);
X = expr;
}
unary_expr(X) ::= TILDE unary_expr(A). [UNARY]
{
UNARY_EXPR(A,PEX_BitNot);
X = expr;
}
unary_expr(X) ::= BANG unary_expr(A). [UNARY]
{
UNARY_EXPR(A,PEX_BoolNot);
X = expr;
}
unary_expr(X) ::= SIZEOF unary_expr(A). [UNARY]
{
UNARY_EXPR(A,PEX_SizeOf);
X = expr;
}
unary_expr(X) ::= ALIGNOF unary_expr(A). [UNARY]
{
UNARY_EXPR(A,PEX_AlignOf);
X = expr;
}
/* Due to parsing conflicts, C-style casting is not supported. You
* must use C++ function call-style casting instead.
*/
/*----- Binary Expressions -----*/
expr(X) ::= unary_expr(A).
{
A = X;
}
expr(X) ::= expr(A) ADD expr(B). /* a + b */
{
BINARY_EXPR(A,B,PEX_Add);
X = expr;
}
expr(X) ::= expr(A) SUB expr(B). /* a - b */
{
BINARY_EXPR(A,B,PEX_Sub);
X = expr;
}
expr(X) ::= expr(A) MUL expr(B). /* a * b */
{
BINARY_EXPR(A,B,PEX_Mul);
X = expr;
}
expr(X) ::= expr(A) DIV expr(B). /* a / b */
{
BINARY_EXPR(A,B,PEX_Div);
X = expr;
}
expr(X) ::= expr(A) MOD expr(B). /* a % b */
{
BINARY_EXPR(A,B,PEX_Mod);
X = expr;
}
expr(X) ::= expr(A) POW expr(B). /* a ** b */
{
BINARY_EXPR(A,B,PEX_Pow);
X = expr;
}
expr(X) ::= expr(A) CROSSPROD expr(B). /* a cross b */
{
BINARY_EXPR(A,B,PEX_CrossProduct);
X = expr;
}
expr(X) ::= expr(A) DOTPROD expr(B). /* a dot b */
{
BINARY_EXPR(A,B,PEX_DotProduct);
X = expr;
}
expr(X) ::= expr(A) LSH expr(B). /* a << b */
{
BINARY_EXPR(A,B,PEX_LeftShift);
X = expr;
}
expr(X) ::= expr(A) RSH expr(B). /* a >> b */
{
BINARY_EXPR(A,B,PEX_RightShift);
X = expr;
}
expr(X) ::= expr(A) DOTDOT expr(B). /* a .. b */
{
BINARY_EXPR(A,B,PEX_Concat);
X = expr;
}
expr(X) ::= expr(A) LT expr(B). /* a < b */
{
BINARY_EXPR(A,B,PEX_LT);
X = expr;
}
expr(X) ::= expr(A) GT expr(B). /* a > b */
{
BINARY_EXPR(A,B,PEX_GT);
X = expr;
}
expr(X) ::= expr(A) LTEQ expr(B). /* a <= b */
{
BINARY_EXPR(A,B,PEX_LTEQ);
X = expr;
}
expr(X) ::= expr(A) GTEQ expr(B). /* a >= b */
{
BINARY_EXPR(A,B,PEX_GTEQ);
X = expr;
}
expr(X) ::= expr(A) LTGTEQ expr(B). /* a <>= b */
{
BINARY_EXPR(A,B,PEX_LTGTEQ);
X = expr;
}
expr(X) ::= expr(A) IS expr(B). /* a is b */
{
BINARY_EXPR(A,B,PEX_Is);
X = expr;
}
expr(X) ::= expr(A) EQEQ expr(B). /* a == b */
{
BINARY_EXPR(A,B,PEX_EQEQ);
X = expr;
}
expr(X) ::= expr(A) NEQ expr(B). /* a != b */
{
BINARY_EXPR(A,B,PEX_NEQ);
X = expr;
}
expr(X) ::= expr(A) APPROXEQ expr(B). /* a ~== b */
{
BINARY_EXPR(A,B,PEX_APREQ);
X = expr;
}
expr(X) ::= expr(A) AND expr(B). /* a & b */
{
BINARY_EXPR(A,B,PEX_BitAnd);
X = expr;
}
expr(X) ::= expr(A) XOR expr(B). /* a ^ b */
{
BINARY_EXPR(A,B,PEX_BitXor);
X = expr;
}
expr(X) ::= expr(A) OR expr(B). /* a | b */
{
BINARY_EXPR(A,B,PEX_BitOr);
X = expr;
}
expr(X) ::= expr(A) ANDAND expr(B). /* a && b */
{
BINARY_EXPR(A,B,PEX_BoolAnd);
X = expr;
}
expr(X) ::= expr(A) OROR expr(B). /* a || b */
{
BINARY_EXPR(A,B,PEX_BoolOr);
X = expr;
}
expr(X) ::= expr(A) SCOPE expr(B).
{
BINARY_EXPR(A,B,PEX_Scope);
X = expr;
}
/*----- Trinary Expression -----*/
expr(X) ::= expr(A) QUESTION expr(B) COLON expr(C).
{
NEW_AST_NODE(ExprTrinary, expr);
expr->Operation = PEX_Trinary;
expr->Test = A;
expr->Left = B;
expr->Right = C;
X = expr;
}
/************ Expression Lists ***********/
%type opt_expr_list{ZCC_Expression *}
%type expr_list{ZCC_Expression *}
opt_expr_list(X) ::= .
{
X = NULL;
}
opt_expr_list(X) ::= expr_list(A).
{
X = A;
}
expr_list(X) ::= expr(A).
{
X = A;
}
expr_list(X) ::= expr_list(A) COMMA expr(B).
{
X = A;
A->AppendSibling(B);
}
/*----- Function argument lists -----*/
/* A function expression list can also specify a parameter's name,
* but once you do that, all remaining parameters must also be named.
* We let higher-level code handle this to keep this file simpler. */
%type func_expr_list{ZCC_FuncParm *}
%type named_expr{ZCC_FuncParm *}
func_expr_list(X) ::= .
{
X = NULL;
}
func_expr_list(X) ::= named_expr(A).
{
X = A;
}
func_expr_list(X) ::= func_expr_list(A) COMMA named_expr(B).
{
X = A;
A->AppendSibling(B);
}
named_expr(X) ::= IDENTIFIER(A) COLON expr(B).
{
NEW_AST_NODE(FuncParm, parm);
parm->Value = B;
parm->Label = ENamedName(A.Int);
X = parm;
}
named_expr(X) ::= expr(B).
{
NEW_AST_NODE(FuncParm, parm);
parm->Value = B;
parm->Label = NAME_None;
X = parm;
}
/************ Constants ************/
/* Allow C-like concatenation of adjacent string constants. */
%type string_constant{ZCC_ExprString *}
string_constant(X) ::= STRCONST(A).
{
NEW_AST_NODE(ExprString, strconst);
strconst->Operation = PEX_StringConst;
strconst->Value = A.String;
X = strconst;
}
string_constant(X) ::= string_constant(A) STRCONST(B).
{
NEW_AST_NODE(ExprString, strconst);
strconst->Operation = PEX_StringConst;
strconst->Value = stat->Strings.Alloc(*(A->Value) + *(B.String));
X = strconst;
}
constant(X) ::= string_constant(A).
{
X = A;
}
constant(X) ::= INTCONST(A).
{
NEW_AST_NODE(ExprInt, intconst);
intconst->Operation = PEX_IntConst;
intconst->Value = A.Int;
X = intconst;
}
constant(X) ::= FLOATCONST(A).
{
NEW_AST_NODE(ExprFloat, floatconst);
floatconst->Operation = PEX_FloatConst;
floatconst->Value = A.Float;
X = floatconst;
}
/************ Statements ************/
function_body ::= compound_statement.
%type statement{ZCC_Statement *}
statement ::= SEMICOLON.
statement ::= labeled_statement.
statement ::= compound_statement.
statement ::= expression_statement SEMICOLON.
statement ::= selection_statement.
statement ::= iteration_statement.
statement ::= jump_statement.
statement ::= assign_statement SEMICOLON.
statement ::= local_var SEMICOLON.
statement ::= error SEMICOLON.
/*----- Jump Statements -----*/
%type jump_statement{ZCC_Statement *}
jump_statement(A) ::= CONTINUE SEMICOLON.
{
NEW_AST_NODE(ContinueStmt, stmt);
A = stmt;
}
jump_statement(A) ::= BREAK SEMICOLON.
{
NEW_AST_NODE(BreakStmt, stmt);
A = stmt;
}
jump_statement(A) ::= RETURN SEMICOLON.
{
NEW_AST_NODE(ReturnStmt, stmt);
stmt->Values = NULL;
A = stmt;
}
jump_statement(A) ::= RETURN expr_list(X) SEMICOLON.
{
NEW_AST_NODE(ReturnStmt, stmt);
stmt->Values = X;
A = stmt;
}
/*----- Compound Statements -----*/
%type compound_statement{ZCC_CompoundStmt *}
%type statement_list{ZCC_Statement *}
compound_statement(X) ::= LBRACE RBRACE.
{
NEW_AST_NODE(CompoundStmt,stmt);
stmt->Content = NULL;
X = stmt;
}
compound_statement(X) ::= LBRACE statement_list(A) RBRACE.
{
NEW_AST_NODE(CompoundStmt,stmt);
stmt->Content = A;
X = stmt;
}
compound_statement(X) ::= LBRACE error RBRACE.
{
NEW_AST_NODE(CompoundStmt,stmt);
stmt->Content = NULL;
X = stmt;
}
statement_list(X) ::= statement(A).
{
X = A;
}
statement_list(X) ::= statement_list(A) statement(B).
{
X = A;
A->AppendSibling(B);
}
/*----- Expression Statements -----*/
%type expression_statement{ZCC_ExpressionStmt *}
expression_statement(X) ::= expr(A).
{
NEW_AST_NODE(ExpressionStmt, stmt);
stmt->Expression = A;
X = stmt;
}
/*----- Iteration Statements -----*/
%type iteration_statement{ZCC_Statement *}
// while/until (expr) statement
iteration_statement(X) ::= while_or_until(TY) LPAREN expr(EX) RPAREN statement(ST).
{
NEW_AST_NODE(IterationStmt, iter);
if (TY.Int == ZCC_UNTIL)
{ // Negate the loop condition
UNARY_EXPR(EX,PEX_BoolNot);
iter->LoopCondition = expr;
}
else
{
iter->LoopCondition = EX;
}
iter->LoopStatement = ST;
iter->LoopBumper = NULL;
iter->CheckAt = ZCC_IterationStmt::Start;
X = iter;
}
// do statement while/until (expr)
iteration_statement(X) ::= DO statement(ST) while_or_until(TY) LPAREN expr(EX) RPAREN.
{
NEW_AST_NODE(IterationStmt, iter);
if (TY.Int == ZCC_UNTIL)
{ // Negate the loop condition
UNARY_EXPR(EX,PEX_BoolNot);
iter->LoopCondition = expr;
}
else
{
iter->LoopCondition = EX;
}
iter->LoopStatement = ST;
iter->LoopBumper = NULL;
iter->CheckAt = ZCC_IterationStmt::End;
X = iter;
}
// for (init; cond; bump) statement
iteration_statement(X) ::= FOR LPAREN for_init(IN) SEMICOLON opt_expr(EX) SEMICOLON for_bump(DO) RPAREN statement(ST).
{
NEW_AST_NODE(IterationStmt, iter);
iter->LoopCondition = EX;
iter->LoopStatement = ST;
iter->LoopBumper = DO;
iter->CheckAt = ZCC_IterationStmt::Start;
// The initialization expression appears outside the loop
IN->AppendSibling(iter);
// And the whole thing gets wrapped inside a compound statement in case the loop
// initializer defined any variables.
NEW_AST_NODE(CompoundStmt, wrap);
wrap->Content = IN;
X = wrap;
}
while_or_until(X) ::= WHILE.
{
X.Int = ZCC_WHILE;
}
while_or_until(X) ::= UNTIL.
{
X.Int = ZCC_UNTIL;
}
%type for_init{ZCC_Statement *}
for_init(X) ::= local_var(A). { X = A; }
for_init(X) ::= for_bump(A). { X = A; }
%type for_bump{ZCC_Statement *}
for_bump(X) ::= . { X = NULL; }
for_bump(X) ::= expression_statement(A). { X = A; }
for_bump(X) ::= assign_statement(A). { X = A; }
/*----- If Statements -----*/
/* Resolve the shift-reduce conflict here in favor of the shift.
* This is the default behavior, but using precedence symbols
* lets us do it without warnings.
*/
%left IF.
%left ELSE.
%type selection_statement{ZCC_Statement *}
%type if_front{ZCC_IfStmt *}
selection_statement(X) ::= if_front(A). [IF]
{
X = A;
}
selection_statement(X) ::= if_front(A) ELSE statement(B). [ELSE]
{
A->FalsePath = B;
X = A;
}
if_front(X) ::= IF LPAREN expr(A) RPAREN statement(B).
{
NEW_AST_NODE(IfStmt,stmt);
stmt->Condition = A;
stmt->TruePath = B;
stmt->FalsePath = NULL;
X = stmt;
}
/*----- Switch Statements -----*/
selection_statement(X) ::= SWITCH LPAREN expr(A) RPAREN statement(B).
{
NEW_AST_NODE(SwitchStmt,stmt);
stmt->Condition = A;
stmt->Content = B;
X = stmt;
}
/*----- Case Label "Statements" -----*/
%type labeled_statement{ZCC_CaseStmt *}
labeled_statement(X) ::= CASE expr(A) COLON.
{
NEW_AST_NODE(CaseStmt,stmt);
stmt->Condition = A;
X = stmt;
}
labeled_statement(X) ::= DEFAULT COLON.
{
NEW_AST_NODE(CaseStmt,stmt);
stmt->Condition = NULL;
X = stmt;
}
/*----- Assignment Statements -----*/
%type assign_statement{ZCC_AssignStmt *}
assign_statement(X) ::= expr_list(A) assign_op(OP) expr_list(B). [EQ]
{
NEW_AST_NODE(AssignStmt,stmt);
stmt->AssignOp = OP.Int;
stmt->Dests = A;
stmt->Sources = B;
X = stmt;
}
assign_op ::= EQ.
assign_op ::= MULEQ.
assign_op ::= DIVEQ.
assign_op ::= MODEQ.
assign_op ::= ADDEQ.
assign_op ::= SUBEQ.
assign_op ::= LSHEQ.
assign_op ::= RSHEQ.
assign_op ::= ANDEQ.
assign_op ::= OREQ.
assign_op ::= XOREQ.
/*----- Local Variable Definition "Statements" -----*/
%type local_var{ZCC_LocalVarStmt *}
local_var(X) ::= type(A) variable_list(B) var_init(C).
{
NEW_AST_NODE(LocalVarStmt,vardef);
vardef->Type = A;
vardef->Vars = B;
vardef->Inits = C;
X = vardef;
}
%type var_init{ZCC_Expression *}
var_init(X) ::= . { X = NULL; }
var_init(X) ::= EQ expr_list(A). { X = A; }