From 3272b5d83d2e2167eed24748557df88bd66584ee Mon Sep 17 00:00:00 2001 From: tomsmeding Date: Fri, 5 Jan 2018 23:42:24 +0100 Subject: There's actually a chance that, correctly stringified, this will work --- compiler.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 76 insertions(+), 19 deletions(-) (limited to 'compiler.c') 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; } -- cgit v1.2.3-54-g00ecf