%include { // Allocates a new AST node off the parse state's arena. #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 // If a is non-null, appends b to a. Otherwise, sets a to b. #define SAFE_APPEND(a,b) \ if (a == NULL) a = b; else a->AppendSibling(b); } %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; } /************ Class Definition ************/ /* Can only occur at global scope. */ %type class_definition{ZCC_Class *} %type class_head{ZCC_Class *} %type class_innards{ZCC_Class *} %type class_body{ZCC_TreeNode *} class_definition(X) ::= class_head(A) class_body(B). { A->Body = B; X = A; } class_head(X) ::= CLASS dottable_id(A) class_ancestry(B) class_flags(C). { NEW_AST_NODE(Class,head); head->ClassName = A; head->ParentName = B; head->Flags = C.Flags; head->Replaces = C.Replaces; X = head; } %type class_ancestry{ZCC_Identifier *} class_ancestry(X) ::= . { X = NULL; } class_ancestry(X) ::= COLON dottable_id(A). { X = A; } %type class_flags{ClassFlagsBlock} %include{ struct ClassFlagsBlock { VM_UWORD Flags; ZCC_Identifier *Replaces; }; } class_flags(X) ::= . { X.Flags = 0; X.Replaces = NULL; } class_flags(X) ::= class_flags(A) ABSTRACT. { X.Flags = A.Flags | 0/*FIXME*/; X.Replaces = A.Replaces; } class_flags(X) ::= class_flags(A) NATIVE. { X.Flags = A.Flags | 0/*FIXME*/; X.Replaces = A.Replaces; } class_flags(X) ::= class_flags(A) REPLACES dottable_id(B). { X.Flags = A.Flags; X.Replaces = B; } /*----- Dottable Identifier -----*/ // This can be either a single identifier or two identifiers connected by a . %type dottable_id{ZCC_Identifier *} dottable_id(X) ::= IDENTIFIER(A). { NEW_AST_NODE(Identifier,id); id->Id = A.Name(); X = id; } dottable_id(X) ::= dottable_id(A) DOT IDENTIFIER(B). { NEW_AST_NODE(Identifier,id2); id2->Id = B.Name(); A->AppendSibling(id2); X = A; } /*------ Class Body ------*/ // Body is a list of: // * variable definitions // * function definitions // * enum definitions // * struct definitions // * state definitions // * constants // * defaults class_body ::= SEMICOLON class_innards EOF. class_body ::= LBRACE class_innards RBRACE. class_innards ::= . class_innards ::= class_innards class_member. %type struct_def{ZCC_Struct *} %type enum_def {ZCC_Enum *} %type states_def {ZCC_States *} class_member ::= declarator. class_member ::= enum_def. class_member ::= struct_def. class_member ::= states_def. class_member ::= default_def. class_member ::= const_def. /*----- Struct Definition -----*/ /* Structs can define variables, enums, and structs. */ %type struct_body{ZCC_TreeNode *} %type struct_member{ZCC_TreeNode *} struct_def(X) ::= STRUCT IDENTIFIER(A) LBRACE struct_body(B) RBRACE opt_semicolon. { NEW_AST_NODE(Struct,def); def->StructName = A.Name(); def->Body = B; X = def; } struct_body(X) ::= error. { X = NULL; } struct_body(X) ::= struct_member(A). { X = A; } struct_body(X) ::= struct_member(A) struct_body(B). { X = A; A->AppendSibling(B); } struct_member(X) ::= declarator_no_fun(A). { X = A; } struct_member(X) ::= enum_def(A). { X = A; } /*----- Enum Definition -----*/ /* Enumerators are lists of named integers. */ %type enum_type {EZCCIntType} %type enum_list {ZCC_EnumNode *} %type enumerator {ZCC_EnumNode *} enum_def(X) ::= ENUM IDENTIFIER(A) enum_type(B) LBRACE enum_list(C) opt_comma RBRACE opt_semicolon. { NEW_AST_NODE(Enum,def); def->EnumName = A.Name(); def->EnumType = B; def->Elements = C; X = def; } enum_type(X) ::= . { X = ZCCINT_Auto; } enum_type(X) ::= COLON int_type(A). { X = A; } enum_list(X) ::= error. { X = NULL; } enum_list(X) ::= enumerator(A). { X = A; } enum_list(X) ::= enum_list(A) COMMA enumerator(B). { X = A; A->AppendSibling(B); } enumerator(X) ::= IDENTIFIER(A). { NEW_AST_NODE(EnumNode,node); node->ElemName = A.Name(); node->ElemValue = NULL; X = node; } enumerator(X) ::= IDENTIFIER(A) EQ expr(B). /* Expression must be constant. */ { NEW_AST_NODE(EnumNode,node); node->ElemName = A.Name(); node->ElemValue = B; X = node; } /************ States ************/ %type states_body {ZCC_StatePart *} %type state_line {ZCC_StatePart *} %type state_label {ZCC_StatePart *} %type state_flow {ZCC_StatePart *} %type state_flow_type {ZCC_StatePart *} %type state_goto_offset {ZCC_Expression *} %type state_action {ZCC_TreeNode *} %type state_call {ZCC_ExprFuncCall *} %include { struct StateOpts { ZCC_Expression *Offset; bool Bright; }; } %type state_opts {StateOpts} states_def(X) ::= STATES scanner_mode LBRACE states_body(A) RBRACE. { NEW_AST_NODE(States,def); def->Body = A; X = def; } /* 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(X) ::= . { X = NULL; } states_body(X) ::= error. { X = NULL; } states_body(X) ::= states_body(A) state_line(B). { SAFE_APPEND(A,B); X = A; } states_body(X) ::= states_body(A) state_label(B). { SAFE_APPEND(A,B); X = A; } states_body(X) ::= states_body(A) state_flow(B). { SAFE_APPEND(A,B); X = A; } state_label(X) ::= NWS(A) COLON. { NEW_AST_NODE(StateLabel, label); label->Label = A.Name(); X = label; } state_flow(X) ::= state_flow_type(A) scanner_mode SEMICOLON. { X = A; } state_flow_type(X) ::= STOP. { NEW_AST_NODE(StateStop, flow); X = flow; } state_flow_type(X) ::= WAIT. { NEW_AST_NODE(StateWait, flow); X = flow; } state_flow_type(X) ::= FAIL. { NEW_AST_NODE(StateFail, flow); X = flow; } state_flow_type(X) ::= LOOP. { NEW_AST_NODE(StateLoop, flow); X = flow; } state_flow_type(X) ::= GOTO dottable_id(A) state_goto_offset(B). { NEW_AST_NODE(StateGoto, flow); flow->Label = A; flow->Offset = B; X = flow; } state_goto_offset(X) ::= . { X = NULL; } state_goto_offset(X) ::= PLUS expr(A). { X = A; } /* Must evaluate to a non-negative integer constant. */ state_line(X) ::= NWS(A) NWS(B) expr state_opts(C) state_action(D). { NEW_AST_NODE(StateLine, line); const char *sprite = FName(A.Name()).GetChars(); memset(line, 0, sizeof(*line)); if (strlen(sprite) != 4) { Printf("Sprite name '%s' must be four characters", sprite); } else { memcpy(line->Sprite, sprite, 4); } line->Frames = stat->Strings.Alloc(FName(B.Name()).GetChars()); line->bBright = C.Bright; line->Offset = C.Offset; line->Action = D; X = line; } state_opts(X) ::= . { StateOpts opts; opts.Offset = NULL; opts.Bright = false; X = opts; } state_opts(X) ::= state_opts(A) BRIGHT. { A.Bright = true; X = A; } state_opts(X) ::= state_opts(A) OFFSET LPAREN expr(B) COMMA expr(C) RPAREN. { A.Offset = B; B->AppendSibling(C); X = A; } state_opts(X) ::= state_opts(A) LIGHT LPAREN light_list RPAREN. { X = A; } 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(X) ::= LBRACE statement_list(A) scanner_mode RBRACE. { X = A; } state_action(X) ::= LBRACE error scanner_mode RBRACE. { X = NULL; } state_action(X) ::= state_call(A) scanner_mode SEMICOLON. { X = A; } state_call(X) ::= . { X = NULL; } state_call(X) ::= IDENTIFIER(A) func_params(B). { NEW_AST_NODE(ExprFuncCall, expr); NEW_AST_NODE(ExprID, func); func->Operation = PEX_ID; func->Identifier = A.Name(); expr->Operation = PEX_FuncCall; expr->Function = func; expr->Parameters = B; X = expr; } /* Definition of a default class instance. */ default_def ::= DEFAULT compound_statement. /* Type names */ %type int_type {EZCCIntType} %type type_name {PType *} int_type(X) ::= SBYTE. { X = ZCCINT_SInt8; } int_type(X) ::= BYTE. { X = ZCCINT_UInt8; } int_type(X) ::= SHORT. { X = ZCCINT_SInt16; } int_type(X) ::= USHORT. { X = ZCCINT_UInt16; } int_type(X) ::= INT. { X = ZCCINT_SInt32; } int_type(X) ::= UINT. { X = ZCCINT_UInt32; } 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 */ aggregate_type ::= CLASS class_restrictor. /* class */ 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. /* 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 = A.Name(); 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 expr_list{ZCC_Expression *} 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; }