diff options
| -rw-r--r-- | ast.c | 15 | ||||
| -rw-r--r-- | ast.h | 18 | ||||
| -rw-r--r-- | codegen.c | 145 | ||||
| -rw-r--r-- | parser.c | 67 | ||||
| -rw-r--r-- | scope.c | 183 | ||||
| -rw-r--r-- | scope.h | 31 |
6 files changed, 286 insertions, 173 deletions
@@ -5,15 +5,6 @@ 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->def); -} - -static void var_decl_destroy(struct var_decl_node* node) { - free(node->ident); - type_destroy(&node->type); -} - static void var_ref_destroy(struct var_ref_node* node) { free(node->ident); } @@ -21,7 +12,6 @@ static void var_ref_destroy(struct var_ref_node* node) { static void lval_destroy(struct lval_node* node) { switch (node->type) { case LVAL_VAR_DECL: - var_decl_destroy(&node->inner.var_decl); break; case LVAL_VAR_REF: var_ref_destroy(&node->inner.var_ref); @@ -50,16 +40,12 @@ static void group_destroy(struct group_node* node) { static void args_decl_destroy(struct args_decl_node* node) { if (node != NULL) { - var_decl_destroy(node->decl); free(node->decl); args_decl_destroy(node->next); } } static void fn_decl_destroy(struct fn_decl_node* node) { - type_destroy(&node->return_type); - free(node->name); - args_decl_destroy(node->args); free(node->args); @@ -152,7 +138,6 @@ static void stmt_destroy(struct stmt_node* node) { expr_destroy(&node->inner.expr); break; case STMT_VAR_DECL: - var_decl_destroy(&node->inner.var_decl); break; case STMT_RETURN: return_destroy(&node->inner.return_); @@ -6,12 +6,9 @@ struct stmt_node; struct expr_node; -struct type_node { - bool is_unsigned; - bool is_short; - bool is_long; +struct type_ref_node { unsigned char ptr_level; - struct type_def* def; + const struct type_def* def_ref; }; struct int_lit_node { @@ -35,8 +32,8 @@ struct var_ref_node { }; struct var_decl_node { - struct type_node type; - char* ident; + struct type_ref_node type; + struct var_def* def_ref; }; struct lval_node { @@ -108,10 +105,7 @@ struct expr_node { struct binary_node binary; } inner; - struct { - bool is_signed; - unsigned long long sz; - } evaluated_type; + const struct type_def* resolved_type; }; struct group_node { @@ -125,7 +119,7 @@ struct args_decl_node { }; struct fn_decl_node { - struct type_node return_type; + struct type_ref_node return_type; char* name; struct args_decl_node* args; struct group_node body; @@ -15,8 +15,8 @@ } struct lval_def { + const struct type_def* type; struct storage_location loc; - unsigned long long sz; }; static const struct storage_location RV_LOC = { @@ -36,39 +36,42 @@ static struct scope* scope; static const struct fn_decl_node* active_fn; static unsigned long long branch_counter = 0; -static struct lval_def allocate_register(unsigned long long sz) { +static struct lval_def allocate_register(const struct type_def* type) { return (struct lval_def) { .loc = { .type = STO_REG, .reg = &RAX, /* TODO: no real register coloring happening LOL */ }, - .sz = sz, + .type = type, }; } -static struct lval_def allocate_stack(FILE* outfile, unsigned long long sz) { - fprintf(outfile, "\tsub rsp, %llu\n", sz); - scope->bp_offset += sz; +static struct lval_def allocate_stack( + FILE* outfile, + const struct type_def* type +) { + fprintf(outfile, "\tsub rsp, %llu\n", type->sz); + scope->bp_offset += type->sz; return (struct lval_def) { .loc = { .type = STO_STACK, .bp_offset = scope->bp_offset, }, - .sz = sz, + .type = type, }; } static struct lval_def allocate_temporary( FILE* outfile, - unsigned long long sz + const struct type_def* type ) { - return allocate_stack(outfile, sz); + return allocate_stack(outfile, type); } static void deallocate_temporary(FILE* outfile, const struct lval_def* tmp) { if (tmp->loc.type == STO_STACK) { - fprintf(outfile, "\tadd rsp, %llu\n", tmp->sz); - scope->bp_offset -= tmp->sz; + fprintf(outfile, "\tadd rsp, %llu\n", tmp->type->sz); + scope->bp_offset -= tmp->type->sz; } } @@ -146,32 +149,32 @@ static void emit_mov( switch (dst->loc.type) { case STO_REG: - if (src->type == STO_REG && dst->sz < 4) { + if (src->type == STO_REG && dst->type->sz < 4) { fprintf(outfile, "\tmovzx "); emit_storage_loc(outfile, &dst->loc, FULL_REG_SZ); } else { fprintf(outfile, "\tmov "); - emit_storage_loc(outfile, &dst->loc, dst->sz); + emit_storage_loc(outfile, &dst->loc, dst->type->sz); } fprintf(outfile, ", "); - emit_storage_loc(outfile, src, dst->sz); + emit_storage_loc(outfile, src, dst->type->sz); break; case STO_STACK: if (src->type == STO_STACK) { /* `mov mem, mem` is illegal in x86_64 */ - struct lval_def tmp = allocate_register(dst->sz); + struct lval_def tmp = allocate_register(dst->type); emit_mov(outfile, &tmp, src); emit_mov(outfile, dst, &tmp.loc); return; } fprintf(outfile, "\tmov "); - if (src->type == STO_IMM) emit_size_const(outfile, dst->sz); + if (src->type == STO_IMM) emit_size_const(outfile, dst->type->sz); - emit_storage_loc(outfile, &dst->loc, dst->sz); + emit_storage_loc(outfile, &dst->loc, dst->type->sz); fprintf(outfile, ", "); - emit_storage_loc(outfile, src, dst->sz); + emit_storage_loc(outfile, src, dst->type->sz); break; case STO_LABEL: case STO_IMM: @@ -186,11 +189,11 @@ static void emit_cmp_zero(FILE* outfile, const struct lval_def* lval) { fprintf(outfile, "\tcmp "); switch (lval->loc.type) { case STO_REG: - emit_storage_loc(outfile, &lval->loc, lval->sz); + emit_storage_loc(outfile, &lval->loc, lval->type->sz); break; case STO_STACK: - emit_size_const(outfile, lval->sz); - emit_storage_loc(outfile, &lval->loc, lval->sz); + emit_size_const(outfile, lval->type->sz); + emit_storage_loc(outfile, &lval->loc, lval->type->sz); break; case STO_LABEL: case STO_IMM: @@ -201,17 +204,17 @@ static void emit_cmp_zero(FILE* outfile, const struct lval_def* lval) { fprintf(outfile, ", 0\n"); } -/* TODO: move this utility to the type checker and use evaluated_type */ -static unsigned long long get_type_size(const struct type_node* type) { +/* TODO: move this utility to the type checker and use resolved_type */ +static unsigned long long get_type_size(const struct type_ref_node* type) { if (type->ptr_level > 0) return PTR_SIZE; - return type->def->sz; + return type->def_ref->sz; } static inline struct lval_def make_stack_lval( FILE* outfile, - const struct type_node* type + const struct type_def* type ) { - return allocate_stack(outfile, get_type_size(type)); + return allocate_stack(outfile, type); } static void emit_expr( @@ -270,8 +273,8 @@ static void emit_str_lit( } } -static struct var_def get_var(const char* name) { - struct var_def var_def; +static struct var_def* get_var(const char* name) { + struct var_def* var_def; if (!scope_get_var(scope, &var_def, name)) CGEN_PANIC("reference to undefined variable %s", name); return var_def; @@ -283,25 +286,19 @@ static void emit_var_ref( const struct lval_def* dst ) { if (dst != NULL) { - struct var_def var_def = get_var(node->ident); - emit_mov(outfile, dst, &var_def.loc); + emit_mov(outfile, dst, &get_var(node->ident)->loc); } } static void emit_stmt(FILE* outfile, const struct stmt_node* node); -static struct var_def emit_var_decl( +static struct var_def* emit_var_decl( FILE* outfile, const struct var_decl_node* node ) { - /* TODO: type checker should define vars, we just set their loc */ - struct lval_def var_dst = make_stack_lval(outfile, &node->type); - struct var_def var_def = { - .name = node->ident, - .loc = var_dst.loc, - .sz = var_dst.sz, - }; - scope_define_var(scope, var_def); + struct lval_def var_dst = make_stack_lval(outfile, node->type.def_ref); + struct var_def* var_def = node->def_ref; + var_def->loc = var_dst.loc; return var_def; } @@ -309,14 +306,20 @@ static struct lval_def emit_lval( FILE* outfile, const struct lval_node* node ) { - struct var_def var_def; + struct var_def* var_def; switch (node->type) { case LVAL_VAR_DECL: var_def = emit_var_decl(outfile, &node->inner.var_decl); - return (struct lval_def) {.loc = var_def.loc, .sz = var_def.sz}; + return (struct lval_def) { + .loc = var_def->loc, + .type = var_def->resolved_type, + }; case LVAL_VAR_REF: var_def = get_var(node->inner.var_ref.ident); - return (struct lval_def) {.loc = var_def.loc, .sz = var_def.sz}; + return (struct lval_def) { + .loc = var_def->loc, + .type = var_def->resolved_type, + }; } CGEN_PANIC("unknown lval type: %d", node->type); } @@ -343,7 +346,7 @@ static void emit_call( struct args_eval_node* arg_eval = node->args; while (arg_decl != NULL && arg_eval != NULL) { struct lval_def arg_dst = - make_stack_lval(outfile, &arg_decl->decl->type); + make_stack_lval(outfile, arg_decl->decl->type.def_ref); emit_expr(outfile, arg_eval->expr, &arg_dst); arg_decl = arg_decl->next; @@ -368,14 +371,14 @@ static void emit_call( struct lval_def arg_dst; if (arg_regnum < CC_N_REGS) arg_dst = (struct lval_def) { + .type = arg_decl->decl->type.def_ref, .loc = (struct storage_location) { .type = STO_REG, .reg = CALLING_CONV[arg_regnum++], }, - .sz = type_sz, }; else - arg_dst = make_stack_lval(outfile, &arg_decl->decl->type); + arg_dst = make_stack_lval(outfile, arg_decl->decl->type.def_ref); emit_mov(outfile, &arg_dst, &(struct storage_location) { .type = STO_STACK, @@ -411,8 +414,11 @@ static void emit_unary( switch (node->op) { case UNARY_NEG: fprintf(outfile, "\tneg "); - if (dst->loc.type == STO_STACK) emit_size_const(outfile, dst->sz); - emit_storage_loc(outfile, &dst->loc, dst->sz); + + if (dst->loc.type == STO_STACK) + emit_size_const(outfile, dst->type->sz); + + emit_storage_loc(outfile, &dst->loc, dst->type->sz); fprintf(outfile, "\n"); break; } @@ -431,29 +437,29 @@ static void emit_binary( } /* LHS goes in RAX explicitly because imul and idiv are weird */ - struct lval_def rhs_dst = allocate_temporary(outfile, dst->sz); + struct lval_def rhs_dst = allocate_temporary(outfile, dst->type); emit_expr(outfile, node->rhs, &rhs_dst); struct lval_def lhs_dst = (struct lval_def) { .loc = MULDIV_LOC, - .sz = dst->sz, + .type = dst->type, }; emit_expr(outfile, node->lhs, &lhs_dst); switch (node->op) { case BINARY_ADD: fprintf(outfile, "\tadd "); - emit_storage_loc(outfile, &lhs_dst.loc, dst->sz); + emit_storage_loc(outfile, &lhs_dst.loc, dst->type->sz); fprintf(outfile, ", "); break; case BINARY_SUB: fprintf(outfile, "\tsub "); - emit_storage_loc(outfile, &lhs_dst.loc, dst->sz); + emit_storage_loc(outfile, &lhs_dst.loc, dst->type->sz); fprintf(outfile, ", "); break; case BINARY_MUL: fprintf(outfile, "\timul "); if (rhs_dst.loc.type == STO_STACK) - emit_size_const(outfile, dst->sz); + emit_size_const(outfile, dst->type->sz); break; case BINARY_DIV: /* nothing in the top half reg */ @@ -465,11 +471,11 @@ static void emit_binary( fprintf(outfile, "\tidiv "); if (rhs_dst.loc.type == STO_STACK) - emit_size_const(outfile, dst->sz); + emit_size_const(outfile, dst->type->sz); break; } - emit_storage_loc(outfile, &rhs_dst.loc, dst->sz); + emit_storage_loc(outfile, &rhs_dst.loc, dst->type->sz); fprintf(outfile, "\n"); /* TODO: deal with RDX overflow shit for imul and idiv */ @@ -517,10 +523,10 @@ static void emit_expr( static void emit_return(FILE* outfile, const struct return_node* node) { if (active_fn == NULL) CGEN_PANIC("must be inside a function to return"); - unsigned long long return_type_sz = get_type_size(&active_fn->return_type); + const struct type_def* return_type = active_fn->return_type.def_ref; if (node->ret_val != NULL) { - if (return_type_sz == 0) + if (return_type->sz == 0) CGEN_PANIC( "returning a value from void function %s", active_fn->name); @@ -529,9 +535,9 @@ static void emit_return(FILE* outfile, const struct return_node* node) { node->ret_val, &(struct lval_def) { .loc = RV_LOC, - .sz = return_type_sz, + .type = return_type, }); - } else if (return_type_sz > 0) { + } else if (return_type > 0) { CGEN_PANIC( "non-void function %s should return a value", active_fn->name); } @@ -561,8 +567,9 @@ static void emit_group(FILE* outfile, const struct group_node* node) { } static void emit_if(FILE* outfile, const struct if_node* node) { - /* TODO: use type checked cond result size; using full reg size causes a segfault */ - struct lval_def cond_result = allocate_temporary(outfile, FULL_REG_SZ); + /* TODO: make type checking real so we aren't passing a null pointer here */ + struct lval_def cond_result = + allocate_temporary(outfile, node->cond->resolved_type); emit_expr(outfile, node->cond, &cond_result); emit_cmp_zero(outfile, &cond_result); @@ -622,17 +629,11 @@ static void emit_fn_decl(FILE* outfile, const struct fn_decl_node* node) { long long spilled_bp_ofs = -16; // return address + old bp unsigned char arg_regnum = 0; struct args_decl_node* arg_decl = node->args; - while (arg_decl != NULL) { + for (; arg_decl != NULL; arg_decl = arg_decl->next) { + struct var_def* arg_def = arg_decl->decl->def_ref; 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) { - .name = arg_decl->decl->ident, - .loc = arg_dst.loc, - .sz = arg_dst.sz, - }); + make_stack_lval(outfile, arg_decl->decl->type.def_ref); + arg_def->loc = arg_dst.loc; struct storage_location arg_src; if (arg_regnum < CC_N_REGS) { @@ -645,11 +646,9 @@ static void emit_fn_decl(FILE* outfile, const struct fn_decl_node* node) { .type = STO_STACK, .bp_offset = spilled_bp_ofs, }; - spilled_bp_ofs -= arg_dst.sz; + spilled_bp_ofs -= arg_decl->decl->type.def_ref->sz; } emit_mov(outfile, &arg_dst, &arg_src); - - arg_decl = arg_decl->next; } emit_group_contents(outfile, &node->body); @@ -61,15 +61,25 @@ static void expect_kw(const char* kw) { tok.data.ident = NULL; } -static void parse_type(struct type_node* p_node) { +static void parse_type_ref(struct type_ref_node* p_node) { /* TODO: modifiers, void rules, arrays, etc. */ /* TODO: struct, union, enum */ expect(TK_IDENT); - struct type_def* type_def = protected_alloc(sizeof(struct type_def)); - if (!scope_get_type(scope, type_def, tok.data.ident)) + const struct type_def* type_def; + if (!scope_get_type( + scope, + &type_def, + &(struct type_key) { + .name = tok.data.ident, + /* TODO: parse modifiers */ + .how_long = 0, + .marked_signed = 0, + .marked_unsigned = 0, + })) PARSER_PANIC("unknown type name: %s", tok.data.ident); - p_node->def = type_def; + free(tok.data.ident); + p_node->def_ref = type_def; peek_or_panic(); p_node->ptr_level = 0; @@ -143,15 +153,16 @@ static void parse_args_eval(struct args_eval_node** pp_arg) { static void parse_expr_call(struct expr_node* p_node) { switch (p_node->type) { case EXPR_VAR_REF: - struct var_def var_def; + struct var_def* var_def; if (!scope_get_var(scope, &var_def, p_node->inner.var_ref.ident)) PARSER_PANIC( "%s is not a known function", p_node->inner.var_ref.ident); - if (var_def.loc.type != STO_FN) + /* TODO: I would like to include functions in the resolve type rather than checking storage */ + if (var_def->loc.type != STO_FN) PARSER_PANIC("called object is not a function"); - p_node->inner.call.called_fn_ref = var_def.loc.decl; + p_node->inner.call.called_fn_ref = var_def->loc.decl; break; default: PARSER_PANIC("expression is not callable"); @@ -264,14 +275,16 @@ static void parse_expr(struct expr_node* p_node) { } static void parse_var_decl(struct var_decl_node* p_node) { - parse_type(&p_node->type); + parse_type_ref(&p_node->type); expect(TK_IDENT); - p_node->ident = tok.data.ident; - scope_define_var(scope, (struct var_def) { - .name = p_node->ident, + + p_node->def_ref = scope_define_var(scope, (struct var_def) { + .name = tok.data.ident, .loc.type = STO_UNRESOLVED, - .sz = 0, /* unknown */ + .resolved_type = p_node->type.def_ref, }); + if (p_node->def_ref == NULL) + PARSER_PANIC("redefinition of '%s'", tok.data.ident); } static void parse_stmt(struct stmt_node* p_node); @@ -372,7 +385,15 @@ static void parse_stmt(struct stmt_node* p_node) { p_node->type = STMT_RETURN; parse_return(&p_node->inner.return_); break; - } else if (scope_get_type(scope, NULL, tok.data.ident)) { + } else if (scope_get_type( + scope, + NULL, + &(struct type_key) { + .name = tok.data.ident, + .how_long = 0, + .marked_signed = false, + .marked_unsigned = false, + })) { p_node->type = STMT_VAR_DECL; parse_var_decl(&p_node->inner.var_decl); break; @@ -400,18 +421,20 @@ static void parse_args_decl(struct args_decl_node** pp_decl) { } static void parse_fn_decl(struct fn_decl_node* p_node) { - parse_type(&p_node->return_type); + parse_type_ref(&p_node->return_type); expect(TK_IDENT); - p_node->name = tok.data.ident; - scope_define_var(scope, (struct var_def) { - .name = p_node->name, - .loc = { - .type = STO_FN, - .decl = p_node, - }, - }); + if (scope_define_var(scope, (struct var_def) { + .name = tok.data.ident, + .loc = { + .type = STO_FN, + .decl = p_node, + }, + }) == NULL) + PARSER_PANIC("redefinition of '%s'", tok.data.ident) + + p_node->name = tok.data.ident; expect(TK_LPAREN); @@ -11,34 +11,77 @@ static void scope_init(struct scope* scope) { scope->var_cap = DEFAULT_SIZE; } +static void type_destroy(struct type_def* type) { + free(type->key.name); +} + +static void var_destroy(struct var_def* var) { + free(var->name); +} + void scope_destroy(struct scope* scope) { for (unsigned long long i = 0; i < scope->type_cap; i++) { - if (scope->types[i] != NULL) free(scope->types[i]); + if (scope->types[i] != NULL) { + type_destroy(scope->types[i]); + free(scope->types[i]); + } } free(scope->types); for (unsigned long long i = 0; i < scope->var_cap; i++) { - if (scope->vars[i] != NULL) free(scope->vars[i]); + if (scope->vars[i] != NULL) { + var_destroy(scope->vars[i]); + free(scope->vars[i]); + } } free(scope->vars); } -unsigned long long hash_name(const char* name) { +static inline unsigned long long advance_hash( + unsigned long long hash, + unsigned long long val, + unsigned long long cap +) { + return ((hash << 5) - hash + val) % cap;; +} + +static unsigned long long hash_name(const char* name, unsigned long long cap) { unsigned long long hash = 0, i = 0; - while (name[i] != 0) hash = (hash << 5) - hash + name[i++]; + while (name[i] != 0) hash = advance_hash(hash, name[i++], cap); return hash; } +unsigned long long hash_type_key( + const struct type_key* key, + unsigned long long cap +) { + unsigned long long hash = hash_name(key->name, cap); + hash = advance_hash(hash, key->how_long, cap); + hash = advance_hash(hash, key->marked_signed, cap); + hash = advance_hash(hash, key->marked_unsigned, cap); + return hash; +} + +static bool type_keys_equal( + const struct type_key* a, + const struct type_key* b +) { + return a->how_long == b->how_long + && a->marked_signed == b->marked_signed + && a->marked_unsigned == b->marked_unsigned + && strcmp(a->name, b->name) == 0; +} + static struct type_def** type_cell( const struct scope* scope, - const char* name + const struct type_key* key ) { - unsigned long long orig_idx = hash_name(name) % scope->type_cap; + unsigned long long orig_idx = hash_type_key(key, scope->type_cap); unsigned long long idx = orig_idx; do { if (scope->types[idx] == NULL - || strcmp(name, scope->types[idx]->name) == 0) + || type_keys_equal(key, &scope->types[idx]->key)) return &scope->types[idx]; } while ((idx = (idx + 1) % scope->type_cap) != orig_idx); return NULL; @@ -57,7 +100,7 @@ static void rehash_types(struct scope* scope) { 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); + struct type_def** cell = type_cell(scope, &old_types[i]->key); if (cell == NULL) { fprintf(stderr, "ccc: types rehash failed, likely a bug\n"); exit(1); @@ -71,7 +114,7 @@ static struct var_def** var_cell( const struct scope* scope, const char* name ) { - unsigned long long orig_idx = hash_name(name) % scope->var_cap; + unsigned long long orig_idx = hash_name(name, scope->var_cap); unsigned long long idx = orig_idx; do { @@ -117,106 +160,164 @@ void scope_pop(struct scope** p_scope) { } void scope_install_default_types(struct scope* scope) { + /* TODO: don't let people make void variables */ scope_define_type(scope, (struct type_def) { - .name = "void", - .sz = 0, - .is_primitive = true, + .key = { + .name = "void", + .how_long = 0, + .marked_signed = false, + .marked_unsigned = false, + }, .is_signed = false, + .is_floating = false, + .sz = 0, }); + scope_define_type(scope, (struct type_def) { - .name = "bool", + .key = { + .name = "bool", + .how_long = 0, + .marked_signed = false, + .marked_unsigned = false, + }, .sz = 1, - .is_primitive = true, .is_signed = false, + .is_floating = false, }); + scope_define_type(scope, (struct type_def) { - .name = "char", + .key = { + .name = "char", + .how_long = 0, + .marked_signed = false, + .marked_unsigned = false, + }, .sz = 1, - .is_primitive = true, .is_signed = true, /* implementation defined babyyyyyy */ + .is_floating = false, }); + scope_define_type(scope, (struct type_def) { - .name = "short", + .key = { + .name = "short", + .how_long = 0, + .marked_signed = false, + .marked_unsigned = false, + }, .sz = 2, - .is_primitive = true, .is_signed = true, + .is_floating = false, }); + scope_define_type(scope, (struct type_def) { - .name = "int", + .key = { + .name = "int", + .how_long = 0, + .marked_signed = false, + .marked_unsigned = false, + }, .sz = 4, - .is_primitive = true, .is_signed = true, + .is_floating = false, }); + scope_define_type(scope, (struct type_def) { - .name = "float", - .sz = 4, - .is_primitive = true, - .is_signed = true, /* floats can't be unsigned but wtv */ + .key = { + .name = "long", + .how_long = 0, + .marked_signed = false, + .marked_unsigned = false, + }, + .sz = 8, + .is_signed = true, + .is_floating = false, }); + scope_define_type(scope, (struct type_def) { - .name = "long", - .sz = 8, - .is_primitive = true, + .key = { + .name = "float", + .how_long = 0, + .marked_signed = false, + .marked_unsigned = false, + }, + .sz = 4, .is_signed = true, + .is_floating = true, }); + scope_define_type(scope, (struct type_def) { - .name = "double", + .key = { + .name = "double", + .how_long = 0, + .marked_signed = false, + .marked_unsigned = false, + }, .sz = 8, - .is_primitive = true, - .is_signed = true, /* doubles also can't be unsigned */ + .is_signed = true, + .is_floating = true, }); } bool scope_get_type( const struct scope* scope, - struct type_def* p_entry, - const char* name + const struct type_def** p_entry, + const struct type_key* key ) { for (; scope != NULL; scope = scope->next_out) { - struct type_def** cell = type_cell(scope, name); + struct type_def** cell = type_cell(scope, key); if (cell == NULL || *cell == NULL) continue; - if (p_entry != NULL) *p_entry = **cell; + if (p_entry != NULL) *p_entry = *cell; return true; } return false; } -void scope_define_type(struct scope* scope, struct type_def type) { - struct type_def** cell = type_cell(scope, type.name); +const struct type_def* scope_define_type( + struct scope* scope, + struct type_def type +) { + struct type_def** cell = type_cell(scope, &type.key); while (cell == NULL) { rehash_types(scope); - cell = type_cell(scope, type.name); + cell = type_cell(scope, &type.key); } + /* redefinition leaks memory, so refuse */ + if (*cell != NULL) return NULL; + *cell = calloc(1, sizeof(struct type_def)); if (*cell == NULL) { fprintf(stderr, "ccc: out of memory\n"); exit(1); } **cell = type; + return *cell; } bool scope_get_var( const struct scope* scope, - struct var_def* p_entry, + struct var_def** p_entry, const char* name ) { for (; scope != NULL; scope = scope->next_out) { struct var_def** cell = var_cell(scope, name); if (cell == NULL || *cell == NULL) continue; - if (p_entry != NULL) *p_entry = **cell; + if (p_entry != NULL) *p_entry = *cell; return true; } return false; } -void scope_define_var(struct scope* scope, struct var_def var) { +struct var_def* scope_define_var(struct scope* scope, struct var_def var) { struct var_def** cell = var_cell(scope, var.name); while (cell == NULL) { rehash_vars(scope); cell = var_cell(scope, var.name); } + /* redefinition leaks memory, so refuse */ + if (*cell != NULL) return NULL; + if (*cell == NULL) { *cell = calloc(1, sizeof(struct var_def)); if (*cell == NULL) { @@ -224,6 +325,6 @@ void scope_define_var(struct scope* scope, struct var_def var) { exit(1); } } - /* technically C allows redefinition :/ */ **cell = var; + return *cell; } @@ -7,6 +7,8 @@ struct storage_location { STO_LABEL, STO_STACK, STO_IMM, + /* I would like to solve functions using the type system + * and kill STO_FN and STO_UNRESOLVED in favor of STO_LABEL. */ STO_FN, STO_UNRESOLVED, } type; @@ -19,17 +21,24 @@ struct storage_location { }; }; +struct type_key { + char* name; + unsigned char how_long; + bool marked_unsigned; + bool marked_signed; +}; + struct type_def { - const char* name; - unsigned long long sz; - bool is_primitive; + struct type_key key; bool is_signed; + bool is_floating; + unsigned long long sz; }; struct var_def { - const char* name; + char* name; struct storage_location loc; - unsigned long long sz; + const struct type_def* resolved_type; }; struct scope { @@ -51,13 +60,15 @@ void scope_destroy(struct scope* scope); void scope_install_default_types(struct scope* scope); bool scope_get_type( const struct scope* scope, - struct type_def* p_entry, - const char* name); -void scope_define_type(struct scope* scope, struct type_def type); + const struct type_def** p_entry, + const struct type_key* key); +const struct type_def* scope_define_type( + struct scope* scope, + struct type_def type); bool scope_get_var( const struct scope* scope, - struct var_def* p_entry, + struct var_def** p_entry, const char* name); -void scope_define_var(struct scope* scope, struct var_def var); +struct var_def* scope_define_var(struct scope* scope, struct var_def var); #endif
\ No newline at end of file |
