summaryrefslogtreecommitdiff
path: root/scope.c
diff options
context:
space:
mode:
Diffstat (limited to 'scope.c')
-rw-r--r--scope.c183
1 files changed, 142 insertions, 41 deletions
diff --git a/scope.c b/scope.c
index 2bb686a..119fc77 100644
--- a/scope.c
+++ b/scope.c
@@ -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;
}