%pure-parser %name-prefix="nseel" %parse-param { compileContext* context } %lex-param { void* scanner } /* this will prevent y.tab.c from ever calling yydestruct(), since we do not use it and it is a waste */ %destructor { #define yydestruct(a,b,c,d,e) } VALUE %{ #ifdef _WIN32 #include #endif #include #include #include #include #include "y.tab.h" #include "ns-eel-int.h" #define scanner context->scanner #define YY_(x) ("") %} %token VALUE IDENTIFIER TOKEN_SHL TOKEN_SHR %token TOKEN_LTE TOKEN_GTE TOKEN_EQ TOKEN_EQ_EXACT TOKEN_NE TOKEN_NE_EXACT TOKEN_LOGICAL_AND TOKEN_LOGICAL_OR %token TOKEN_ADD_OP TOKEN_SUB_OP TOKEN_MOD_OP TOKEN_OR_OP TOKEN_AND_OP TOKEN_XOR_OP TOKEN_DIV_OP TOKEN_MUL_OP TOKEN_POW_OP %token STRING_LITERAL STRING_IDENTIFIER %expect 75 %start program %% more_params: expression | expression ',' more_params { $$ = nseel_createMoreParametersOpcode(context,$1,$3); } ; string: STRING_LITERAL | STRING_LITERAL string { ((struct eelStringSegmentRec *)$1)->_next = (struct eelStringSegmentRec *)$2; $$ = $1; } ; assignable_value: IDENTIFIER { if (!($$ = nseel_resolve_named_symbol(context, $1, -1, NULL))) /* convert from purely named to namespace-relative, etc */ { yyerror(&yyloc, context, ""); YYERROR; } } /* we used to have VALUE in here rather than rvalue, to allow 1=1 1+=2 etc, but silly to, though this breaks Vmorph, which does 1=1 for a nop, and Jonas DrumReaplacer, which does x = 0 = y = 0 */ | '(' expression ')' { $$ = $2; } | IDENTIFIER '(' expression ')' '(' expression ')' { int err; if (!($$ = nseel_setCompiledFunctionCallParameters(context,$1, $3, 0, 0, $6, &err))) { if (err == -1) yyerror(&yylsp[-2], context, ""); else if (err == 0) yyerror(&yylsp[-6], context, ""); else yyerror(&yylsp[-3], context, ""); // parameter count wrong YYERROR; } } | IDENTIFIER '(' expression ')' { int err; if (!($$ = nseel_setCompiledFunctionCallParameters(context,$1, $3, 0, 0, 0, &err))) { if (err == 0) yyerror(&yylsp[-3], context, ""); else yyerror(&yylsp[0], context, ""); // parameter count wrong YYERROR; } } | IDENTIFIER '(' ')' { int err; if (!($$ = nseel_setCompiledFunctionCallParameters(context,$1, nseel_createCompiledValue(context,0.0), 0, 0, 0,&err))) { if (err == 0) yyerror(&yylsp[-2], context, ""); // function not found else yyerror(&yylsp[0], context, ""); // parameter count wrong YYERROR; } } | IDENTIFIER '(' expression ',' expression ')' { int err; if (!($$ = nseel_setCompiledFunctionCallParameters(context,$1, $3, $5, 0, 0,&err))) { if (err == 0) yyerror(&yylsp[-5], context, ""); else if (err == 2) yyerror(&yylsp[0], context, ""); // needs more than 2 parameters else yyerror(&yylsp[-2], context, ""); // less than 2 YYERROR; } } | IDENTIFIER '(' expression ',' expression ',' more_params ')' { int err; if (!($$ = nseel_setCompiledFunctionCallParameters(context,$1, $3, $5, $7, 0, &err))) { if (err == 0) yyerror(&yylsp[-7], context, ""); else if (err==2) yyerror(&yylsp[0], context, ""); // needs more parameters else if (err==4) yyerror(&yylsp[-4], context, ""); // needs single parameter else yyerror(&yylsp[-2], context, ""); // less parm YYERROR; } } | rvalue '[' ']' { $$ = nseel_createMemoryAccess(context,$1,0); } | rvalue '[' expression ']' { $$ = nseel_createMemoryAccess(context,$1,$3); } ; rvalue: VALUE | STRING_IDENTIFIER | string { $$ = nseel_eelMakeOpcodeFromStringSegments(context,(struct eelStringSegmentRec *)$1); } | assignable_value ; assignment: rvalue | assignable_value '=' if_else_expr { $$ = nseel_createSimpleCompiledFunction(context,FN_ASSIGN,2,$1,$3); } | assignable_value TOKEN_ADD_OP if_else_expr { $$ = nseel_createSimpleCompiledFunction(context,FN_ADD_OP,2,$1,$3); } | assignable_value TOKEN_SUB_OP if_else_expr { $$ = nseel_createSimpleCompiledFunction(context,FN_SUB_OP,2,$1,$3); } | assignable_value TOKEN_MOD_OP if_else_expr { $$ = nseel_createSimpleCompiledFunction(context,FN_MOD_OP,2,$1,$3); } | assignable_value TOKEN_OR_OP if_else_expr { $$ = nseel_createSimpleCompiledFunction(context,FN_OR_OP,2,$1,$3); } | assignable_value TOKEN_AND_OP if_else_expr { $$ = nseel_createSimpleCompiledFunction(context,FN_AND_OP,2,$1,$3); } | assignable_value TOKEN_XOR_OP if_else_expr { $$ = nseel_createSimpleCompiledFunction(context,FN_XOR_OP,2,$1,$3); } | assignable_value TOKEN_DIV_OP if_else_expr { $$ = nseel_createSimpleCompiledFunction(context,FN_DIV_OP,2,$1,$3); } | assignable_value TOKEN_MUL_OP if_else_expr { $$ = nseel_createSimpleCompiledFunction(context,FN_MUL_OP,2,$1,$3); } | assignable_value TOKEN_POW_OP if_else_expr { $$ = nseel_createSimpleCompiledFunction(context,FN_POW_OP,2,$1,$3); } | STRING_IDENTIFIER '=' if_else_expr { $$ = nseel_createFunctionByName(context,"strcpy",2,$1,$3,NULL); } | STRING_IDENTIFIER TOKEN_ADD_OP if_else_expr { $$ = nseel_createFunctionByName(context,"strcat",2,$1,$3,NULL); } ; unary_expr: assignment | '+' unary_expr { $$ = $2; } | '-' unary_expr { $$ = nseel_createSimpleCompiledFunction(context,FN_UMINUS,1,$2,0); } | '!' unary_expr { $$ = nseel_createSimpleCompiledFunction(context,FN_NOT,1,$2,0); } ; pow_expr: unary_expr | pow_expr '^' unary_expr { $$ = nseel_createSimpleCompiledFunction(context,FN_POW,2,$1,$3); } ; mod_expr: pow_expr | mod_expr '%' pow_expr { $$ = nseel_createSimpleCompiledFunction(context,FN_MOD,2,$1,$3); } | mod_expr TOKEN_SHL pow_expr { $$ = nseel_createSimpleCompiledFunction(context,FN_SHL,2,$1,$3); } | mod_expr TOKEN_SHR pow_expr { $$ = nseel_createSimpleCompiledFunction(context,FN_SHR,2,$1,$3); } ; div_expr: mod_expr | div_expr '/' mod_expr { $$ = nseel_createSimpleCompiledFunction(context,FN_DIVIDE,2,$1,$3); } ; mul_expr: div_expr | mul_expr '*' div_expr { $$ = nseel_createSimpleCompiledFunction(context,FN_MULTIPLY,2,$1,$3); } ; sub_expr: mul_expr | sub_expr '-' mul_expr { $$ = nseel_createSimpleCompiledFunction(context,FN_SUB,2,$1,$3); } ; add_expr: sub_expr | add_expr '+' sub_expr { $$ = nseel_createSimpleCompiledFunction(context,FN_ADD,2,$1,$3); } ; andor_expr: add_expr | andor_expr '&' add_expr { $$ = nseel_createSimpleCompiledFunction(context,FN_AND,2,$1,$3); } | andor_expr '|' add_expr { $$ = nseel_createSimpleCompiledFunction(context,FN_OR,2,$1,$3); } | andor_expr '~' add_expr { $$ = nseel_createSimpleCompiledFunction(context,FN_XOR,2,$1,$3); } ; cmp_expr: andor_expr | cmp_expr '<' andor_expr { $$ = nseel_createSimpleCompiledFunction(context,FN_LT,2,$1,$3); } | cmp_expr '>' andor_expr { $$ = nseel_createSimpleCompiledFunction(context,FN_GT,2,$1,$3); } | cmp_expr TOKEN_LTE andor_expr { $$ = nseel_createSimpleCompiledFunction(context,FN_LTE,2,$1,$3); } | cmp_expr TOKEN_GTE andor_expr { $$ = nseel_createSimpleCompiledFunction(context,FN_GTE,2,$1,$3); } | cmp_expr TOKEN_EQ andor_expr { $$ = nseel_createSimpleCompiledFunction(context,FN_EQ,2,$1,$3); } | cmp_expr TOKEN_EQ_EXACT andor_expr { $$ = nseel_createSimpleCompiledFunction(context,FN_EQ_EXACT,2,$1,$3); } | cmp_expr TOKEN_NE andor_expr { $$ = nseel_createSimpleCompiledFunction(context,FN_NE,2,$1,$3); } | cmp_expr TOKEN_NE_EXACT andor_expr { $$ = nseel_createSimpleCompiledFunction(context,FN_NE_EXACT,2,$1,$3); } ; logical_and_or_expr: cmp_expr | logical_and_or_expr TOKEN_LOGICAL_AND cmp_expr { $$ = nseel_createSimpleCompiledFunction(context,FN_LOGICAL_AND,2,$1,$3); } | logical_and_or_expr TOKEN_LOGICAL_OR cmp_expr { $$ = nseel_createSimpleCompiledFunction(context,FN_LOGICAL_OR,2,$1,$3); } ; if_else_expr: logical_and_or_expr | logical_and_or_expr '?' if_else_expr ':' if_else_expr { $$ = nseel_createIfElse(context, $1, $3, $5); } | logical_and_or_expr '?' ':' if_else_expr { $$ = nseel_createIfElse(context, $1, 0, $4); } | logical_and_or_expr '?' if_else_expr { $$ = nseel_createIfElse(context, $1, $3, 0); } ; expression: if_else_expr | expression ';' if_else_expr { $$ = nseel_createSimpleCompiledFunction(context,FN_JOIN_STATEMENTS,2,$1,$3); } | expression ';' { $$ = $1; } ; program: expression { if (@1.first_line) { } context->result = $1; } ; %%