%{ #include #include #include #include "defs.h" #include "symtab.h" #include "codegen.h" int yyparse(void); int yylex(void); int yyerror(char *s); void warning(char *s); extern int yylineno; int out_lin = 0; char char_buffer[CHAR_BUFFER_LENGTH]; int error_count = 0; int warning_count = 0; int var_num = 0; int fun_idx = -1; int fcall_idx = -1; int lab_num = -1; FILE *output; int tip; int isReturn=0; int reg = -1; int checkId = -1; int checkVar = -1; int caseVal = -1; int current_block_var = -1; int block_idx = -1; int param_cnt = 0; int args_cnt = 0; int arg_val = 0; int declarationIdx = -1; int check_type = 0; int checkIdx = 0; char checkLiteralts[100][10]; int numberOfLitInCheck = -1; %} %union { int i; char *s; } %token _TYPE %token _IF %token _ELSE %token _RETURN %token _ID %token _INT_NUMBER %token _UINT_NUMBER %token _LPAREN %token _RPAREN %token _LBRACKET %token _RBRACKET %token _ASSIGN %token _SEMICOLON %token _COMMA %token _INC %token _DVOTACKA %token _LOOP %token _PUKA %token _MANAWA %token _HOPAU %token _CHECK %token _LSQBRACKET %token _RSQBRACKET %token _WHEN %token _ARROW %token _BREAK %token _DEFAULT %token _QMARK %token _AROP %token _RELOP %type num_exp cond_operator exp literal argument_list post_increment when when_list %type function_call argument rel_exp if_part %nonassoc ONLY_IF %nonassoc _ELSE %% program : global_variable_list function_list { if(lookup_symbol("main", FUN) == NO_INDEX) err("undefined reference to 'main'"); } ; global_variable_list : /*empty*/ | global_variable_list global_variable ; global_variable : _TYPE _ID _SEMICOLON { if(lookup_symbol($2, GVAR) == NO_INDEX) insert_symbol($2, GVAR, $1, NO_ATR, NO_ATR); else err("redefinition of '%s'", $2); code("\n%s:", $2); code("\n\tWORD 1"); } ; function_list : function | function_list function ; function : _TYPE _ID { fun_idx = lookup_symbol($2, FUN); if(fun_idx == NO_INDEX) fun_idx = insert_symbol($2, FUN, $1, NO_ATR, NO_ATR); else err("redefinition of function '%s'", $2); code("\n%s:", $2); code("\n\t\tPUSH\t%%14"); code("\n\t\tMOV \t%%15,%%14"); param_cnt = 0; } _LPAREN parameter _RPAREN body { if(isReturn == 2 && get_type(fun_idx) == VOID) err("function should not return value"); else if(isReturn == 1 && get_type(fun_idx) != VOID) warn("function should return value"); else if(isReturn == 0 && get_type(fun_idx) != VOID) warn("function should return value"); isReturn = 0; for(int i = fun_idx + 1; i < get_last_element(); i++) { if(get_atr2(i) == 0 && (get_kind(i) == VAR || get_kind(i) == PAR)) { printf("Variable '%s' not assigned", get_name(i)); } } clear_symbols(fun_idx + 1); var_num = 0; code("\n@%s_exit:", $2); code("\n\t\tMOV \t%%14,%%15"); code("\n\t\tPOP \t%%14"); code("\n\t\tRET"); } ; parameter : /* empty */ { set_atr1(fun_idx, param_cnt); } | parametar_list ; parametar_list : _TYPE _ID { int idx = insert_symbol($2, PAR, $1, ++param_cnt, NO_ATR); set_atr1(fun_idx, param_cnt); set_atr2(fun_idx, get_atr2(fun_idx) * 10 + $1); } | parametar_list _COMMA _TYPE _ID { int idx = lookup_symbol($4, PAR); if(idx == NO_INDEX) idx = insert_symbol($4, PAR, $3, ++param_cnt, NO_ATR); else err("redefinition of '%s'", $4); set_atr1(fun_idx, param_cnt); set_atr2(fun_idx, get_atr2(fun_idx) * 10 + $3); } ; body : _LBRACKET variable_list { if(var_num) code("\n\t\tSUBS\t%%15,$%d,%%15", 4*var_num); code("\n@%s_body:", get_name(fun_idx)); } statement_list _RBRACKET ; variable_list : /* empty */ | variable_list variables ; vars : _TYPE _ID { int idx = lookup_symbol($2, VAR|PAR); if(idx == NO_INDEX) current_block_var = insert_symbol($2, VAR, $1, ++var_num, block_idx); else if(idx != NO_INDEX && get_atr2(idx) == block_idx) err("redefinition of '%s'", $2); else current_block_var = insert_symbol($2, VAR, $1, ++var_num, block_idx); if($1 == VOID) { err("type of variable cannot be 'void'"); } tip = $1; declarationIdx = idx; } | vars _COMMA _ID { if(lookup_symbol($3, VAR|PAR) == NO_INDEX) current_block_var = insert_symbol($3, VAR, tip, ++var_num, block_idx); else err("redefinition of '%s'", $3); } ; variables : vars _SEMICOLON { } |vars _SEMICOLON _ASSIGN literal { for(int i = declarationIdx; i < get_last_element(); i++) { set_atr2(i, 1); //setovana je promenljiva } } ; statement_list : /* empty */ | statement_list statement ; statement : compound_statement | assignment_statement | if_statement | increment_statement | return_statement | loop_statement | check_statement ; compound_statement : _LBRACKET statement_list _RBRACKET ; check_statement : _CHECK _LSQBRACKET _ID _RSQBRACKET _LBRACKET { int idx = lookup_symbol($3, VAR|PAR); if(idx == NO_INDEX) err("invalid lvalue '%s' in check", $3); checkIdx= idx; code("\n@check%d:",checkIdx); for(int i = 0; i < 100; i++) strcpy(checkLiteralts[i], ""); numberOfLitInCheck = 0; } when_list default _RBRACKET { code("\n@check_exit%d:",checkIdx); } ; default : /*empty*/ { code("\n@default%d:", checkIdx); } | _DEFAULT _ARROW { code("\n@default%d:", checkIdx); } statement ; when : _WHEN literal _ARROW { if(get_type(checkIdx) != get_type($2)) err("invalid when expresion in check"); $$ = $2; int lit = atoi(get_name($2)); code("\n@check%d_when%d:", checkIdx, lit); gen_cmp(checkIdx, $2); code("\n\t\tJEQ\t@check%d_stmt%d", checkIdx, lit); code("\n\t\tJMP\t@check%d_stmt%d_exit", checkIdx, lit); code("\n@check%d_stmt%d:", checkIdx, lit); for(int i = 0; i < numberOfLitInCheck; i++) { if(strcmp(get_name($2), checkLiteralts[i]) == 0) { err("literal alredy defined."); break; } } strcpy(checkLiteralts[numberOfLitInCheck], get_name($2)); numberOfLitInCheck++; } statement break { int lit = atoi(get_name($2)); $$ = $4; code("\n@check%d_stmt%d_exit:", checkIdx, lit); } ; when_list : when { } | when_list when { } ; break : /*empty*/ | _BREAK _SEMICOLON { code("\n\t\tJMP @check_exit%d", checkIdx); } ; assignment_statement : _ID _ASSIGN num_exp _SEMICOLON { int idx = lookup_symbol($1, VAR|PAR|GVAR); if(idx == NO_INDEX) err("invalid lvalue '%s' in assignment", $1); else if(get_type(idx) != get_type($3)) err("incompatible types in assignment"); gen_mov($3, idx); set_atr2(idx, 1); } ; loop_statement : _LOOP { code("\nloop_statement%d:", ++lab_num); $$ = lab_num; } statement _PUKA _MANAWA _LPAREN { code("\nloop_condition%d:", $2); } rel_exp _RPAREN _HOPAU _LOOP _SEMICOLON { code("\n\t\t%s loop_statement%d", jumps[$8], $2); } ; post_increment : _ID _INC { int idx = lookup_symbol($1, VAR|PAR|FUN|GVAR); if(idx == NO_INDEX) err("invalid lvalue '%s' in increment", $1); if(get_kind(idx) == FUN) { err("increment can't be called on function"); } int reg = take_reg(); gen_mov(idx, reg); if(get_type(idx) == INT) code("\n\t\tADDS\t"); else code("\n\t\tADDU\t"); gen_sym_name(idx); code(", $1, "); gen_sym_name(idx); $$=reg; } ; increment_statement : post_increment _SEMICOLON ; num_exp : exp | num_exp _AROP exp { if(get_type($1) != get_type($3)) err("invalid operands: arithmetic operation"); int t1 = get_type($1); code("\n\t\t%s\t", ar_instructions[$2 + (t1 - 1) * AROP_NUMBER]); gen_sym_name($1); code(","); gen_sym_name($3); code(","); free_if_reg($3); free_if_reg($1); $$ = take_reg(); gen_sym_name($$); set_type($$, t1); } ; exp : literal | _ID { $$ = lookup_symbol($1, VAR|PAR|GVAR); if($$ == NO_INDEX) err("'%s' undeclared", $1); } | function_call { $$ = take_reg(); gen_mov(FUN_REG, $$); } | _LPAREN num_exp _RPAREN { $$ = $2; } | post_increment { $$ = $1; } | cond_operator { $$ = reg; } ; literal : _INT_NUMBER { $$ = insert_literal($1, INT); } | _UINT_NUMBER { $$ = insert_literal($1, UINT); } ; function_call : _ID { fcall_idx = lookup_symbol($1, FUN); if(fcall_idx == NO_INDEX) err("'%s' is not a function", $1); } _LPAREN argument_list _RPAREN { if(get_atr1(fcall_idx) != args_cnt) err("wrong number of arguments"); if(get_atr2(fcall_idx) != arg_val) err("wrong argument types."); code("\n\t\t\tCALL\t%s", get_name(fcall_idx)); if(args_cnt > 0) code("\n\t\t\tADDS\t%%15,$%d,%%15", args_cnt * 4); set_type(FUN_REG, get_type(fcall_idx)); $$ = FUN_REG; args_cnt = 0; arg_val = 0; } ; argument : /* empty */ { $$ = 0; } | num_exp { free_if_reg($1); code("\n\t\t\tPUSH\t"); gen_sym_name($1); arg_val = arg_val * 10 + get_type($1); args_cnt++; $$ = 1; } ; argument_list : argument { $$ = $1; } | argument_list _COMMA argument { $$ = $3; } ; cond_operator : _LPAREN rel_exp _RPAREN _QMARK { int lab = ++lab_num; reg = take_reg(); code("\n\t\t%s\t@false%d", opp_jumps[$2], lab_num); code("\n@true%d:", lab_num); } exp { gen_mov($6, reg); code("\nJMP\t\t@exit%d",lab_num); code("\n@false%d:", lab_num); } _DVOTACKA exp { gen_mov($9, reg); code("\n@exit%d:", lab_num); $$ = reg; } ; if_statement : if_part %prec ONLY_IF { code("\n@exit%d:", $1); } | if_part _ELSE statement { code("\n@exit%d:", $1); } ; if_part : _IF _LPAREN { $$ = ++lab_num; code("\n@if%d:", lab_num); } rel_exp { code("\n\t\t%s\t@false%d", opp_jumps[$4], $3); code("\n@true%d:", $3); } _RPAREN statement { code("\n\t\tJMP \t@exit%d", $3); code("\n@false%d:", $3); $$ = $3; } ; rel_exp : num_exp _RELOP num_exp { if(get_type($1) != get_type($3)) err("invalid operands: relational operator"); $$ = $2 + ((get_type($1) - 1) * RELOP_NUMBER); gen_cmp($1, $3); } ; return_statement : _RETURN num_exp _SEMICOLON { if(get_type(fun_idx) != get_type($2)) err("incompatible types in return"); isReturn = 2; gen_mov($2, FUN_REG); code("\n\t\tJMP \t@%s_exit", get_name(fun_idx)); } | _RETURN _SEMICOLON { isReturn = 1; } /*empty*/ { isReturn = 0; } ; %% int yyerror(char *s) { fprintf(stderr, "\nline %d: ERROR: %s", yylineno, s); error_count++; return 0; } void warning(char *s) { fprintf(stderr, "\nline %d: WARNING: %s", yylineno, s); warning_count++; } int main() { int synerr; init_symtab(); output = fopen("output.asm", "w+"); synerr = yyparse(); clear_symtab(); fclose(output); if(warning_count) printf("\n%d warning(s).\n", warning_count); if(error_count) { remove("output.asm"); printf("\n%d error(s).\n", error_count); } if(synerr) return -1; //syntax error else if(error_count) return error_count & 127; //semantic errors else if(warning_count) return (warning_count & 127) + 127; //warnings else return 0; //OK }