1 // ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code.
2 // Copyright (C) 1998-2020 Marco Baye
3 // Have a look at "acme.c" for further info
4 //
5 // symbol stuff
6 //
7 // 22 Nov 2007 "warn on indented labels" is now a CLI switch
8 // 25 Sep 2011 Fixed bug in !sl (colons in filename could be interpreted as EOS)
9 // 23 Nov 2014 Added label output in VICE format
10 #include "symbol.h"
11 #include <stdio.h>
12 #include "acme.h"
13 #include "alu.h"
14 #include "dynabuf.h"
15 #include "global.h"
16 #include "input.h"
17 #include "output.h"
18 #include "platform.h"
19 #include "section.h"
20 #include "tree.h"
21 #include "typesystem.h"
22
23
24 // variables
25 struct rwnode *symbols_forest[256] = { NULL }; // because of 8-bit hash - must be (at least partially) pre-defined so array will be zeroed!
26
27
28 // Dump symbol value and flags to dump file
dump_one_symbol(struct rwnode * node,FILE * fd)29 static void dump_one_symbol(struct rwnode *node, FILE *fd)
30 {
31 struct symbol *symbol = node->body;
32
33 // if symbol is neither int nor float, skip
34 if (symbol->object.type != &type_number)
35 return;
36
37 // CAUTION: if more types are added, check for NULL before using type pointer!
38
39 // output name
40 if (config.warn_on_type_mismatch
41 && symbol->object.u.number.addr_refs == 1)
42 fprintf(fd, "!addr");
43 fprintf(fd, "\t%s", node->id_string);
44 switch (symbol->object.u.number.flags & NUMBER_FORCEBITS) {
45 case NUMBER_FORCES_16:
46 fprintf(fd, "+2\t= ");
47 break;
48 case NUMBER_FORCES_16 | NUMBER_FORCES_24:
49 /*FALLTHROUGH*/
50 case NUMBER_FORCES_24:
51 fprintf(fd, "+3\t= ");
52 break;
53 default:
54 fprintf(fd, "\t= ");
55 }
56 if (symbol->object.u.number.ntype == NUMTYPE_UNDEFINED)
57 fprintf(fd, " ?"); // TODO - maybe write "UNDEFINED" instead? then the file could at least be parsed without errors
58 else if (symbol->object.u.number.ntype == NUMTYPE_INT)
59 fprintf(fd, "$%x", (unsigned) symbol->object.u.number.val.intval);
60 else if (symbol->object.u.number.ntype == NUMTYPE_FLOAT)
61 fprintf(fd, "%.30f", symbol->object.u.number.val.fpval); //FIXME %g
62 else
63 Bug_found("IllegalNumberType4", symbol->object.u.number.ntype);
64 if (symbol->object.u.number.flags & NUMBER_EVER_UNDEFINED)
65 fprintf(fd, "\t; ?"); // TODO - write "forward" instead?
66 if (!symbol->has_been_read)
67 fprintf(fd, "\t; unused");
68 fprintf(fd, "\n");
69 }
70
71
72 // output symbols in VICE format (example: "al C:09ae .nmi1")
dump_vice_address(struct rwnode * node,FILE * fd)73 static void dump_vice_address(struct rwnode *node, FILE *fd)
74 {
75 struct symbol *symbol = node->body;
76
77 // dump address symbols even if they are not used
78 if ((symbol->object.type == &type_number)
79 && (symbol->object.u.number.ntype == NUMTYPE_INT)
80 && (symbol->object.u.number.addr_refs == 1))
81 fprintf(fd, "al C:%04x .%s\n", (unsigned) symbol->object.u.number.val.intval, node->id_string);
82 }
dump_vice_usednonaddress(struct rwnode * node,FILE * fd)83 static void dump_vice_usednonaddress(struct rwnode *node, FILE *fd)
84 {
85 struct symbol *symbol = node->body;
86
87 // dump non-addresses that are used
88 if (symbol->has_been_read
89 && (symbol->object.type == &type_number)
90 && (symbol->object.u.number.ntype == NUMTYPE_INT)
91 && (symbol->object.u.number.addr_refs != 1))
92 fprintf(fd, "al C:%04x .%s\n", (unsigned) symbol->object.u.number.val.intval, node->id_string);
93 }
dump_vice_unusednonaddress(struct rwnode * node,FILE * fd)94 static void dump_vice_unusednonaddress(struct rwnode *node, FILE *fd)
95 {
96 struct symbol *symbol = node->body;
97
98 // dump non-addresses that are unused
99 if (!symbol->has_been_read
100 && (symbol->object.type == &type_number)
101 && (symbol->object.u.number.ntype == NUMTYPE_INT)
102 && (symbol->object.u.number.addr_refs != 1))
103 fprintf(fd, "al C:%04x .%s\n", (unsigned) symbol->object.u.number.val.intval, node->id_string);
104 }
105
106
107 // search for symbol. if it does not exist, create with NULL object (CAUTION!).
108 // the symbol name must be held in GlobalDynaBuf.
symbol_find(scope_t scope)109 struct symbol *symbol_find(scope_t scope)
110 {
111 struct rwnode *node;
112 struct symbol *symbol;
113 boolean node_created;
114
115 node_created = Tree_hard_scan(&node, symbols_forest, scope, TRUE);
116 // if node has just been created, create symbol as well
117 if (node_created) {
118 // create new symbol structure
119 symbol = safe_malloc(sizeof(*symbol));
120 node->body = symbol;
121 // finish empty symbol item
122 symbol->object.type = NULL; // no object yet (CAUTION!)
123 symbol->pass = pass.number;
124 symbol->has_been_read = FALSE;
125 symbol->has_been_reported = FALSE;
126 symbol->pseudopc = NULL;
127 } else {
128 symbol = node->body;
129 }
130 return symbol; // now symbol->object.type can be tested to see if this was freshly created.
131 // CAUTION: this only works if caller always sets a type pointer after checking! if NULL is kept, the struct still looks new later on...
132 }
133
134
135 // assign object to symbol. the function acts upon the symbol's flag bits and
136 // produces an error if needed.
137 // using "power" bits, caller can state which changes are ok.
138 // called by:
139 // implicit label definitions (including anons, backward anons have POWER_CHANGE_VALUE)
140 // explicit symbol assignments
141 // explicit symbol assignments via "!set" (has all powers)
142 // loop counter var init via "!for" (has POWER_CHANGE_VALUE and POWER_CHANGE_NUMTYPE)
143 // CAUTION: actual incrementing of counter is then done directly without calls here!
symbol_set_object(struct symbol * symbol,struct object * new_value,bits powers)144 void symbol_set_object(struct symbol *symbol, struct object *new_value, bits powers)
145 {
146 // if symbol has no object assigned to it yet, fine:
147 if (symbol->object.type == NULL) {
148 symbol->object = *new_value; // copy whole struct including type
149 // as long as the symbol has not been read, the force bits can
150 // be changed, so the caller still has a chance to do that.
151 return;
152 }
153
154 // now we know symbol already has a type
155
156 // compare types
157 // if too different, needs power (or complains)
158 if (symbol->object.type != new_value->type) {
159 if (!(powers & POWER_CHANGE_OBJTYPE))
160 Throw_error(exception_symbol_defined);
161 // CAUTION: if above line throws error, we still go ahead and change type!
162 // this is to keep "!for" working, where the counter var is accessed.
163 symbol->object = *new_value; // copy whole struct including type
164 // clear flag so caller can adjust force bits:
165 symbol->has_been_read = FALSE; // it's basically a new symbol now
166 return;
167 }
168
169 // now we know symbol and new value have compatible types, so call handler:
170 symbol->object.type->assign(&symbol->object, new_value, !!(powers & POWER_CHANGE_VALUE));
171 }
172
173
174 // set force bit of symbol. trying to change to a different one will raise error.
symbol_set_force_bit(struct symbol * symbol,bits force_bit)175 void symbol_set_force_bit(struct symbol *symbol, bits force_bit)
176 {
177 if (!force_bit)
178 Bug_found("ForceBitZero", 0);
179 if (symbol->object.type == NULL)
180 Bug_found("NullTypeObject", 0);
181
182 if (symbol->object.type != &type_number) {
183 Throw_error("Force bits can only be given to numbers.");
184 return;
185 }
186
187 // if change is ok, change
188 if (!symbol->has_been_read) {
189 symbol->object.u.number.flags &= ~NUMBER_FORCEBITS;
190 symbol->object.u.number.flags |= force_bit;
191 return; // and be done with it
192 }
193
194 // it's too late to change, so check if the wanted bit is actually different
195 if ((symbol->object.u.number.flags & NUMBER_FORCEBITS) != force_bit)
196 Throw_error("Too late for postfix.");
197 }
198
199
200 // set global symbol to integer value, no questions asked (for "-D" switch)
201 // Name must be held in GlobalDynaBuf.
symbol_define(intval_t value)202 void symbol_define(intval_t value)
203 {
204 struct object result;
205 struct symbol *symbol;
206
207 result.type = &type_number;
208 result.u.number.ntype = NUMTYPE_INT;
209 result.u.number.flags = 0;
210 result.u.number.val.intval = value;
211 symbol = symbol_find(SCOPE_GLOBAL);
212 symbol->object = result;
213 }
214
215
216 // dump global symbols to file
symbols_list(FILE * fd)217 void symbols_list(FILE *fd)
218 {
219 Tree_dump_forest(symbols_forest, SCOPE_GLOBAL, dump_one_symbol, fd);
220 }
221
222
symbols_vicelabels(FILE * fd)223 void symbols_vicelabels(FILE *fd)
224 {
225 // FIXME - if type checking is enabled, maybe only output addresses?
226 // the order of dumped labels is important because VICE will prefer later defined labels
227 // dump unused labels
228 Tree_dump_forest(symbols_forest, SCOPE_GLOBAL, dump_vice_unusednonaddress, fd);
229 fputc('\n', fd);
230 // dump other used labels
231 Tree_dump_forest(symbols_forest, SCOPE_GLOBAL, dump_vice_usednonaddress, fd);
232 fputc('\n', fd);
233 // dump address symbols
234 Tree_dump_forest(symbols_forest, SCOPE_GLOBAL, dump_vice_address, fd);
235 // TODO - add trace points and watch points with load/store/exec args!
236 }
237
238
239 // fix name of anonymous forward label (held in DynaBuf, NOT TERMINATED!) so it
240 // references the *next* anonymous forward label definition. The tricky bit is,
241 // each name length would need its own counter. But hey, ACME's real quick in
242 // finding symbols, so I'll just abuse the symbol system to store those counters.
243 // example:
244 // forward anon name is "+++"
245 // we look up that symbol's value in the current local scope -> $12
246 // we attach hex digits to name -> "+++21"
247 // that's the name of the symbol that _actually_ contains the address
248 // caller sets "increment" to TRUE for writing, FALSE for reading
symbol_fix_forward_anon_name(boolean increment)249 void symbol_fix_forward_anon_name(boolean increment)
250 {
251 struct symbol *counter_symbol;
252 unsigned long number;
253
254 // terminate name, find "counter" symbol and read value
255 DynaBuf_append(GlobalDynaBuf, '\0');
256 counter_symbol = symbol_find(section_now->local_scope);
257 if (counter_symbol->object.type == NULL) {
258 // finish freshly created symbol item
259 counter_symbol->object.type = &type_number;
260 counter_symbol->object.u.number.ntype = NUMTYPE_INT;
261 counter_symbol->object.u.number.flags = 0;
262 counter_symbol->object.u.number.addr_refs = 0;
263 counter_symbol->object.u.number.val.intval = 0;
264 } else if (counter_symbol->object.type != &type_number) {
265 // sanity check: it must be a number!
266 Bug_found("ForwardAnonCounterNotInt", 0);
267 }
268 // make sure it gets reset to zero in each new pass
269 if (counter_symbol->pass != pass.number) {
270 counter_symbol->pass = pass.number;
271 counter_symbol->object.u.number.val.intval = 0;
272 }
273 number = (unsigned long) counter_symbol->object.u.number.val.intval;
274 // now append to the name to make it unique
275 GlobalDynaBuf->size--; // forget terminator, we want to append
276 do {
277 DYNABUF_APPEND(GlobalDynaBuf, 'a' + (number & 15));
278 number >>= 4;
279 } while (number);
280 DynaBuf_append(GlobalDynaBuf, '\0');
281 if (increment)
282 counter_symbol->object.u.number.val.intval++;
283 }
284