summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarson Fleming <cflems@cflems.net>2026-03-28 17:05:37 -1000
committerCarson Fleming <cflems@cflems.net>2026-03-28 17:05:37 -1000
commitb4d7305730606126d74862ca472a3efed964c2d8 (patch)
tree933ee0e11e30ec03181aba9051795513b94b0421
parent0dc409ab0967d9973f36c138825067462b9a216f (diff)
downloadccc-b4d7305730606126d74862ca472a3efed964c2d8.tar.gz
rehashing and size tracking corrections
-rw-r--r--ast.c9
-rw-r--r--ast.h18
-rw-r--r--codegen.c86
-rw-r--r--main.c25
-rw-r--r--parser.c26
-rw-r--r--scope.c72
-rw-r--r--scope.h3
-rw-r--r--test/manyvars.c9
8 files changed, 203 insertions, 45 deletions
diff --git a/ast.c b/ast.c
index 05f2755..8c3461f 100644
--- a/ast.c
+++ b/ast.c
@@ -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);
diff --git a/ast.h b/ast.h
index 6b7c3d5..5ae0d12 100644
--- a/ast.h
+++ b/ast.h
@@ -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;
diff --git a/codegen.c b/codegen.c
index c8a9933..37dea28 100644
--- a/codegen.c
+++ b/codegen.c
@@ -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;
}
diff --git a/main.c b/main.c
index 5c26dd3..4cb0ba7 100644
--- a/main.c
+++ b/main.c
@@ -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);
}
}
diff --git a/parser.c b/parser.c
index d7dc3fb..157ffb1 100644
--- a/parser.c
+++ b/parser.c
@@ -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;
diff --git a/scope.c b/scope.c
index 310a111..17bc22b 100644
--- a/scope.c
+++ b/scope.c
@@ -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,
});
}
diff --git a/scope.h b/scope.h
index a67c66b..2066a51 100644
--- a/scope.h
+++ b/scope.h
@@ -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;
+}