summaryrefslogtreecommitdiff
path: root/codegen.c
diff options
context:
space:
mode:
authorCarson Fleming <cflems@cflems.net>2026-07-17 00:38:51 -0400
committerCarson Fleming <cflems@cflems.net>2026-07-17 00:38:51 -0400
commita5c12fd6f4438fc172f28b722e54908b575c6ce1 (patch)
tree5f9b2d48681e02d392567eb8798ba614cb96bfbd /codegen.c
parent1dfa2971999b4adf36a33866b0b07af07188da08 (diff)
downloadccc-a5c12fd6f4438fc172f28b722e54908b575c6ce1.tar.gz
before I do something crazy
Diffstat (limited to 'codegen.c')
-rw-r--r--codegen.c124
1 files changed, 60 insertions, 64 deletions
diff --git a/codegen.c b/codegen.c
index 662097e..749c85d 100644
--- a/codegen.c
+++ b/codegen.c
@@ -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);
}