1 | /*****************************************************************************/ |
2 | /* */ |
3 | /* symentry.c */ |
4 | /* */ |
5 | /* Symbol table entry for the ca65 macroassembler */ |
6 | /* */ |
7 | /* */ |
8 | /* */ |
9 | /* (C) 1998-2011, Ullrich von Bassewitz */ |
10 | /* Roemerstrasse 52 */ |
11 | /* D-70794 Filderstadt */ |
12 | /* EMail: uz@cc65.org */ |
13 | /* */ |
14 | /* */ |
15 | /* This software is provided 'as-is', without any expressed or implied */ |
16 | /* warranty. In no event will the authors be held liable for any damages */ |
17 | /* arising from the use of this software. */ |
18 | /* */ |
19 | /* Permission is granted to anyone to use this software for any purpose, */ |
20 | /* including commercial applications, and to alter it and redistribute it */ |
21 | /* freely, subject to the following restrictions: */ |
22 | /* */ |
23 | /* 1. The origin of this software must not be misrepresented; you must not */ |
24 | /* claim that you wrote the original software. If you use this software */ |
25 | /* in a product, an acknowledgment in the product documentation would be */ |
26 | /* appreciated but is not required. */ |
27 | /* 2. Altered source versions must be plainly marked as such, and must not */ |
28 | /* be misrepresented as being the original software. */ |
29 | /* 3. This notice may not be removed or altered from any source */ |
30 | /* distribution. */ |
31 | /* */ |
32 | /*****************************************************************************/ |
33 | |
34 | |
35 | |
36 | #include <string.h> |
37 | |
38 | /* common */ |
39 | #include "addrsize.h" |
40 | #include "symdefs.h" |
41 | #include "xmalloc.h" |
42 | |
43 | /* ca65 */ |
44 | #include "error.h" |
45 | #include "expr.h" |
46 | #include "global.h" |
47 | #include "scanner.h" |
48 | #include "segment.h" |
49 | #include "spool.h" |
50 | #include "studyexpr.h" /* ### */ |
51 | #include "symentry.h" |
52 | #include "symtab.h" |
53 | |
54 | |
55 | |
56 | /*****************************************************************************/ |
57 | /* Data */ |
58 | /*****************************************************************************/ |
59 | |
60 | |
61 | |
62 | /* List of all symbol table entries */ |
63 | SymEntry* SymList = 0; |
64 | |
65 | /* Pointer to last defined symbol */ |
66 | SymEntry* SymLast = 0; |
67 | |
68 | |
69 | |
70 | /*****************************************************************************/ |
71 | /* Code */ |
72 | /*****************************************************************************/ |
73 | |
74 | |
75 | |
76 | SymEntry* NewSymEntry (const StrBuf* Name, unsigned Flags) |
77 | /* Allocate a symbol table entry, initialize and return it */ |
78 | { |
79 | unsigned I; |
80 | |
81 | /* Allocate memory */ |
82 | SymEntry* S = xmalloc (sizeof (SymEntry)); |
83 | |
84 | /* Initialize the entry */ |
85 | S->Left = 0; |
86 | S->Right = 0; |
87 | S->Locals = 0; |
88 | S->Sym.Tab = 0; |
89 | S->DefLines = EmptyCollection; |
90 | S->RefLines = EmptyCollection; |
91 | for (I = 0; I < sizeof (S->GuessedUse) / sizeof (S->GuessedUse[0]); ++I) { |
92 | S->GuessedUse[I] = 0; |
93 | } |
94 | S->HLLSym = 0; |
95 | S->Flags = Flags; |
96 | S->DebugSymId = ~0U; |
97 | S->ImportId = ~0U; |
98 | S->ExportId = ~0U; |
99 | S->Expr = 0; |
100 | S->ExprRefs = AUTO_COLLECTION_INITIALIZER; |
101 | S->ExportSize = ADDR_SIZE_DEFAULT; |
102 | S->AddrSize = ADDR_SIZE_DEFAULT; |
103 | memset (S->ConDesPrio, 0, sizeof (S->ConDesPrio)); |
104 | S->Name = GetStrBufId (Name); |
105 | |
106 | /* Insert it into the list of all entries */ |
107 | S->List = SymList; |
108 | SymList = S; |
109 | |
110 | /* Return the initialized entry */ |
111 | return S; |
112 | } |
113 | |
114 | |
115 | |
116 | int SymSearchTree (SymEntry* T, const StrBuf* Name, SymEntry** E) |
117 | /* Search in the given tree for a name. If we find the symbol, the function |
118 | ** will return 0 and put the entry pointer into E. If we did not find the |
119 | ** symbol, and the tree is empty, E is set to NULL. If the tree is not empty, |
120 | ** E will be set to the last entry, and the result of the function is <0 if |
121 | ** the entry should be inserted on the left side, and >0 if it should get |
122 | ** inserted on the right side. |
123 | */ |
124 | { |
125 | /* Is there a tree? */ |
126 | if (T == 0) { |
127 | *E = 0; |
128 | return 1; |
129 | } |
130 | |
131 | /* We have a table, search it */ |
132 | while (1) { |
133 | |
134 | /* Get the symbol name */ |
135 | const StrBuf* SymName = GetStrBuf (T->Name); |
136 | |
137 | /* Choose next entry */ |
138 | int Cmp = SB_Compare (Name, SymName); |
139 | if (Cmp < 0 && T->Left) { |
140 | T = T->Left; |
141 | } else if (Cmp > 0 && T->Right) { |
142 | T = T->Right; |
143 | } else { |
144 | /* Found or end of search, return the result */ |
145 | *E = T; |
146 | return Cmp; |
147 | } |
148 | } |
149 | } |
150 | |
151 | |
152 | |
153 | void SymTransferExprRefs (SymEntry* From, SymEntry* To) |
154 | /* Transfer all expression references from one symbol to another. */ |
155 | { |
156 | unsigned I; |
157 | |
158 | for (I = 0; I < CollCount (&From->ExprRefs); ++I) { |
159 | |
160 | /* Get the expression node */ |
161 | ExprNode* E = CollAtUnchecked (&From->ExprRefs, I); |
162 | |
163 | /* Safety */ |
164 | CHECK (E->Op == EXPR_SYMBOL && E->V.Sym == From); |
165 | |
166 | /* Replace the symbol reference */ |
167 | E->V.Sym = To; |
168 | |
169 | /* Add the expression reference */ |
170 | SymAddExprRef (To, E); |
171 | } |
172 | |
173 | /* Remove all symbol references from the old symbol */ |
174 | CollDeleteAll (&From->ExprRefs); |
175 | } |
176 | |
177 | |
178 | |
179 | static void SymReplaceExprRefs (SymEntry* S) |
180 | /* Replace the references to this symbol by a copy of the symbol expression */ |
181 | { |
182 | unsigned I; |
183 | long Val; |
184 | |
185 | /* Check if the expression is const and get its value */ |
186 | int IsConst = IsConstExpr (S->Expr, &Val); |
187 | CHECK (IsConst); |
188 | |
189 | /* Loop over all references */ |
190 | for (I = 0; I < CollCount (&S->ExprRefs); ++I) { |
191 | |
192 | /* Get the expression node */ |
193 | ExprNode* E = CollAtUnchecked (&S->ExprRefs, I); |
194 | |
195 | /* Safety */ |
196 | CHECK (E->Op == EXPR_SYMBOL && E->V.Sym == S); |
197 | |
198 | /* We cannot touch the root node, since there are pointers to it. |
199 | ** Replace it by a literal node. |
200 | */ |
201 | E->Op = EXPR_LITERAL; |
202 | E->V.IVal = Val; |
203 | } |
204 | |
205 | /* Remove all symbol references from the symbol */ |
206 | CollDeleteAll (&S->ExprRefs); |
207 | } |
208 | |
209 | |
210 | |
211 | void SymDef (SymEntry* S, ExprNode* Expr, unsigned char AddrSize, unsigned Flags) |
212 | /* Define a new symbol */ |
213 | { |
214 | if (S->Flags & SF_IMPORT) { |
215 | /* Defined symbol is marked as imported external symbol */ |
216 | Error ("Symbol '%m%p' is already an import" , GetSymName (S)); |
217 | return; |
218 | } |
219 | if ((Flags & SF_VAR) != 0 && (S->Flags & (SF_EXPORT | SF_GLOBAL))) { |
220 | /* Variable symbols cannot be exports or globals */ |
221 | Error ("Var symbol '%m%p' cannot be an export or global symbol" , GetSymName (S)); |
222 | return; |
223 | } |
224 | if (S->Flags & SF_DEFINED) { |
225 | /* Multiple definition. In case of a variable, this is legal. */ |
226 | if ((S->Flags & SF_VAR) == 0) { |
227 | Error ("Symbol '%m%p' is already defined" , GetSymName (S)); |
228 | S->Flags |= SF_MULTDEF; |
229 | return; |
230 | } else { |
231 | /* Redefinition must also be a variable symbol */ |
232 | if ((Flags & SF_VAR) == 0) { |
233 | Error ("Symbol '%m%p' is already different kind" , GetSymName (S)); |
234 | return; |
235 | } |
236 | /* Delete the current symbol expression, since it will get |
237 | ** replaced |
238 | */ |
239 | FreeExpr (S->Expr); |
240 | S->Expr = 0; |
241 | } |
242 | } |
243 | |
244 | /* Map a default address size to a real value */ |
245 | if (AddrSize == ADDR_SIZE_DEFAULT) { |
246 | /* ### Must go! Delay address size calculation until end of assembly! */ |
247 | ExprDesc ED; |
248 | ED_Init (&ED); |
249 | StudyExpr (Expr, &ED); |
250 | AddrSize = ED.AddrSize; |
251 | ED_Done (&ED); |
252 | } |
253 | |
254 | /* Set the symbol value */ |
255 | S->Expr = Expr; |
256 | |
257 | /* In case of a variable symbol, walk over all expressions containing |
258 | ** this symbol and replace the (sub-)expression by the literal value of |
259 | ** the tree. Be sure to replace the expression node in place, since there |
260 | ** may be pointers to it. |
261 | */ |
262 | if (Flags & SF_VAR) { |
263 | SymReplaceExprRefs (S); |
264 | } |
265 | |
266 | /* If the symbol is marked as global, export it. Address size is checked |
267 | ** below. |
268 | */ |
269 | if (S->Flags & SF_GLOBAL) { |
270 | S->Flags = (S->Flags & ~SF_GLOBAL) | SF_EXPORT; |
271 | ReleaseFullLineInfo (&S->DefLines); |
272 | } |
273 | |
274 | /* Mark the symbol as defined and use the given address size */ |
275 | S->Flags |= (SF_DEFINED | Flags); |
276 | S->AddrSize = AddrSize; |
277 | |
278 | /* Remember the line info of the symbol definition */ |
279 | GetFullLineInfo (&S->DefLines); |
280 | |
281 | /* If the symbol is exported, check the address sizes */ |
282 | if (S->Flags & SF_EXPORT) { |
283 | if (S->ExportSize == ADDR_SIZE_DEFAULT) { |
284 | /* Use the real size of the symbol */ |
285 | S->ExportSize = S->AddrSize; |
286 | } else if (S->AddrSize > S->ExportSize) { |
287 | /* We're exporting a symbol smaller than it actually is */ |
288 | Warning (1, "Symbol '%m%p' is %s but exported %s" , |
289 | GetSymName (S), AddrSizeToStr (S->AddrSize), |
290 | AddrSizeToStr (S->ExportSize)); |
291 | } |
292 | } |
293 | |
294 | /* If this is not a local symbol, remember it as the last global one */ |
295 | if ((S->Flags & SF_LOCAL) == 0) { |
296 | SymLast = S; |
297 | } |
298 | } |
299 | |
300 | |
301 | |
302 | void SymRef (SymEntry* S) |
303 | /* Mark the given symbol as referenced */ |
304 | { |
305 | /* Mark the symbol as referenced */ |
306 | S->Flags |= SF_REFERENCED; |
307 | |
308 | /* Remember the current location */ |
309 | CollAppend (&S->RefLines, GetAsmLineInfo ()); |
310 | } |
311 | |
312 | |
313 | |
314 | void SymImport (SymEntry* S, unsigned char AddrSize, unsigned Flags) |
315 | /* Mark the given symbol as an imported symbol */ |
316 | { |
317 | if (S->Flags & SF_DEFINED) { |
318 | Error ("Symbol '%m%p' is already defined" , GetSymName (S)); |
319 | S->Flags |= SF_MULTDEF; |
320 | return; |
321 | } |
322 | if (S->Flags & SF_EXPORT) { |
323 | /* The symbol is already marked as exported symbol */ |
324 | Error ("Cannot import exported symbol '%m%p'" , GetSymName (S)); |
325 | return; |
326 | } |
327 | |
328 | /* If no address size is given, use the address size of the enclosing |
329 | ** segment. |
330 | */ |
331 | if (AddrSize == ADDR_SIZE_DEFAULT) { |
332 | AddrSize = GetCurrentSegAddrSize (); |
333 | } |
334 | |
335 | /* If the symbol is marked as import or global, check the address size, |
336 | ** then do silently remove the global flag. |
337 | */ |
338 | if (S->Flags & SF_IMPORT) { |
339 | if ((Flags & SF_FORCED) != (S->Flags & SF_FORCED)) { |
340 | Error ("Redeclaration mismatch for symbol '%m%p'" , GetSymName (S)); |
341 | } |
342 | if (AddrSize != S->AddrSize) { |
343 | Error ("Address size mismatch for symbol '%m%p'" , GetSymName (S)); |
344 | } |
345 | } |
346 | if (S->Flags & SF_GLOBAL) { |
347 | S->Flags &= ~SF_GLOBAL; |
348 | if (AddrSize != S->AddrSize) { |
349 | Error ("Address size mismatch for symbol '%m%p'" , GetSymName (S)); |
350 | } |
351 | } |
352 | |
353 | /* Set the symbol data */ |
354 | S->Flags |= (SF_IMPORT | Flags); |
355 | S->AddrSize = AddrSize; |
356 | |
357 | /* Mark the position of the import as the position of the definition. |
358 | ** Please note: In case of multiple .global or .import statements, the line |
359 | ** infos add up. |
360 | */ |
361 | GetFullLineInfo (&S->DefLines); |
362 | } |
363 | |
364 | |
365 | |
366 | void SymExport (SymEntry* S, unsigned char AddrSize, unsigned Flags) |
367 | /* Mark the given symbol as an exported symbol */ |
368 | { |
369 | /* Check if it's ok to export the symbol */ |
370 | if (S->Flags & SF_IMPORT) { |
371 | /* The symbol is already marked as imported external symbol */ |
372 | Error ("Symbol '%m%p' is already an import" , GetSymName (S)); |
373 | return; |
374 | } |
375 | if (S->Flags & SF_VAR) { |
376 | /* Variable symbols cannot be exported */ |
377 | Error ("Var symbol '%m%p' cannot be exported" , GetSymName (S)); |
378 | return; |
379 | } |
380 | |
381 | /* If the symbol was marked as global before, remove the global flag and |
382 | ** proceed, but check the address size. |
383 | */ |
384 | if (S->Flags & SF_GLOBAL) { |
385 | if (AddrSize != S->ExportSize) { |
386 | Error ("Address size mismatch for symbol '%m%p'" , GetSymName (S)); |
387 | } |
388 | S->Flags &= ~SF_GLOBAL; |
389 | |
390 | /* .GLOBAL remembers line infos in case an .IMPORT follows. We have |
391 | ** to remove these here. |
392 | */ |
393 | ReleaseFullLineInfo (&S->DefLines); |
394 | } |
395 | |
396 | /* If the symbol was already marked as an export, but wasn't defined |
397 | ** before, the address sizes in both definitions must match. |
398 | */ |
399 | if ((S->Flags & (SF_EXPORT|SF_DEFINED)) == SF_EXPORT) { |
400 | if (S->ExportSize != AddrSize) { |
401 | Error ("Address size mismatch for symbol '%m%p'" , GetSymName (S)); |
402 | } |
403 | } |
404 | S->ExportSize = AddrSize; |
405 | |
406 | /* If the symbol is already defined, check symbol size against the |
407 | ** exported size. |
408 | */ |
409 | if (S->Flags & SF_DEFINED) { |
410 | if (S->ExportSize == ADDR_SIZE_DEFAULT) { |
411 | /* No export size given, use the real size of the symbol */ |
412 | S->ExportSize = S->AddrSize; |
413 | } else if (S->AddrSize > S->ExportSize) { |
414 | /* We're exporting a symbol smaller than it actually is */ |
415 | Warning (1, "Symbol '%m%p' is %s but exported %s" , |
416 | GetSymName (S), AddrSizeToStr (S->AddrSize), |
417 | AddrSizeToStr (S->ExportSize)); |
418 | } |
419 | } |
420 | |
421 | /* Set the symbol data */ |
422 | S->Flags |= (SF_EXPORT | SF_REFERENCED | Flags); |
423 | |
424 | /* Remember line info for this reference */ |
425 | CollAppend (&S->RefLines, GetAsmLineInfo ()); |
426 | } |
427 | |
428 | |
429 | |
430 | void SymGlobal (SymEntry* S, unsigned char AddrSize, unsigned Flags) |
431 | /* Mark the given symbol as a global symbol, that is, as a symbol that is |
432 | ** either imported or exported. |
433 | */ |
434 | { |
435 | if (S->Flags & SF_VAR) { |
436 | /* Variable symbols cannot be exported or imported */ |
437 | Error ("Var symbol '%m%p' cannot be made global" , GetSymName (S)); |
438 | return; |
439 | } |
440 | |
441 | /* If the symbol is already marked as import, the address size must match. |
442 | ** Apart from that, ignore the global declaration. |
443 | */ |
444 | if (S->Flags & SF_IMPORT) { |
445 | if (AddrSize == ADDR_SIZE_DEFAULT) { |
446 | /* Use the size of the current segment */ |
447 | AddrSize = GetCurrentSegAddrSize (); |
448 | } |
449 | if (AddrSize != S->AddrSize) { |
450 | Error ("Address size mismatch for symbol '%m%p'" , GetSymName (S)); |
451 | } |
452 | return; |
453 | } |
454 | |
455 | /* If the symbol is already an export: If it is not defined, the address |
456 | ** sizes must match. |
457 | */ |
458 | if (S->Flags & SF_EXPORT) { |
459 | if ((S->Flags & SF_DEFINED) == 0) { |
460 | /* Symbol is undefined */ |
461 | if (AddrSize != S->ExportSize) { |
462 | Error ("Address size mismatch for symbol '%m%p'" , GetSymName (S)); |
463 | } |
464 | } else if (AddrSize != ADDR_SIZE_DEFAULT) { |
465 | /* Symbol is defined and address size given */ |
466 | if (AddrSize != S->ExportSize) { |
467 | Error ("Address size mismatch for symbol '%m%p'" , GetSymName (S)); |
468 | } |
469 | } |
470 | return; |
471 | } |
472 | |
473 | /* If the symbol is already marked as global, the address size must match. |
474 | ** Use the ExportSize here, since it contains the actual address size |
475 | ** passed to this function. |
476 | */ |
477 | if (S->Flags & SF_GLOBAL) { |
478 | if (AddrSize != S->ExportSize) { |
479 | Error ("Address size mismatch for symbol '%m%p'" , GetSymName (S)); |
480 | } |
481 | return; |
482 | } |
483 | |
484 | /* If we come here, the symbol was neither declared as export, import or |
485 | ** global before. Check if it is already defined, in which case it will |
486 | ** become an export. If it is not defined, mark it as global and remember |
487 | ** the given address sizes. |
488 | */ |
489 | if (S->Flags & SF_DEFINED) { |
490 | /* The symbol is defined, export it */ |
491 | S->ExportSize = AddrSize; |
492 | if (S->ExportSize == ADDR_SIZE_DEFAULT) { |
493 | /* No export size given, use the real size of the symbol */ |
494 | S->ExportSize = S->AddrSize; |
495 | } else if (S->AddrSize > S->ExportSize) { |
496 | /* We're exporting a symbol smaller than it actually is */ |
497 | Warning (1, "Symbol '%m%p' is %s but exported %s" , |
498 | GetSymName (S), AddrSizeToStr (S->AddrSize), |
499 | AddrSizeToStr (S->ExportSize)); |
500 | } |
501 | S->Flags |= (SF_EXPORT | Flags); |
502 | } else { |
503 | /* Since we don't know if the symbol will get exported or imported, |
504 | ** remember two different address sizes: One for an import in AddrSize, |
505 | ** and the other one for an export in ExportSize. |
506 | */ |
507 | S->AddrSize = AddrSize; |
508 | if (S->AddrSize == ADDR_SIZE_DEFAULT) { |
509 | /* Use the size of the current segment */ |
510 | S->AddrSize = GetCurrentSegAddrSize (); |
511 | } |
512 | S->ExportSize = AddrSize; |
513 | S->Flags |= (SF_GLOBAL | Flags); |
514 | |
515 | /* Remember the current location as location of definition in case |
516 | ** an .IMPORT follows later. |
517 | */ |
518 | GetFullLineInfo (&S->DefLines); |
519 | } |
520 | } |
521 | |
522 | |
523 | |
524 | void SymConDes (SymEntry* S, unsigned char AddrSize, unsigned Type, unsigned Prio) |
525 | /* Mark the given symbol as a module constructor/destructor. This will also |
526 | ** mark the symbol as an export. Initializers may never be zero page symbols. |
527 | */ |
528 | { |
529 | /* Check the parameters */ |
530 | #if (CD_TYPE_MIN != 0) |
531 | CHECK (Type >= CD_TYPE_MIN && Type <= CD_TYPE_MAX); |
532 | #else |
533 | CHECK (Type <= CD_TYPE_MAX); |
534 | #endif |
535 | CHECK (Prio >= CD_PRIO_MIN && Prio <= CD_PRIO_MAX); |
536 | |
537 | /* Check for errors */ |
538 | if (S->Flags & SF_IMPORT) { |
539 | /* The symbol is already marked as imported external symbol */ |
540 | Error ("Symbol '%m%p' is already an import" , GetSymName (S)); |
541 | return; |
542 | } |
543 | if (S->Flags & SF_VAR) { |
544 | /* Variable symbols cannot be exported or imported */ |
545 | Error ("Var symbol '%m%p' cannot be exported" , GetSymName (S)); |
546 | return; |
547 | } |
548 | |
549 | /* If the symbol was already marked as an export or global, check if |
550 | ** this was done specifiying the same address size. In case of a global |
551 | ** declaration, silently remove the global flag. |
552 | */ |
553 | if (S->Flags & (SF_EXPORT | SF_GLOBAL)) { |
554 | if (S->ExportSize != AddrSize) { |
555 | Error ("Address size mismatch for symbol '%m%p'" , GetSymName (S)); |
556 | } |
557 | S->Flags &= ~SF_GLOBAL; |
558 | } |
559 | S->ExportSize = AddrSize; |
560 | |
561 | /* If the symbol is already defined, check symbol size against the |
562 | ** exported size. |
563 | */ |
564 | if (S->Flags & SF_DEFINED) { |
565 | if (S->ExportSize == ADDR_SIZE_DEFAULT) { |
566 | /* Use the real size of the symbol */ |
567 | S->ExportSize = S->AddrSize; |
568 | } else if (S->AddrSize != S->ExportSize) { |
569 | Error ("Address size mismatch for symbol '%m%p'" , GetSymName (S)); |
570 | } |
571 | } |
572 | |
573 | /* If the symbol already was declared as a condes of this type, |
574 | ** check if the new priority value is the same as the old one. |
575 | */ |
576 | if (S->ConDesPrio[Type] != CD_PRIO_NONE) { |
577 | if (S->ConDesPrio[Type] != Prio) { |
578 | Error ("Redeclaration mismatch for symbol '%m%p'" , GetSymName (S)); |
579 | } |
580 | } |
581 | S->ConDesPrio[Type] = Prio; |
582 | |
583 | /* Set the symbol data */ |
584 | S->Flags |= (SF_EXPORT | SF_REFERENCED); |
585 | |
586 | /* Remember the line info for this reference */ |
587 | CollAppend (&S->RefLines, GetAsmLineInfo ()); |
588 | } |
589 | |
590 | |
591 | |
592 | void SymGuessedAddrSize (SymEntry* Sym, unsigned char AddrSize) |
593 | /* Mark the address size of the given symbol as guessed. The address size |
594 | ** passed as argument is the one NOT used, because the actual address size |
595 | ** wasn't known. Example: Zero page addressing was not used because symbol |
596 | ** is undefined, and absolute addressing was available. |
597 | */ |
598 | { |
599 | /* We must have a valid address size passed */ |
600 | PRECONDITION (AddrSize != ADDR_SIZE_DEFAULT); |
601 | |
602 | /* We do not support all address sizes currently */ |
603 | if (AddrSize > sizeof (Sym->GuessedUse) / sizeof (Sym->GuessedUse[0])) { |
604 | return; |
605 | } |
606 | |
607 | /* We can only remember one such occurance */ |
608 | if (Sym->GuessedUse[AddrSize-1]) { |
609 | return; |
610 | } |
611 | |
612 | /* Ok, remember the file position */ |
613 | Sym->GuessedUse[AddrSize-1] = xdup (&CurTok.Pos, sizeof (CurTok.Pos)); |
614 | } |
615 | |
616 | |
617 | |
618 | void SymExportFromGlobal (SymEntry* S) |
619 | /* Called at the end of assembly. Converts a global symbol that is defined |
620 | ** into an export. |
621 | */ |
622 | { |
623 | /* Remove the global flag and make the symbol an export */ |
624 | S->Flags &= ~SF_GLOBAL; |
625 | S->Flags |= SF_EXPORT; |
626 | } |
627 | |
628 | |
629 | |
630 | void SymImportFromGlobal (SymEntry* S) |
631 | /* Called at the end of assembly. Converts a global symbol that is undefined |
632 | ** into an import. |
633 | */ |
634 | { |
635 | /* Remove the global flag and make it an import */ |
636 | S->Flags &= ~SF_GLOBAL; |
637 | S->Flags |= SF_IMPORT; |
638 | } |
639 | |
640 | |
641 | |
642 | int SymIsConst (const SymEntry* S, long* Val) |
643 | /* Return true if the given symbol has a constant value. If Val is not NULL |
644 | ** and the symbol has a constant value, store it's value there. |
645 | */ |
646 | { |
647 | /* Check for constness */ |
648 | return (SymHasExpr (S) && IsConstExpr (S->Expr, Val)); |
649 | } |
650 | |
651 | |
652 | |
653 | SymTable* GetSymParentScope (SymEntry* S) |
654 | /* Get the parent scope of the symbol (not the one it is defined in). Return |
655 | ** NULL if the symbol is a cheap local, or defined on global level. |
656 | */ |
657 | { |
658 | if ((S->Flags & SF_LOCAL) != 0) { |
659 | /* This is a cheap local symbol */ |
660 | return 0; |
661 | } else if (S->Sym.Tab == 0) { |
662 | /* Symbol not in a table. This may happen if there have been errors |
663 | ** before. Return NULL in this case to avoid further errors. |
664 | */ |
665 | return 0; |
666 | } else { |
667 | /* This is a global symbol */ |
668 | return S->Sym.Tab->Parent; |
669 | } |
670 | } |
671 | |
672 | |
673 | |
674 | struct ExprNode* GetSymExpr (SymEntry* S) |
675 | /* Get the expression for a non-const symbol */ |
676 | { |
677 | PRECONDITION (S != 0 && SymHasExpr (S)); |
678 | return S->Expr; |
679 | } |
680 | |
681 | |
682 | |
683 | const struct ExprNode* SymResolve (const SymEntry* S) |
684 | /* Helper function for DumpExpr. Resolves a symbol into an expression or return |
685 | ** NULL. Do not call in other contexts! |
686 | */ |
687 | { |
688 | return SymHasExpr (S)? S->Expr : 0; |
689 | } |
690 | |
691 | |
692 | |
693 | long GetSymVal (SymEntry* S) |
694 | /* Return the value of a symbol assuming it's constant. FAIL will be called |
695 | ** in case the symbol is undefined or not constant. |
696 | */ |
697 | { |
698 | long Val; |
699 | CHECK (S != 0 && SymHasExpr (S) && IsConstExpr (GetSymExpr (S), &Val)); |
700 | return Val; |
701 | } |
702 | |
703 | |
704 | |
705 | unsigned GetSymImportId (const SymEntry* S) |
706 | /* Return the import id for the given symbol */ |
707 | { |
708 | PRECONDITION (S != 0 && (S->Flags & SF_IMPORT) && S->ImportId != ~0U); |
709 | return S->ImportId; |
710 | } |
711 | |
712 | |
713 | |
714 | unsigned GetSymExportId (const SymEntry* S) |
715 | /* Return the export id for the given symbol */ |
716 | { |
717 | PRECONDITION (S != 0 && (S->Flags & SF_EXPORT) && S->ExportId != ~0U); |
718 | return S->ExportId; |
719 | } |
720 | |
721 | |
722 | |
723 | unsigned GetSymInfoFlags (const SymEntry* S, long* ConstVal) |
724 | /* Return a set of flags used when writing symbol information into a file. |
725 | ** If the SYM_CONST bit is set, ConstVal will contain the constant value |
726 | ** of the symbol. The result does not include the condes count. |
727 | ** See common/symdefs.h for more information. |
728 | */ |
729 | { |
730 | /* Setup info flags */ |
731 | unsigned Flags = 0; |
732 | Flags |= SymIsConst (S, ConstVal)? SYM_CONST : SYM_EXPR; |
733 | Flags |= (S->Flags & SF_LABEL)? SYM_LABEL : SYM_EQUATE; |
734 | Flags |= (S->Flags & SF_LOCAL)? SYM_CHEAP_LOCAL : SYM_STD; |
735 | if (S->Flags & SF_EXPORT) { |
736 | Flags |= SYM_EXPORT; |
737 | } |
738 | if (S->Flags & SF_IMPORT) { |
739 | Flags |= SYM_IMPORT; |
740 | } |
741 | |
742 | /* Return the result */ |
743 | return Flags; |
744 | } |
745 | |