comparison lwasm/symbol.c @ 0:2c24602be78f

Initial import from lwtools 3.0.1 version, with new hand built build system and file reorganization
author lost@l-w.ca
date Wed, 19 Jan 2011 22:27:17 -0700
parents
children 6dafb4f0fa56
comparison
equal deleted inserted replaced
-1:000000000000 0:2c24602be78f
1 /*
2 symbol.c
3
4 Copyright © 2010 William Astle
5
6 This file is part of LWTOOLS.
7
8 LWTOOLS is free software: you can redistribute it and/or modify it under the
9 terms of the GNU General Public License as published by the Free Software
10 Foundation, either version 3 of the License, or (at your option) any later
11 version.
12
13 This program is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 more details.
17
18 You should have received a copy of the GNU General Public License along with
19 this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include <lw_alloc.h>
27 #include <lw_expr.h>
28 #include <lw_string.h>
29
30 #include "lwasm.h"
31
32 struct symtabe *symbol_findprev(asmstate_t *as, struct symtabe *se)
33 {
34 struct symtabe *se1, *se2;
35 int i;
36
37 for (se2 = NULL, se1 = as -> symtab.head; se1; se1 = se1 -> next)
38 {
39 debug_message(as, 200, "Sorting; looking at symbol %s (%p) for %s", se1 -> symbol, se1, se -> symbol);
40 /* compare se with se1 */
41 i = strcasecmp(se -> symbol, se1 -> symbol);
42
43 /* if the symbol sorts before se1, we just need to return */
44 if (i < 0)
45 return se2;
46
47 if (i == 0)
48 {
49 /* symbol name matches; compare other things */
50
51 /*if next version is greater than this one, return */
52 if (se -> version > se1 -> version)
53 return se2;
54 /* if next context is great than this one, return */
55 if (se -> context > se1 -> context)
56 return se2;
57
58 /* if section name is greater, return */
59 /* if se has no section but se1 does, we go first */
60 if (se -> section == NULL && se1 -> section != NULL)
61 return se2;
62 if (se -> section != NULL && se -> section != NULL)
63 {
64 /* compare section names and if se < se1, return */
65 i = strcasecmp(se -> section -> name, se1 -> section -> name);
66 if (i < 0)
67 return se2;
68 }
69 }
70
71 se2 = se1;
72 }
73 return se2;
74 }
75
76 struct symtabe *register_symbol(asmstate_t *as, line_t *cl, char *sym, lw_expr_t val, int flags)
77 {
78 struct symtabe *se;
79 struct symtabe *sprev;
80 int islocal = 0;
81 int context = -1;
82 int version = -1;
83 char *cp;
84
85 debug_message(as, 200, "Register symbol %s (%02X), %s", sym, flags, lw_expr_print(val));
86
87 if (!(flags & symbol_flag_nocheck))
88 {
89 if (!sym || !*sym)
90 {
91 lwasm_register_error(as, cl, "Bad symbol (%s)", sym);
92 return NULL;
93 }
94 if (*sym < 0x80 && (!strchr(SSYMCHARS, *sym) && !strchr(sym + 1, '$') && !strchr(sym + 1, '@') && !strchr(sym + 1, '?')))
95 {
96 lwasm_register_error(as, cl, "Bad symbol (%s)", sym);
97 return NULL;
98 }
99
100 if ((*sym == '$' || *sym == '@') && (sym[1] >= '0' && sym[1] <= '9'))
101 {
102 lwasm_register_error(as, cl, "Bad symbol (%s)", sym);
103 return NULL;
104 }
105 }
106
107 for (cp = sym; *cp; cp++)
108 {
109 if (*cp == '@' || *cp == '?')
110 islocal = 1;
111 if (*cp == '$' && !(CURPRAGMA(cl, PRAGMA_DOLLARNOTLOCAL)))
112 islocal = 1;
113
114 // bad symbol
115 if (!(flags & symbol_flag_nocheck) && *cp < 0x80 && !strchr(SYMCHARS, *cp))
116 {
117 lwasm_register_error(as, cl, "Bad symbol (%s)", sym);
118 return NULL;
119 }
120 }
121
122 if (islocal)
123 context = cl -> context;
124
125 // first, look up symbol to see if it is already defined
126 for (se = as -> symtab.head; se; se = se -> next)
127 {
128 debug_message(as, 300, "Symbol add lookup: %p, %p", se, se -> next);
129 if (!strcmp(sym, se -> symbol))
130 {
131 if (se -> context != context)
132 continue;
133 if ((flags & symbol_flag_set) && (se -> flags & symbol_flag_set))
134 {
135 if (version < se -> version)
136 version = se -> version;
137 continue;
138 }
139 break;
140 }
141 }
142
143 if (se)
144 {
145 // multiply defined symbol
146 lwasm_register_error(as, cl, "Multiply defined symbol (%s)", sym);
147 return NULL;
148 }
149
150 if (flags & symbol_flag_set)
151 {
152 version++;
153 }
154
155 // symplify the symbol expression - replaces "SET" symbols with
156 // symbol table entries
157 lwasm_reduce_expr(as, val);
158
159 se = lw_alloc(sizeof(struct symtabe));
160 se -> context = context;
161 se -> version = version;
162 se -> flags = flags;
163 se -> value = lw_expr_copy(val);
164 se -> symbol = lw_strdup(sym);
165 se -> section = cl -> csect;
166 sprev = symbol_findprev(as, se);
167 if (!sprev)
168 {
169 debug_message(as, 200, "Adding symbol at head of symbol table");
170 se -> next = as -> symtab.head;
171 as -> symtab.head = se;
172 }
173 else
174 {
175 debug_message(as, 200, "Adding symbol in middle of symbol table");
176 se -> next = sprev -> next;
177 sprev -> next = se;
178 }
179 return se;
180 }
181
182 // for "SET" symbols, always returns the LAST definition of the
183 // symbol. This works because the lwasm_reduce_expr() call in
184 // register_symbol will ensure there are no lingering "var" references
185 // to the set symbol anywhere in the symbol table; they will all be
186 // converted to direct references
187 // NOTE: this means that for a forward reference to a SET symbol,
188 // the LAST definition will be the one used.
189 // This arrangement also ensures that any reference to the symbol
190 // itself inside a "set" definition will refer to the previous version
191 // of the symbol.
192 struct symtabe * lookup_symbol(asmstate_t *as, line_t *cl, char *sym)
193 {
194 int local = 0;
195 struct symtabe *s, *s2;
196
197 // check if this is a local symbol
198 if (strchr(sym, '@') || strchr(sym, '?'))
199 local = 1;
200
201 if (cl && !CURPRAGMA(cl, PRAGMA_DOLLARNOTLOCAL) && strchr(sym, '$'))
202 local = 1;
203 if (!cl && !(as -> pragmas & PRAGMA_DOLLARNOTLOCAL) && strchr(sym, '$'))
204 local = 1;
205
206 // cannot look up local symbol in global context!!!!!
207 if (!cl && local)
208 return NULL;
209
210 for (s = as -> symtab.head, s2 = NULL; s; s = s -> next)
211 {
212 if (!strcmp(sym, s -> symbol))
213 {
214 if (local && s -> context != cl -> context)
215 continue;
216
217 if (s -> flags & symbol_flag_set)
218 {
219 // look for highest version of symbol
220 if (s -> version > s2 -> version)
221 s2 = s;
222 continue;
223 }
224 break;
225 }
226 }
227 if (!s && s2)
228 s = s2;
229
230 return s;
231 }
232
233 struct listinfo
234 {
235 sectiontab_t *sect;
236 asmstate_t *as;
237 int complex;
238 };
239
240 int list_symbols_test(lw_expr_t e, void *p)
241 {
242 struct listinfo *li = p;
243
244 if (li -> complex)
245 return 0;
246
247 if (lw_expr_istype(e, lw_expr_type_special))
248 {
249 if (lw_expr_specint(e) == lwasm_expr_secbase)
250 {
251 if (li -> sect)
252 {
253 li -> complex = 1;
254 }
255 else
256 {
257 li -> sect = lw_expr_specptr(e);
258 }
259 }
260 }
261 return 0;
262 }
263
264 void list_symbols(asmstate_t *as, FILE *of)
265 {
266 struct symtabe *s;
267 lw_expr_t te;
268 struct listinfo li;
269
270 li.as = as;
271
272 fprintf(of, "\nSymbol Table:\n");
273
274 for (s = as -> symtab.head; s; s = s -> next)
275 {
276 lwasm_reduce_expr(as, s -> value);
277 fputc('[', of);
278 if (s -> flags & symbol_flag_set)
279 fputc('S', of);
280 else
281 fputc(' ', of);
282 if (as -> output_format == OUTPUT_OBJ)
283 {
284 if (lw_expr_istype(s -> value, lw_expr_type_int))
285 fputc('c', of);
286 else
287 fputc('s', of);
288 }
289 if (s -> context < 0)
290 fputc('G', of);
291 else
292 fputc('L', of);
293
294 fputc(']', of);
295 fputc(' ', of);
296 fprintf(of, "%-32s ", s -> symbol);
297
298 te = lw_expr_copy(s -> value);
299 li.complex = 0;
300 li.sect = NULL;
301 lw_expr_testterms(te, list_symbols_test, &li);
302 if (li.sect)
303 {
304 as -> exportcheck = 1;
305 as -> csect = li.sect;
306 lwasm_reduce_expr(as, te);
307 as -> exportcheck = 0;
308 }
309
310 if (lw_expr_istype(te, lw_expr_type_int))
311 {
312 fprintf(of, "%04X", lw_expr_intval(te));
313 if (li.sect)
314 {
315 fprintf(of, " (%s)", li.sect -> name);
316 }
317 fprintf(of, "\n");
318 }
319 else
320 {
321 fprintf(of, "<<incomplete>>\n");
322 // fprintf(of, "%s\n", lw_expr_print(s -> value));
323 }
324 lw_expr_destroy(te);
325 }
326 }