%{ #include #include #include #include #include #include "node.h" #include "ir.h" static void yyerror(const char*); int yylex(void); static enum operator addop_to_oper(const char *op); static enum operator mulop_to_oper(const char *op); static enum operator relop_to_oper(const char *op); static enum operator boolop_to_oper(const char *op); extern int lineno; struct node *root_node; %} %start start %token ID NUM INT VOID IF ELSE WHILE FOR RETURN PTR ASM %token DEREF ADDROF NEGATE NOT ADDOP MULOP RELOP BOOLOP ASSIGN %token NEWLINE // only sent in asm mode %token ASMINS0 ASMINS1 ASMINS2 ASMINS_NAME ASMREG ASMVARNAME %left ASSIGN %left BOOLOP %left RELOP %left ADDOP %left MULOP %left NOT NEGATE DEREF ADDROF %type ID NUM ADDOP MULOP RELOP BOOLOP ASMVARNAME %type toplevel toplevel_decl var_decl func_decl parameter_list parameter_list_rest %type parameter block statement statement_list open_statement matched_statement %type other_statement expression atom_expr expression_list %type asm_statement_list_terminated asm_statement_list_terminated_trailer asm_statement %type type INT VOID %type ASMINS0 ASMINS1 ASMINS2 ASMINS_NAME %type ASMREG asm_arg %union { char *id; struct node *node; struct type *type; enum instype instype; struct ref ref; } %destructor { free($$); } %destructor { node_delete_recursive($$); } %destructor { irins_delete($$); } %% start: toplevel { root_node = $1; } ; toplevel: toplevel_decl toplevel { $$ = node_make_2(N_LIST, $1, $2); } | toplevel_decl { $$ = $1; } ; toplevel_decl: var_decl | func_decl ; var_decl: type ID ASSIGN expression ';' { $$ = node_make_1(N_VAR_DECL_INIT, $4); $$->rtype = $1; $$->name = $2; } | type ID ';' { $$ = node_make_0(N_VAR_DECL); $$->rtype = $1; $$->name = $2; } ; func_decl: type ID '(' parameter_list ')' block { $$ = node_make_2(N_FUNC_DECL, $4, $6); $$->rtype = $1; $$->name = $2; } ; type: type PTR { $$ = type_ptr($1); } | INT { $$ = type_int(16); } | VOID { $$ = type_void(); } ; parameter_list: { $$ = node_make_0(N_LIST_END); } | parameter parameter_list_rest { $$ = node_make_2(N_LIST, $1, $2); } ; parameter_list_rest: { $$ = node_make_0(N_LIST_END); } | ',' parameter parameter_list_rest { $$ = node_make_2(N_LIST, $2, $3); } ; parameter: type ID { $$ = node_make_0(N_VAR_DECL); $$->rtype = $1; $$->name = $2; } ; block: '{' '}' { $$ = node_make_1(N_BLOCK, node_make_0(N_LIST_END)); } | '{' statement_list '}' { $$ = node_make_1(N_BLOCK, $2); } ; statement_list: statement { $$ = node_make_2(N_LIST, $1, node_make_0(N_LIST_END)); } | statement statement_list { $$ = node_make_2(N_LIST, $1, $2); } ; statement: open_statement | matched_statement ; open_statement: IF '(' expression ')' statement { $$ = node_make_3(N_IF, $3, $5, node_make_0(N_LIST_END)); } | IF '(' expression ')' matched_statement ELSE open_statement { $$ = node_make_3(N_IF, $3, $5, $7); } | WHILE '(' expression ')' open_statement { $$ = node_make_2(N_WHILE, $3, $5); } /*| FOR '(' statement ';' expression ';' statement ')' open_statement { $$ = node_make_1(N_BLOCK, node_make_list( $3, node_make_2(N_WHILE, $5, node_make_list($9, $7)))); }*/ ; matched_statement: IF '(' expression ')' matched_statement ELSE matched_statement { $$ = node_make_3(N_IF, $3, $5, $7); } | WHILE '(' expression ')' matched_statement { $$ = node_make_2(N_WHILE, $3, $5); } /*| FOR '(' statement ';' expression ';' statement ')' matched_statement { $$ = node_make_1(N_BLOCK, node_make_list( $3, node_make_2(N_WHILE, $5, node_make_list($9, $7)))); }*/ | other_statement ; other_statement: var_decl | expression ';' | block | RETURN ';' { $$ = node_make_0(N_RETURN); } | RETURN expression ';' { $$ = node_make_1(N_RETURNV, $2); } | ASM '{' newlines '}' { $$ = node_make_0(N_LIST_END); } | ASM '{' newlines asm_statement_list_terminated { $$ = $4; } ; expression: atom_expr | NOT expression { $$ = node_make_1(N_UNOP, $2); $$->oper = OP_NOT; } | NEGATE expression { $$ = node_make_1(N_UNOP, $2); $$->oper = OP_NEG; } | DEREF expression { $$ = node_make_1(N_UNOP, $2); $$->oper = OP_DEREF; } | ADDROF expression { $$ = node_make_1(N_UNOP, $2); $$->oper = OP_ADDROF; } | expression ADDOP expression { $$ = node_make_2(N_BINOP, $1, $3); $$->oper = addop_to_oper($2); free($2); } | expression MULOP expression { $$ = node_make_2(N_BINOP, $1, $3); $$->oper = mulop_to_oper($2); free($2); } | expression RELOP expression { $$ = node_make_2(N_BINOP, $1, $3); $$->oper = relop_to_oper($2); free($2); } | expression BOOLOP expression { $$ = node_make_2(N_BINOP, $1, $3); $$->oper = boolop_to_oper($2); free($2); } | atom_expr ASSIGN expression { $$ = node_make_2(N_BINOP, $1, $3); $$->oper = OP_ASSIGN; } ; atom_expr: NUM { $$ = node_make_0(N_NUM); $$->value = strtol($1, NULL, 10); free($1); } | ID { $$ = node_make_0(N_VAR); $$->name = $1; } | '(' expression ')' { $$ = $2; } | ID '(' expression_list ')' { $$ = node_make_1(N_CALL, $3); $$->name = $1; } | atom_expr '[' expression ']' { $$ = node_make_1(N_UNOP, node_make_2(N_BINOP, $1, $3)); $$->child2->oper = OP_ADD; $$->oper = OP_DEREF; } ; expression_list: expression { $$ = node_make_2(N_LIST, $1, node_make_0(N_LIST_END)); } | expression ',' expression_list { $$ = node_make_2(N_LIST, $1, $3); } ; newlines: | NEWLINE newlines ; asm_statement_list_terminated: asm_statement NEWLINE newlines asm_statement_list_terminated_trailer { $$ = node_make_2(N_LIST, $1, $4); } | asm_statement '}' { $$ = node_make_2(N_LIST, $1, node_make_0(N_LIST_END)); } ; asm_statement_list_terminated_trailer: asm_statement_list_terminated | '}' { $$ = node_make_0(N_LIST_END); } ; asm_statement: ID ':' { $$ = node_make_0(N_IRINS); $$->irins = irins_make_name(INS_LBL, $1); } | ASMINS0 { $$ = node_make_0(N_IRINS); $$->irins = irins_make($1); } | ASMINS1 asm_arg { $$ = node_make_0(N_IRINS); struct irins *ins; switch ($1) { case INS_NEG: ins = irins_make_01($1, $2, $2); break; case INS_NOT: ins = irins_make_01($1, $2, $2); break; case INS_PUSH: ins = irins_make_1($1, $2); break; case INS_POP: ins = irins_make_0($1, $2); break; case INS_HWI: ins = irins_make_1($1, $2); break; default: assert(false); } $$->irins = ins; } | ASMINS2 asm_arg ',' asm_arg { $$ = node_make_0(N_IRINS); struct irins *ins; switch ($1) { case INS_ADD: ins = irins_make_012($1, $2, $2, $4); break; case INS_SUB: ins = irins_make_012($1, $2, $2, $4); break; case INS_MUL: ins = irins_make_012($1, $2, $2, $4); break; case INS_DIV: ins = irins_make_012($1, $2, $2, $4); break; case INS_MOD: ins = irins_make_012($1, $2, $2, $4); break; case INS_TEST: ins = irins_make_12($1, $2, $4); break; case INS_CMP: ins = irins_make_12($1, $2, $4); break; case INS_MOV: ins = irins_make_01($1, $2, $4); break; default: assert(false); } $$->irins = ins; } | ASMINS_NAME ID { $$ = node_make_0(N_IRINS); $$->irins = irins_make_name($1, $2); } ; asm_arg: ASMREG | NUM { $$ = ref_imm(strtol($1, NULL, 0)); } | ASMVARNAME { $$ = ref_varname($1); } | '[' NUM ']' { $$ = ref_mem(REG_UNUSED, strtol($2, NULL, 0), REFREL_ZERO); } | '[' ASMREG ']' { $$ = ref_mem($2.reg, 0, REFREL_ZERO); } | '[' ASMREG '+' NUM ']' { $$ = ref_mem($2.reg, strtol($4, NULL, 0), REFREL_ZERO); } | '[' ASMREG '-' NUM ']' { $$ = ref_mem($2.reg, -strtol($4, NULL, 0), REFREL_ZERO); } %% static void yyerror(const char *s) { fprintf(stderr, "Parse error: %s\n", s); exit(1); } static enum operator addop_to_oper(const char *op) { if (strcmp(op, "+") == 0) return OP_ADD; else if (strcmp(op, "-") == 0) return OP_SUB; else assert(false); } static enum operator mulop_to_oper(const char *op) { if (strcmp(op, "*") == 0) return OP_MUL; else if (strcmp(op, "/") == 0) return OP_DIV; else if (strcmp(op, "%") == 0) return OP_MOD; else assert(false); } static enum operator relop_to_oper(const char *op) { if (strcmp(op, "==") == 0) return OP_EQ; else if (strcmp(op, "!=") == 0) return OP_NEQ; else if (strcmp(op, "<") == 0) return OP_LT; else if (strcmp(op, ">") == 0) return OP_GT; else if (strcmp(op, "<=") == 0) return OP_LEQ; else if (strcmp(op, ">=") == 0) return OP_GEQ; else assert(false); } static enum operator boolop_to_oper(const char *op) { if (strcmp(op, "&&") == 0) return OP_AND; else if (strcmp(op, "||") == 0) return OP_OR; else assert(false); } /* vim:et:ts=4:sw=4 */