-
Notifications
You must be signed in to change notification settings - Fork 0
/
var_table.c
116 lines (86 loc) · 3.37 KB
/
var_table.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#include "var_table.h"
#include "util.h"
#include "vector.h"
struct var_table_scope var_table_scope_create(struct var_table_scope *prev) {
struct var_table_scope var_table_scope = {
.next = NULL,
.prev = prev,
.entries = vector_create(sizeof(struct var_table_entry)),
.scope = prev ? prev->scope + 1 : SCOPE_GLOBAL};
return var_table_scope;
}
struct var_table var_table_create(struct arena_allocator *arena) {
// known memory leak here, no `free` function atm
struct var_table var_table = {
.arena = arena,
.first = arena_alloc(arena, sizeof(*var_table.first)),
.last = NULL};
*var_table.first = var_table_scope_create(NULL);
var_table.last = var_table.first;
return var_table;
}
struct var_table_entry *create_entry(struct var_table *var_table,
const char *name) {
struct var_table_scope *last = var_table->last;
struct var_table_entry entry = {.name = name,
.scope = last->scope,
.flags = VAR_TABLE_ENTRY_FLAG_NONE,
.value = NULL};
struct var_table_entry *p = vector_push_back(last->entries, &entry);
p->value = NULL;
return p;
}
// to show all entries
// size_t num_entries = vector_length(var_table->entries);
// for (size_t i = 0; i < num_entries; i++) {
// struct var_table_entry *entry = vector_get(var_table->entries, i);
// err("%s @ %d", entry->name, entry->scope);
// }
int cur_scope(struct var_table *var_table) { return var_table->last->scope; }
void push_scope(struct var_table *var_table) {
struct var_table_scope *last = var_table->last;
last->next = arena_alloc(var_table->arena, sizeof(*last->next));
*last->next = var_table_scope_create(last);
var_table->last = last->next;
}
void pop_scope(struct var_table *var_table) {
struct var_table_scope *last = var_table->last;
debug_assert(last->scope != SCOPE_GLOBAL,
"popping global scope is never correct");
vector_free(&last->entries);
debug_assert(!last->next, "popping var_table_scope but it has a `next` "
"entry? should be impossible");
var_table->last = last->prev;
last->prev->next = NULL;
last->prev = NULL;
}
struct var_table_entry *get_or_create_entry(struct var_table *var_table,
const char *name) {
struct var_table_entry *entry = get_entry(var_table, name);
if (entry) {
return entry;
}
trace("couldn't find variable, creating new entry '%s' with scope '%d'", name,
var_table->last->scope);
return create_entry(var_table, name);
}
struct var_table_entry *get_entry(struct var_table *var_table,
const char *name) {
// super inefficient, TODO: make efficient
// does linear scan for entry at current scope, if that fails, tries at
// higher scope, until scope is global then creates new entry
struct var_table_scope *scope = var_table->last;
while (scope) {
size_t num_vars = vector_length(scope->entries);
for (size_t i = 0; i < num_vars; i++) {
struct var_table_entry *entry = vector_get(scope->entries, i);
if (strcmp(entry->name, name) == 0) {
trace("found '%s' at scope %d", entry->name, scope->scope);
return entry;
}
}
scope = scope->prev;
}
trace("did not find entry for %s", name);
return NULL;
}