aboutsummaryrefslogtreecommitdiff
path: root/c.y
diff options
context:
space:
mode:
Diffstat (limited to 'c.y')
-rw-r--r--c.y105
1 files changed, 101 insertions, 4 deletions
diff --git a/c.y b/c.y
index 4de4cae..96866ef 100644
--- a/c.y
+++ b/c.y
@@ -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);
+ }
+
%%