diff options
| author | Carson Fleming <cflems@cflems.net> | 2026-07-17 00:38:51 -0400 |
|---|---|---|
| committer | Carson Fleming <cflems@cflems.net> | 2026-07-17 00:38:51 -0400 |
| commit | a5c12fd6f4438fc172f28b722e54908b575c6ce1 (patch) | |
| tree | 5f9b2d48681e02d392567eb8798ba614cb96bfbd /codegen.c | |
| parent | 1dfa2971999b4adf36a33866b0b07af07188da08 (diff) | |
| download | ccc-a5c12fd6f4438fc172f28b722e54908b575c6ce1.tar.gz | |
before I do something crazy
Diffstat (limited to 'codegen.c')
| -rw-r--r-- | codegen.c | 124 |
1 files changed, 60 insertions, 64 deletions
@@ -180,9 +180,10 @@ static void emit_mov( fprintf(outfile, "\n"); } +/* TODO: move this utility to the type checker and use evaluated_type */ static unsigned long long get_type_size(const struct type_node* type) { if (type->ptr_level > 0) return PTR_SIZE; - return type->def.sz; + return type->def->sz; } static inline struct lval_def make_stack_lval( @@ -272,6 +273,7 @@ static struct var_def emit_var_decl( FILE* outfile, const struct var_decl_node* node ) { + /* TODO: type checker should define vars, we just set their loc */ struct lval_def var_dst = make_stack_lval(outfile, &node->type); struct var_def var_def = { .name = node->ident, @@ -289,10 +291,10 @@ static struct lval_def emit_lval( struct var_def var_def; switch (node->type) { case LVAL_VAR_DECL: - var_def = emit_var_decl(outfile, &node->as._var_decl); + var_def = emit_var_decl(outfile, &node->inner.var_decl); return (struct lval_def) {.loc = var_def.loc, .sz = var_def.sz}; case LVAL_VAR_REF: - var_def = get_var(node->as._var_ref.ident); + var_def = get_var(node->inner.var_ref.ident); return (struct lval_def) {.loc = var_def.loc, .sz = var_def.sz}; } CGEN_PANIC("unknown lval type: %d", node->type); @@ -316,25 +318,30 @@ static void emit_call( unsigned long long orig_bp_offset = scope->bp_offset; unsigned long long arg_bp_offset = orig_bp_offset; - struct var_decl_node* arg_decl = node->called_fn->args_head; - struct expr_node* arg_eval = node->args_head; + struct args_decl_node* arg_decl = node->called_fn_ref->args; + struct args_eval_node* arg_eval = node->args; while (arg_decl != NULL && arg_eval != NULL) { - struct lval_def arg_dst = make_stack_lval(outfile, &arg_decl->type); - emit_expr(outfile, arg_eval, &arg_dst); + struct lval_def arg_dst = + make_stack_lval(outfile, &arg_decl->decl->type); + emit_expr(outfile, arg_eval->expr, &arg_dst); arg_decl = arg_decl->next; arg_eval = arg_eval->next; } if (arg_decl != NULL) - CGEN_PANIC("too many arguments to function %s", node->called_fn->name); + CGEN_PANIC( + "too many arguments to function %s", + node->called_fn_ref->name); if (arg_eval != NULL) - CGEN_PANIC("missing arguments to function %s", node->called_fn->name); + CGEN_PANIC( + "missing arguments to function %s", + node->called_fn_ref->name); unsigned char arg_regnum = 0; - arg_decl = node->called_fn->args_head; + arg_decl = node->called_fn_ref->args; while (arg_decl != NULL) { - unsigned long long type_sz = get_type_size(&arg_decl->type); + unsigned long long type_sz = get_type_size(&arg_decl->decl->type); arg_bp_offset += type_sz; struct lval_def arg_dst; @@ -347,7 +354,7 @@ static void emit_call( .sz = type_sz, }; else - arg_dst = make_stack_lval(outfile, &arg_decl->type); + arg_dst = make_stack_lval(outfile, &arg_decl->decl->type); emit_mov(outfile, &arg_dst, &(struct storage_location) { .type = STO_STACK, @@ -356,9 +363,9 @@ static void emit_call( arg_decl = arg_decl->next; } - fprintf(outfile, "\tcall %s\n", node->called_fn->name); + fprintf(outfile, "\tcall %s\n", node->called_fn_ref->name); if (dst != NULL) { - if (node->called_fn->return_type.def.sz == 0) + if (get_type_size(&node->called_fn_ref->return_type) == 0) CGEN_PANIC("can't assign the result of a void function"); emit_mov(outfile, dst, &RV_LOC); @@ -458,31 +465,31 @@ static void emit_expr( ) { switch (node->type) { case EXPR_INT_LIT: - emit_int_lit(outfile, &node->as._int_lit, dst); + emit_int_lit(outfile, &node->inner.int_lit, dst); break; case EXPR_FLOAT_LIT: - emit_float_lit(outfile, &node->as._float_lit, dst); + emit_float_lit(outfile, &node->inner.float_lit, dst); break; case EXPR_CHAR_LIT: - emit_char_lit(outfile, &node->as._char_lit, dst); + emit_char_lit(outfile, &node->inner.char_lit, dst); break; case EXPR_STR_LIT: - emit_str_lit(outfile, &node->as._str_lit, dst); + emit_str_lit(outfile, &node->inner.str_lit, dst); break; case EXPR_VAR_REF: - emit_var_ref(outfile, &node->as._var_ref, dst); + emit_var_ref(outfile, &node->inner.var_ref, dst); break; case EXPR_ASSIGN: - emit_assignment(outfile, &node->as._assign, dst); + emit_assignment(outfile, &node->inner.assign, dst); break; case EXPR_CALL: - emit_call(outfile, &node->as._call, dst); + emit_call(outfile, &node->inner.call, dst); break; case EXPR_UNARY: - emit_unary(outfile, &node->as._unary, dst); + emit_unary(outfile, &node->inner.unary, dst); break; case EXPR_BINARY: - emit_binary(outfile, &node->as._binary, dst); + emit_binary(outfile, &node->inner.binary, dst); break; } } @@ -491,7 +498,7 @@ static void emit_return(FILE* outfile, const struct return_node* node) { if (active_fn == NULL) CGEN_PANIC("must be inside a function to return"); if (node->ret_val != NULL) { - if (active_fn->return_type.def.sz == 0) + if (active_fn->return_type.def->sz == 0) CGEN_PANIC( "returning a value from void function %s", active_fn->name); @@ -500,9 +507,9 @@ static void emit_return(FILE* outfile, const struct return_node* node) { node->ret_val, &(struct lval_def) { .loc = RV_LOC, - .sz = active_fn->return_type.def.sz, + .sz = active_fn->return_type.def->sz, }); - } else if (active_fn->return_type.def.sz > 0) { + } else if (active_fn->return_type.def->sz > 0) { CGEN_PANIC( "non-void function %s should return a value", active_fn->name); } @@ -511,7 +518,7 @@ static void emit_return(FILE* outfile, const struct return_node* node) { } static void emit_group(FILE* outfile, const struct group_node* node) { - const struct stmt_node* body_node = node->body_head; + const struct stmt_node* body_node = node->head; while (body_node != NULL) { emit_stmt(outfile, body_node); body_node = body_node->next; @@ -519,14 +526,16 @@ static void emit_group(FILE* outfile, const struct group_node* node) { } static void emit_stmt_group(FILE* outfile, const struct group_node* node) { - scope_push(&scope); + if (node->scope->next_out != scope) CGEN_PANIC("scopes are misaligned"); + + scope = node->scope; scope->bp_offset = scope->next_out->bp_offset; /* don't reset bp */ emit_group(outfile, node); /* don't reset sp because alloca needs to work */ scope->next_out->bp_offset = scope->bp_offset; - scope_pop(&scope); + scope = scope->next_out; } static void emit_stmt(FILE* outfile, const struct stmt_node* node) { @@ -534,16 +543,16 @@ static void emit_stmt(FILE* outfile, const struct stmt_node* node) { case STMT_EMPTY: break; case STMT_VAR_DECL: - emit_var_decl(outfile, &node->as._var_decl); + emit_var_decl(outfile, &node->inner.var_decl); break; case STMT_RETURN: - emit_return(outfile, &node->as._return); + emit_return(outfile, &node->inner.return_); break; case STMT_EXPR: - emit_expr(outfile, &node->as._expr, NULL); + emit_expr(outfile, &node->inner.expr, NULL); break; case STMT_GROUP: - emit_stmt_group(outfile, &node->as._group); + emit_stmt_group(outfile, &node->inner.group); break; } } @@ -560,18 +569,20 @@ static void emit_fn_decl(FILE* outfile, const struct fn_decl_node* node) { fprintf(outfile, "\tpush rbp\n"); fprintf(outfile, "\tmov rbp, rsp\n"); - scope_push(&scope); + if (node->scope->next_out != scope) CGEN_PANIC("scopes are misaligned"); + scope = node->scope; scope->bp_offset = 0; long long spilled_bp_ofs = -16; // return address + old bp unsigned char arg_regnum = 0; - struct var_decl_node* args_node = node->args_head; - while (args_node != NULL) { - struct lval_def arg_dst = make_stack_lval(outfile, &args_node->type); + struct args_decl_node* arg_decl = node->args; + while (arg_decl != NULL) { + struct lval_def arg_dst = + make_stack_lval(outfile, &arg_decl->decl->type); scope_define_var( scope, (struct var_def) { - .name = args_node->ident, + .name = arg_decl->decl->ident, .loc = arg_dst.loc, .sz = arg_dst.sz, }); @@ -591,12 +602,12 @@ static void emit_fn_decl(FILE* outfile, const struct fn_decl_node* node) { } emit_mov(outfile, &arg_dst, &arg_src); - args_node = args_node->next; + arg_decl = arg_decl->next; } emit_group(outfile, &node->body); - scope_pop(&scope); + scope = scope->next_out; fprintf(outfile, RETURN_LABEL_FMT ":\n", node->name); fprintf(outfile, "\tmov rsp, rbp\n"); @@ -608,48 +619,33 @@ static void emit_fn_decl(FILE* outfile, const struct fn_decl_node* node) { static void emit_root_node(FILE* outfile, const struct root_node* node) { switch (node->type) { case ROOT_FN_DECL: - emit_fn_decl(outfile, &node->as._fn_decl); + emit_fn_decl(outfile, &node->inner.fn_decl); break; } } -void emit_code(const struct root_node* ast, const char* path) { +void emit_code(struct ast* ast, const char* path) { FILE* outfile = fopen(path, "w"); if (outfile == NULL) CCC_PANIC; + scope = ast->root_scope; fprintf(outfile, "section .text\n"); - scope_push(&scope); - scope_install_default_types(scope); - - /* output all non-static function declarations as globals */ - const struct root_node* node = ast; - while (node != NULL) { - if (node->type == ROOT_FN_DECL) { - const char* fn_name = node->as._fn_decl.name; - scope_define_var(scope, (struct var_def) { - .name = fn_name, - .loc = { - .type = STO_LABEL, - .label = fn_name, - }, - /* sz ignored, not relevant to functions */ - }); - fprintf(outfile, "global %s\n", fn_name); - } - node = node->next; + /* output all function declarations in the root scope as globals */ + const struct root_node* node = ast->root_node; + for (; node != NULL; node = node->next) { + if (node->type != ROOT_FN_DECL) continue; + fprintf(outfile, "global %s\n", node->inner.fn_decl.name); } - fprintf(outfile, "\n"); /* actual code body */ - node = ast; + node = ast->root_node; while (node != NULL) { emit_root_node(outfile, node); if (node->next != NULL) fprintf(outfile, "\n"); node = node->next; } - scope_pop(&scope); fclose(outfile); } |
