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