Mercurial > hg > index.cgi
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 } |