diff options
Diffstat (limited to 'scope.c')
| -rw-r--r-- | scope.c | 183 |
1 files changed, 142 insertions, 41 deletions
@@ -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; } |
