aboutsummaryrefslogtreecommitdiff
path: root/compiler.c
diff options
context:
space:
mode:
Diffstat (limited to 'compiler.c')
-rw-r--r--compiler.c70
1 files changed, 56 insertions, 14 deletions
diff --git a/compiler.c b/compiler.c
index 42ad25c..34372f3 100644
--- a/compiler.c
+++ b/compiler.c
@@ -13,6 +13,12 @@ static void write_func_params(struct pair_tn *params, struct node *list) {
write_func_params(params + 1, list->child2);
}
+static void write_node_list(struct node **dest, struct node *list) {
+ if (list->type == N_LIST_END) return;
+ dest[0] = list->child1;
+ write_node_list(dest + 1, list->child2);
+}
+
static bool oper_is_basic_arith(enum operator oper) {
return oper == OP_ADD || oper == OP_SUB || oper == OP_MUL || oper == OP_DIV || oper == OP_MOD;
}
@@ -78,6 +84,10 @@ static struct ref compile_expr(struct ir *ir, struct symtab *symtab, struct node
fprintf(stderr, "Use of undeclared variable '%s'\n", node->name);
exit(1);
}
+ if (sym->stype != ST_VAR) {
+ fprintf(stderr, "Cannot use function name in expression\n");
+ exit(1);
+ }
return sym->ref;
}
@@ -146,12 +156,12 @@ static struct ref compile_expr(struct ir *ir, struct symtab *symtab, struct node
struct ref addr = compile_expr(ir, symtab, node->child1);
struct ref r1;
switch (addr.type) {
- case REF_REG: r1 = ref_mem(addr.reg, 0, false); break;
- case REF_IMM: r1 = ref_mem(-1, addr.imm, false); break;
+ case REF_REG: r1 = ref_mem(addr.reg, 0, REFREL_ZERO); break;
+ case REF_IMM: r1 = ref_mem(REG_UNUSED, addr.imm, REFREL_ZERO); break;
case REF_MEM: {
r1 = ref_next_register();
ir_append(ir, irins_make_01(INS_MOV, r1, addr));
- r1 = ref_mem(r1.reg, 0, false); break;
+ r1 = ref_mem(r1.reg, 0, REFREL_ZERO); break;
break;
}
}
@@ -170,14 +180,38 @@ static struct ref compile_expr(struct ir *ir, struct symtab *symtab, struct node
}
case N_CALL: {
- fprintf(stderr, "function calls not implemented\n");
- exit(1);
- /*struct symbol *sym = symtab_find(symtab, node->name);
+ struct symbol *sym = symtab_find(symtab, node->name);
if (!sym) {
fprintf(stderr, "Call of undeclared function '%s'\n", node->name);
exit(1);
}
- ;*/
+ if (sym->stype != ST_FUNC) {
+ fprintf(stderr, "Cannot call variable\n");
+ exit(1);
+ }
+ if (node_list_length(node->child1) != sym->numparams) {
+ fprintf(stderr, "Invalid number of parameters to function '%s' (typechecker, come on)\n", node->name);
+ exit(1);
+ }
+ struct node **args = malloc(sym->numparams * sizeof(struct node*));
+ write_node_list(args, node->child1);
+ for (int i = sym->numparams - 1; i >= 0; i--) {
+ struct ref r = compile_expr(ir, symtab, args[i]);
+ ir_append(ir, irins_make_1(INS_PUSH, r));
+ }
+ free(args);
+ struct ref retref;
+ if (node->rtype == type_void()) {
+ ir_append(ir, irins_make_name(INS_CALL, node->name));
+ retref = ref_reg(REG_UNUSED); // TODO make nicer; typechecker should've caught usages though
+ } else {
+ retref = ref_next_register();
+ struct irins *ins = irins_make_0(INS_CALLV, retref);
+ ins->name = strdup(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)));
+ return retref;
}
default:
@@ -209,10 +243,13 @@ static void compile_node(struct ir *ir, struct symtab *symtab, struct node *node
fprintf(stderr, "Redeclaration of variable '%s'\n", node->name);
exit(1);
}
+ 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();
symtab_insert(symtab, sym);
- ir_append(ir, irins_make_01(INS_MOV, sym->ref, ref_imm(node->value)));
+ ir_append(ir, irins_make_01(INS_MOV, sym->ref, vref));
break;
}
@@ -227,17 +264,22 @@ static void compile_node(struct ir *ir, struct symtab *symtab, struct node *node
symtab_insert(symtab_root(symtab), sym);
ir_append(ir, irins_make_name(INS_LBL, strdup(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);
+ 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);
break;
}
case N_IF: {
+ char *thenlbl = gen_label_name();
char *elselbl = gen_label_name();
char *afterlbl = gen_label_name();
- struct ref condref = compile_expr(ir, symtab, node->child1);
- ir_append(ir, irins_make_12(INS_TEST, condref, condref));
- ir_append(ir, irins_make_jcc(elselbl, CCZ));
+ compile_boolexpr(ir, symtab, node->child1, thenlbl, elselbl);
+ ir_append(ir, irins_make_name(INS_LBL, thenlbl));
compile_node(ir, symtab, node->child2);
ir_append(ir, irins_make_name(INS_JMP, afterlbl));
ir_append(ir, irins_make_name(INS_LBL, elselbl));
@@ -248,11 +290,11 @@ 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();
ir_append(ir, irins_make_name(INS_LBL, startlbl));
- struct ref condref = compile_expr(ir, symtab, node->child1);
- ir_append(ir, irins_make_12(INS_TEST, condref, condref));
- ir_append(ir, irins_make_jcc(afterlbl, CCZ));
+ compile_boolexpr(ir, symtab, node->child1, bodylbl, afterlbl);
+ ir_append(ir, irins_make_name(INS_LBL, bodylbl));
compile_node(ir, symtab, node->child2);
ir_append(ir, irins_make_name(INS_JMP, startlbl));
ir_append(ir, irins_make_name(INS_LBL, afterlbl));