%{ // Make sure we don't get gram.h twice. #define _BASGRAM_H_ #define _CMDGRAM_H_ #include #include #include "console/console.h" #include "console/compiler.h" #include "console/consoleInternal.h" #ifndef YYDEBUG #define YYDEBUG 0 #endif #define YYSSIZE 350 int outtext(char *fmt, ...); extern int serrors; #define nil 0 #undef YY_ARGS #define YY_ARGS(x) x int BASlex(); void BASerror(char *a, ...); #define alloca dMalloc %} %{ /* Reserved Word Definitions */ /* IMPORTANT: SEE COMMENTS BELOW IF YOU ARE THINKING ABOUT MODIFYING TOKENS */ /* ALL TOKENS BETWEEN HERE AND ADDITIONAL TOKENS BELOW MUST BE IDENTICAL TO THOSE IN CS_CMD.y OTHERWISE BAD STUFF HAPPENS */ %} %token rwDEFINE rwENDDEF rwDECLARE %token rwBREAK rwELSE rwCONTINUE rwGLOBAL %token rwIF rwNIL rwRETURN rwWHILE %token rwENDIF rwENDWHILE rwENDFOR rwDEFAULT %token rwFOR rwDATABLOCK rwSWITCH rwCASE rwSWITCHSTR %token rwCASEOR rwPACKAGE %token ILLEGAL_TOKEN %{ /* Constants and Identifier Definitions */ %} %token CHRCONST %token INTCONST %token TTAG %token VAR %token IDENT %token STRATOM %token TAGATOM %token FLTCONST %{ /* Operator Definitions */ %} %token '+' '-' '*' '/' '<' '>' '=' '.' '|' '&' '%' %token '(' ')' ',' ':' ';' '{' '}' '^' '~' '!' '@' %token opMINUSMINUS opPLUSPLUS %token STMT_SEP %token opSHL opSHR opPLASN opMIASN opMLASN opDVASN opMODASN opANDASN %token opXORASN opORASN opSLASN opSRASN opCAT %token opEQ opNE opGE opLE opAND opOR opSTREQ %token opCOLONCOLON %union { char c; int i; const char *s; char *str; double f; StmtNode *stmt; ExprNode *expr; SlotAssignNode *slist; VarNode *var; SlotDecl slot; ObjectBlockDecl odcl; ObjectDeclNode *od; AssignDecl asn; IfStmtNode *ifnode; } %type parent_block %type case_block %type switch_stmt %type decl %type decl_list %type package_decl %type fn_decl_stmt %type fn_decl_list %type statement_list %type stmt %type expr_list %type expr_list_decl %type aidx_expr %type funcall_expr %type object_name %type object_args %type stmt_expr %type case_expr %type class_name_expr %type if_stmt %type while_stmt %type for_stmt %type stmt_block %type datablock_decl %type object_decl %type object_decl_list %type object_declare_block %type expr %type slot_assign_list %type slot_assign %type slot_acc %type expression_stmt %type var_list %type var_list_decl %type assign_op_struct %left '[' %right opMODASN opANDASN opXORASN opPLASN opMIASN opMLASN opDVASN opMDASN opNDASN opNTASN opORASN opSLASN opSRASN '=' %left '?' ':' %left opOR %left opAND %left '|' %left '^' %left '&' %left opEQ opNE %left '<' opLE '>' opGE %left '@' opCAT opSTREQ opSTRNE %left opSHL opSHR %left '+' '-' %left '*' '/' '%' %right '!' '~' opPLUSPLUS opMINUSMINUS UNARY %left '.' %{ /* Additional tokens NOTE: These MUST be here, otherwise the definitions of the usual TorqueScript tokens changes which will break the compiler. Double check the standard TS tokens arent being redefined before testing a build. */ %} %token rwTHEN rwEND rwBEGIN rwCFOR rwTO rwSTEP %% start : decl_list { } ; decl_list : { $$ = nil; } | decl_list decl { if(!statementList) { statementList = $2; } else { statementList->append($2); } } ; decl : stmt { $$ = $1; } | fn_decl_stmt { $$ = $1; } | package_decl { $$ = $1; } ; package_decl : rwPACKAGE IDENT fn_decl_list rwEND { $$ = $3; for(StmtNode *walk = ($3);walk;walk = walk->getNext() ) walk->setPackage($2); } ; fn_decl_list : fn_decl_stmt { $$ = $1; } | fn_decl_list fn_decl_stmt { $$ = $1; ($1)->append($2); } ; statement_list : { $$ = nil; } | statement_list stmt { if(!$1) { $$ = $2; } else { ($1)->append($2); $$ = $1; } } ; stmt : if_stmt | while_stmt | for_stmt | datablock_decl | switch_stmt | rwBREAK semicolon { $$ = BreakStmtNode::alloc(); } | rwCONTINUE semicolon { $$ = ContinueStmtNode::alloc(); } | rwRETURN semicolon { $$ = ReturnStmtNode::alloc(NULL); } | rwRETURN expr semicolon { $$ = ReturnStmtNode::alloc($2); } | expression_stmt semicolon { $$ = $1; } | TTAG '=' expr semicolon { $$ = TTagSetStmtNode::alloc($1, $3, NULL); } | TTAG '=' expr ',' expr semicolon { $$ = TTagSetStmtNode::alloc($1, $3, $5); } ; fn_decl_stmt : rwDEFINE IDENT '(' var_list_decl ')' statement_list rwEND { $$ = FunctionDeclStmtNode::alloc($2, NULL, $4, $6); } | rwDEFINE IDENT opCOLONCOLON IDENT '(' var_list_decl ')' statement_list rwEND { $$ = FunctionDeclStmtNode::alloc($4, $2, $6, $8); } ; var_list_decl : { $$ = NULL; } | var_list { $$ = $1; } ; var_list : VAR { $$ = VarNode::alloc($1, NULL); } | var_list ',' VAR { $$ = $1; ((StmtNode*)($1))->append((StmtNode*)VarNode::alloc($3, NULL)); } ; datablock_decl : rwDATABLOCK IDENT '(' IDENT parent_block ')' slot_assign_list rwEND { $$ = ObjectDeclNode::alloc(ConstantNode::alloc($2), ConstantNode::alloc($4), NULL, $5, $7, NULL, true); } ; object_decl : rwDECLARE class_name_expr '(' object_name parent_block object_args ')' object_declare_block rwEND { $$ = ObjectDeclNode::alloc($2, $4, $6, $5, $8.slots, $8.decls, false); } | rwDECLARE class_name_expr '(' object_name parent_block object_args ')' rwEND { $$ = ObjectDeclNode::alloc($2, $4, $6, $5, NULL, NULL, false); } ; parent_block : { $$ = NULL; } | ':' IDENT { $$ = $2; } ; object_name : { $$ = StrConstNode::alloc("", false); } | expr { $$ = $1; } ; object_args : { $$ = NULL; } | ',' expr_list { $$ = $2; } ; object_declare_block : { $$.slots = NULL; $$.decls = NULL; } | slot_assign_list { $$.slots = $1; $$.decls = NULL; } | object_decl_list { $$.slots = NULL; $$.decls = $1; } | slot_assign_list object_decl_list { $$.slots = $1; $$.decls = $2; } ; object_decl_list : object_decl semicolon { $$ = $1; } | object_decl_list object_decl semicolon { $1->append($2); $$ = $1; } ; stmt_block : rwBEGIN statement_list rwEND { $$ = $2; } | stmt { $$ = $1; } ; switch_stmt : rwSWITCH expr case_block rwEND { $$ = $3; $3->propagateSwitchExpr($2, false); } | rwSWITCHSTR expr case_block rwEND { $$ = $3; $3->propagateSwitchExpr($2, true); } ; case_block : rwCASE case_expr ':' statement_list { $$ = IfStmtNode::alloc($1, $2, $4, NULL, false); } | rwCASE case_expr ':' statement_list rwDEFAULT ':' statement_list { $$ = IfStmtNode::alloc($1, $2, $4, $7, false); } | rwCASE case_expr ':' statement_list case_block { $$ = IfStmtNode::alloc($1, $2, $4, $5, true); } ; case_expr : expr { $$ = $1;} | case_expr rwCASEOR expr { ($1)->append($3); $$=$1; } ; if_stmt : rwIF expr rwTHEN statement_list rwEND { $$ = IfStmtNode::alloc($1, $2, $4, NULL, false); } | rwIF expr rwTHEN statement_list rwELSE statement_list rwEND { $$ = IfStmtNode::alloc($1, $2, $4, $6, false); } ; while_stmt : rwWHILE expr rwBEGIN statement_list rwEND { $$ = LoopStmtNode::alloc($1, nil, $2, nil, $4, false); } ; for_stmt : rwFOR expr ',' expr ',' expr rwBEGIN statement_list rwEND { $$ = LoopStmtNode::alloc($1, $2, $4, $6, $8, false); } ; expression_stmt : stmt_expr { $$ = $1; } ; expr : stmt_expr { $$ = $1; } | '(' expr ')' { $$ = $2; } | expr '^' expr { $$ = IntBinaryExprNode::alloc($2, $1, $3); } | expr '%' expr { $$ = IntBinaryExprNode::alloc($2, $1, $3); } | expr '&' expr { $$ = IntBinaryExprNode::alloc($2, $1, $3); } | expr '|' expr { $$ = IntBinaryExprNode::alloc($2, $1, $3); } | expr '+' expr { $$ = FloatBinaryExprNode::alloc($2, $1, $3); } | expr '-' expr { $$ = FloatBinaryExprNode::alloc($2, $1, $3); } | expr '*' expr { $$ = FloatBinaryExprNode::alloc($2, $1, $3); } | expr '/' expr { $$ = FloatBinaryExprNode::alloc($2, $1, $3); } | '-' expr %prec UNARY { $$ = FloatUnaryExprNode::alloc($1, $2); } | '*' expr %prec UNARY { $$ = TTagDerefNode::alloc($2); } | TTAG { $$ = TTagExprNode::alloc($1); } | expr '?' expr ':' expr { $$ = ConditionalExprNode::alloc($1, $3, $5); } | expr '<' expr { $$ = IntBinaryExprNode::alloc($2, $1, $3); } | expr '>' expr { $$ = IntBinaryExprNode::alloc($2, $1, $3); } | expr opGE expr { $$ = IntBinaryExprNode::alloc($2, $1, $3); } | expr opLE expr { $$ = IntBinaryExprNode::alloc($2, $1, $3); } | expr opEQ expr { $$ = IntBinaryExprNode::alloc($2, $1, $3); } | expr opNE expr { $$ = IntBinaryExprNode::alloc($2, $1, $3); } | expr opOR expr { $$ = IntBinaryExprNode::alloc($2, $1, $3); } | expr opSHL expr { $$ = IntBinaryExprNode::alloc($2, $1, $3); } | expr opSHR expr { $$ = IntBinaryExprNode::alloc($2, $1, $3); } | expr opAND expr { $$ = IntBinaryExprNode::alloc($2, $1, $3); } | expr opSTREQ expr { $$ = StreqExprNode::alloc($1, $3, true); } | expr opSTRNE expr { $$ = StreqExprNode::alloc($1, $3, false); } | expr '@' expr { $$ = StrcatExprNode::alloc($1, $3, $2); } | '!' expr { $$ = IntUnaryExprNode::alloc($1, $2); } | '~' expr { $$ = IntUnaryExprNode::alloc($1, $2); } | TAGATOM { $$ = StrConstNode::alloc($1, true); } | FLTCONST { $$ = FloatNode::alloc($1); } | INTCONST { $$ = IntNode::alloc($1); } | rwBREAK { $$ = ConstantNode::alloc(StringTable->insert("break")); } | slot_acc { $$ = SlotAccessNode::alloc($1.object, $1.array, $1.slotName); } | IDENT { $$ = ConstantNode::alloc($1); } | STRATOM { $$ = StrConstNode::alloc($1, false); } | VAR { $$ = (ExprNode*)VarNode::alloc($1, NULL); } | VAR '[' aidx_expr ']' { $$ = (ExprNode*)VarNode::alloc($1, $3); } ; slot_acc : expr '.' IDENT { $$.object = $1; $$.slotName = $3; $$.array = NULL; } | expr '.' IDENT '[' aidx_expr ']' { $$.object = $1; $$.slotName = $3; $$.array = $5; } ; class_name_expr : IDENT { $$ = ConstantNode::alloc($1); } | '(' expr ')' { $$ = $2; } ; assign_op_struct : opPLUSPLUS { $$.token = '+'; $$.expr = FloatNode::alloc(1); } | opMINUSMINUS { $$.token = '-'; $$.expr = FloatNode::alloc(1); } | opPLASN expr { $$.token = '+'; $$.expr = $2; } | opMIASN expr { $$.token = '-'; $$.expr = $2; } | opMLASN expr { $$.token = '*'; $$.expr = $2; } | opDVASN expr { $$.token = '/'; $$.expr = $2; } | opMODASN expr { $$.token = '%'; $$.expr = $2; } | opANDASN expr { $$.token = '&'; $$.expr = $2; } | opXORASN expr { $$.token = '^'; $$.expr = $2; } | opORASN expr { $$.token = '|'; $$.expr = $2; } | opSLASN expr { $$.token = opSHL; $$.expr = $2; } | opSRASN expr { $$.token = opSHR; $$.expr = $2; } ; stmt_expr : funcall_expr { $$ = $1; } | object_decl { $$ = $1; } | VAR '=' expr { $$ = AssignExprNode::alloc($1, NULL, $3); } | VAR '[' aidx_expr ']' '=' expr { $$ = AssignExprNode::alloc($1, $3, $6); } | VAR assign_op_struct { $$ = AssignOpExprNode::alloc($1, NULL, $2.expr, $2.token); } | VAR '[' aidx_expr ']' assign_op_struct { $$ = AssignOpExprNode::alloc($1, $3, $5.expr, $5.token); } | slot_acc assign_op_struct { $$ = SlotAssignOpNode::alloc($1.object, $1.slotName, $1.array, $2.token, $2.expr); } | slot_acc '=' expr { $$ = SlotAssignNode::alloc($1.object, $1.array, $1.slotName, $3); } | slot_acc '=' '{' expr_list '}' { $$ = SlotAssignNode::alloc($1.object, $1.array, $1.slotName, $4); } ; funcall_expr : IDENT '(' expr_list_decl ')' { $$ = FuncCallExprNode::alloc($1, NULL, $3, false); } | IDENT opCOLONCOLON IDENT '(' expr_list_decl ')' { $$ = FuncCallExprNode::alloc($3, $1, $5, false); } | expr '.' IDENT '(' expr_list_decl ')' { $1->append($5); $$ = FuncCallExprNode::alloc($3, NULL, $1, true); } ; expr_list_decl : { $$ = NULL; } | expr_list { $$ = $1; } ; expr_list : expr { $$ = $1; } | expr_list ',' expr { ($1)->append($3); $$ = $1; } ; slot_assign_list : slot_assign { $$ = $1; } | slot_assign_list slot_assign { $1->append($2); $$ = $1; } ; slot_assign : IDENT '=' expr semicolon { $$ = SlotAssignNode::alloc(NULL, NULL, $1, $3); } | rwDATABLOCK '=' expr semicolon { $$ = SlotAssignNode::alloc(NULL, NULL, StringTable->insert("datablock"), $3); } | IDENT '[' aidx_expr ']' '=' expr semicolon { $$ = SlotAssignNode::alloc(NULL, $3, $1, $6); } ; aidx_expr : expr { $$ = $1; } | aidx_expr ',' expr { $$ = CommaCatExprNode::alloc($1, $3); } ; semicolon: | semicolon ';' ; %%