/** Bombs-Must-Detonate: Parser Generator **/ %token ENDOFFILE %token IDENTIFIER %token STR %token INCLUDE %token INT FLOAT STRING BOOL VOID %token ENUM STRUCT LIST ARRAY %token REF %token REMOTABLE %token LPAREN RPAREN LBRACKET RBRACKET LT GT LCURLBRACKET RCURLBRACKET %token QUOTES COMMA PERIOD SEMICOLON COLON EXCLAMATION TILDE DOLLAR %token AMPER PIPE %token INTVAL %token FLOATVAL %token TRUE FALSE %token NIL %token EQUALS %token IF ELSE WHILE FOR BREAK CONTINUE DO %token CAR CDR TRUNC NOT NULL %token AND OR NOR XOR NAND ADD SUB MUL DIV IDIV MOD CONCAT %token BREAK CONTINUE %token RETURN %token TEMPLATE %token STATEMACHINE STATE FSMINIT TRANSITION PREDICATE TARGET %left REMOTABLE %left RETURN BREAK CONTINUE INCLUDE SEMICOLON LCURLBRACKET RCURLBRACKET %left ELSE %left IF WHILE FOR DO %left CAR CDR NULL %left NOT TILDE %left TRUNC %left LBRACKET RBRACKET %left LIST %left ARRAY %left REF %left ENUM STRUCT %left INT FLOAT STRING BOOL VOID %left EQUALS %left EXCLAMATION %right AND OR NOR XOR AND AMPER PIPE %left CONCAT COLON DOLLAR %left LT GT %left ADD SUB %left MUL DIV IDIV MOD %left QUOTES COMMA PERIOD %left TRUE FALSE NIL INTVAL FLOATVAL IDENTIFIER STR %left LPAREN RPAREN %left LPRI %left MPRI %left HPRI %start program %type program %% program: ENDOFFILE { [] } | global_expression program { $1::$2 } global_expression: function_declaration SEMICOLON { $1 } | function_definition { $1 } | struct_declaration { $1 } | global_enum_declaration { $1 } | global_var_declare { $1 } | INCLUDE QUOTES IDENTIFIER QUOTES { Ast.SynInclude (ref (Ast.IncludeFileName $3)) } | INCLUDE STR { Ast.SynInclude (ref (Ast.IncludeFileName $2)) } | fsm_state_machine { Ast.SynStateMachine $1 } /* Functions */ function_declaration: data_type IDENTIFIER LPAREN arg_list RPAREN { Ast.SynFunctionDeclare ($1,$2,$4) } | REMOTABLE data_type IDENTIFIER LPAREN arg_list RPAREN { Ast.SynRemotableFunctionDeclare ($2,$3,$5) } | TEMPLATE LT identifier_list GT function_declaration { Ast.SynTemplatedDeclare ($3,$5) } function_definition: function_declaration LCURLBRACKET function_body RCURLBRACKET { match $1 with Ast.SynFunctionDeclare (a,b,c) -> Ast.SynFunctionDefine ((a,b,c),$3) | Ast.SynTemplatedDeclare (lst,Ast.SynFunctionDeclare (a,b,c)) -> Ast.SynTemplatedDefine (lst,Ast.SynFunctionDefine ((a,b,c),$3)) | _ -> raise (Failure "Remotable keyword should be used in function declaration, not in function definition.") } function_body: /* empty */ { [] } | expression function_body { $1::$2 } arg_list: /* empty */ { [] } | arg_list_nonempty { $1 } arg_list_nonempty: data_type IDENTIFIER COMMA arg_list_nonempty { ($1,$2)::$4 } | data_type IDENTIFIER { ($1,$2)::[] } function_call: IDENTIFIER LPAREN value_producer_list RPAREN { Ast.SynLocalCall ($1,$3,ref false) } | EXCLAMATION LPAREN IDENTIFIER LPAREN value_producer_list RPAREN COMMA var_ident RPAREN { Ast.SynRemoteCall ($3,$5,$8) } | EXCLAMATION LPAREN IDENTIFIER LPAREN value_producer_list RPAREN RPAREN { Ast.SynRemoteCallNoResult ($3,$5) } /* Structs & Enums */ struct_declaration: STRUCT IDENTIFIER LCURLBRACKET struct_list RCURLBRACKET SEMICOLON { Ast.SynStructDeclare ($2,$4) } global_enum_declaration: ENUM IDENTIFIER LCURLBRACKET identifier_list RCURLBRACKET SEMICOLON { Ast.SynGlobalEnumDeclare ($2,$4) } enum_declaration: ENUM IDENTIFIER LCURLBRACKET identifier_list RCURLBRACKET { Ast.SynEnumDeclare ($2,$4) } struct_list: data_type IDENTIFIER SEMICOLON struct_list { (Ast.SynVarDeclareNoInit ($1,$2))::$4 } | data_type IDENTIFIER SEMICOLON { (Ast.SynVarDeclareNoInit ($1,$2))::[] } identifier_list: IDENTIFIER COMMA identifier_list { $1::$3 } | IDENTIFIER { $1::[] } /* Global Var Declare */ global_var_declare: data_type IDENTIFIER SEMICOLON { Ast.SynGlobalVarDeclare (Ast.SynVarDeclareNoInit ($1,$2)) } /* Data Types */ data_type: INT { Ast.SynIntType } | FLOAT { Ast.SynFloatType } | STRING { Ast.SynStringType } | BOOL { Ast.SynBoolType } | VOID { Ast.SynVoidType } | IDENTIFIER { Ast.SynEnumOrStructType ($1,ref []) } | data_type ARRAY LBRACKET value_producer RBRACKET { Ast.SynArrayType ($1,$4) } | data_type ARRAY LBRACKET RBRACKET { Ast.SynArrayType ($1,Ast.SynValue (Ast.SynIntValue 0)) } | data_type LIST { Ast.SynListType $1 } | data_type REF { Ast.SynRefType $1 } | LPAREN data_type_list RPAREN SUB GT data_type { Ast.SynArrowType ($2,$6) } data_type_list: data_type { [$1] } | data_type COMMA data_type_list { $1::$3 } /* Values */ var_ident: IDENTIFIER { Ast.SynVarName $1 } | var_ident PERIOD IDENTIFIER { Ast.SynStructOrEnumValue ($1,$3,ref Ast.VIdUnspecified) } | var_ident LBRACKET value_producer RBRACKET { Ast.SynArrayCell ($1,$3) } value_producer: | value { Ast.SynValue $1 } | function_call { Ast.SynFunctionCallValue $1 } | var_ident { Ast.SynVarIdentifier $1 } %prec LPRI | value_producer binop value_producer { Ast.SynBinop ($1,$2,$3) } %prec MPRI | pre_unop value_producer { Ast.SynPrefixUnop ($1,$2) } %prec HPRI | LPAREN value_producer RPAREN { Ast.SynParenthesized $2 } %prec HPRI | LCURLBRACKET array_value_producer_list RCURLBRACKET { Ast.SynArrayValueProducer $2 } | list_value_producer { Ast.SynListValueProducer $1 } value: INTVAL { Ast.SynIntValue $1 } | FLOATVAL { Ast.SynFloatValue $1 } | STR { Ast.SynStringValue $1 } | QUOTES IDENTIFIER QUOTES { Ast.SynStringValue $2 } | TRUE { Ast.SynBoolValue true } | FALSE { Ast.SynBoolValue false } value_producer_list: /* empty */ { [] } | value_producer_list_nonempty { $1 } value_producer_list_nonempty: value_producer COMMA value_producer_list_nonempty { $1::$3 } | value_producer { $1::[] } %prec MPRI list_value_producer_list: value_producer SEMICOLON list_value_producer_list { $1::$3 } | value_producer { $1::[] } %prec MPRI array_value_producer_list: value_producer COMMA array_value_producer_list { $1::$3 } | value_producer { $1::[] } %prec MPRI list_value_producer: NIL LBRACKET data_type RBRACKET { Ast.SynListNil $3 } | LBRACKET list_value_producer_list RBRACKET { Ast.SynListList $2 } | value_producer COLON COLON value_producer { Ast.SynListCons ($1,$4) } /* Comparisons and Operators */ pre_unop: NOT { Ast.SynUnopNot } | TILDE { Ast.SynUnopNot } | CAR { Ast.SynUnopCar } | CDR { Ast.SynUnopCdr } | TRUNC { Ast.SynUnopTrunc } | DOLLAR { Ast.SynUnopDeref } | SUB { Ast.SynUnopNeg } | NULL { Ast.SynUnopNull } binop: AND { Ast.SynBinopAnd } | OR { Ast.SynBinopOr } | ADD { Ast.SynBinopAdd } | SUB { Ast.SynBinopSub } | MUL { Ast.SynBinopMul } | DIV { Ast.SynBinopDiv } | IDIV { Ast.SynBinopIDiv } | MOD { Ast.SynBinopMod } | CONCAT { Ast.SynBinopConcat } | COLON COLON { Ast.SynBinopCons } | LT EQUALS { Ast.SynCompLte } %prec HPRI | GT EQUALS { Ast.SynCompGte } %prec HPRI | LT { Ast.SynCompLt } %prec MPRI | GT { Ast.SynCompGt } %prec MPRI | EQUALS { Ast.SynCompEq } %prec MPRI | EXCLAMATION EQUALS { Ast.SynCompNeq } /* Expressions */ expression: var_declaration SEMICOLON { $1 } | enum_declaration SEMICOLON { $1 } | var_assign SEMICOLON { Ast.SynVarAssign $1 } | conditional { Ast.SynCond $1 } | loop { Ast.SynLoop $1 } | function_call SEMICOLON { Ast.SynFunctionCall $1 } | return_statement SEMICOLON { $1 } | BREAK SEMICOLON { Ast.SynBreak } | CONTINUE SEMICOLON { Ast.SynContinue } expression_list: /* empty */ { [] } | expression_list_nonempty { $1 } expression_list_nonempty: expression expression_list_nonempty { $1::$2 } | expression { $1::[] } var_declaration: data_type IDENTIFIER { Ast.SynVarDeclare (Ast.SynVarDeclareNoInit ($1,$2)) } | data_type IDENTIFIER EQUALS value_producer { Ast.SynVarDeclare (Ast.SynVarDeclareWithInit ($1,$2,$4)) } var_assign: var_ident EQUALS value_producer { Ast.SynVarAssignment ($1,$3) } | var_ident binop EQUALS value_producer { Ast.SynVarModify ($1,$2,$4) } /* Conditionals */ conditional: IF value_producer LCURLBRACKET expression_list RCURLBRACKET { Ast.SynIf ($2,$4) } | IF value_producer LCURLBRACKET expression_list RCURLBRACKET continued_conditional { Ast.SynIfCase ($2,$4,$6) } continued_conditional: ELSE LCURLBRACKET expression_list RCURLBRACKET { Ast.SynFinalElse $3 } | ELSE conditional { Ast.SynElse $2 } /* Loops */ loop: WHILE value_producer LCURLBRACKET expression_list RCURLBRACKET { Ast.SynWhile ($2,$4) } | FOR LPAREN expression value_producer SEMICOLON expression RPAREN LCURLBRACKET expression_list RCURLBRACKET { Ast.SynFor ($3,$4,$6,$9) } | DO LCURLBRACKET expression_list RCURLBRACKET WHILE value_producer SEMICOLON { Ast.SynDoWhile ($3,$6) } return_statement: RETURN { Ast.SynReturnStatement (Ast.SynVoidReturn) } | RETURN value_producer { Ast.SynReturnStatement (Ast.SynValueReturn $2) } /* State Machine Syntax */ fsm_state_machine: STATEMACHINE IDENTIFIER LCURLBRACKET fsm_init fsm_state_list RCURLBRACKET { ($2,$4,$5) } fsm_state: STATE IDENTIFIER LCURLBRACKET fsm_callback_list fsm_transition_list RCURLBRACKET { ($2,$4,$5) } fsm_state_list: fsm_state { [$1] } | fsm_state fsm_state_list { $1::$2 } fsm_callback: IDENTIFIER COLON IDENTIFIER SEMICOLON { match $1 with "onInit" -> Ast.SynFsmOnInit $3 | "onMoveRequest" -> Ast.SynFsmOnMoveRequest $3 | "onTeammateDeath" -> Ast.SynFsmOnTeammateDeath $3 | "onBombDetonate" -> Ast.SynFsmOnBombDetonate $3 | "onDeath" -> Ast.SynFsmOnDeath $3 | _ -> raise Parse_error } fsm_callback_list: /* empty */ { [] } | fsm_callback_list_nonempty { $1 } fsm_callback_list_nonempty: fsm_callback { [$1] } | fsm_callback fsm_callback_list_nonempty { $1::$2 } fsm_init: FSMINIT COLON IDENTIFIER SEMICOLON { $3 } fsm_transition: TRANSITION LCURLBRACKET PREDICATE COLON identifier_list SEMICOLON TARGET COLON fsm_transition_target_list SEMICOLON RCURLBRACKET { ($5,$9) } fsm_transition_list: /* empty */ { [] } | fsm_transition_list_nonempty { $1 } fsm_transition_list_nonempty: fsm_transition { [$1] } | fsm_transition fsm_transition_list_nonempty { $1::$2 } fsm_transition_target: IDENTIFIER FLOATVAL { if $2 <= 0.0 then raise Parse_error else ($1,$2) } fsm_transition_target_list: /* empty */ { [] } | fsm_transition_target_list_nonempty { $1 } fsm_transition_target_list_nonempty: fsm_transition_target { [$1] } | fsm_transition_target COMMA fsm_transition_target_list_nonempty { $1::$3 }