diff options
| author | Carson Fleming <[email protected]> | 2026-03-26 19:46:35 -0700 |
|---|---|---|
| committer | Carson Fleming <[email protected]> | 2026-03-26 19:46:35 -0700 |
| commit | 28157efe6ef65394d8930a79200b9243ee919f47 (patch) | |
| tree | 5dd492ae8d27e99d066b88e76f5304fad270ee11 /codegen.c | |
| parent | 2e4f713ede25fb6147571858779fde542144c76f (diff) | |
| download | ccc-28157efe6ef65394d8930a79200b9243ee919f47.tar.gz | |
mostly there except need to implement one more hash map
Diffstat (limited to 'codegen.c')
| -rw-r--r-- | codegen.c | 139 |
1 files changed, 124 insertions, 15 deletions
@@ -1,42 +1,95 @@ #include "ccc.h" -#include "ast.h" +#include "codegen.h" +#include "scope.h" #include <stdlib.h> #include <stdio.h> -static void emit_stmt(FILE* outfile, const struct stmt_node* node); -static void emit_expr( +#define CGEN_PANIC(format, ...) {\ + fprintf(\ + stderr,\ + "ccc: code gen error: " format "\n" __VA_OPT__(,)\ + __VA_ARGS__);\ + exit(1);\ +} + +static const struct storage_location RV_LOC = { + .type = REGISTER, + .label = "rax", +}; + +static struct scope* scope; + +static void emit_storage_loc( FILE* outfile, - const struct expr_node* node, - const char* reg); + const struct storage_location* loc +) { + switch (loc->type) { + case REGISTER: + case JMP_LABEL: + fprintf(outfile, "%s", loc->label); + break; + case BP_OFFSET: + if (loc->offset < 0) + fprintf(outfile, "[rbp + %lld]", -loc->offset); + else if (loc->offset > 0) + fprintf(outfile, "[rbp - %lld]", loc->offset); + else + fprintf(outfile, "[rbp]"); + } +} static void emit_int_lit( FILE* outfile, const struct int_lit_node* node, - const char* reg + const struct storage_location* storage ) { - fprintf(outfile, "\tmov %s, %lld\n", reg, node->val); + if (storage != NULL) { + fprintf(outfile, "\tmov "); + emit_storage_loc(outfile, storage); + fprintf(outfile, ", %lld\n", node->val); + } } static void emit_expr( FILE* outfile, const struct expr_node* node, - const char* reg + const struct storage_location* storage ) { switch (node->type) { case EXPR_EMPTY: break; case EXPR_INT_LIT: - emit_int_lit(outfile, &node->as._int_lit, reg); + emit_int_lit(outfile, &node->as._int_lit, storage); break; } } +static void emit_stmt(FILE* outfile, const struct stmt_node* node); + +static struct type_def get_type_def(const char* type_name) { + struct type_def type_def; + if (!scope_get_type(scope, &type_def, type_name)) + CGEN_PANIC("size of type %s is not known", type_name); + return type_def; +} + static void emit_var_decl(FILE* outfile, const struct var_decl_node* node) { - /* TODO: make do smth */ + struct type_def type_def = get_type_def(node->type.type); + fprintf(outfile, "\tsub rsp, %llu\n", type_def.size); + scope->bp_offset += type_def.size; + scope_define_var(scope, (struct var_def) { + .name = node->ident, + .loc = { + .type = BP_OFFSET, + .offset = scope->bp_offset, + }, + }); } static void emit_return(FILE* outfile, const struct return_node* node) { - if (node->ret_val != NULL) emit_expr(outfile, node->ret_val, "rax"); + if (node->ret_val != NULL) emit_expr(outfile, node->ret_val, &RV_LOC); + fprintf(outfile, "\tmov rsp, rbp\n"); + fprintf(outfile, "\tpop rbp\n"); fprintf(outfile, "\tret\n"); } @@ -48,6 +101,25 @@ 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); + scope->bp_offset = scope->next_out->bp_offset; /* don't reset bp */ + + emit_group(outfile, node); + + scope_pop(&scope); + if (scope->bp_offset == 0) + fprintf(outfile, "\tmov rsp, rbp\n"); + else { + fprintf(outfile, "\tlea rsp, "); + emit_storage_loc(outfile, &(struct storage_location) { + .type = BP_OFFSET, + .offset = scope->bp_offset, + }); + fprintf(outfile, "\n"); + } +} + static void emit_stmt(FILE* outfile, const struct stmt_node* node) { switch (node->type) { case STMT_VAR_DECL: @@ -60,15 +132,41 @@ static void emit_stmt(FILE* outfile, const struct stmt_node* node) { emit_expr(outfile, &node->as._expr, NULL); break; case STMT_GROUP: - emit_group(outfile, &node->as._group); + emit_stmt_group(outfile, &node->as._group); break; } } static void emit_fn_decl(FILE* outfile, const struct fn_decl_node* node) { fprintf(outfile, "%s:\n", node->name); - /* TODO: probably something to map the args to temporaries lol */ + fprintf(outfile, "\tpush rbp\n"); + fprintf(outfile, "\tmov rbp, rsp\n"); + + scope_push(&scope); + scope->bp_offset = 0; + + struct var_decl_node* args_node = node->args_head; + long long arg_bp_offset = -8; + while (args_node != NULL) { + struct type_def type_def = get_type_def(args_node->type.type); + scope_define_var(scope, (struct var_def) { + .name = args_node->ident, + .loc = { + .type = BP_OFFSET, + .offset = arg_bp_offset, + }, + }); + arg_bp_offset -= type_def.size; + args_node = args_node->next; + } + emit_group(outfile, &node->body); + + scope_pop(&scope); + + fprintf(outfile, "\tmov rsp, rbp\n"); + fprintf(outfile, "\tpop rbp\n"); + fprintf(outfile, "\tret\n"); } static void emit_root_node(FILE* outfile, const struct root_node* node) { @@ -84,12 +182,22 @@ void emit_code(const struct root_node* ast, const char* path) { if (outfile == NULL) CCC_PANIC; fprintf(outfile, "section .text\n"); + scope_push(&scope); /* output all non-static function declarations as globals */ const struct root_node* node = ast; while (node != NULL) { - if (node->type == ROOT_FN_DECL) - fprintf(outfile, "global %s\n", node->as._fn_decl.name); + 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 = JMP_LABEL, + .label = fn_name, + }, + }); + fprintf(outfile, "global %s\n", fn_name); + } node = node->next; } @@ -104,5 +212,6 @@ void emit_code(const struct root_node* ast, const char* path) { node = node->next; } + scope_pop(&scope); fclose(outfile); } |
