- %{
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #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 <i> _TYPE
- %token _IF
- %token _ELSE
- %token _RETURN
- %token <s> _ID
- %token <s> _INT_NUMBER
- %token <s> _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 <i> _AROP
- %token <i> _RELOP
- %type <i> num_exp cond_operator exp literal argument_list post_increment when when_list
- %type <i> 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");
- $<i>$ = $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));
- $$ = $<i>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);
- $<i>$ = lab_num;
- }
- statement _PUKA _MANAWA _LPAREN
- {
- code("\nloop_condition%d:", $<i>2);
- }
- rel_exp _RPAREN _HOPAU _LOOP _SEMICOLON
- {
- code("\n\t\t%s loop_statement%d", jumps[$8], $<i>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
- {
- $<i>$ = ++lab_num;
- code("\n@if%d:", lab_num);
- }
- rel_exp
- {
- code("\n\t\t%s\t@false%d", opp_jumps[$4], $<i>3);
- code("\n@true%d:", $<i>3);
- }
- _RPAREN statement
- {
- code("\n\t\tJMP \t@exit%d", $<i>3);
- code("\n@false%d:", $<i>3);
- $$ = $<i>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
- }