1 /*****************************************************************************/
5 /* Symbol table entry forward for the ca65 macroassembler */
9 /* (C) 1998-2004 Ullrich von Bassewitz */
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 char* Name, unsigned Flags)
76 /* Allocate a symbol table entry, initialize and return it */
79 SymEntry* S = xmalloc (sizeof (SymEntry));
81 /* Initialize the entry */
89 S->ExprRefs = AUTO_COLLECTION_INITIALIZER;
90 S->ExportSize = ADDR_SIZE_DEFAULT;
91 S->AddrSize = ADDR_SIZE_DEFAULT;
92 memset (S->ConDesPrio, 0, sizeof (S->ConDesPrio));
93 S->Name = GetStringId (Name);
95 /* Insert it into the list of all entries */
99 /* Return the initialized entry */
105 int SymSearchTree (SymEntry* T, const char* Name, SymEntry** E)
106 /* Search in the given tree for a name. If we find the symbol, the function
107 * will return 0 and put the entry pointer into E. If we did not find the
108 * symbol, and the tree is empty, E is set to NULL. If the tree is not empty,
109 * E will be set to the last entry, and the result of the function is <0 if
110 * the entry should be inserted on the left side, and >0 if it should get
111 * inserted on the right side.
114 /* Is there a tree? */
120 /* We have a table, search it */
123 /* Get the symbol name */
124 const char* SymName = GetString (T->Name);
126 /* Choose next entry */
127 int Cmp = strcmp (Name, SymName);
128 if (Cmp < 0 && T->Left) {
130 } else if (Cmp > 0&& T->Right) {
133 /* Found or end of search, return the result */
142 void SymRef (SymEntry* S)
143 /* Mark the given symbol as referenced */
145 /* Mark the symbol as referenced */
146 S->Flags |= SF_REFERENCED;
151 void SymTransferExprRefs (SymEntry* From, SymEntry* To)
152 /* Transfer all expression references from one symbol to another. */
156 for (I = 0; I < CollCount (&From->ExprRefs); ++I) {
158 /* Get the expression node */
159 ExprNode* E = CollAtUnchecked (&From->ExprRefs, I);
162 CHECK (E->Op == EXPR_SYMBOL && E->V.Sym == From);
164 /* Replace the symbol reference */
167 /* Add the expression reference */
168 SymAddExprRef (To, E);
171 /* Remove all symbol references from the old symbol */
172 CollDeleteAll (&From->ExprRefs);
177 static void SymReplaceExprRefs (SymEntry* S)
178 /* Replace the references to this symbol by a copy of the symbol expression */
183 /* Check if the expression is const and get its value */
184 int IsConst = IsConstExpr (S->Expr, &Val);
187 /* Loop over all references */
188 for (I = 0; I < CollCount (&S->ExprRefs); ++I) {
190 /* Get the expression node */
191 ExprNode* E = CollAtUnchecked (&S->ExprRefs, I);
194 CHECK (E->Op == EXPR_SYMBOL && E->V.Sym == S);
196 /* We cannot touch the root node, since there are pointers to it.
197 * Replace it by a literal node.
199 E->Op = EXPR_LITERAL;
203 /* Remove all symbol references from the symbol */
204 CollDeleteAll (&S->ExprRefs);
209 void SymDef (SymEntry* S, ExprNode* Expr, unsigned char AddrSize, unsigned Flags)
210 /* Define a new symbol */
212 if (S->Flags & SF_IMPORT) {
213 /* Defined symbol is marked as imported external symbol */
214 Error ("Symbol `%s' is already an import", GetSymName (S));
217 if ((Flags & SF_VAR) != 0 && (S->Flags & (SF_EXPORT | SF_GLOBAL))) {
218 /* Variable symbols cannot be exports or globals */
219 Error ("Var symbol `%s' cannot be an export or global symbol", GetSymName (S));
222 if (S->Flags & SF_DEFINED) {
223 /* Multiple definition. In case of a variable, this is legal. */
224 if ((S->Flags & SF_VAR) == 0) {
225 Error ("Symbol `%s' is already defined", GetSymName (S));
226 S->Flags |= SF_MULTDEF;
229 /* Redefinition must also be a variable symbol */
230 if ((Flags & SF_VAR) == 0) {
231 Error ("Symbol `%s' is already different kind", GetSymName (S));
234 /* Delete the current symbol expression, since it will get
242 /* Map a default address size to a real value */
243 if (AddrSize == ADDR_SIZE_DEFAULT) {
244 /* ### Must go! Delay address size calculation until end of assembly! */
247 StudyExpr (Expr, &ED);
248 AddrSize = ED.AddrSize;
252 /* Set the symbol value */
255 /* In case of a variable symbol, walk over all expressions containing
256 * this symbol and replace the (sub-)expression by the literal value of
257 * the tree. Be sure to replace the expression node in place, since there
258 * may be pointers to it.
260 if (Flags & SF_VAR) {
261 SymReplaceExprRefs (S);
264 /* If the symbol is marked as global, export it. Address size is checked
267 if (S->Flags & SF_GLOBAL) {
268 S->Flags = (S->Flags & ~SF_GLOBAL) | SF_EXPORT;
271 /* Mark the symbol as defined and use the given address size */
272 S->Flags |= (SF_DEFINED | Flags);
273 S->AddrSize = AddrSize;
275 /* If the symbol is exported, check the address sizes */
276 if (S->Flags & SF_EXPORT) {
277 if (S->ExportSize == ADDR_SIZE_DEFAULT) {
278 /* Use the real size of the symbol */
279 S->ExportSize = S->AddrSize;
280 } else if (S->AddrSize > S->ExportSize) {
281 /* We're exporting a symbol smaller than it actually is */
282 PWarning (GetSymPos (S), 1, "Symbol `%s' is %s but exported %s",
283 GetSymName (S), AddrSizeToStr (S->AddrSize),
284 AddrSizeToStr (S->ExportSize));
288 /* If this is not a local symbol, remember it as the last global one */
289 if ((S->Flags & SF_LOCAL) == 0) {
296 void SymImport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
297 /* Mark the given symbol as an imported symbol */
299 if (S->Flags & SF_DEFINED) {
300 Error ("Symbol `%s' is already defined", GetSymName (S));
301 S->Flags |= SF_MULTDEF;
304 if (S->Flags & SF_EXPORT) {
305 /* The symbol is already marked as exported symbol */
306 Error ("Cannot import exported symbol `%s'", GetSymName (S));
310 /* If no address size is given, use the address size of the enclosing
313 if (AddrSize == ADDR_SIZE_DEFAULT) {
314 AddrSize = GetCurrentSegAddrSize ();
317 /* If the symbol is marked as import or global, check the address size,
318 * then do silently remove the global flag.
320 if (S->Flags & SF_IMPORT) {
321 if ((Flags & SF_FORCED) != (S->Flags & SF_FORCED)) {
322 Error ("Redeclaration mismatch for symbol `%s'", GetSymName (S));
324 if (AddrSize != S->AddrSize) {
325 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
328 if (S->Flags & SF_GLOBAL) {
329 S->Flags &= ~SF_GLOBAL;
330 if (AddrSize != S->AddrSize) {
331 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
335 /* Set the symbol data */
336 S->Flags |= (SF_IMPORT | Flags);
337 S->AddrSize = AddrSize;
342 void SymExport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
343 /* Mark the given symbol as an exported symbol */
345 /* Check if it's ok to export the symbol */
346 if (S->Flags & SF_IMPORT) {
347 /* The symbol is already marked as imported external symbol */
348 Error ("Symbol `%s' is already an import", GetSymName (S));
351 if (S->Flags & SF_VAR) {
352 /* Variable symbols cannot be exported */
353 Error ("Var symbol `%s' cannot be exported", GetSymName (S));
357 /* If the symbol was marked as global before, remove the global flag and
358 * proceed, but check the address size.
360 if (S->Flags & SF_GLOBAL) {
361 if (AddrSize != S->ExportSize) {
362 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
364 S->Flags &= ~SF_GLOBAL;
367 /* If the symbol was already marked as an export, but wasn't defined
368 * before, the address sizes in both definitions must match.
370 if ((S->Flags & (SF_EXPORT|SF_DEFINED)) == SF_EXPORT) {
371 if (S->ExportSize != AddrSize) {
372 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
375 S->ExportSize = AddrSize;
377 /* If the symbol is already defined, check symbol size against the
380 if (S->Flags & SF_DEFINED) {
381 if (S->ExportSize == ADDR_SIZE_DEFAULT) {
382 /* No export size given, use the real size of the symbol */
383 S->ExportSize = S->AddrSize;
384 } else if (S->AddrSize > S->ExportSize) {
385 /* We're exporting a symbol smaller than it actually is */
386 Warning (1, "Symbol `%s' is %s but exported %s",
387 GetSymName (S), AddrSizeToStr (S->AddrSize),
388 AddrSizeToStr (S->ExportSize));
392 /* Set the symbol data */
393 S->Flags |= (SF_EXPORT | SF_REFERENCED | Flags);
398 void SymGlobal (SymEntry* S, unsigned char AddrSize, unsigned Flags)
399 /* Mark the given symbol as a global symbol, that is, as a symbol that is
400 * either imported or exported.
403 if (S->Flags & SF_VAR) {
404 /* Variable symbols cannot be exported or imported */
405 Error ("Var symbol `%s' cannot be made global", GetSymName (S));
409 /* If the symbol is already marked as import, the address size must match.
410 * Apart from that, ignore the global declaration.
412 if (S->Flags & SF_IMPORT) {
413 if (AddrSize == ADDR_SIZE_DEFAULT) {
414 /* Use the size of the current segment */
415 AddrSize = GetCurrentSegAddrSize ();
417 if (AddrSize != S->AddrSize) {
418 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
423 /* If the symbol is already an export: If it is not defined, the address
426 if (S->Flags & SF_EXPORT) {
427 if ((S->Flags & SF_DEFINED) == 0) {
428 /* Symbol is undefined */
429 if (AddrSize != S->ExportSize) {
430 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
432 } else if (AddrSize != ADDR_SIZE_DEFAULT) {
433 /* Symbol is defined and address size given */
434 if (AddrSize != S->ExportSize) {
435 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
441 /* If the symbol is already marked as global, the address size must match.
442 * Use the ExportSize here, since it contains the actual address size
443 * passed to this function.
445 if (S->Flags & SF_GLOBAL) {
446 if (AddrSize != S->ExportSize) {
447 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
452 /* If we come here, the symbol was neither declared as export, import or
453 * global before. Check if it is already defined, in which case it will
454 * become an export. If it is not defined, mark it as global and remember
455 * the given address sizes.
457 if (S->Flags & SF_DEFINED) {
458 /* The symbol is defined, export it */
459 S->ExportSize = AddrSize;
460 if (S->ExportSize == ADDR_SIZE_DEFAULT) {
461 /* No export size given, use the real size of the symbol */
462 S->ExportSize = S->AddrSize;
463 } else if (S->AddrSize > S->ExportSize) {
464 /* We're exporting a symbol smaller than it actually is */
465 Warning (1, "Symbol `%s' is %s but exported %s",
466 GetSymName (S), AddrSizeToStr (S->AddrSize),
467 AddrSizeToStr (S->ExportSize));
469 S->Flags |= (SF_EXPORT | Flags);
471 /* Since we don't know if the symbol will get exported or imported,
472 * remember two different address sizes: One for an import in AddrSize,
473 * and the other one for an export in ExportSize.
475 S->AddrSize = AddrSize;
476 if (S->AddrSize == ADDR_SIZE_DEFAULT) {
477 /* Use the size of the current segment */
478 S->AddrSize = GetCurrentSegAddrSize ();
480 S->ExportSize = AddrSize;
481 S->Flags |= (SF_GLOBAL | Flags);
487 void SymConDes (SymEntry* S, unsigned char AddrSize, unsigned Type, unsigned Prio)
488 /* Mark the given symbol as a module constructor/destructor. This will also
489 * mark the symbol as an export. Initializers may never be zero page symbols.
492 /* Check the parameters */
493 #if (CD_TYPE_MIN != 0)
494 CHECK (Type >= CD_TYPE_MIN && Type <= CD_TYPE_MAX);
496 CHECK (Type <= CD_TYPE_MAX);
498 CHECK (Prio >= CD_PRIO_MIN && Prio <= CD_PRIO_MAX);
500 /* Check for errors */
501 if (S->Flags & SF_IMPORT) {
502 /* The symbol is already marked as imported external symbol */
503 Error ("Symbol `%s' is already an import", GetSymName (S));
506 if (S->Flags & SF_VAR) {
507 /* Variable symbols cannot be exported or imported */
508 Error ("Var symbol `%s' cannot be exported", GetSymName (S));
512 /* If the symbol was already marked as an export or global, check if
513 * this was done specifiying the same address size. In case of a global
514 * declaration, silently remove the global flag.
516 if (S->Flags & (SF_EXPORT | SF_GLOBAL)) {
517 if (S->ExportSize != AddrSize) {
518 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
520 S->Flags &= ~SF_GLOBAL;
522 S->ExportSize = AddrSize;
524 /* If the symbol is already defined, check symbol size against the
527 if (S->Flags & SF_DEFINED) {
528 if (S->ExportSize == ADDR_SIZE_DEFAULT) {
529 /* Use the real size of the symbol */
530 S->ExportSize = S->AddrSize;
531 } else if (S->AddrSize != S->ExportSize) {
532 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
536 /* If the symbol was already declared as a condes, check if the new
537 * priority value is the same as the old one.
539 if (S->ConDesPrio[Type] != CD_PRIO_NONE) {
540 if (S->ConDesPrio[Type] != Prio) {
541 Error ("Redeclaration mismatch for symbol `%s'", GetSymName (S));
544 S->ConDesPrio[Type] = Prio;
546 /* Set the symbol data */
547 S->Flags |= (SF_EXPORT | SF_REFERENCED);
552 void SymExportFromGlobal (SymEntry* S)
553 /* Called at the end of assembly. Converts a global symbol that is defined
557 /* Remove the global flag and make the symbol an export */
558 S->Flags &= ~SF_GLOBAL;
559 S->Flags |= SF_EXPORT;
564 void SymImportFromGlobal (SymEntry* S)
565 /* Called at the end of assembly. Converts a global symbol that is undefined
569 /* Remove the global flag and make it an import */
570 S->Flags &= ~SF_GLOBAL;
571 S->Flags |= SF_IMPORT;
576 int SymIsConst (SymEntry* S, long* Val)
577 /* Return true if the given symbol has a constant value. If Val is not NULL
578 * and the symbol has a constant value, store it's value there.
581 /* Check for constness */
582 return (SymHasExpr (S) && IsConstExpr (S->Expr, Val));
587 SymTable* GetSymParentScope (SymEntry* S)
588 /* Get the parent scope of the symbol (not the one it is defined in). Return
589 * NULL if the symbol is a cheap local, or defined on global level.
592 return (S->SymTab && S->SymTab->Parent)? S->SymTab->Parent : 0;
597 struct ExprNode* GetSymExpr (SymEntry* S)
598 /* Get the expression for a non-const symbol */
600 PRECONDITION (S != 0 && SymHasExpr (S));
606 const struct ExprNode* SymResolve (const SymEntry* S)
607 /* Helper function for DumpExpr. Resolves a symbol into an expression or return
608 * NULL. Do not call in other contexts!
611 return SymHasExpr (S)? S->Expr : 0;
616 long GetSymVal (SymEntry* S)
617 /* Return the value of a symbol assuming it's constant. FAIL will be called
618 * in case the symbol is undefined or not constant.
622 CHECK (S != 0 && SymHasExpr (S) && IsConstExpr (GetSymExpr (S), &Val));
628 unsigned GetSymIndex (const SymEntry* S)
629 /* Return the symbol index for the given symbol */
631 PRECONDITION (S != 0 && (S->Flags & SF_INDEXED) != 0);