summaryrefslogtreecommitdiff
path: root/codegen.c
diff options
context:
space:
mode:
authorCarson Fleming <[email protected]>2026-03-26 19:46:35 -0700
committerCarson Fleming <[email protected]>2026-03-26 19:46:35 -0700
commit28157efe6ef65394d8930a79200b9243ee919f47 (patch)
tree5dd492ae8d27e99d066b88e76f5304fad270ee11 /codegen.c
parent2e4f713ede25fb6147571858779fde542144c76f (diff)
downloadccc-28157efe6ef65394d8930a79200b9243ee919f47.tar.gz
mostly there except need to implement one more hash map
Diffstat (limited to 'codegen.c')
-rw-r--r--codegen.c139
1 files changed, 124 insertions, 15 deletions
diff --git a/codegen.c b/codegen.c
index 37c7a91..cfb4cca 100644
--- a/codegen.c
+++ b/codegen.c
@@ -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);
}