diff options
| author | Carson Fleming <cflems@cflems.net> | 2026-03-27 10:30:10 -1000 |
|---|---|---|
| committer | Carson Fleming <cflems@cflems.net> | 2026-03-27 10:30:10 -1000 |
| commit | fca3bf239cfdf03c4479f5d0c14a21c1fd96ea3e (patch) | |
| tree | 0618ad64a13e949ce9273098df724d8d25bdcb36 | |
| parent | 21f688c1eac5fb09ae68fd9b3cfcff687de36601 (diff) | |
| download | ccc-fca3bf239cfdf03c4479f5d0c14a21c1fd96ea3e.tar.gz | |
woah we got variables
| -rw-r--r-- | ast.c | 9 | ||||
| -rw-r--r-- | ast.h | 57 | ||||
| -rw-r--r-- | codegen.c | 47 | ||||
| -rw-r--r-- | parser.c | 53 | ||||
| -rw-r--r-- | scope.c | 39 | ||||
| -rw-r--r-- | scope.h | 1 | ||||
| -rw-r--r-- | test/weird.c | 3 |
7 files changed, 169 insertions, 40 deletions
@@ -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; } } @@ -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, @@ -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; @@ -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; } @@ -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; @@ -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; +} |
