%{ #include #include #include #include "symbol_table.h" #include "code_gen.h" #include "tree.h" %} %start Input %token FUNC END STRUCT VAR IF THEN ELSE WHILE DO RETURN OR NOT %token ID NUM ASSIGN GREATER @autoinh symbols stack_offset all_pars @autosyn node defined_vars immediate @attributes { char *name; } ID @attributes { long value; } NUM @attributes { struct symbol_t *fields; struct symbol_t *symbols; } Program @attributes { struct symbol_t *fields; } Structdef @attributes { struct symbol_t *fields; int offset; } Ids @attributes { struct symbol_t *pars; int num_pars; int all_pars; } Pars @attributes { struct symbol_t *symbols; int defined_vars; } Funcdef @attributes { struct symbol_t *symbols; int defined_vars; int stack_offset; } Stats @attributes { struct symbol_t *symbols; treenode *node; int immediate; } Expr Term Plusterm Malterm @attributes { struct symbol_t *symbols; treenode *node; } Bool Call Lexpr Field Bterm Orterm Exprs @attributes { struct symbol_t *in_symbols; struct symbol_t *out_symbols; treenode *node; int defined_vars; int stack_offset; } Stat @traversal @postorder check @traversal @preorder reg @traversal @postorder codegen %% Input: Program @{ @i @Program.symbols@ = @Program.fields@; @codegen @revorder(1) printf("\t.text\n"); @} ; Program: Funcdef ';' Program @{ @i @Program.fields@ = @Program.1.fields@; @} | Structdef ';' Program @{ @i @Program.fields@ = table_merge(@Structdef.fields@, @Program.1.fields@, 1); @i @Program.1.symbols@ = @Program.0.symbols@; @} | @{ @i @Program.fields@ = new_table(); @} ; Funcdef: FUNC ID '(' Pars ')' Stats END @{ @i @Stats.symbols@ = table_merge(@Funcdef.symbols@, @Pars.pars@, 0); @i @Stats.stack_offset@ = 0; @i @Pars.all_pars@ = @Pars.num_pars@; @codegen @revorder(1) function_header(@ID.name@); @} | FUNC ID '(' ')' Stats END @{ @i @Stats.symbols@ = table_merge(@Funcdef.symbols@, new_table(), 0); @i @Stats.stack_offset@ = 0; @codegen @revorder(1) function_header(@ID.name@); @} ; Structdef: STRUCT Ids END @{ @i @Structdef.fields@ = @Ids.fields@; @i @Ids.offset@ = 0; @} ; Ids: ID Ids @{ @i @Ids.fields@ = table_add_symbol(@Ids.1.fields@, @ID.name@, SYMBOL_TYPE_FIELD, 1, @Ids.offset@); @i @Ids.1.offset@ = @Ids.offset@ + 1; @} | @{ @i @Ids.fields@ = new_table(); @} ; Pars: Pars ',' ID @{ @i @Pars.pars@ = table_add_symbol(@Pars.1.pars@, @ID.name@, SYMBOL_TYPE_PARAM, 0, -@Pars.num_pars@); @i @Pars.num_pars@ = @Pars.1.num_pars@ + 1; @} | ID @{ @i @Pars.pars@ = table_add_symbol(new_table(), @ID.name@, SYMBOL_TYPE_PARAM, 0, -1); @i @Pars.num_pars@ = 1; @} ; Stats: Stat ';' Stats @{ @i @Stat.in_symbols@ = @Stats.symbols@; @i @Stats.1.symbols@ = @Stat.out_symbols@; @i @Stats.defined_vars@ = @Stat.defined_vars@ + @Stats.1.defined_vars@; @i @Stats.1.stack_offset@ = @Stats.stack_offset@ + @Stat.defined_vars@ * 8; @codegen /* write_tree(@Stat.node@, 0); */ burm_label(@Stat.node@); burm_reduce(@Stat.node@, 1); @} | @{ @i @Stats.defined_vars@ = 0; @} ; Stat: VAR ID ASSIGN Expr @{ @i @Stat.out_symbols@ = table_add_symbol(clone_table(@Stat.in_symbols@), @ID.name@, SYMBOL_TYPE_VAR, 0, 0); @i @Expr.symbols@ = @Stat.in_symbols@; @i @Stat.node@ = (treenode *)NULL; @i @Stat.defined_vars@ = 1; @} | Lexpr ASSIGN Expr @{ @i @Stat.out_symbols@ = @Stat.in_symbols@; @i @Lexpr.symbols@ = @Stat.in_symbols@; @i @Expr.symbols@ = @Stat.in_symbols@; @i @Stat.node@ = (treenode *)NULL; @i @Stat.defined_vars@ = 0; @} | IF Bool THEN Stats END @{ @i @Bool.symbols@ = @Stat.in_symbols@; @i @Stats.symbols@ = @Stat.in_symbols@; @i @Stat.out_symbols@ = @Stat.in_symbols@; @i @Stat.node@ = (treenode *)NULL; @} | IF Bool THEN Stats ELSE Stats END @{ @i @Bool.symbols@ = @Stat.in_symbols@; @i @Stats.symbols@ = @Stat.in_symbols@; @i @Stats.1.symbols@ = @Stat.in_symbols@; @i @Stat.out_symbols@ = @Stat.in_symbols@; @i @Stat.node@ = (treenode *)NULL; @i @Stat.defined_vars@ = @Stats.defined_vars@ + @Stats.1.defined_vars@; @} | WHILE Bool DO Stats END @{ @i @Bool.symbols@ = @Stat.in_symbols@; @i @Stats.symbols@ = @Stat.in_symbols@; @i @Stat.out_symbols@ = @Stat.in_symbols@; @i @Stat.node@ = (treenode *)NULL; @} | Call @{ @i @Call.symbols@ = @Stat.in_symbols@; @i @Stat.out_symbols@ = @Stat.in_symbols@; @i @Stat.node@ = (treenode *)NULL; @i @Stat.defined_vars@ = 0; @} | RETURN Expr @{ @i @Expr.symbols@ = @Stat.in_symbols@; @i @Stat.out_symbols@ = @Stat.in_symbols@; @i @Stat.node@ = new_node(OP_Return, @Expr.node@, (treenode *)NULL); @reg @Stat.node@->reg = get_next_reg((char *)NULL, 0); @Expr.node@->reg = @Stat.node@->reg; @i @Stat.defined_vars@ = 0; @} ; Lexpr: ID @{ @i @Lexpr.node@ = (treenode *)NULL; @check check_variable(@Lexpr.symbols@, @ID.name@); @} | Field ; Expr: '-' Term @{ @i @Expr.node@ = new_node(OP_Negation, @Term.node@, (treenode *)NULL); @reg @Term.node@->reg = @Expr.node@->reg; @} | Term @{ @reg @Term.node@->reg = @Expr.node@->reg; @} | Term Plusterm @{ @i @Expr.node@ = new_node(OP_Addition, @Term.node@, @Plusterm.node@); @i @Expr.immediate@ = @Term.immediate@ && @Plusterm.immediate@; @reg if(!@Plusterm.immediate@) { @Plusterm.node@->reg = @Expr.node@->reg; @Term.node@->reg = (@Term.node@->op==OP_ID && table_lookup(@Term.symbols@, @Term.node@->name)->type==SYMBOL_TYPE_PARAM) ? get_param_reg(-table_lookup(@Term.symbols@, @Term.node@->name)->stack_offset) : get_next_reg(@Plusterm.node@->reg, @Expr.node@->skip_reg); @Plusterm.node@->skip_reg = 1; } else { @Term.node@->reg = @Expr.node@->reg; @Plusterm.node@->reg = get_next_reg(@Term.node@->reg, @Expr.node@->skip_reg); } @} | Term Malterm @{ @i @Expr.node@ = new_node(OP_Multiplication, @Term.node@, @Malterm.node@); @i @Expr.immediate@ = @Term.immediate@ && @Malterm.immediate@; @reg if(!@Malterm.immediate@) { @Malterm.node@->reg = @Expr.node@->reg; @Term.node@->reg = (@Term.node@->op==OP_ID && table_lookup(@Term.symbols@, @Term.node@->name)->type==SYMBOL_TYPE_PARAM) ? get_param_reg(-table_lookup(@Term.symbols@, @Term.node@->name)->stack_offset) : get_next_reg(@Malterm.node@->reg, @Expr.node@->skip_reg); @Malterm.node@->skip_reg = 1; } else { @Term.node@-> reg = @Expr.node@->reg; @Malterm.node@->reg = get_next_reg(@Term.node@->reg, @Expr.node@->skip_reg); } @} ; Plusterm: '+' Term Plusterm @{ @i @Plusterm.node@ = new_node(OP_Addition, @Term.node@, @Plusterm.1.node@); @i @Plusterm.immediate@ = @Term.immediate@ && @Plusterm.1.immediate@; @reg @Plusterm.1.node@->reg = @Plusterm.node@->reg; @Term.node@->reg = (@Term.node@->op==OP_ID && table_lookup(@Term.symbols@, @Term.node@->name)->type==SYMBOL_TYPE_PARAM) ? get_param_reg(-table_lookup(@Term.symbols@, @Term.node@->name)->stack_offset) : get_next_reg(@Plusterm.1.node@->reg, @Plusterm.node@->skip_reg); @} | '+' Term @{ @reg @Term.node@->reg = @Plusterm.node@->reg; @} ; Malterm: '*' Term Malterm @{ @i @Malterm.node@ = new_node(OP_Multiplication, @Term.node@, @Malterm.1.node@); @i @Malterm.immediate@ = @Term.immediate@ && @Malterm.1.immediate@; @reg @Malterm.1.node@->reg = @Malterm.node@->reg; @Term.node@->reg = (@Term.node@->op==OP_ID && table_lookup(@Term.symbols@, @Term.node@->name)->type==SYMBOL_TYPE_PARAM) ? get_param_reg(-table_lookup(@Term.symbols@, @Term.node@->name)->stack_offset) : get_next_reg(@Malterm.1.node@->reg, @Malterm.node@->skip_reg); @} | '*' Term @{ @reg @Term.node@->reg = @Malterm.node@->reg; @} ; Term: '(' Expr ')' @{ @reg @Expr.node@->reg = @Term.node@->reg; @} | ID @{ @i @Term.node@ = new_named_leaf_value(OP_ID, @ID.name@, (table_lookup(@Term.symbols@, @ID.name@)==NULL) ? 0 : table_lookup(@Term.symbols@, @ID.name@)->stack_offset); @i @Term.immediate@ = 0; @check check_variable(@Term.symbols@, @ID.name@); @} | NUM @{ @i @Term.node@ = new_number_leaf(@NUM.value@); @i @Term.immediate@ = 1; @} | Call @{ @i @Term.immediate@ = 0; @} | Field @{ @i @Term.immediate@ = 0; @reg @Field.node@->reg = @Term.node@->reg; @} ; Bool: Bterm | Bterm Orterm @{ @i @Bool.node@ = new_node(OP_Disjunction, @Bterm.node@, @Orterm.node@); @} | NOT Bterm @{ @i @Bool.node@ = new_node(OP_Not, @Bterm.node@, (treenode *)NULL); @} ; Orterm: OR Bterm Orterm @{ @i @Orterm.node@ = new_node(OP_Disjunction, @Bterm.node@, @Orterm.1.node@); @} | OR Bterm ; Bterm: Term GREATER Term @{ @i @Bterm.node@ = new_node(OP_Greater, @Term.node@, @Term.1.node@); @} | Term '=' Term @{ @i @Bterm.node@ = new_node(OP_Equal, @Term.node@, @Term.1.node@); @} | '(' Bool ')' ; Field: Term '.' ID @{ @i @Field.node@ = new_node_value(OP_Field, @Term.node@, new_named_leaf(OP_ID, @ID.name@), table_lookup(@Field.symbols@, @ID.name@)==(struct symbol_t *)NULL ? 0 : table_lookup(@Field.symbols@, @ID.name@)->stack_offset); @check check_field(@Field.symbols@, @ID.name@); @reg @Term.node@->reg = @Field.node@->reg; @Field.node@->kids[1]->reg = get_next_reg(@Field.node@->reg, 0); @} ; Call: ID '(' Exprs ')' @{ @i @Call.node@ = new_node(OP_Call, new_named_leaf(OP_ID, @ID.name@), @Exprs.node@); @} | ID '(' ')' @{ @i @Call.node@ = new_node(OP_Call, new_named_leaf(OP_ID, @ID.name@), NULL); @} ; Exprs: Expr | Exprs ',' Expr @{ @i @Exprs.node@ = new_node(OP_Exprs, @Exprs.1.node@, @Expr.node@); @} ; %% extern int yylex(); extern int yylineno; int yyerror(char *error_text) { fprintf(stderr,"Line %i: %s\n",yylineno, error_text); exit(2); } int main(int argc, char **argv) { yyparse(); return 0; }