diff options
Diffstat (limited to 'c.y')
-rw-r--r-- | c.y | 105 |
1 files changed, 101 insertions, 4 deletions
@@ -6,6 +6,7 @@ #include <string.h> #include <assert.h> #include "node.h" +#include "ir.h" static void yyerror(const char*); @@ -24,8 +25,10 @@ struct node *root_node; %start start -%token ID NUM INT VOID IF ELSE WHILE FOR RETURN PTR +%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 @@ -34,20 +37,26 @@ struct node *root_node; %left MULOP %left NOT NEGATE DEREF ADDROF -%type <id> ID NUM ADDOP MULOP RELOP BOOLOP +%type <id> ID NUM ADDOP MULOP RELOP BOOLOP ASMVARNAME %type <node> toplevel toplevel_decl var_decl func_decl parameter_list parameter_list_rest %type <node> parameter block statement statement_list open_statement matched_statement %type <node> other_statement expression atom_expr expression_list +%type <node> asm_statement_list_terminated asm_statement_list_terminated_trailer asm_statement %type <type> type INT VOID +%type <instype> ASMINS0 ASMINS1 ASMINS2 ASMINS_NAME +%type <ref> ASMREG asm_arg %union { char *id; struct node *node; struct type *type; + enum instype instype; + struct ref ref; } %destructor { free($$); } <id> %destructor { node_delete_recursive($$); } <node> +%destructor { irins_delete($$); } <irins> %% @@ -155,7 +164,14 @@ other_statement: } | 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; } @@ -209,13 +225,94 @@ atom_expr: NUM { $$->oper = OP_DEREF; } ; -expression_list: expression { +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); + } + %% |