-
Notifications
You must be signed in to change notification settings - Fork 0
/
symbol.c
199 lines (177 loc) · 6.14 KB
/
symbol.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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
/* MIX simulator, copyright 1994 by Darius Bacon */
#include "mix.h"
#include "asm.h" /* this is a sign of bad factoring */
#include "symbol.h"
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
Here's the theory on forward references.
We need to handle 3 sorts of references: ordinary symbols, local symbols
like 7B and 7F, and implicit constants like =123=. First let's discuss
ordinary symbols. Any symbol that's been referred to but not yet defined
has a list of all locations, in the object program built so far, that
refer to it. That list is added to by the forward_reference() function.
When the symbol is defined, we fix up all the references to it, using the
list. After assembly is done, we check if there are any unresolved
references, in resolve_generated_futures() (whose main job I'll get to
shortly). A minor problem: we don't hold onto the source-line number of a
reference, so if it's unresolved we get a misleading error message.
The forward_reference() function returns a meaningless value just for
historical reasons: originally the list of unresolved references for a
symbol was threaded through the simulated memory locations themselves,
and so forward_reference() had to return the value to put in the
latest referencing location to maintain the list. Now that I've come
to my senses, I suppose I should get rid of the return value.
Local symbols work just like regular ones, except that a reference to,
say, 7B, gets the value defined in the latest definition of 7H, and
similarly a reference to 7F is always a forward ref to the next definition
of 7H. This can be arranged by having define_symbol() adjust 7B and 7F
appropriately when it sees 7H.
We handle implicit constants like =123= by generating a unique symbol for
each value that occurs in such a constant. (It's of the form "=123", which
can't conflict with ordinary or local symbols.) Then a reference to such a
constant is simply a forward reference to the generated symbol. After
assembly is complete resolve_generated_futures() resolves all the generated
symbols with appropriate addresses. Note that this scheme uniquifies the
constant references for free.
*/
/* Pre: size != 0 */
static void *allot(size_t size)
{
void *result = malloc(size);
if (!result)
fatal_error("Out of heap space");
return result;
}
#if !defined(__MINGW32__)
static int stricmp(const char *s, const char *t)
{
while (*s && *t)
if (tolower(*s) != tolower(*t))
return 1;
else
s++, t++;
return tolower(*s) != tolower(*t);
}
#endif
/* --- The symbol table --- */
static Symbol symbol_table[17];
/* Apply proc to each symbol in the symbol table. */
static void for_each_symbol(void (*proc)(Symbol))
{
unsigned i;
for (i = 0; i < sizeof symbol_table / sizeof symbol_table[0]; ++i) {
Symbol s = symbol_table[i];
for (; s; s = s->next)
proc(s);
}
}
static unsigned hash(const char *s)
{
unsigned h = 0;
for (; *s; s++)
h = (h << 5) - h + toupper(*s);
return h % (sizeof symbol_table / sizeof symbol_table[0]);
}
Symbol string_to_symbol(const char *name)
{
Symbol *bucket = symbol_table + hash(name);
Symbol p = *bucket;
for (; p; p = p->next)
if (stricmp(name, p->name) == 0)
return p;
{ /* Symbol doesn't exist yet. */
Symbol result = allot(sizeof(struct Symbol));
strcpy(result->name = allot(strlen(name) + 1), name);
result->defined = false;
result->references = NULL;
result->next = *bucket;
result->cell = zero;
*bucket = result;
return result;
}
}
Flag is_defined(Symbol symbol) { return symbol->defined; }
Cell symbol_value(Symbol symbol)
{
assert(symbol->defined);
return symbol->cell;
}
void forward_reference(Symbol symbol, Address address)
{
assert(!symbol->defined);
{
AddressList refs = allot(sizeof(struct AddressList));
refs->address = address;
refs->next = symbol->references;
symbol->references = refs;
}
}
/* Pre: !is_defined(symbol)
Set the address field of each cell in symbol's set of references
to definition. Frees the set of references. */
static void resolve_references(Symbol symbol, Cell definition)
{
AddressList refs, rest;
assert(!symbol->defined);
for (refs = symbol->references; refs; refs = rest) {
asm_store_field(refs->address, 0, 2, definition);
rest = refs->next;
free(refs);
}
}
void define_symbol(Symbol symbol, Cell cell)
{
{ /* handle local symbols */
const char *name = symbol->name;
if (isdigit(name[0]) && strlen(name) == 2) {
char c = toupper(name[1]);
if (c == 'F' || c == 'B') {
error("Definition of local ref: %s", name);
return;
} else if (c == 'H') {
char new_name[3];
Symbol nB, nF;
strcpy(new_name, name);
new_name[1] = 'B'; nB = string_to_symbol(new_name);
nB->defined = true, nB->cell = cell;
new_name[1] = 'F'; nF = string_to_symbol(new_name);
resolve_references(nF, cell);
nF->defined = false, nF->references = NULL;
return;
} else
; /* not a local; fall through */
}
}
if (symbol->defined)
warn("'%s' multiply-defined", symbol->name);
else
resolve_references(symbol, cell);
symbol->defined = true, symbol->cell = cell;
}
Symbol generate_future_sym(Cell value)
{
char name[12];
sprintf(name, "=%ld", cell_to_long(value));
return string_to_symbol(name);
}
static void resolve_if_dangling(Symbol symbol)
{
if (symbol->defined)
return;
if (symbol->name[0] == '=') { /* it's a generated symbol */
define_symbol(symbol, address_to_cell(here));
assemble(long_to_cell(atol(symbol->name + 1)));
} else { /* it's a user symbol */
if (symbol->references)
error("Unresolved reference: %s", symbol->name);
/* it would be nice to print the reference list, too */
}
}
void resolve_generated_futures(void)
{
for_each_symbol(resolve_if_dangling);
}
/* vim: set ts=4 sw=4 et: */