1 /*****************************************************************************/
5 /* Symbol table entry for the ca65 macroassembler */
9 /* (C) 1998-2008 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 /*****************************************************************************/
49 #include "studyexpr.h" /* ### */
55 /*****************************************************************************/
57 /*****************************************************************************/
61 /* List of all symbol table entries */
62 SymEntry* SymList = 0;
64 /* Pointer to last defined symbol */
65 SymEntry* SymLast = 0;
69 /*****************************************************************************/
71 /*****************************************************************************/
75 SymEntry* NewSymEntry (const StrBuf* Name, unsigned Flags)
76 /* Allocate a symbol table entry, initialize and return it */
81 SymEntry* S = xmalloc (sizeof (SymEntry));
83 /* Initialize the entry */
89 for (I = 0; I < sizeof (S->GuessedUse) / sizeof (S->GuessedUse[0]); ++I) {
94 S->ExprRefs = AUTO_COLLECTION_INITIALIZER;
95 S->ExportSize = ADDR_SIZE_DEFAULT;
96 S->AddrSize = ADDR_SIZE_DEFAULT;
97 memset (S->ConDesPrio, 0, sizeof (S->ConDesPrio));
98 S->Name = GetStrBufId (Name);
100 /* Insert it into the list of all entries */
104 /* Return the initialized entry */
110 int SymSearchTree (SymEntry* T, const StrBuf* Name, SymEntry** E)
111 /* Search in the given tree for a name. If we find the symbol, the function
112 * will return 0 and put the entry pointer into E. If we did not find the
113 * symbol, and the tree is empty, E is set to NULL. If the tree is not empty,
114 * E will be set to the last entry, and the result of the function is <0 if
115 * the entry should be inserted on the left side, and >0 if it should get
116 * inserted on the right side.
119 /* Is there a tree? */
125 /* We have a table, search it */
128 /* Get the symbol name */
129 const StrBuf* SymName = GetStrBuf (T->Name);
131 /* Choose next entry */
132 int Cmp = SB_Compare (Name, SymName);
133 if (Cmp < 0 && T->Left) {
135 } else if (Cmp > 0&& T->Right) {
138 /* Found or end of search, return the result */
147 void SymRef (SymEntry* S)
148 /* Mark the given symbol as referenced */
150 /* Mark the symbol as referenced */
151 S->Flags |= SF_REFERENCED;
156 void SymTransferExprRefs (SymEntry* From, SymEntry* To)
157 /* Transfer all expression references from one symbol to another. */
161 for (I = 0; I < CollCount (&From->ExprRefs); ++I) {
163 /* Get the expression node */
164 ExprNode* E = CollAtUnchecked (&From->ExprRefs, I);
167 CHECK (E->Op == EXPR_SYMBOL && E->V.Sym == From);
169 /* Replace the symbol reference */
172 /* Add the expression reference */
173 SymAddExprRef (To, E);
176 /* Remove all symbol references from the old symbol */
177 CollDeleteAll (&From->ExprRefs);
182 static void SymReplaceExprRefs (SymEntry* S)
183 /* Replace the references to this symbol by a copy of the symbol expression */
188 /* Check if the expression is const and get its value */
189 int IsConst = IsConstExpr (S->Expr, &Val);
192 /* Loop over all references */
193 for (I = 0; I < CollCount (&S->ExprRefs); ++I) {
195 /* Get the expression node */
196 ExprNode* E = CollAtUnchecked (&S->ExprRefs, I);
199 CHECK (E->Op == EXPR_SYMBOL && E->V.Sym == S);
201 /* We cannot touch the root node, since there are pointers to it.
202 * Replace it by a literal node.
204 E->Op = EXPR_LITERAL;
208 /* Remove all symbol references from the symbol */
209 CollDeleteAll (&S->ExprRefs);
214 void SymDef (SymEntry* S, ExprNode* Expr, unsigned char AddrSize, unsigned Flags)
215 /* Define a new symbol */
217 if (S->Flags & SF_IMPORT) {
218 /* Defined symbol is marked as imported external symbol */
219 Error ("Symbol `%m%p' is already an import", GetSymName (S));
222 if ((Flags & SF_VAR) != 0 && (S->Flags & (SF_EXPORT | SF_GLOBAL))) {
223 /* Variable symbols cannot be exports or globals */
224 Error ("Var symbol `%m%p' cannot be an export or global symbol", GetSymName (S));
227 if (S->Flags & SF_DEFINED) {
228 /* Multiple definition. In case of a variable, this is legal. */
229 if ((S->Flags & SF_VAR) == 0) {
230 Error ("Symbol `%m%p' is already defined", GetSymName (S));
231 S->Flags |= SF_MULTDEF;
234 /* Redefinition must also be a variable symbol */
235 if ((Flags & SF_VAR) == 0) {
236 Error ("Symbol `%m%p' is already different kind", GetSymName (S));
239 /* Delete the current symbol expression, since it will get
247 /* Map a default address size to a real value */
248 if (AddrSize == ADDR_SIZE_DEFAULT) {
249 /* ### Must go! Delay address size calculation until end of assembly! */
252 StudyExpr (Expr, &ED);
253 AddrSize = ED.AddrSize;
257 /* Set the symbol value */
260 /* In case of a variable symbol, walk over all expressions containing
261 * this symbol and replace the (sub-)expression by the literal value of
262 * the tree. Be sure to replace the expression node in place, since there
263 * may be pointers to it.
265 if (Flags & SF_VAR) {
266 SymReplaceExprRefs (S);
269 /* If the symbol is marked as global, export it. Address size is checked
272 if (S->Flags & SF_GLOBAL) {
273 S->Flags = (S->Flags & ~SF_GLOBAL) | SF_EXPORT;
276 /* Mark the symbol as defined and use the given address size */
277 S->Flags |= (SF_DEFINED | Flags);
278 S->AddrSize = AddrSize;
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 PWarning (GetSymPos (S), 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 SymImport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
302 /* Mark the given symbol as an imported symbol */
304 if (S->Flags & SF_DEFINED) {
305 Error ("Symbol `%m%p' is already defined", GetSymName (S));
306 S->Flags |= SF_MULTDEF;
309 if (S->Flags & SF_EXPORT) {
310 /* The symbol is already marked as exported symbol */
311 Error ("Cannot import exported symbol `%m%p'", GetSymName (S));
315 /* If no address size is given, use the address size of the enclosing
318 if (AddrSize == ADDR_SIZE_DEFAULT) {
319 AddrSize = GetCurrentSegAddrSize ();
322 /* If the symbol is marked as import or global, check the address size,
323 * then do silently remove the global flag.
325 if (S->Flags & SF_IMPORT) {
326 if ((Flags & SF_FORCED) != (S->Flags & SF_FORCED)) {
327 Error ("Redeclaration mismatch for symbol `%m%p'", GetSymName (S));
329 if (AddrSize != S->AddrSize) {
330 Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
333 if (S->Flags & SF_GLOBAL) {
334 S->Flags &= ~SF_GLOBAL;
335 if (AddrSize != S->AddrSize) {
336 Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
340 /* Set the symbol data */
341 S->Flags |= (SF_IMPORT | Flags);
342 S->AddrSize = AddrSize;
347 void SymExport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
348 /* Mark the given symbol as an exported symbol */
350 /* Check if it's ok to export the symbol */
351 if (S->Flags & SF_IMPORT) {
352 /* The symbol is already marked as imported external symbol */
353 Error ("Symbol `%m%p' is already an import", GetSymName (S));
356 if (S->Flags & SF_VAR) {
357 /* Variable symbols cannot be exported */
358 Error ("Var symbol `%m%p' cannot be exported", GetSymName (S));
362 /* If the symbol was marked as global before, remove the global flag and
363 * proceed, but check the address size.
365 if (S->Flags & SF_GLOBAL) {
366 if (AddrSize != S->ExportSize) {
367 Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
369 S->Flags &= ~SF_GLOBAL;
372 /* If the symbol was already marked as an export, but wasn't defined
373 * before, the address sizes in both definitions must match.
375 if ((S->Flags & (SF_EXPORT|SF_DEFINED)) == SF_EXPORT) {
376 if (S->ExportSize != AddrSize) {
377 Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
380 S->ExportSize = AddrSize;
382 /* If the symbol is already defined, check symbol size against the
385 if (S->Flags & SF_DEFINED) {
386 if (S->ExportSize == ADDR_SIZE_DEFAULT) {
387 /* No export size given, use the real size of the symbol */
388 S->ExportSize = S->AddrSize;
389 } else if (S->AddrSize > S->ExportSize) {
390 /* We're exporting a symbol smaller than it actually is */
391 Warning (1, "Symbol `%m%p' is %s but exported %s",
392 GetSymName (S), AddrSizeToStr (S->AddrSize),
393 AddrSizeToStr (S->ExportSize));
397 /* Set the symbol data */
398 S->Flags |= (SF_EXPORT | SF_REFERENCED | Flags);
403 void SymGlobal (SymEntry* S, unsigned char AddrSize, unsigned Flags)
404 /* Mark the given symbol as a global symbol, that is, as a symbol that is
405 * either imported or exported.
408 if (S->Flags & SF_VAR) {
409 /* Variable symbols cannot be exported or imported */
410 Error ("Var symbol `%m%p' cannot be made global", GetSymName (S));
414 /* If the symbol is already marked as import, the address size must match.
415 * Apart from that, ignore the global declaration.
417 if (S->Flags & SF_IMPORT) {
418 if (AddrSize == ADDR_SIZE_DEFAULT) {
419 /* Use the size of the current segment */
420 AddrSize = GetCurrentSegAddrSize ();
422 if (AddrSize != S->AddrSize) {
423 Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
428 /* If the symbol is already an export: If it is not defined, the address
431 if (S->Flags & SF_EXPORT) {
432 if ((S->Flags & SF_DEFINED) == 0) {
433 /* Symbol is undefined */
434 if (AddrSize != S->ExportSize) {
435 Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
437 } else if (AddrSize != ADDR_SIZE_DEFAULT) {
438 /* Symbol is defined and address size given */
439 if (AddrSize != S->ExportSize) {
440 Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
446 /* If the symbol is already marked as global, the address size must match.
447 * Use the ExportSize here, since it contains the actual address size
448 * passed to this function.
450 if (S->Flags & SF_GLOBAL) {
451 if (AddrSize != S->ExportSize) {
452 Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
457 /* If we come here, the symbol was neither declared as export, import or
458 * global before. Check if it is already defined, in which case it will
459 * become an export. If it is not defined, mark it as global and remember
460 * the given address sizes.
462 if (S->Flags & SF_DEFINED) {
463 /* The symbol is defined, export it */
464 S->ExportSize = AddrSize;
465 if (S->ExportSize == ADDR_SIZE_DEFAULT) {
466 /* No export size given, use the real size of the symbol */
467 S->ExportSize = S->AddrSize;
468 } else if (S->AddrSize > S->ExportSize) {
469 /* We're exporting a symbol smaller than it actually is */
470 Warning (1, "Symbol `%m%p' is %s but exported %s",
471 GetSymName (S), AddrSizeToStr (S->AddrSize),
472 AddrSizeToStr (S->ExportSize));
474 S->Flags |= (SF_EXPORT | Flags);
476 /* Since we don't know if the symbol will get exported or imported,
477 * remember two different address sizes: One for an import in AddrSize,
478 * and the other one for an export in ExportSize.
480 S->AddrSize = AddrSize;
481 if (S->AddrSize == ADDR_SIZE_DEFAULT) {
482 /* Use the size of the current segment */
483 S->AddrSize = GetCurrentSegAddrSize ();
485 S->ExportSize = AddrSize;
486 S->Flags |= (SF_GLOBAL | Flags);
492 void SymConDes (SymEntry* S, unsigned char AddrSize, unsigned Type, unsigned Prio)
493 /* Mark the given symbol as a module constructor/destructor. This will also
494 * mark the symbol as an export. Initializers may never be zero page symbols.
497 /* Check the parameters */
498 #if (CD_TYPE_MIN != 0)
499 CHECK (Type >= CD_TYPE_MIN && Type <= CD_TYPE_MAX);
501 CHECK (Type <= CD_TYPE_MAX);
503 CHECK (Prio >= CD_PRIO_MIN && Prio <= CD_PRIO_MAX);
505 /* Check for errors */
506 if (S->Flags & SF_IMPORT) {
507 /* The symbol is already marked as imported external symbol */
508 Error ("Symbol `%m%p' is already an import", GetSymName (S));
511 if (S->Flags & SF_VAR) {
512 /* Variable symbols cannot be exported or imported */
513 Error ("Var symbol `%m%p' cannot be exported", GetSymName (S));
517 /* If the symbol was already marked as an export or global, check if
518 * this was done specifiying the same address size. In case of a global
519 * declaration, silently remove the global flag.
521 if (S->Flags & (SF_EXPORT | SF_GLOBAL)) {
522 if (S->ExportSize != AddrSize) {
523 Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
525 S->Flags &= ~SF_GLOBAL;
527 S->ExportSize = AddrSize;
529 /* If the symbol is already defined, check symbol size against the
532 if (S->Flags & SF_DEFINED) {
533 if (S->ExportSize == ADDR_SIZE_DEFAULT) {
534 /* Use the real size of the symbol */
535 S->ExportSize = S->AddrSize;
536 } else if (S->AddrSize != S->ExportSize) {
537 Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
541 /* If the symbol was already declared as a condes, check if the new
542 * priority value is the same as the old one.
544 if (S->ConDesPrio[Type] != CD_PRIO_NONE) {
545 if (S->ConDesPrio[Type] != Prio) {
546 Error ("Redeclaration mismatch for symbol `%m%p'", GetSymName (S));
549 S->ConDesPrio[Type] = Prio;
551 /* Set the symbol data */
552 S->Flags |= (SF_EXPORT | SF_REFERENCED);
557 void SymGuessedAddrSize (SymEntry* Sym, unsigned char AddrSize)
558 /* Mark the address size of the given symbol as guessed. The address size
559 * passed as argument is the one NOT used, because the actual address size
560 * wasn't known. Example: Zero page addressing was not used because symbol
561 * is undefined, and absolute addressing was available.
564 /* We must have a valid address size passed */
565 PRECONDITION (AddrSize != ADDR_SIZE_DEFAULT);
567 /* We do not support all address sizes currently */
568 if (AddrSize > sizeof (Sym->GuessedUse) / sizeof (Sym->GuessedUse[0])) {
572 /* We can only remember one such occurance */
573 if (Sym->GuessedUse[AddrSize-1]) {
577 /* Ok, remember the file position */
578 Sym->GuessedUse[AddrSize-1] = xdup (&CurPos, sizeof (CurPos));
583 void SymExportFromGlobal (SymEntry* S)
584 /* Called at the end of assembly. Converts a global symbol that is defined
588 /* Remove the global flag and make the symbol an export */
589 S->Flags &= ~SF_GLOBAL;
590 S->Flags |= SF_EXPORT;
595 void SymImportFromGlobal (SymEntry* S)
596 /* Called at the end of assembly. Converts a global symbol that is undefined
600 /* Remove the global flag and make it an import */
601 S->Flags &= ~SF_GLOBAL;
602 S->Flags |= SF_IMPORT;
607 int SymIsConst (SymEntry* S, long* Val)
608 /* Return true if the given symbol has a constant value. If Val is not NULL
609 * and the symbol has a constant value, store it's value there.
612 /* Check for constness */
613 return (SymHasExpr (S) && IsConstExpr (S->Expr, Val));
618 SymTable* GetSymParentScope (SymEntry* S)
619 /* Get the parent scope of the symbol (not the one it is defined in). Return
620 * NULL if the symbol is a cheap local, or defined on global level.
623 return (S->SymTab && S->SymTab->Parent)? S->SymTab->Parent : 0;
628 struct ExprNode* GetSymExpr (SymEntry* S)
629 /* Get the expression for a non-const symbol */
631 PRECONDITION (S != 0 && SymHasExpr (S));
637 const struct ExprNode* SymResolve (const SymEntry* S)
638 /* Helper function for DumpExpr. Resolves a symbol into an expression or return
639 * NULL. Do not call in other contexts!
642 return SymHasExpr (S)? S->Expr : 0;
647 long GetSymVal (SymEntry* S)
648 /* Return the value of a symbol assuming it's constant. FAIL will be called
649 * in case the symbol is undefined or not constant.
653 CHECK (S != 0 && SymHasExpr (S) && IsConstExpr (GetSymExpr (S), &Val));
659 unsigned GetSymIndex (const SymEntry* S)
660 /* Return the symbol index for the given symbol */
662 PRECONDITION (S != 0 && (S->Flags & SF_INDEXED) != 0);