summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--codegen.c7
-rw-r--r--parser.c15
-rw-r--r--scope.h1
-rw-r--r--test/fibonacci.c8
-rw-r--r--type_checker.c3
5 files changed, 29 insertions, 5 deletions
diff --git a/codegen.c b/codegen.c
index ae94d9f..bdc3cbf 100644
--- a/codegen.c
+++ b/codegen.c
@@ -100,6 +100,8 @@ static void emit_storage_loc(
case STO_IMM:
fprintf(outfile, "%llu", loc->value);
break;
+ case STO_UNRESOLVED:
+ CGEN_PANIC("can't emit unresolved storage location");
}
}
@@ -120,6 +122,8 @@ static bool locs_equal(
return strcmp(a->label, b->label) == 0;
case STO_FN:
return a->decl == b->decl;
+ case STO_UNRESOLVED:
+ return false;
}
CGEN_PANIC("unhandled storage type case");
}
@@ -176,6 +180,8 @@ static void emit_mov(
case STO_IMM:
CGEN_PANIC(
"can't move value into immediate value %lld", dst->loc.value);
+ case STO_UNRESOLVED:
+ CGEN_PANIC("can't move value into unresolved storage");
}
fprintf(outfile, "\n");
}
@@ -580,6 +586,7 @@ static void emit_fn_decl(FILE* outfile, const struct fn_decl_node* node) {
while (arg_decl != NULL) {
struct lval_def arg_dst =
make_stack_lval(outfile, &arg_decl->decl->type);
+ /* TODO: type checker should define vars, we just set their loc */
scope_define_var(
scope,
(struct var_def) {
diff --git a/parser.c b/parser.c
index 42a7f49..e078ae9 100644
--- a/parser.c
+++ b/parser.c
@@ -268,7 +268,11 @@ static void parse_var_decl(struct var_decl_node* p_node) {
parse_type(&p_node->type);
expect(TK_IDENT);
p_node->ident = tok.data.ident;
- scope_define_var(scope, (struct var_def) { .name = p_node->ident });
+ scope_define_var(scope, (struct var_def) {
+ .name = p_node->ident,
+ .loc.type = STO_UNRESOLVED,
+ .sz = 0, /* unknown */
+ });
}
static void parse_stmt(struct stmt_node* p_node);
@@ -389,10 +393,7 @@ static void parse_fn_decl(struct fn_decl_node* p_node) {
expect(TK_RPAREN);
- parse_group(&p_node->body);
-
- scope_pop(&scope);
-
+ /* defining here makes recursion possible */
scope_define_var(scope, (struct var_def) {
.name = p_node->name,
.loc = {
@@ -400,6 +401,10 @@ static void parse_fn_decl(struct fn_decl_node* p_node) {
.decl = p_node,
},
});
+
+ parse_group(&p_node->body);
+
+ scope_pop(&scope);
}
static bool parse_root(struct root_node* p_node) {
diff --git a/scope.h b/scope.h
index 2dfa110..dfbb2c1 100644
--- a/scope.h
+++ b/scope.h
@@ -8,6 +8,7 @@ struct storage_location {
STO_STACK,
STO_IMM,
STO_FN,
+ STO_UNRESOLVED,
} type;
union {
const struct reg* reg;
diff --git a/test/fibonacci.c b/test/fibonacci.c
new file mode 100644
index 0000000..c241be9
--- /dev/null
+++ b/test/fibonacci.c
@@ -0,0 +1,8 @@
+int fib (int n) {
+ if (n <= 1) return 1;
+ return n * fib(n - 1);
+}
+
+int main (int argc, char** argv) {
+ return fib(argc);
+}
diff --git a/type_checker.c b/type_checker.c
index f914c34..d1a6c32 100644
--- a/type_checker.c
+++ b/type_checker.c
@@ -48,11 +48,14 @@ static void type_check_group(struct group_node* node) {
type_check_stmt(stmt);
stmt = stmt->next;
}
+ scope = scope->next_out;
}
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;
type_check_group(&node->body);
+ scope = scope->next_out;
}
static void type_check_root(struct root_node* node) {