aboutsummaryrefslogtreecommitdiff
path: root/compiler.c
diff options
context:
space:
mode:
Diffstat (limited to 'compiler.c')
-rw-r--r--compiler.c95
1 files changed, 76 insertions, 19 deletions
diff --git a/compiler.c b/compiler.c
index 34372f3..ea9f768 100644
--- a/compiler.c
+++ b/compiler.c
@@ -32,7 +32,7 @@ static bool oper_is_comparison(enum operator oper) {
static struct ref compile_expr(struct ir *ir, struct symtab *symtab, struct node *node);
static void compile_boolexpr(
- struct ir *ir, struct symtab *symtab, struct node *node, char *truedest, char *falsedest) {
+ struct ir *ir, struct symtab *symtab, struct node *node, const char *truedest, const char *falsedest) {
if (node->type == N_BINOP && oper_is_comparison(node->oper)) {
struct ref r1 = compile_expr(ir, symtab, node->child1);
@@ -51,12 +51,12 @@ static void compile_boolexpr(
ir_append(ir, irins_make_jcc(falsedest, condcode));
ir_append(ir, irins_make_name(INS_JMP, truedest));
} else if (node->type == N_BINOP && node->oper == OP_AND) {
- char *try2lbl = gen_label_name();
+ const char *try2lbl = gen_label_name();
compile_boolexpr(ir, symtab, node->child1, try2lbl, falsedest);
ir_append(ir, irins_make_name(INS_LBL, try2lbl));
compile_boolexpr(ir, symtab, node->child2, truedest, falsedest);
} else if (node->type == N_BINOP && node->oper == OP_OR) {
- char *try2lbl = gen_label_name();
+ const char *try2lbl = gen_label_name();
compile_boolexpr(ir, symtab, node->child1, truedest, try2lbl);
ir_append(ir, irins_make_name(INS_LBL, try2lbl));
compile_boolexpr(ir, symtab, node->child2, truedest, falsedest);
@@ -108,9 +108,9 @@ static struct ref compile_expr(struct ir *ir, struct symtab *symtab, struct node
ir_append(ir, irins_make_012(instype, r0, r1, r2));
return r0;
} else if (oper_is_comparison(node->oper) || node->oper == OP_AND || node->oper == OP_OR) {
- char *truelbl = gen_label_name();
- char *falselbl = gen_label_name();
- char *afterlbl = gen_label_name();
+ const char *truelbl = gen_label_name();
+ const char *falselbl = gen_label_name();
+ const char *afterlbl = gen_label_name();
compile_boolexpr(ir, symtab, node, truelbl, falselbl);
struct ref cval = ref_next_register();
ir_append(ir, irins_make_name(INS_LBL, truelbl));
@@ -207,7 +207,7 @@ static struct ref compile_expr(struct ir *ir, struct symtab *symtab, struct node
} else {
retref = ref_next_register();
struct irins *ins = irins_make_0(INS_CALLV, retref);
- ins->name = strdup(node->name);
+ ins->name = ir_str(node->name);
ir_append(ir, ins);
}
ir_append(ir, irins_make_012(INS_ADD, ref_reg(REG_SP), ref_reg(REG_SP), ref_imm(sym->numparams)));
@@ -246,38 +246,50 @@ static void compile_node(struct ir *ir, struct symtab *symtab, struct node *node
struct ref vref;
if (node->type == N_VAR_DECL_INIT) vref = compile_expr(ir, symtab, node->child1);
else vref = ref_imm(0);
- struct symbol *sym = symbol_make_var(node->name, node->rtype);
- sym->ref = ref_next_register();
+ struct symbol *sym = symbol_make_var(strdup(node->name), node->rtype);
+ if (symtab->parent == NULL) sym->ref = ir_reserve_global(ir, 1);
+ else sym->ref = ref_next_register();
symtab_insert(symtab, sym);
ir_append(ir, irins_make_01(INS_MOV, sym->ref, vref));
break;
}
case N_FUNC_DECL: {
+ if (memcmp(node->name, "__", 2) == 0) {
+ fprintf(stderr, "Invalid function name '%s' (cannot start with '__')\n", node->name);
+ exit(1);
+ }
if (symtab_find(symtab, node->name)) {
fprintf(stderr, "Redeclaration of function '%s'\n", node->name);
exit(1);
}
int numparams = node_list_length(node->child1);
- struct symbol *sym = symbol_make_func(node->name, node->rtype, numparams);
+ struct symbol *sym = symbol_make_func(strdup(node->name), node->rtype, numparams);
write_func_params(sym->params, node->child1);
symtab_insert(symtab_root(symtab), sym);
- ir_append(ir, irins_make_name(INS_LBL, strdup(node->name)));
+
+ ir_append(ir, irins_make_name(INS_LBL, node->name));
+
symtab = symtab_sub(symtab);
for (int i = 0; i < numparams; i++) {
- struct symbol *parsym = symbol_make_var(sym->params[i].name, sym->params[i].type);
+ struct symbol *parsym = symbol_make_var(strdup(sym->params[i].name), sym->params[i].type);
parsym->ref = ref_mem(REG_BP, -2 - i, REFREL_ZERO);
symtab_insert(symtab, parsym);
}
+
compile_node(ir, symtab, node->child2);
+
symtab = symtab_delete_get_parent(symtab);
+
+ // necessary for void functions, to be sure otherwise
+ ir_append(ir, irins_make(INS_RET));
break;
}
case N_IF: {
- char *thenlbl = gen_label_name();
- char *elselbl = gen_label_name();
- char *afterlbl = gen_label_name();
+ const char *thenlbl = gen_label_name();
+ const char *elselbl = gen_label_name();
+ const char *afterlbl = gen_label_name();
compile_boolexpr(ir, symtab, node->child1, thenlbl, elselbl);
ir_append(ir, irins_make_name(INS_LBL, thenlbl));
compile_node(ir, symtab, node->child2);
@@ -289,9 +301,9 @@ static void compile_node(struct ir *ir, struct symtab *symtab, struct node *node
}
case N_WHILE: {
- char *startlbl = gen_label_name();
- char *bodylbl = gen_label_name();
- char *afterlbl = gen_label_name();
+ const char *startlbl = gen_label_name();
+ const char *bodylbl = gen_label_name();
+ const char *afterlbl = gen_label_name();
ir_append(ir, irins_make_name(INS_LBL, startlbl));
compile_boolexpr(ir, symtab, node->child1, bodylbl, afterlbl);
ir_append(ir, irins_make_name(INS_LBL, bodylbl));
@@ -301,7 +313,11 @@ static void compile_node(struct ir *ir, struct symtab *symtab, struct node *node
break;
}
- case N_RETURN: {
+ case N_RETURN:
+ ir_append(ir, irins_make(INS_RET));
+ break;
+
+ case N_RETURNV: {
struct ref ref = compile_expr(ir, symtab, node->child1);
ir_append(ir, irins_make_1(INS_RETV, ref));
break;
@@ -313,9 +329,50 @@ static void compile_node(struct ir *ir, struct symtab *symtab, struct node *node
}
}
+static void compile_data_setup_node(struct ir *ir, struct symtab *symtab, struct node *node) {
+ switch (node->type) {
+ case N_LIST:
+ if (node->child1->type == N_VAR_DECL || node->child1->type == N_VAR_DECL_INIT) {
+ compile_node(ir, symtab, node->child1);
+ node_delete_recursive(node->child1);
+ node->child1 = node_make_0(N_LIST_END);
+ }
+ compile_data_setup_node(ir, symtab, node->child2);
+ break;
+
+ case N_LIST_END:
+ break;
+
+ case N_VAR_DECL:
+ case N_VAR_DECL_INIT:
+ compile_node(ir, symtab, node);
+ break;
+
+ case N_FUNC_DECL:
+ break;
+
+ default:
+ assert(false);
+ }
+}
+
+static void compile_data_setup(struct ir *ir, struct symtab *symtab, struct node *root) {
+ struct ref flag = ir_reserve_global(ir, 1);
+ ir_append(ir, irins_make_12(INS_TEST, flag, flag));
+ const char *afterlbl = gen_label_name();
+ ir_append(ir, irins_make_jcc(afterlbl, CCNZ));
+
+ compile_data_setup_node(ir, symtab, root);
+
+ ir_append(ir, irins_make_name(INS_LBL, afterlbl));
+ ir_append(ir, irins_make_name(INS_CALL, "main"));
+ ir_append(ir, irins_make(INS_BRK));
+}
+
struct ir* compile(struct node *node) {
struct ir *ir = ir_make();
struct symtab *symtab = symtab_make();
+ compile_data_setup(ir, symtab, node);
compile_node(ir, symtab, node);
return ir;
}