summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarson Fleming <cflems@cflems.net>2026-03-27 10:30:10 -1000
committerCarson Fleming <cflems@cflems.net>2026-03-27 10:30:10 -1000
commitfca3bf239cfdf03c4479f5d0c14a21c1fd96ea3e (patch)
tree0618ad64a13e949ce9273098df724d8d25bdcb36
parent21f688c1eac5fb09ae68fd9b3cfcff687de36601 (diff)
downloadccc-fca3bf239cfdf03c4479f5d0c14a21c1fd96ea3e.tar.gz
woah we got variables
-rw-r--r--ast.c9
-rw-r--r--ast.h57
-rw-r--r--codegen.c47
-rw-r--r--parser.c53
-rw-r--r--scope.c39
-rw-r--r--scope.h1
-rw-r--r--test/weird.c3
7 files changed, 169 insertions, 40 deletions
diff --git a/ast.c b/ast.c
index ac95413..1334073 100644
--- a/ast.c
+++ b/ast.c
@@ -5,7 +5,7 @@ static void expr_destroy(struct expr_node* node);
static void stmt_destroy(struct stmt_node* node);
static void type_destroy(struct type_node* node) {
- free(node->type);
+ free(node->name);
}
static void var_decl_destroy(struct var_decl_node* node) {
@@ -14,6 +14,10 @@ static void var_decl_destroy(struct var_decl_node* node) {
free(node->ident);
}
+static void var_ref_destroy(struct var_ref_node* node) {
+ free(node->ident);
+}
+
static void group_destroy(struct group_node* node) {
struct stmt_node* body_node = node->body_head;
while (body_node != NULL) {
@@ -52,6 +56,9 @@ static void expr_destroy(struct expr_node* node) {
case EXPR_EMPTY:
case EXPR_INT_LIT:
break;
+ case EXPR_VAR_REF:
+ var_ref_destroy(&node->as._var_ref);
+ break;
}
}
diff --git a/ast.h b/ast.h
index b058487..e5354ae 100644
--- a/ast.h
+++ b/ast.h
@@ -5,7 +5,19 @@ struct stmt_node;
struct expr_node;
struct type_node {
- char* type;
+ bool _unsigned;
+ bool _short;
+ bool _long;
+ unsigned char ptr_level;
+ char* name;
+};
+
+struct int_lit_node {
+ long long val;
+};
+
+struct var_ref_node {
+ char* ident;
};
struct var_decl_node {
@@ -15,6 +27,35 @@ struct var_decl_node {
struct var_decl_node* next;
};
+struct lval_node {
+ enum {
+ LVAL_VAR_DECL,
+ LVAL_VAR_USE,
+ } type;
+ union {
+ struct var_ref_node _var_ref;
+ struct var_decl_node _var_decl;
+ } as;
+};
+
+/* TODO: add to expression, parse */
+struct assign_node {
+ struct lval_node lval;
+ struct expr_node* rval;
+};
+
+struct expr_node {
+ enum {
+ EXPR_EMPTY,
+ EXPR_INT_LIT,
+ EXPR_VAR_REF,
+ } type;
+ union {
+ struct int_lit_node _int_lit;
+ struct var_ref_node _var_ref;
+ } as;
+};
+
struct group_node {
struct stmt_node* body_head;
};
@@ -30,20 +71,6 @@ struct return_node {
struct expr_node* ret_val; /* null to return void */
};
-struct int_lit_node {
- long long val;
-};
-
-struct expr_node {
- enum {
- EXPR_EMPTY,
- EXPR_INT_LIT,
- } type;
- union {
- struct int_lit_node _int_lit;
- } as;
-};
-
struct stmt_node {
enum {
STMT_EXPR,
diff --git a/codegen.c b/codegen.c
index d6f212a..ab3660b 100644
--- a/codegen.c
+++ b/codegen.c
@@ -50,6 +50,24 @@ static void emit_int_lit(
}
}
+static void emit_var_ref(
+ FILE* outfile,
+ const struct var_ref_node* node,
+ const struct storage_location* storage
+) {
+ if (storage != NULL) {
+ struct var_def var_def;
+ if (!scope_get_var(scope, &var_def, node->ident))
+ CGEN_PANIC("reference to undefined variable %s", node->ident);
+
+ fprintf(outfile, "\tmov ");
+ emit_storage_loc(outfile, &var_def.loc);
+ fprintf(outfile, ", ");
+ emit_storage_loc(outfile, storage);
+ fprintf(outfile, "\n");
+ }
+}
+
static void emit_expr(
FILE* outfile,
const struct expr_node* node,
@@ -61,22 +79,28 @@ static void emit_expr(
case EXPR_INT_LIT:
emit_int_lit(outfile, &node->as._int_lit, storage);
break;
+ case EXPR_VAR_REF:
+ emit_var_ref(outfile, &node->as._var_ref, storage);
}
}
static void emit_stmt(FILE* outfile, const struct stmt_node* node);
-static struct type_def get_type_def(const char* type_name) {
+static unsigned long long get_type_size(const struct type_node* type) {
+ if (type->ptr_level > 0) return 8;
+
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;
+ if (!scope_get_type(scope, &type_def, type->name))
+ CGEN_PANIC("size of type %s is not known", type->name);
+
+ return type_def.size;
}
static void emit_var_decl(FILE* outfile, const struct var_decl_node* node) {
- 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;
+ unsigned long long type_sz = get_type_size(&node->type);
+
+ fprintf(outfile, "\tsub rsp, %llu\n", type_sz);
+ scope->bp_offset += type_sz;
scope_define_var(scope, (struct var_def) {
.name = node->ident,
.loc = {
@@ -148,7 +172,8 @@ static void emit_fn_decl(FILE* outfile, const struct fn_decl_node* node) {
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);
+ unsigned long long type_sz = get_type_size(&args_node->type);
+
scope_define_var(scope, (struct var_def) {
.name = args_node->ident,
.loc = {
@@ -156,7 +181,8 @@ static void emit_fn_decl(FILE* outfile, const struct fn_decl_node* node) {
.offset = arg_bp_offset,
},
});
- arg_bp_offset -= type_def.size;
+
+ arg_bp_offset -= type_sz;
args_node = args_node->next;
}
@@ -183,8 +209,7 @@ void emit_code(const struct root_node* ast, const char* path) {
fprintf(outfile, "section .text\n");
scope_push(&scope);
-
- /* TODO: register all basic types */
+ scope_install_default_types(scope);
/* output all non-static function declarations as globals */
const struct root_node* node = ast;
diff --git a/parser.c b/parser.c
index 7de4ce9..699f345 100644
--- a/parser.c
+++ b/parser.c
@@ -1,5 +1,6 @@
#include "parser.h"
#include "lexer.h"
+#include "scope.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@@ -16,6 +17,7 @@
}
static struct token tok;
+static struct scope* scope;
static void* protected_alloc(size_t sz) {
void* ptr = calloc(1, sz);
@@ -38,14 +40,27 @@ static void expect(enum token_type expected) {
if (tok.type != expected) unexpected_token(expected);
}
+static void peek_or_panic() {
+ if (!lexer_peek(&tok))
+ PARSER_PANIC("unexpected EOF");
+}
+
/* "handle" indicates that we've peeked already */
static void handle_expr(struct expr_node* p_node);
static void handle_stmt(struct stmt_node* p_node);
-static void parse_type(struct type_node* p_node) {
- expect(TK_IDENT);
- /* TODO: maybe check that this type is real haha */
- p_node->type = tok.data.ident;
+static void handle_type(struct type_node* p_node) {
+ /* TODO: need some concept of known types in scope */
+ /* TODO: modifiers, void rules, arrays, etc. */
+ /* TODO: struct, union, enum */
+ p_node->name = tok.data.ident;
+
+ peek_or_panic();
+ p_node->ptr_level = 0;
+ while (tok.type == TK_STAR) {
+ p_node->ptr_level++;
+ expect(TK_STAR);
+ }
}
static void parse_return(struct return_node* p_node) {
@@ -70,6 +85,11 @@ static void parse_int_lit(struct int_lit_node* p_node) {
p_node->val = tok.data.int_lit;
}
+static void parse_var_ref(struct var_ref_node* p_node) {
+ expect(TK_IDENT);
+ p_node->ident = tok.data.ident;
+}
+
static void handle_expr(struct expr_node* p_node) {
switch (tok.type) {
case TK_SEMI:
@@ -79,13 +99,17 @@ static void handle_expr(struct expr_node* p_node) {
p_node->type = EXPR_INT_LIT;
parse_int_lit(&p_node->as._int_lit);
return;
+ case TK_IDENT:
+ p_node->type = EXPR_VAR_REF;
+ parse_var_ref(&p_node->as._var_ref);
+ return;
default:
PARSER_PANIC("expected expression");
}
}
-static void parse_var_decl(struct var_decl_node* p_node) {
- parse_type(&p_node->type);
+static void handle_var_decl(struct var_decl_node* p_node) {
+ handle_type(&p_node->type);
expect(TK_IDENT);
p_node->ident = tok.data.ident;
}
@@ -118,11 +142,12 @@ static void handle_stmt(struct stmt_node* p_node) {
if (strcmp(tok.data.ident, "return") == 0) {
p_node->type = STMT_RETURN;
parse_return(&p_node->as._return);
- } else {
+ break;
+ } else if (scope_get_type(scope, NULL, tok.data.ident)) {
p_node->type = STMT_VAR_DECL;
- parse_var_decl(&p_node->as._var_decl);
+ handle_var_decl(&p_node->as._var_decl);
+ break;
}
- break;
default:
p_node->type = STMT_EXPR;
handle_expr(&p_node->as._expr);
@@ -132,8 +157,10 @@ static void handle_stmt(struct stmt_node* p_node) {
static void parse_arg_list(struct var_decl_node** pp_arg) {
for (;;) {
+ expect(TK_IDENT);
+
*pp_arg = protected_alloc(sizeof(struct var_decl_node));
- parse_var_decl(*pp_arg);
+ handle_var_decl(*pp_arg);
pp_arg = &((*pp_arg)->next);
if (!lexer_peek(&tok))
@@ -145,7 +172,8 @@ static void parse_arg_list(struct var_decl_node** pp_arg) {
}
static void parse_fn_decl(struct fn_decl_node* p_node) {
- parse_type(&p_node->return_type);
+ expect(TK_IDENT);
+ handle_type(&p_node->return_type);
expect(TK_IDENT);
p_node->name = tok.data.ident;
@@ -173,6 +201,8 @@ static bool parse_root(struct root_node* p_node) {
struct root_node* parse(const char* path) {
lexer_load(path);
+ scope_push(&scope);
+ scope_install_default_types(scope);
struct root_node* root;
struct root_node** p_node = &root;
@@ -187,6 +217,7 @@ struct root_node* parse(const char* path) {
p_node = &((*p_node)->next);
}
+ scope_pop(&scope);
lexer_close();
return root;
}
diff --git a/scope.c b/scope.c
index 251aa51..3bd070b 100644
--- a/scope.c
+++ b/scope.c
@@ -79,6 +79,41 @@ void scope_pop(struct scope** p_scope) {
free(discarded_scope);
}
+void scope_install_default_types(struct scope* scope) {
+ scope_define_type(scope, (struct type_def) {
+ .name = "void",
+ .size = 0,
+ });
+ scope_define_type(scope, (struct type_def) {
+ .name = "bool",
+ .size = 1,
+ });
+ scope_define_type(scope, (struct type_def) {
+ .name = "char",
+ .size = 1,
+ });
+ scope_define_type(scope, (struct type_def) {
+ .name = "short",
+ .size = 2,
+ });
+ scope_define_type(scope, (struct type_def) {
+ .name = "int",
+ .size = 4,
+ });
+ scope_define_type(scope, (struct type_def) {
+ .name = "float",
+ .size = 4,
+ });
+ scope_define_type(scope, (struct type_def) {
+ .name = "long",
+ .size = 8,
+ });
+ scope_define_type(scope, (struct type_def) {
+ .name = "double",
+ .size = 8,
+ });
+}
+
bool scope_get_type(
const struct scope* scope,
struct type_def* p_entry,
@@ -87,7 +122,7 @@ bool scope_get_type(
for (; scope != NULL; scope = scope->next_out) {
struct type_def* type_def = *type_cell(scope, name);
if (type_def == NULL) continue;
- *p_entry = *type_def;
+ if (p_entry != NULL) *p_entry = *type_def;
return true;
}
return false;
@@ -115,7 +150,7 @@ bool scope_get_var(
for (; scope != NULL; scope = scope->next_out) {
struct var_def* var_def = *var_cell(scope, name);
if (var_def == NULL) continue;
- *p_entry = *var_def;
+ if (p_entry != NULL) *p_entry = *var_def;
return true;
}
return false;
diff --git a/scope.h b/scope.h
index 4975df4..36b6a93 100644
--- a/scope.h
+++ b/scope.h
@@ -38,6 +38,7 @@ struct scope {
void scope_push(struct scope** p_scope);
void scope_pop(struct scope** p_scope);
+void scope_install_default_types(struct scope* scope);
bool scope_get_type(
const struct scope* scope,
struct type_def* p_entry,
diff --git a/test/weird.c b/test/weird.c
new file mode 100644
index 0000000..74a74be
--- /dev/null
+++ b/test/weird.c
@@ -0,0 +1,3 @@
+int main(int argc) {
+ return argc;
+}