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->DefLines = EmptyCollection;
90 S->RefLines = EmptyCollection;
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 SymTransferExprRefs (SymEntry* From, SymEntry* To)
153 /* Transfer all expression references from one symbol to another. */
157 for (I = 0; I < CollCount (&From->ExprRefs); ++I) {
159 /* Get the expression node */
160 ExprNode* E = CollAtUnchecked (&From->ExprRefs, I);
163 CHECK (E->Op == EXPR_SYMBOL && E->V.Sym == From);
165 /* Replace the symbol reference */
168 /* Add the expression reference */
169 SymAddExprRef (To, E);
172 /* Remove all symbol references from the old symbol */
173 CollDeleteAll (&From->ExprRefs);
178 static void SymReplaceExprRefs (SymEntry* S)
179 /* Replace the references to this symbol by a copy of the symbol expression */
184 /* Check if the expression is const and get its value */
185 int IsConst = IsConstExpr (S->Expr, &Val);
188 /* Loop over all references */
189 for (I = 0; I < CollCount (&S->ExprRefs); ++I) {
191 /* Get the expression node */
192 ExprNode* E = CollAtUnchecked (&S->ExprRefs, I);
195 CHECK (E->Op == EXPR_SYMBOL && E->V.Sym == S);
197 /* We cannot touch the root node, since there are pointers to it.
198 * Replace it by a literal node.
200 E->Op = EXPR_LITERAL;
204 /* Remove all symbol references from the symbol */
205 CollDeleteAll (&S->ExprRefs);
210 void SymDef (SymEntry* S, ExprNode* Expr, unsigned char AddrSize, unsigned Flags)
211 /* Define a new symbol */
213 if (S->Flags & SF_IMPORT) {
214 /* Defined symbol is marked as imported external symbol */
215 Error ("Symbol `%m%p' is already an import", GetSymName (S));
218 if ((Flags & SF_VAR) != 0 && (S->Flags & (SF_EXPORT | SF_GLOBAL))) {
219 /* Variable symbols cannot be exports or globals */
220 Error ("Var symbol `%m%p' cannot be an export or global symbol", GetSymName (S));
223 if (S->Flags & SF_DEFINED) {
224 /* Multiple definition. In case of a variable, this is legal. */
225 if ((S->Flags & SF_VAR) == 0) {
226 Error ("Symbol `%m%p' is already defined", GetSymName (S));
227 S->Flags |= SF_MULTDEF;
230 /* Redefinition must also be a variable symbol */
231 if ((Flags & SF_VAR) == 0) {
232 Error ("Symbol `%m%p' is already different kind", GetSymName (S));
235 /* Delete the current symbol expression, since it will get
243 /* Map a default address size to a real value */
244 if (AddrSize == ADDR_SIZE_DEFAULT) {
245 /* ### Must go! Delay address size calculation until end of assembly! */
248 StudyExpr (Expr, &ED);
249 AddrSize = ED.AddrSize;
253 /* Set the symbol value */
256 /* In case of a variable symbol, walk over all expressions containing
257 * this symbol and replace the (sub-)expression by the literal value of
258 * the tree. Be sure to replace the expression node in place, since there
259 * may be pointers to it.
261 if (Flags & SF_VAR) {
262 SymReplaceExprRefs (S);
265 /* If the symbol is marked as global, export it. Address size is checked
268 if (S->Flags & SF_GLOBAL) {
269 S->Flags = (S->Flags & ~SF_GLOBAL) | SF_EXPORT;
270 ReleaseFullLineInfo (&S->DefLines);
273 /* Mark the symbol as defined and use the given address size */
274 S->Flags |= (SF_DEFINED | Flags);
275 S->AddrSize = AddrSize;
277 /* Remember the line info of the symbol definition */
278 GetFullLineInfo (&S->DefLines);
280 /* If the symbol is exported, check the address sizes */
281 if (S->Flags & SF_EXPORT) {
282 if (S->ExportSize == ADDR_SIZE_DEFAULT) {
283 /* Use the real size of the symbol */
284 S->ExportSize = S->AddrSize;
285 } else if (S->AddrSize > S->ExportSize) {
286 /* We're exporting a symbol smaller than it actually is */
287 Warning (1, "Symbol `%m%p' is %s but exported %s",
288 GetSymName (S), AddrSizeToStr (S->AddrSize),
289 AddrSizeToStr (S->ExportSize));
293 /* If this is not a local symbol, remember it as the last global one */
294 if ((S->Flags & SF_LOCAL) == 0) {
301 void SymRef (SymEntry* S)
302 /* Mark the given symbol as referenced */
304 /* Mark the symbol as referenced */
305 S->Flags |= SF_REFERENCED;
307 /* Remember the current location */
308 CollAppend (&S->RefLines, GetAsmLineInfo ());
313 void SymImport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
314 /* Mark the given symbol as an imported symbol */
316 if (S->Flags & SF_DEFINED) {
317 Error ("Symbol `%m%p' is already defined", GetSymName (S));
318 S->Flags |= SF_MULTDEF;
321 if (S->Flags & SF_EXPORT) {
322 /* The symbol is already marked as exported symbol */
323 Error ("Cannot import exported symbol `%m%p'", GetSymName (S));
327 /* If no address size is given, use the address size of the enclosing
330 if (AddrSize == ADDR_SIZE_DEFAULT) {
331 AddrSize = GetCurrentSegAddrSize ();
334 /* If the symbol is marked as import or global, check the address size,
335 * then do silently remove the global flag.
337 if (S->Flags & SF_IMPORT) {
338 if ((Flags & SF_FORCED) != (S->Flags & SF_FORCED)) {
339 Error ("Redeclaration mismatch for symbol `%m%p'", GetSymName (S));
341 if (AddrSize != S->AddrSize) {
342 Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
345 if (S->Flags & SF_GLOBAL) {
346 S->Flags &= ~SF_GLOBAL;
347 if (AddrSize != S->AddrSize) {
348 Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
352 /* Set the symbol data */
353 S->Flags |= (SF_IMPORT | Flags);
354 S->AddrSize = AddrSize;
356 /* Mark the position of the import as the position of the definition.
357 * Please note: In case of multiple .global or .import statements, the line
360 GetFullLineInfo (&S->DefLines);
365 void SymExport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
366 /* Mark the given symbol as an exported symbol */
368 /* Check if it's ok to export the symbol */
369 if (S->Flags & SF_IMPORT) {
370 /* The symbol is already marked as imported external symbol */
371 Error ("Symbol `%m%p' is already an import", GetSymName (S));
374 if (S->Flags & SF_VAR) {
375 /* Variable symbols cannot be exported */
376 Error ("Var symbol `%m%p' cannot be exported", GetSymName (S));
380 /* If the symbol was marked as global before, remove the global flag and
381 * proceed, but check the address size.
383 if (S->Flags & SF_GLOBAL) {
384 if (AddrSize != S->ExportSize) {
385 Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
387 S->Flags &= ~SF_GLOBAL;
389 /* .GLOBAL remembers line infos in case an .IMPORT follows. We have
390 * to remove these here.
392 ReleaseFullLineInfo (&S->DefLines);
395 /* If the symbol was already marked as an export, but wasn't defined
396 * before, the address sizes in both definitions must match.
398 if ((S->Flags & (SF_EXPORT|SF_DEFINED)) == SF_EXPORT) {
399 if (S->ExportSize != AddrSize) {
400 Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
403 S->ExportSize = AddrSize;
405 /* If the symbol is already defined, check symbol size against the
408 if (S->Flags & SF_DEFINED) {
409 if (S->ExportSize == ADDR_SIZE_DEFAULT) {
410 /* No export size given, use the real size of the symbol */
411 S->ExportSize = S->AddrSize;
412 } else if (S->AddrSize > S->ExportSize) {
413 /* We're exporting a symbol smaller than it actually is */
414 Warning (1, "Symbol `%m%p' is %s but exported %s",
415 GetSymName (S), AddrSizeToStr (S->AddrSize),
416 AddrSizeToStr (S->ExportSize));
420 /* Set the symbol data */
421 S->Flags |= (SF_EXPORT | SF_REFERENCED | Flags);
423 /* Remember line info for this reference */
424 CollAppend (&S->RefLines, GetAsmLineInfo ());
429 void SymGlobal (SymEntry* S, unsigned char AddrSize, unsigned Flags)
430 /* Mark the given symbol as a global symbol, that is, as a symbol that is
431 * either imported or exported.
434 if (S->Flags & SF_VAR) {
435 /* Variable symbols cannot be exported or imported */
436 Error ("Var symbol `%m%p' cannot be made global", GetSymName (S));
440 /* If the symbol is already marked as import, the address size must match.
441 * Apart from that, ignore the global declaration.
443 if (S->Flags & SF_IMPORT) {
444 if (AddrSize == ADDR_SIZE_DEFAULT) {
445 /* Use the size of the current segment */
446 AddrSize = GetCurrentSegAddrSize ();
448 if (AddrSize != S->AddrSize) {
449 Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
454 /* If the symbol is already an export: If it is not defined, the address
457 if (S->Flags & SF_EXPORT) {
458 if ((S->Flags & SF_DEFINED) == 0) {
459 /* Symbol is undefined */
460 if (AddrSize != S->ExportSize) {
461 Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
463 } else if (AddrSize != ADDR_SIZE_DEFAULT) {
464 /* Symbol is defined and address size given */
465 if (AddrSize != S->ExportSize) {
466 Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
472 /* If the symbol is already marked as global, the address size must match.
473 * Use the ExportSize here, since it contains the actual address size
474 * passed to this function.
476 if (S->Flags & SF_GLOBAL) {
477 if (AddrSize != S->ExportSize) {
478 Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
483 /* If we come here, the symbol was neither declared as export, import or
484 * global before. Check if it is already defined, in which case it will
485 * become an export. If it is not defined, mark it as global and remember
486 * the given address sizes.
488 if (S->Flags & SF_DEFINED) {
489 /* The symbol is defined, export it */
490 S->ExportSize = AddrSize;
491 if (S->ExportSize == ADDR_SIZE_DEFAULT) {
492 /* No export size given, use the real size of the symbol */
493 S->ExportSize = S->AddrSize;
494 } else if (S->AddrSize > S->ExportSize) {
495 /* We're exporting a symbol smaller than it actually is */
496 Warning (1, "Symbol `%m%p' is %s but exported %s",
497 GetSymName (S), AddrSizeToStr (S->AddrSize),
498 AddrSizeToStr (S->ExportSize));
500 S->Flags |= (SF_EXPORT | Flags);
502 /* Since we don't know if the symbol will get exported or imported,
503 * remember two different address sizes: One for an import in AddrSize,
504 * and the other one for an export in ExportSize.
506 S->AddrSize = AddrSize;
507 if (S->AddrSize == ADDR_SIZE_DEFAULT) {
508 /* Use the size of the current segment */
509 S->AddrSize = GetCurrentSegAddrSize ();
511 S->ExportSize = AddrSize;
512 S->Flags |= (SF_GLOBAL | Flags);
514 /* Remember the current location as location of definition in case
515 * an .IMPORT follows later.
517 GetFullLineInfo (&S->DefLines);
523 void SymConDes (SymEntry* S, unsigned char AddrSize, unsigned Type, unsigned Prio)
524 /* Mark the given symbol as a module constructor/destructor. This will also
525 * mark the symbol as an export. Initializers may never be zero page symbols.
528 /* Check the parameters */
529 #if (CD_TYPE_MIN != 0)
530 CHECK (Type >= CD_TYPE_MIN && Type <= CD_TYPE_MAX);
532 CHECK (Type <= CD_TYPE_MAX);
534 CHECK (Prio >= CD_PRIO_MIN && Prio <= CD_PRIO_MAX);
536 /* Check for errors */
537 if (S->Flags & SF_IMPORT) {
538 /* The symbol is already marked as imported external symbol */
539 Error ("Symbol `%m%p' is already an import", GetSymName (S));
542 if (S->Flags & SF_VAR) {
543 /* Variable symbols cannot be exported or imported */
544 Error ("Var symbol `%m%p' cannot be exported", GetSymName (S));
548 /* If the symbol was already marked as an export or global, check if
549 * this was done specifiying the same address size. In case of a global
550 * declaration, silently remove the global flag.
552 if (S->Flags & (SF_EXPORT | SF_GLOBAL)) {
553 if (S->ExportSize != AddrSize) {
554 Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
556 S->Flags &= ~SF_GLOBAL;
558 S->ExportSize = AddrSize;
560 /* If the symbol is already defined, check symbol size against the
563 if (S->Flags & SF_DEFINED) {
564 if (S->ExportSize == ADDR_SIZE_DEFAULT) {
565 /* Use the real size of the symbol */
566 S->ExportSize = S->AddrSize;
567 } else if (S->AddrSize != S->ExportSize) {
568 Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
572 /* If the symbol was already declared as a condes, check if the new
573 * priority value is the same as the old one.
575 if (S->ConDesPrio[Type] != CD_PRIO_NONE) {
576 if (S->ConDesPrio[Type] != Prio) {
577 Error ("Redeclaration mismatch for symbol `%m%p'", GetSymName (S));
580 S->ConDesPrio[Type] = Prio;
582 /* Set the symbol data */
583 S->Flags |= (SF_EXPORT | SF_REFERENCED);
585 /* In case we have no line info for the definition, record it now */
586 if (CollCount (&S->DefLines) == 0) {
587 GetFullLineInfo (&S->DefLines);
593 void SymGuessedAddrSize (SymEntry* Sym, unsigned char AddrSize)
594 /* Mark the address size of the given symbol as guessed. The address size
595 * passed as argument is the one NOT used, because the actual address size
596 * wasn't known. Example: Zero page addressing was not used because symbol
597 * is undefined, and absolute addressing was available.
600 /* We must have a valid address size passed */
601 PRECONDITION (AddrSize != ADDR_SIZE_DEFAULT);
603 /* We do not support all address sizes currently */
604 if (AddrSize > sizeof (Sym->GuessedUse) / sizeof (Sym->GuessedUse[0])) {
608 /* We can only remember one such occurance */
609 if (Sym->GuessedUse[AddrSize-1]) {
613 /* Ok, remember the file position */
614 Sym->GuessedUse[AddrSize-1] = xdup (&CurTok.Pos, sizeof (CurTok.Pos));
619 void SymExportFromGlobal (SymEntry* S)
620 /* Called at the end of assembly. Converts a global symbol that is defined
624 /* Remove the global flag and make the symbol an export */
625 S->Flags &= ~SF_GLOBAL;
626 S->Flags |= SF_EXPORT;
631 void SymImportFromGlobal (SymEntry* S)
632 /* Called at the end of assembly. Converts a global symbol that is undefined
636 /* Remove the global flag and make it an import */
637 S->Flags &= ~SF_GLOBAL;
638 S->Flags |= SF_IMPORT;
643 int SymIsConst (const SymEntry* S, long* Val)
644 /* Return true if the given symbol has a constant value. If Val is not NULL
645 * and the symbol has a constant value, store it's value there.
648 /* Check for constness */
649 return (SymHasExpr (S) && IsConstExpr (S->Expr, Val));
654 SymTable* GetSymParentScope (SymEntry* S)
655 /* Get the parent scope of the symbol (not the one it is defined in). Return
656 * NULL if the symbol is a cheap local, or defined on global level.
659 if ((S->Flags & SF_LOCAL) != 0) {
660 /* This is a cheap local symbol */
662 } else if (S->Sym.Tab == 0) {
663 /* Symbol not in a table. This may happen if there have been errors
664 * before. Return NULL in this case to avoid further errors.
668 /* This is a global symbol */
669 return S->Sym.Tab->Parent;
675 struct ExprNode* GetSymExpr (SymEntry* S)
676 /* Get the expression for a non-const symbol */
678 PRECONDITION (S != 0 && SymHasExpr (S));
684 const struct ExprNode* SymResolve (const SymEntry* S)
685 /* Helper function for DumpExpr. Resolves a symbol into an expression or return
686 * NULL. Do not call in other contexts!
689 return SymHasExpr (S)? S->Expr : 0;
694 long GetSymVal (SymEntry* S)
695 /* Return the value of a symbol assuming it's constant. FAIL will be called
696 * in case the symbol is undefined or not constant.
700 CHECK (S != 0 && SymHasExpr (S) && IsConstExpr (GetSymExpr (S), &Val));
706 unsigned GetSymImportId (const SymEntry* S)
707 /* Return the import id for the given symbol */
709 PRECONDITION (S != 0 && (S->Flags & SF_IMPORT) && S->ImportId != ~0U);
715 unsigned GetSymExportId (const SymEntry* S)
716 /* Return the export id for the given symbol */
718 PRECONDITION (S != 0 && (S->Flags & SF_EXPORT) && S->ExportId != ~0U);
724 unsigned GetSymInfoFlags (const SymEntry* S, long* ConstVal)
725 /* Return a set of flags used when writing symbol information into a file.
726 * If the SYM_CONST bit is set, ConstVal will contain the constant value
727 * of the symbol. The result does not include the condes count.
728 * See common/symdefs.h for more information.
731 /* Setup info flags */
733 Flags |= SymIsConst (S, ConstVal)? SYM_CONST : SYM_EXPR;
734 Flags |= (S->Flags & SF_LABEL)? SYM_LABEL : SYM_EQUATE;
735 Flags |= (S->Flags & SF_LOCAL)? SYM_CHEAP_LOCAL : SYM_STD;
736 if (S->Flags & SF_EXPORT) {
739 if (S->Flags & SF_IMPORT) {
743 /* Return the result */