#include "scope.h" #include #include #include #define DEFAULT_SIZE 16 static void scope_init(struct scope* scope) { scope->types = calloc(DEFAULT_SIZE, sizeof(struct type_def*)); scope->type_cap = DEFAULT_SIZE; scope->vars = calloc(DEFAULT_SIZE, sizeof(struct var_def*)); scope->var_cap = DEFAULT_SIZE; } static 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]); } free(scope->types); for (unsigned long long i = 0; i < scope->var_cap; i++) { if (scope->vars[i] != NULL) free(scope->vars[i]); } free(scope->vars); } unsigned long long hash_name(const char* name) { unsigned long long hash = 0, i = 0; while (name[i] != 0) hash = (hash << 5) - hash + name[i++]; 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 ) { unsigned long long orig_idx = hash_name(name) % scope->type_cap; unsigned long long idx = orig_idx; do { if (scope->types[idx] == NULL || strcmp(name, scope->types[idx]->name) == 0) return &scope->types[idx]; } while ((idx = (idx + 1) % scope->type_cap) != orig_idx); 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 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 idx = orig_idx; do { if (scope->vars[idx] == NULL || strcmp(name, scope->vars[idx]->name) == 0) return &scope->vars[idx]; } while ((idx = (idx + 1) % scope->var_cap) != orig_idx); return NULL; } void scope_push(struct scope** p_scope) { struct scope* inner_scope = calloc(1, sizeof(struct scope)); scope_init(inner_scope); inner_scope->next_out = *p_scope; *p_scope = inner_scope; } void scope_pop(struct scope** p_scope) { struct scope* discarded_scope = *p_scope; *p_scope = (*p_scope)->next_out; scope_destroy(discarded_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, const char* name ) { for (; scope != NULL; scope = scope->next_out) { struct type_def** cell = type_cell(scope, name); if (cell == NULL || *cell == NULL) continue; 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); while (cell == NULL) { rehash_types(scope); cell = type_cell(scope, type.name); } *cell = calloc(1, sizeof(struct type_def)); if (*cell == NULL) { fprintf(stderr, "ccc: out of memory\n"); exit(1); } **cell = type; } bool scope_get_var( const struct scope* scope, 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; return true; } return false; } void 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); } if (*cell == NULL) { *cell = calloc(1, sizeof(struct var_def)); if (*cell == NULL) { fprintf(stderr, "ccc: out of memory\n"); exit(1); } } /* technically C allows redefinition :/ */ **cell = var; }