diff options
| author | Carson Fleming <cflems@cflems.net> | 2026-03-28 17:05:37 -1000 |
|---|---|---|
| committer | Carson Fleming <cflems@cflems.net> | 2026-03-28 17:05:37 -1000 |
| commit | b4d7305730606126d74862ca472a3efed964c2d8 (patch) | |
| tree | 933ee0e11e30ec03181aba9051795513b94b0421 | |
| parent | 0dc409ab0967d9973f36c138825067462b9a216f (diff) | |
| download | ccc-b4d7305730606126d74862ca472a3efed964c2d8.tar.gz | |
rehashing and size tracking corrections
| -rw-r--r-- | ast.c | 9 | ||||
| -rw-r--r-- | ast.h | 18 | ||||
| -rw-r--r-- | codegen.c | 86 | ||||
| -rw-r--r-- | main.c | 25 | ||||
| -rw-r--r-- | parser.c | 26 | ||||
| -rw-r--r-- | scope.c | 72 | ||||
| -rw-r--r-- | scope.h | 3 | ||||
| -rw-r--r-- | test/manyvars.c | 9 |
8 files changed, 203 insertions, 45 deletions
@@ -68,9 +68,18 @@ static void return_destroy(struct return_node* node) { } } +static void str_lit_destroy(struct str_lit_node* node) { + free(node->val); +} + static void expr_destroy(struct expr_node* node) { switch (node->type) { case EXPR_INT_LIT: + case EXPR_FLOAT_LIT: + case EXPR_CHAR_LIT: + break; + case EXPR_STR_LIT: + str_lit_destroy(&node->as._str_lit); break; case EXPR_VAR_REF: var_ref_destroy(&node->as._var_ref); @@ -16,6 +16,18 @@ struct int_lit_node { long long val; }; +struct float_lit_node { + double val; +}; + +struct char_lit_node { + char val; +}; + +struct str_lit_node { + char* val; +}; + struct var_ref_node { char* ident; }; @@ -47,11 +59,17 @@ struct assign_node { struct expr_node { enum { EXPR_INT_LIT, + EXPR_FLOAT_LIT, + EXPR_CHAR_LIT, + EXPR_STR_LIT, EXPR_VAR_REF, EXPR_ASSIGN, } type; union { struct int_lit_node _int_lit; + struct float_lit_node _float_lit; + struct char_lit_node _char_lit; + struct str_lit_node _str_lit; struct var_ref_node _var_ref; struct assign_node _assign; } as; @@ -53,9 +53,14 @@ static void emit_storage_loc( static void emit_mov( FILE* outfile, const struct storage_location* dst, - const struct storage_location* src, - unsigned long long sz + const struct storage_location* src ) { + /* size is only defined for memory locations */ + unsigned long long sz; + if (dst->type == BP_OFFSET) sz = dst->sz; + else if (src->type == BP_OFFSET) sz = src->sz; + else sz = FULL_REG_SZ; + switch (dst->type) { case REGISTER: if (src->type == REGISTER && sz < 4) { @@ -72,12 +77,20 @@ static void emit_mov( case BP_OFFSET: if (src->type == BP_OFFSET) { /* `mov mem, mem` is illegal in x86_64 */ - emit_mov(outfile, &RV_LOC, src, sz); - emit_mov(outfile, dst, &RV_LOC, sz); + emit_mov(outfile, &RV_LOC, src); + emit_mov(outfile, dst, &RV_LOC); return; } fprintf(outfile, "\tmov "); + if (src->type == IMMEDIATE) { + /* must specify size to move immediates into memory*/ + if (sz > 4) fprintf(outfile, "qword "); + else if (sz > 2) fprintf(outfile, "dword "); + else if (sz > 1) fprintf(outfile, "word "); + else fprintf(outfile, "byte "); + } + emit_storage_loc(outfile, dst, sz); fprintf(outfile, ", "); emit_storage_loc(outfile, src, sz); @@ -109,8 +122,43 @@ static void emit_int_lit( &(struct storage_location) { .type = IMMEDIATE, .value = node->val, - }, - FULL_REG_SZ); + }); +} + +static void emit_float_lit( + FILE* outfile, + const struct float_lit_node* node, + const struct storage_location* storage +) { + if (storage != NULL) { + CGEN_PANIC("float literals are not implemented"); + } +} + +static void emit_char_lit( + FILE* outfile, + const struct char_lit_node* node, + const struct storage_location* storage +) { + if (storage != NULL) { + emit_mov( + outfile, + storage, + &(struct storage_location) { + .type = IMMEDIATE, + .value = (unsigned long long) node->val + }); + } +} + +static void emit_str_lit( + FILE* outfile, + const struct str_lit_node* node, + const struct storage_location* storage +) { + if (storage != NULL) { + CGEN_PANIC("string literals are not implemented"); + } } static struct var_def get_var(const char* name) { @@ -127,7 +175,7 @@ static void emit_var_ref( ) { if (storage != NULL) { struct var_def var_def = get_var(node->ident); - emit_mov(outfile, storage, &var_def.loc, var_def.sz); + emit_mov(outfile, storage, &var_def.loc); } } @@ -140,7 +188,7 @@ static unsigned long long get_type_size(const struct type_node* type) { if (!scope_get_type(scope, &type_def, type->name)) CGEN_PANIC("size of type %s is not known", type->name); - return type_def.size; + return type_def.sz; } static struct var_def emit_var_decl( @@ -157,8 +205,8 @@ static struct var_def emit_var_decl( .loc = { .type = BP_OFFSET, .offset = scope->bp_offset, + .sz = type_sz, }, - .sz = type_sz, }; scope_define_var(scope, var_def); return var_def; @@ -177,10 +225,10 @@ static struct lval_def emit_lval( switch (node->type) { case LVAL_VAR_DECL: var_def = emit_var_decl(outfile, &node->as._var_decl); - return (struct lval_def) {.loc = var_def.loc, .sz = var_def.sz}; + return (struct lval_def) {.loc = var_def.loc, .sz = var_def.loc.sz}; case LVAL_VAR_REF: var_def = get_var(node->as._var_ref.ident); - return (struct lval_def) {.loc = var_def.loc, .sz = var_def.sz}; + return (struct lval_def) {.loc = var_def.loc, .sz = var_def.loc.sz}; } CGEN_PANIC("unknown lval type: %d", node->type); } @@ -192,7 +240,7 @@ static void emit_assignment( ) { const struct lval_def lval_def = emit_lval(outfile, &node->lval); emit_expr(outfile, node->rval, &lval_def.loc); - if (storage != NULL) emit_mov(outfile, storage, &lval_def.loc, lval_def.sz); + if (storage != NULL) emit_mov(outfile, storage, &lval_def.loc); } static void emit_expr( @@ -204,6 +252,15 @@ static void emit_expr( case EXPR_INT_LIT: emit_int_lit(outfile, &node->as._int_lit, storage); break; + case EXPR_FLOAT_LIT: + emit_float_lit(outfile, &node->as._float_lit, storage); + break; + case EXPR_CHAR_LIT: + emit_char_lit(outfile, &node->as._char_lit, storage); + break; + case EXPR_STR_LIT: + emit_str_lit(outfile, &node->as._str_lit, storage); + break; case EXPR_VAR_REF: emit_var_ref(outfile, &node->as._var_ref, storage); break; @@ -277,8 +334,8 @@ static void emit_fn_decl(FILE* outfile, const struct fn_decl_node* node) { .loc = { .type = BP_OFFSET, .offset = scope->bp_offset, + .sz = type_sz, }, - .sz = type_sz, }; scope_define_var(scope, var_def); @@ -292,10 +349,11 @@ static void emit_fn_decl(FILE* outfile, const struct fn_decl_node* node) { arg_src = (struct storage_location) { .type = BP_OFFSET, .offset = spilled_bp_ofs, + .sz = type_sz, }; spilled_bp_ofs -= type_sz; } - emit_mov(outfile, &var_def.loc, &arg_src, type_sz); + emit_mov(outfile, &var_def.loc, &arg_src); args_node = args_node->next; } @@ -41,13 +41,28 @@ void test_parser(int argc, char** argv) { for (int i = 1; i < argc; i++) { struct root_node* root = parse(argv[i]); unsigned int fn_sz = strlen(argv[i]); - char outfile[fn_sz + 1]; - strcpy(outfile, argv[i]); - outfile[fn_sz - 1] = 's'; - outfile[fn_sz] = 0; + char asm_file[fn_sz + 1]; + strcpy(asm_file, argv[i]); + asm_file[fn_sz - 1] = 's'; + asm_file[fn_sz] = 0; - emit_code(root, outfile); + emit_code(root, asm_file); ast_destroy(root); + + char obj_file[fn_sz + 1]; + strcpy(obj_file, argv[i]); + obj_file[fn_sz - 1] = 'o'; + obj_file[fn_sz] = 0; + + char cmd_buffer[2*fn_sz + 20]; + snprintf( + cmd_buffer, + sizeof(cmd_buffer), + "nasm -f elf64 %s -o %s", + asm_file, + obj_file); + int status = system(cmd_buffer); + if (status != 0) exit(status); } } @@ -80,9 +80,23 @@ static void parse_type(struct type_node* p_node) { static void parse_expr(struct expr_node* p_node); -static void parse_int_lit(struct int_lit_node* p_node) { - expect(TK_INT_LIT); - p_node->val = tok.data.int_lit; +static void parse_literal(struct expr_node* p_node) { + peek_or_panic(); + + switch (tok.type) { + case TK_INT_LIT: + expect(TK_INT_LIT); + p_node->type = EXPR_INT_LIT; + p_node->as._int_lit.val = tok.data.int_lit; + break; + case TK_CHAR_LIT: + expect(TK_CHAR_LIT); + p_node->type = EXPR_CHAR_LIT; + p_node->as._char_lit.val = tok.data.char_lit; + break; + default: + PARSER_PANIC("invalid literal type"); + } } static void parse_var_ref(struct var_ref_node* p_node) { @@ -124,8 +138,10 @@ static void parse_expr(struct expr_node* p_node) { expect(TK_RPAREN); break; case TK_INT_LIT: - p_node->type = EXPR_INT_LIT; - parse_int_lit(&p_node->as._int_lit); + case TK_CHAR_LIT: + case TK_FLOAT_LIT: + case TK_STR_LIT: + parse_literal(p_node); break; case TK_IDENT: p_node->type = EXPR_VAR_REF; @@ -2,7 +2,7 @@ #include <stdlib.h> #include <stdio.h> #include <string.h> -#define DEFAULT_SIZE 16 +#define DEFAULT_SIZE 4 static void scope_init(struct scope* scope) { scope->types = calloc(DEFAULT_SIZE, sizeof(struct type_def*)); @@ -29,12 +29,6 @@ unsigned long long hash_name(const char* name) { return hash; } -static void rehash_types(struct scope* scope) { - /* TODO: rehashing :'( */ - fprintf(stderr, "ccc: would have to rehash and I don't wanna\n"); - exit(1); -} - static struct type_def** type_cell( const struct scope* scope, const char* name @@ -50,10 +44,27 @@ static struct type_def** type_cell( return NULL; } -static void rehash_vars(struct scope* scope) { - /* TODO: rehashing :'( */ - fprintf(stderr, "ccc: would have to rehash and I don't wanna\n"); - exit(1); +static void rehash_types(struct scope* scope) { + struct type_def** old_types = scope->types; + unsigned long long old_cap = scope->type_cap; + scope->type_cap *= 2; + scope->types = calloc(scope->type_cap, sizeof(struct type_def*)); + if (scope->types == NULL) { + fprintf(stderr, "ccc: out of memory\n"); + exit(1); + } + + for (unsigned long long i = 0; i < old_cap; i++) { + if (old_types[i] == NULL) continue; + + struct type_def** cell = type_cell(scope, old_types[i]->name); + if (cell == NULL) { + fprintf(stderr, "ccc: types rehash failed, likely a bug\n"); + exit(1); + } + *cell = old_types[i]; + } + free(old_types); } static struct var_def** var_cell( @@ -71,6 +82,29 @@ static struct var_def** var_cell( return NULL; } +static void rehash_vars(struct scope* scope) { + struct var_def** old_vars = scope->vars; + unsigned long long old_cap = scope->var_cap; + scope->var_cap *= 2; + scope->vars = calloc(scope->var_cap, sizeof(struct var_def*)); + if (scope->vars == NULL) { + fprintf(stderr, "ccc: out of memory\n"); + exit(1); + } + + for (unsigned long long i = 0; i < old_cap; i++) { + if (old_vars[i] == NULL) continue; + + struct var_def** cell = var_cell(scope, old_vars[i]->name); + if (cell == NULL) { + fprintf(stderr, "ccc: vars rehash failed, likely a bug\n"); + exit(1); + } + *cell = old_vars[i]; + } + free(old_vars); +} + void scope_push(struct scope** p_scope) { struct scope* inner_scope = calloc(1, sizeof(struct scope)); scope_init(inner_scope); @@ -88,35 +122,35 @@ void scope_pop(struct scope** p_scope) { void scope_install_default_types(struct scope* scope) { scope_define_type(scope, (struct type_def) { .name = "void", - .size = 0, + .sz = 0, }); scope_define_type(scope, (struct type_def) { .name = "bool", - .size = 1, + .sz = 1, }); scope_define_type(scope, (struct type_def) { .name = "char", - .size = 1, + .sz = 1, }); scope_define_type(scope, (struct type_def) { .name = "short", - .size = 2, + .sz = 2, }); scope_define_type(scope, (struct type_def) { .name = "int", - .size = 4, + .sz = 4, }); scope_define_type(scope, (struct type_def) { .name = "float", - .size = 4, + .sz = 4, }); scope_define_type(scope, (struct type_def) { .name = "long", - .size = 8, + .sz = 8, }); scope_define_type(scope, (struct type_def) { .name = "double", - .size = 8, + .sz = 8, }); } @@ -19,13 +19,12 @@ struct storage_location { struct type_def { const char* name; - unsigned long long size; + unsigned long long sz; }; struct var_def { const char* name; struct storage_location loc; - unsigned long long sz; }; struct scope { diff --git a/test/manyvars.c b/test/manyvars.c new file mode 100644 index 0000000..50ef22c --- /dev/null +++ b/test/manyvars.c @@ -0,0 +1,9 @@ +int main (int argc, char** argv) { + int x = 2; + int y = 3; + char c = 'a'; + int z = 5; + int a = 6; + char d = 'f'; + return z; +} |
