1 /*****************************************************************************/
5 /* Symbol table entry for the ca65 macroassembler */
9 /* (C) 1998-2011, Ullrich von Bassewitz */
10 /* Roemerstrasse 52 */
11 /* D-70794 Filderstadt */
12 /* EMail: uz@cc65.org */
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. */
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: */
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 */
32 /*****************************************************************************/
50 #include "studyexpr.h" /* ### */
56 /*****************************************************************************/
58 /*****************************************************************************/
62 /* List of all symbol table entries */
63 SymEntry* SymList = 0;
65 /* Pointer to last defined symbol */
66 SymEntry* SymLast = 0;
70 /*****************************************************************************/
72 /*****************************************************************************/
76 SymEntry* NewSymEntry (const StrBuf* Name, unsigned Flags)
77 /* Allocate a symbol table entry, initialize and return it */
82 SymEntry* S = xmalloc (sizeof (SymEntry));
84 /* Initialize the entry */
89 S->LineInfos = EmptyCollection;
90 GetFullLineInfo (&S->LineInfos, 1);
91 for (I = 0; I < sizeof (S->GuessedUse) / sizeof (S->GuessedUse[0]); ++I) {
99 S->ExprRefs = AUTO_COLLECTION_INITIALIZER;
100 S->ExportSize = ADDR_SIZE_DEFAULT;
101 S->AddrSize = ADDR_SIZE_DEFAULT;
102 memset (S->ConDesPrio, 0, sizeof (S->ConDesPrio));
103 S->Name = GetStrBufId (Name);
105 /* Insert it into the list of all entries */
109 /* Return the initialized entry */
115 int SymSearchTree (SymEntry* T, const StrBuf* Name, SymEntry** E)
116 /* Search in the given tree for a name. If we find the symbol, the function
117 * will return 0 and put the entry pointer into E. If we did not find the
118 * symbol, and the tree is empty, E is set to NULL. If the tree is not empty,
119 * E will be set to the last entry, and the result of the function is <0 if
120 * the entry should be inserted on the left side, and >0 if it should get
121 * inserted on the right side.
124 /* Is there a tree? */
130 /* We have a table, search it */
133 /* Get the symbol name */
134 const StrBuf* SymName = GetStrBuf (T->Name);
136 /* Choose next entry */
137 int Cmp = SB_Compare (Name, SymName);
138 if (Cmp < 0 && T->Left) {
140 } else if (Cmp > 0&& T->Right) {
143 /* Found or end of search, return the result */
152 void SymRef (SymEntry* S)
153 /* Mark the given symbol as referenced */
155 /* Mark the symbol as referenced */
156 S->Flags |= SF_REFERENCED;
161 void SymTransferExprRefs (SymEntry* From, SymEntry* To)
162 /* Transfer all expression references from one symbol to another. */
166 for (I = 0; I < CollCount (&From->ExprRefs); ++I) {
168 /* Get the expression node */
169 ExprNode* E = CollAtUnchecked (&From->ExprRefs, I);
172 CHECK (E->Op == EXPR_SYMBOL && E->V.Sym == From);
174 /* Replace the symbol reference */
177 /* Add the expression reference */
178 SymAddExprRef (To, E);
181 /* Remove all symbol references from the old symbol */
182 CollDeleteAll (&From->ExprRefs);
187 static void SymReplaceExprRefs (SymEntry* S)
188 /* Replace the references to this symbol by a copy of the symbol expression */
193 /* Check if the expression is const and get its value */
194 int IsConst = IsConstExpr (S->Expr, &Val);
197 /* Loop over all references */
198 for (I = 0; I < CollCount (&S->ExprRefs); ++I) {
200 /* Get the expression node */
201 ExprNode* E = CollAtUnchecked (&S->ExprRefs, I);
204 CHECK (E->Op == EXPR_SYMBOL && E->V.Sym == S);
206 /* We cannot touch the root node, since there are pointers to it.
207 * Replace it by a literal node.
209 E->Op = EXPR_LITERAL;
213 /* Remove all symbol references from the symbol */
214 CollDeleteAll (&S->ExprRefs);
219 void SymDef (SymEntry* S, ExprNode* Expr, unsigned char AddrSize, unsigned Flags)
220 /* Define a new symbol */
222 if (S->Flags & SF_IMPORT) {
223 /* Defined symbol is marked as imported external symbol */
224 Error ("Symbol `%m%p' is already an import", GetSymName (S));
227 if ((Flags & SF_VAR) != 0 && (S->Flags & (SF_EXPORT | SF_GLOBAL))) {
228 /* Variable symbols cannot be exports or globals */
229 Error ("Var symbol `%m%p' cannot be an export or global symbol", GetSymName (S));
232 if (S->Flags & SF_DEFINED) {
233 /* Multiple definition. In case of a variable, this is legal. */
234 if ((S->Flags & SF_VAR) == 0) {
235 Error ("Symbol `%m%p' is already defined", GetSymName (S));
236 S->Flags |= SF_MULTDEF;
239 /* Redefinition must also be a variable symbol */
240 if ((Flags & SF_VAR) == 0) {
241 Error ("Symbol `%m%p' is already different kind", GetSymName (S));
244 /* Delete the current symbol expression, since it will get
252 /* Map a default address size to a real value */
253 if (AddrSize == ADDR_SIZE_DEFAULT) {
254 /* ### Must go! Delay address size calculation until end of assembly! */
257 StudyExpr (Expr, &ED);
258 AddrSize = ED.AddrSize;
262 /* Set the symbol value */
265 /* In case of a variable symbol, walk over all expressions containing
266 * this symbol and replace the (sub-)expression by the literal value of
267 * the tree. Be sure to replace the expression node in place, since there
268 * may be pointers to it.
270 if (Flags & SF_VAR) {
271 SymReplaceExprRefs (S);
274 /* If the symbol is marked as global, export it. Address size is checked
277 if (S->Flags & SF_GLOBAL) {
278 S->Flags = (S->Flags & ~SF_GLOBAL) | SF_EXPORT;
281 /* Mark the symbol as defined and use the given address size */
282 S->Flags |= (SF_DEFINED | Flags);
283 S->AddrSize = AddrSize;
285 /* If the symbol is exported, check the address sizes */
286 if (S->Flags & SF_EXPORT) {
287 if (S->ExportSize == ADDR_SIZE_DEFAULT) {
288 /* Use the real size of the symbol */
289 S->ExportSize = S->AddrSize;
290 } else if (S->AddrSize > S->ExportSize) {
291 /* We're exporting a symbol smaller than it actually is */
292 LIWarning (&S->LineInfos, 1, "Symbol `%m%p' is %s but exported %s",
293 GetSymName (S), AddrSizeToStr (S->AddrSize),
294 AddrSizeToStr (S->ExportSize));
298 /* If this is not a local symbol, remember it as the last global one */
299 if ((S->Flags & SF_LOCAL) == 0) {
306 void SymImport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
307 /* Mark the given symbol as an imported symbol */
309 if (S->Flags & SF_DEFINED) {
310 Error ("Symbol `%m%p' is already defined", GetSymName (S));
311 S->Flags |= SF_MULTDEF;
314 if (S->Flags & SF_EXPORT) {
315 /* The symbol is already marked as exported symbol */
316 Error ("Cannot import exported symbol `%m%p'", GetSymName (S));
320 /* If no address size is given, use the address size of the enclosing
323 if (AddrSize == ADDR_SIZE_DEFAULT) {
324 AddrSize = GetCurrentSegAddrSize ();
327 /* If the symbol is marked as import or global, check the address size,
328 * then do silently remove the global flag.
330 if (S->Flags & SF_IMPORT) {
331 if ((Flags & SF_FORCED) != (S->Flags & SF_FORCED)) {
332 Error ("Redeclaration mismatch for symbol `%m%p'", GetSymName (S));
334 if (AddrSize != S->AddrSize) {
335 Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
338 if (S->Flags & SF_GLOBAL) {
339 S->Flags &= ~SF_GLOBAL;
340 if (AddrSize != S->AddrSize) {
341 Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
345 /* Set the symbol data */
346 S->Flags |= (SF_IMPORT | Flags);
347 S->AddrSize = AddrSize;
352 void SymExport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
353 /* Mark the given symbol as an exported symbol */
355 /* Check if it's ok to export the symbol */
356 if (S->Flags & SF_IMPORT) {
357 /* The symbol is already marked as imported external symbol */
358 Error ("Symbol `%m%p' is already an import", GetSymName (S));
361 if (S->Flags & SF_VAR) {
362 /* Variable symbols cannot be exported */
363 Error ("Var symbol `%m%p' cannot be exported", GetSymName (S));
367 /* If the symbol was marked as global before, remove the global flag and
368 * proceed, but check the address size.
370 if (S->Flags & SF_GLOBAL) {
371 if (AddrSize != S->ExportSize) {
372 Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
374 S->Flags &= ~SF_GLOBAL;
377 /* If the symbol was already marked as an export, but wasn't defined
378 * before, the address sizes in both definitions must match.
380 if ((S->Flags & (SF_EXPORT|SF_DEFINED)) == SF_EXPORT) {
381 if (S->ExportSize != AddrSize) {
382 Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
385 S->ExportSize = AddrSize;
387 /* If the symbol is already defined, check symbol size against the
390 if (S->Flags & SF_DEFINED) {
391 if (S->ExportSize == ADDR_SIZE_DEFAULT) {
392 /* No export size given, use the real size of the symbol */
393 S->ExportSize = S->AddrSize;
394 } else if (S->AddrSize > S->ExportSize) {
395 /* We're exporting a symbol smaller than it actually is */
396 Warning (1, "Symbol `%m%p' is %s but exported %s",
397 GetSymName (S), AddrSizeToStr (S->AddrSize),
398 AddrSizeToStr (S->ExportSize));
402 /* Set the symbol data */
403 S->Flags |= (SF_EXPORT | SF_REFERENCED | Flags);
408 void SymGlobal (SymEntry* S, unsigned char AddrSize, unsigned Flags)
409 /* Mark the given symbol as a global symbol, that is, as a symbol that is
410 * either imported or exported.
413 if (S->Flags & SF_VAR) {
414 /* Variable symbols cannot be exported or imported */
415 Error ("Var symbol `%m%p' cannot be made global", GetSymName (S));
419 /* If the symbol is already marked as import, the address size must match.
420 * Apart from that, ignore the global declaration.
422 if (S->Flags & SF_IMPORT) {
423 if (AddrSize == ADDR_SIZE_DEFAULT) {
424 /* Use the size of the current segment */
425 AddrSize = GetCurrentSegAddrSize ();
427 if (AddrSize != S->AddrSize) {
428 Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
433 /* If the symbol is already an export: If it is not defined, the address
436 if (S->Flags & SF_EXPORT) {
437 if ((S->Flags & SF_DEFINED) == 0) {
438 /* Symbol is undefined */
439 if (AddrSize != S->ExportSize) {
440 Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
442 } else if (AddrSize != ADDR_SIZE_DEFAULT) {
443 /* Symbol is defined and address size given */
444 if (AddrSize != S->ExportSize) {
445 Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
451 /* If the symbol is already marked as global, the address size must match.
452 * Use the ExportSize here, since it contains the actual address size
453 * passed to this function.
455 if (S->Flags & SF_GLOBAL) {
456 if (AddrSize != S->ExportSize) {
457 Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
462 /* If we come here, the symbol was neither declared as export, import or
463 * global before. Check if it is already defined, in which case it will
464 * become an export. If it is not defined, mark it as global and remember
465 * the given address sizes.
467 if (S->Flags & SF_DEFINED) {
468 /* The symbol is defined, export it */
469 S->ExportSize = AddrSize;
470 if (S->ExportSize == ADDR_SIZE_DEFAULT) {
471 /* No export size given, use the real size of the symbol */
472 S->ExportSize = S->AddrSize;
473 } else if (S->AddrSize > S->ExportSize) {
474 /* We're exporting a symbol smaller than it actually is */
475 Warning (1, "Symbol `%m%p' is %s but exported %s",
476 GetSymName (S), AddrSizeToStr (S->AddrSize),
477 AddrSizeToStr (S->ExportSize));
479 S->Flags |= (SF_EXPORT | Flags);
481 /* Since we don't know if the symbol will get exported or imported,
482 * remember two different address sizes: One for an import in AddrSize,
483 * and the other one for an export in ExportSize.
485 S->AddrSize = AddrSize;
486 if (S->AddrSize == ADDR_SIZE_DEFAULT) {
487 /* Use the size of the current segment */
488 S->AddrSize = GetCurrentSegAddrSize ();
490 S->ExportSize = AddrSize;
491 S->Flags |= (SF_GLOBAL | Flags);
497 void SymConDes (SymEntry* S, unsigned char AddrSize, unsigned Type, unsigned Prio)
498 /* Mark the given symbol as a module constructor/destructor. This will also
499 * mark the symbol as an export. Initializers may never be zero page symbols.
502 /* Check the parameters */
503 #if (CD_TYPE_MIN != 0)
504 CHECK (Type >= CD_TYPE_MIN && Type <= CD_TYPE_MAX);
506 CHECK (Type <= CD_TYPE_MAX);
508 CHECK (Prio >= CD_PRIO_MIN && Prio <= CD_PRIO_MAX);
510 /* Check for errors */
511 if (S->Flags & SF_IMPORT) {
512 /* The symbol is already marked as imported external symbol */
513 Error ("Symbol `%m%p' is already an import", GetSymName (S));
516 if (S->Flags & SF_VAR) {
517 /* Variable symbols cannot be exported or imported */
518 Error ("Var symbol `%m%p' cannot be exported", GetSymName (S));
522 /* If the symbol was already marked as an export or global, check if
523 * this was done specifiying the same address size. In case of a global
524 * declaration, silently remove the global flag.
526 if (S->Flags & (SF_EXPORT | SF_GLOBAL)) {
527 if (S->ExportSize != AddrSize) {
528 Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
530 S->Flags &= ~SF_GLOBAL;
532 S->ExportSize = AddrSize;
534 /* If the symbol is already defined, check symbol size against the
537 if (S->Flags & SF_DEFINED) {
538 if (S->ExportSize == ADDR_SIZE_DEFAULT) {
539 /* Use the real size of the symbol */
540 S->ExportSize = S->AddrSize;
541 } else if (S->AddrSize != S->ExportSize) {
542 Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
546 /* If the symbol was already declared as a condes, check if the new
547 * priority value is the same as the old one.
549 if (S->ConDesPrio[Type] != CD_PRIO_NONE) {
550 if (S->ConDesPrio[Type] != Prio) {
551 Error ("Redeclaration mismatch for symbol `%m%p'", GetSymName (S));
554 S->ConDesPrio[Type] = Prio;
556 /* Set the symbol data */
557 S->Flags |= (SF_EXPORT | SF_REFERENCED);
562 void SymGuessedAddrSize (SymEntry* Sym, unsigned char AddrSize)
563 /* Mark the address size of the given symbol as guessed. The address size
564 * passed as argument is the one NOT used, because the actual address size
565 * wasn't known. Example: Zero page addressing was not used because symbol
566 * is undefined, and absolute addressing was available.
569 /* We must have a valid address size passed */
570 PRECONDITION (AddrSize != ADDR_SIZE_DEFAULT);
572 /* We do not support all address sizes currently */
573 if (AddrSize > sizeof (Sym->GuessedUse) / sizeof (Sym->GuessedUse[0])) {
577 /* We can only remember one such occurance */
578 if (Sym->GuessedUse[AddrSize-1]) {
582 /* Ok, remember the file position */
583 Sym->GuessedUse[AddrSize-1] = xdup (&CurTok.Pos, sizeof (CurTok.Pos));
588 void SymExportFromGlobal (SymEntry* S)
589 /* Called at the end of assembly. Converts a global symbol that is defined
593 /* Remove the global flag and make the symbol an export */
594 S->Flags &= ~SF_GLOBAL;
595 S->Flags |= SF_EXPORT;
600 void SymImportFromGlobal (SymEntry* S)
601 /* Called at the end of assembly. Converts a global symbol that is undefined
605 /* Remove the global flag and make it an import */
606 S->Flags &= ~SF_GLOBAL;
607 S->Flags |= SF_IMPORT;
612 int SymIsConst (const SymEntry* S, long* Val)
613 /* Return true if the given symbol has a constant value. If Val is not NULL
614 * and the symbol has a constant value, store it's value there.
617 /* Check for constness */
618 return (SymHasExpr (S) && IsConstExpr (S->Expr, Val));
623 SymTable* GetSymParentScope (SymEntry* S)
624 /* Get the parent scope of the symbol (not the one it is defined in). Return
625 * NULL if the symbol is a cheap local, or defined on global level.
628 if ((S->Flags & SF_LOCAL) != 0) {
629 /* This is a cheap local symbol */
631 } else if (S->Sym.Tab == 0) {
632 /* Symbol not in a table. This may happen if there have been errors
633 * before. Return NULL in this case to avoid further errors.
637 /* This is a global symbol */
638 return S->Sym.Tab->Parent;
644 struct ExprNode* GetSymExpr (SymEntry* S)
645 /* Get the expression for a non-const symbol */
647 PRECONDITION (S != 0 && SymHasExpr (S));
653 const struct ExprNode* SymResolve (const SymEntry* S)
654 /* Helper function for DumpExpr. Resolves a symbol into an expression or return
655 * NULL. Do not call in other contexts!
658 return SymHasExpr (S)? S->Expr : 0;
663 long GetSymVal (SymEntry* S)
664 /* Return the value of a symbol assuming it's constant. FAIL will be called
665 * in case the symbol is undefined or not constant.
669 CHECK (S != 0 && SymHasExpr (S) && IsConstExpr (GetSymExpr (S), &Val));
675 unsigned GetSymImportId (const SymEntry* S)
676 /* Return the import id for the given symbol */
678 PRECONDITION (S != 0 && (S->Flags & SF_IMPORT) && S->ImportId != ~0U);
684 unsigned GetSymExportId (const SymEntry* S)
685 /* Return the export id for the given symbol */
687 PRECONDITION (S != 0 && (S->Flags & SF_IMPORT) && S->ExportId != ~0U);
693 unsigned GetSymInfoFlags (const SymEntry* S, long* ConstVal)
694 /* Return a set of flags used when writing symbol information into a file.
695 * If the SYM_CONST bit is set, ConstVal will contain the constant value
696 * of the symbol. The result does not include the condes count.
697 * See common/symdefs.h for more information.
700 /* Setup info flags */
702 Flags |= SymIsConst (S, ConstVal)? SYM_CONST : SYM_EXPR;
703 Flags |= (S->Flags & SF_LABEL)? SYM_LABEL : SYM_EQUATE;
704 Flags |= (S->Flags & SF_LOCAL)? SYM_CHEAP_LOCAL : SYM_STD;
705 if (S->Flags & SF_EXPORT) {
708 if (S->Flags & SF_IMPORT) {
712 /* Return the result */