summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarson Fleming <cflems@cflems.net>2026-07-18 13:18:45 -0700
committerCarson Fleming <cflems@cflems.net>2026-07-18 13:18:45 -0700
commit385419f95c6b9c35a7c2a6168f82f7aa4a44e22b (patch)
tree981d2e69f6e6d1c558253db6cef4083e98467bc1
parentb43aebd9d3c2e072ee2acc50d4381dcb0f01ec98 (diff)
downloadccc-385419f95c6b9c35a7c2a6168f82f7aa4a44e22b.tar.gz
fix scoping big
-rw-r--r--ast.h1
-rw-r--r--codegen.c36
-rw-r--r--parser.c17
-rw-r--r--test/fibonacci.c2
-rw-r--r--type_checker.c31
5 files changed, 67 insertions, 20 deletions
diff --git a/ast.h b/ast.h
index 918ae68..6ff95df 100644
--- a/ast.h
+++ b/ast.h
@@ -136,6 +136,7 @@ struct if_node {
struct expr_node* cond;
struct stmt_node* true_branch;
struct stmt_node* false_branch;
+ struct scope* scope;
};
struct stmt_node {
diff --git a/codegen.c b/codegen.c
index f126bda..79deb46 100644
--- a/codegen.c
+++ b/codegen.c
@@ -36,6 +36,21 @@ static struct scope* scope;
static const struct fn_decl_node* active_fn;
static unsigned long long branch_counter = 0;
+static void enter_scope(struct scope* child_scope) {
+ if (child_scope == NULL ||
+ child_scope->next_out != scope)
+ CGEN_PANIC("enter_scope: scopes are misaligned");
+
+ scope = child_scope;
+}
+
+static void exit_scope(struct scope* child_scope) {
+ if (child_scope != scope || child_scope->next_out == NULL)
+ CGEN_PANIC("exit_scope: scopes are misaligned");
+
+ scope = child_scope->next_out;
+}
+
static struct lval_def allocate_register(const struct type_def* type) {
return (struct lval_def) {
.loc = {
@@ -547,20 +562,19 @@ static void emit_group_contents(FILE* outfile, const struct group_node* node) {
}
static void emit_group(FILE* outfile, const struct group_node* node) {
- if (node->scope->next_out != scope) CGEN_PANIC("scopes are misaligned");
-
- scope = node->scope;
+ enter_scope(node->scope);
scope->bp_offset = scope->next_out->bp_offset; /* don't reset bp */
emit_group_contents(outfile, node);
/* don't reset sp because alloca needs to work */
scope->next_out->bp_offset = scope->bp_offset;
- scope = scope->next_out;
+ exit_scope(node->scope);
}
static void emit_if(FILE* outfile, const struct if_node* node) {
- /* TODO: make type checking real so we aren't passing a null pointer here */
+ enter_scope(node->scope);
+
struct lval_def cond_result =
allocate_temporary(outfile, node->cond->resolved_type);
emit_expr(outfile, node->cond, &cond_result);
@@ -579,6 +593,8 @@ static void emit_if(FILE* outfile, const struct if_node* node) {
emit_stmt(outfile, node->false_branch);
fprintf(outfile, "branch%lld:\n", end_branch_num);
}
+
+ exit_scope(node->scope);
}
static void emit_stmt(FILE* outfile, const struct stmt_node* node) {
@@ -604,6 +620,8 @@ static void emit_stmt(FILE* outfile, const struct stmt_node* node) {
}
static void emit_fn_decl(FILE* outfile, const struct fn_decl_node* node) {
+ enter_scope(node->scope);
+
if (active_fn != NULL)
CGEN_PANIC(
"can't define function %s inside function %s",
@@ -615,8 +633,6 @@ static void emit_fn_decl(FILE* outfile, const struct fn_decl_node* node) {
fprintf(outfile, "\tpush rbp\n");
fprintf(outfile, "\tmov rbp, rsp\n");
- 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
@@ -644,15 +660,17 @@ static void emit_fn_decl(FILE* outfile, const struct fn_decl_node* node) {
emit_mov(outfile, &arg_dst, &arg_src);
}
+ enter_scope(node->body.scope);
emit_group_contents(outfile, &node->body);
-
- scope = scope->next_out;
+ exit_scope(node->body.scope);
fprintf(outfile, RETURN_LABEL_FMT ":\n", node->name);
fprintf(outfile, "\tmov rsp, rbp\n");
fprintf(outfile, "\tpop rbp\n");
fprintf(outfile, "\tret\n");
+
active_fn = NULL;
+ exit_scope(node->scope);
}
static void emit_root_node(FILE* outfile, const struct root_node* node) {
diff --git a/parser.c b/parser.c
index 40cdb1c..4779e73 100644
--- a/parser.c
+++ b/parser.c
@@ -324,6 +324,9 @@ static void parse_group(struct group_node* p_node) {
static void parse_if(struct if_node* p_node) {
expect_kw("if");
+ scope_push(&scope);
+ p_node->scope = scope;
+
expect(TK_LPAREN);
p_node->cond = protected_alloc(sizeof(struct expr_node));
parse_expr(p_node->cond);
@@ -333,11 +336,14 @@ static void parse_if(struct if_node* p_node) {
parse_stmt(p_node->true_branch);
peek_or_panic();
- if (tok.type != TK_IDENT || strcmp(tok.data.ident, "else") != 0) return;
- expect_kw("else");
+ if (tok.type == TK_IDENT && strcmp(tok.data.ident, "else") == 0) {
+ expect_kw("else");
- p_node->false_branch = protected_alloc(sizeof(struct stmt_node));
- parse_stmt(p_node->false_branch);
+ p_node->false_branch = protected_alloc(sizeof(struct stmt_node));
+ parse_stmt(p_node->false_branch);
+ }
+
+ scope_pop(&scope);
}
static void parse_stmt_assign(struct stmt_node* p_node) {
@@ -419,6 +425,9 @@ static void parse_args_decl(struct args_decl_node** pp_decl) {
}
static void parse_fn_decl(struct fn_decl_node* p_node) {
+ if (scope->next_out != NULL)
+ PARSER_PANIC("functions can only be define in the root scope");
+
parse_type_ref(&p_node->return_type);
expect(TK_IDENT);
diff --git a/test/fibonacci.c b/test/fibonacci.c
index 39a32be..a07c111 100644
--- a/test/fibonacci.c
+++ b/test/fibonacci.c
@@ -1,6 +1,6 @@
int fib (int n) {
if (n) return n * fib(n-1);
- return 1;
+ else return 1;
}
int main (int argc, char** argv) {
diff --git a/type_checker.c b/type_checker.c
index 2842ea2..aabd7c9 100644
--- a/type_checker.c
+++ b/type_checker.c
@@ -33,6 +33,21 @@ static void assert_cast_compatible(
}
}
+static void enter_scope(struct scope* child_scope) {
+ if (child_scope == NULL ||
+ child_scope->next_out != scope)
+ TYPE_PANIC("enter_scope: scopes are misaligned");
+
+ scope = child_scope;
+}
+
+static void exit_scope(struct scope* child_scope) {
+ if (child_scope != scope || child_scope->next_out == NULL)
+ TYPE_PANIC("exit_scope: scopes are misaligned");
+
+ scope = child_scope->next_out;
+}
+
static const struct type_def* resolve_type_ref(struct type_ref_node* node) {
/* TODO: support pointers and such */
if (node->def_ref == NULL) TYPE_PANIC("use of unresolved type");
@@ -160,9 +175,13 @@ static void type_check_return(struct return_node* node) {
}
static void type_check_if(struct if_node* node) {
+ enter_scope(node->scope);
+
type_check_expr(node->cond);
type_check_stmt(node->true_branch);
if (node->false_branch != NULL) type_check_stmt(node->false_branch);
+
+ exit_scope(node->scope);
}
static void type_check_stmt(struct stmt_node* node) {
@@ -188,19 +207,19 @@ static void type_check_stmt(struct stmt_node* node) {
}
static void type_check_group(struct group_node* node) {
- if (node->scope->next_out != scope) TYPE_PANIC("scopes are borked");
- scope = node->scope;
+ enter_scope(node->scope);
+
struct stmt_node* stmt = node->head;
while (stmt != NULL) {
type_check_stmt(stmt);
stmt = stmt->next;
}
- scope = scope->next_out;
+
+ exit_scope(node->scope);
}
static void type_check_fn_decl(struct fn_decl_node* node) {
- if (node->scope->next_out != scope) TYPE_PANIC("scopes are borked");
- scope = node->scope;
+ enter_scope(node->scope);
node->return_type.def_ref = resolve_type_ref(&node->return_type);
@@ -211,7 +230,7 @@ static void type_check_fn_decl(struct fn_decl_node* node) {
type_check_group(&node->body);
- scope = scope->next_out;
+ exit_scope(node->scope);
}
static void type_check_root(struct root_node* node) {