1 /*****************************************************************************/
5 /* Symbol table entry forward for the ca65 macroassembler */
9 /* (C) 1998-2003 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 /*****************************************************************************/
54 /*****************************************************************************/
56 /*****************************************************************************/
60 /* List of all symbol table entries */
61 SymEntry* SymList = 0;
63 /* Pointer to last defined symbol */
64 SymEntry* SymLast = 0;
68 /*****************************************************************************/
70 /*****************************************************************************/
74 int IsLocalName (const char* Name)
75 /* Return true if Name is the name of a local symbol */
77 return (*Name == LocalStart);
82 int IsLocalNameId (unsigned Name)
83 /* Return true if Name is the name of a local symbol */
85 return (*GetString (Name) == LocalStart);
90 static unsigned SymAddrSize (const SymEntry* S)
91 /* Get the default address size for a symbol. */
93 /* Local symbols are always near (is this ok?) */
94 if (IsLocalNameId (S->Name)) {
98 /* Return the address size of the segment */
99 return GetCurrentSegAddrSize ();
104 SymEntry* NewSymEntry (const char* Name)
105 /* Allocate a symbol table entry, initialize and return it */
107 /* Allocate memory */
108 SymEntry* S = xmalloc (sizeof (SymEntry));
110 /* Initialize the entry */
118 S->ExprRefs = AUTO_COLLECTION_INITIALIZER;
119 S->ExportSize = ADDR_SIZE_DEFAULT;
120 S->AddrSize = ADDR_SIZE_DEFAULT;
121 memset (S->ConDesPrio, 0, sizeof (S->ConDesPrio));
122 S->Name = GetStringId (Name);
124 /* Insert it into the list of all entries */
128 /* Return the initialized entry */
134 int SymSearchTree (SymEntry* T, const char* Name, SymEntry** E)
135 /* Search in the given tree for a name. If we find the symbol, the function
136 * will return 0 and put the entry pointer into E. If we did not find the
137 * symbol, and the tree is empty, E is set to NULL. If the tree is not empty,
138 * E will be set to the last entry, and the result of the function is <0 if
139 * the entry should be inserted on the left side, and >0 if it should get
140 * inserted on the right side.
143 /* Is there a tree? */
149 /* We have a table, search it */
152 /* Get the symbol name */
153 const char* SymName = GetString (T->Name);
155 /* Choose next entry */
156 int Cmp = strcmp (Name, SymName);
157 if (Cmp < 0 && T->Left) {
159 } else if (Cmp > 0&& T->Right) {
162 /* Found or end of search, return the result */
171 void SymRef (SymEntry* S)
172 /* Mark the given symbol as referenced */
174 /* Mark the symbol as referenced */
175 S->Flags |= SF_REFERENCED;
180 void SymDef (SymEntry* S, ExprNode* Expr, unsigned char AddrSize, unsigned Flags)
181 /* Define a new symbol */
183 if (S->Flags & SF_IMPORT) {
184 /* Defined symbol is marked as imported external symbol */
185 Error ("Symbol `%s' is already an import", GetSymName (S));
188 if (S->Flags & SF_DEFINED) {
189 /* Multiple definition */
190 Error ("Symbol `%s' is already defined", GetSymName (S));
191 S->Flags |= SF_MULTDEF;
195 /* Map a default address size to a real value */
196 if (AddrSize == ADDR_SIZE_DEFAULT) {
198 if (IsConstExpr (Expr, &Val)) {
199 if (IsByteRange (Val)) {
200 AddrSize = ADDR_SIZE_ZP;
201 } else if (IsWordRange (Val)) {
202 AddrSize = ADDR_SIZE_ABS;
203 } else if (IsFarRange (Val)) {
204 AddrSize = ADDR_SIZE_FAR;
206 AddrSize = ADDR_SIZE_LONG;
209 AddrSize = SymAddrSize (S);
213 /* Set the symbol value */
216 /* If the symbol is marked as global, export it. Address size is checked
219 if (S->Flags & SF_GLOBAL) {
220 S->Flags = (S->Flags & ~SF_GLOBAL) | SF_EXPORT;
223 /* Mark the symbol as defined and use the given address size */
224 S->Flags |= (SF_DEFINED | Flags);
225 S->AddrSize = AddrSize;
227 /* If the symbol is exported, check the address sizes */
228 if (S->Flags & SF_EXPORT) {
229 if (S->ExportSize == ADDR_SIZE_DEFAULT) {
230 /* Use the real size of the symbol */
231 S->ExportSize = S->AddrSize;
232 } else if (S->AddrSize > S->ExportSize) {
233 /* We're exporting a symbol smaller than it actually is */
234 PWarning (GetSymPos (S), 1, "Symbol `%s' is %s but exported %s",
235 GetSymName (S), AddrSizeToStr (S->AddrSize),
236 AddrSizeToStr (S->ExportSize));
240 /* If this is not a local symbol, remember it as the last global one */
241 if (!IsLocalNameId (S->Name)) {
248 void SymImport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
249 /* Mark the given symbol as an imported symbol */
251 /* Don't accept local symbols */
252 if (IsLocalNameId (S->Name)) {
253 Error ("Illegal use of a local symbol");
257 if (S->Flags & SF_DEFINED) {
258 Error ("Symbol `%s' is already defined", GetSymName (S));
259 S->Flags |= SF_MULTDEF;
262 if (S->Flags & SF_EXPORT) {
263 /* The symbol is already marked as exported symbol */
264 Error ("Cannot import exported symbol `%s'", GetSymName (S));
268 /* If no address size is given, use the address size of the enclosing
271 if (AddrSize == ADDR_SIZE_DEFAULT) {
272 AddrSize = GetCurrentSegAddrSize ();
275 /* If the symbol is marked as import or global, check the address size,
276 * then do silently remove the global flag.
278 if (S->Flags & SF_IMPORT) {
279 if ((Flags & SF_FORCED) != (S->Flags & SF_FORCED)) {
280 Error ("Redeclaration mismatch for symbol `%s'", GetSymName (S));
282 if (AddrSize != S->AddrSize) {
283 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
286 if (S->Flags & SF_GLOBAL) {
287 S->Flags &= ~SF_GLOBAL;
288 if (AddrSize != S->AddrSize) {
289 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
293 /* Set the symbol data */
294 S->Flags |= (SF_IMPORT | Flags);
295 S->AddrSize = AddrSize;
300 void SymExport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
301 /* Mark the given symbol as an exported symbol */
303 /* Don't accept local symbols */
304 if (IsLocalNameId (S->Name)) {
305 Error ("Illegal use of a local symbol");
309 /* Check if it's ok to export the symbol */
310 if (S->Flags & SF_IMPORT) {
311 /* The symbol is already marked as imported external symbol */
312 Error ("Symbol `%s' is already an import", GetSymName (S));
316 /* If the symbol was marked as global before, remove the global flag and
317 * proceed, but check the address size.
319 if (S->Flags & SF_GLOBAL) {
320 if (AddrSize != S->ExportSize) {
321 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
323 S->Flags &= ~SF_GLOBAL;
326 /* If the symbol was already marked as an export, but wasn't defined
327 * before, the address sizes in both definitions must match.
329 if ((S->Flags & (SF_EXPORT|SF_DEFINED)) == SF_EXPORT) {
330 if (S->ExportSize != AddrSize) {
331 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
334 S->ExportSize = AddrSize;
336 /* If the symbol is already defined, check symbol size against the
339 if (S->Flags & SF_DEFINED) {
340 if (S->ExportSize == ADDR_SIZE_DEFAULT) {
341 /* No export size given, use the real size of the symbol */
342 S->ExportSize = S->AddrSize;
343 } else if (S->AddrSize > S->ExportSize) {
344 /* We're exporting a symbol smaller than it actually is */
345 Warning (1, "Symbol `%s' is %s but exported %s",
346 GetSymName (S), AddrSizeToStr (S->AddrSize),
347 AddrSizeToStr (S->ExportSize));
351 /* Set the symbol data */
352 S->Flags |= (SF_EXPORT | SF_REFERENCED | Flags);
357 void SymGlobal (SymEntry* S, unsigned char AddrSize, unsigned Flags)
358 /* Mark the given symbol as a global symbol, that is, as a symbol that is
359 * either imported or exported.
362 /* Don't accept local symbols */
363 if (IsLocalNameId (S->Name)) {
364 Error ("Illegal use of a local symbol");
368 /* If the symbol is already marked as import, the address size must match.
369 * Apart from that, ignore the global declaration.
371 if (S->Flags & SF_IMPORT) {
372 if (AddrSize == ADDR_SIZE_DEFAULT) {
373 /* Use the size of the current segment */
374 AddrSize = GetCurrentSegAddrSize ();
376 if (AddrSize != S->AddrSize) {
377 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
382 /* If the symbol is already an export: If it is not defined, the address
385 if (S->Flags & SF_EXPORT) {
386 if ((S->Flags & SF_DEFINED) == 0) {
387 /* Symbol is undefined */
388 if (AddrSize != S->ExportSize) {
389 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
391 } else if (AddrSize != ADDR_SIZE_DEFAULT) {
392 /* Symbol is defined and address size given */
393 if (AddrSize != S->ExportSize) {
394 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
400 /* If the symbol is already marked as global, the address size must match.
401 * Use the ExportSize here, since it contains the actual address size
402 * passed to this function.
404 if (S->Flags & SF_GLOBAL) {
405 if (AddrSize != S->ExportSize) {
406 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
411 /* If we come here, the symbol was neither declared as export, import or
412 * global before. Check if it is already defined, in which case it will
413 * become an export. If it is not defined, mark it as global and remember
414 * the given address sizes.
416 if (S->Flags & SF_DEFINED) {
417 /* The symbol is defined, export it */
418 S->ExportSize = AddrSize;
419 if (S->ExportSize == ADDR_SIZE_DEFAULT) {
420 /* No export size given, use the real size of the symbol */
421 S->ExportSize = S->AddrSize;
422 } else if (S->AddrSize > S->ExportSize) {
423 /* We're exporting a symbol smaller than it actually is */
424 Warning (1, "Symbol `%s' is %s but exported %s",
425 GetSymName (S), AddrSizeToStr (S->AddrSize),
426 AddrSizeToStr (S->ExportSize));
428 S->Flags |= (SF_EXPORT | Flags);
430 /* Since we don't know if the symbol will get exported or imported,
431 * remember two different address sizes: One for an import in AddrSize,
432 * and the other one for an export in ExportSize.
434 S->AddrSize = AddrSize;
435 if (S->AddrSize == ADDR_SIZE_DEFAULT) {
436 /* Use the size of the current segment */
437 S->AddrSize = GetCurrentSegAddrSize ();
439 S->ExportSize = AddrSize;
440 S->Flags |= (SF_GLOBAL | Flags);
446 void SymConDes (SymEntry* S, unsigned char AddrSize, unsigned Type, unsigned Prio)
447 /* Mark the given symbol as a module constructor/destructor. This will also
448 * mark the symbol as an export. Initializers may never be zero page symbols.
451 /* Check the parameters */
452 #if (CD_TYPE_MIN != 0)
453 CHECK (Type >= CD_TYPE_MIN && Type <= CD_TYPE_MAX);
455 CHECK (Type <= CD_TYPE_MAX);
457 CHECK (Prio >= CD_PRIO_MIN && Prio <= CD_PRIO_MAX);
459 /* Don't accept local symbols */
460 if (IsLocalNameId (S->Name)) {
461 Error ("Illegal use of a local symbol");
465 /* Check for errors */
466 if (S->Flags & SF_IMPORT) {
467 /* The symbol is already marked as imported external symbol */
468 Error ("Symbol `%s' is already an import", GetSymName (S));
472 /* If the symbol was already marked as an export or global, check if
473 * this was done specifiying the same address size. In case of a global
474 * declaration, silently remove the global flag.
476 if (S->Flags & (SF_EXPORT | SF_GLOBAL)) {
477 if (S->ExportSize != AddrSize) {
478 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
480 S->Flags &= ~SF_GLOBAL;
482 S->ExportSize = AddrSize;
484 /* If the symbol is already defined, check symbol size against the
487 if (S->Flags & SF_DEFINED) {
488 if (S->ExportSize == ADDR_SIZE_DEFAULT) {
489 /* Use the real size of the symbol */
490 S->ExportSize = S->AddrSize;
491 } else if (S->AddrSize != S->ExportSize) {
492 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
496 /* If the symbol was already declared as a condes, check if the new
497 * priority value is the same as the old one.
499 if (S->ConDesPrio[Type] != CD_PRIO_NONE) {
500 if (S->ConDesPrio[Type] != Prio) {
501 Error ("Redeclaration mismatch for symbol `%s'", GetSymName (S));
504 S->ConDesPrio[Type] = Prio;
506 /* Set the symbol data */
507 S->Flags |= (SF_EXPORT | SF_REFERENCED);
512 int SymIsDef (const SymEntry* S)
513 /* Return true if the given symbol is already defined */
515 return (S->Flags & SF_DEFINED) != 0;
520 int SymIsRef (const SymEntry* S)
521 /* Return true if the given symbol has been referenced */
523 return (S->Flags & SF_REFERENCED) != 0;
528 int SymIsImport (const SymEntry* S)
529 /* Return true if the given symbol is marked as import */
531 /* Resolve trampoline entries */
532 if (S->Flags & SF_TRAMPOLINE) {
536 /* Check the import flag */
537 return (S->Flags & SF_IMPORT) != 0;
542 int SymIsConst (SymEntry* S, long* Val)
543 /* Return true if the given symbol has a constant value. If Val is not NULL
544 * and the symbol has a constant value, store it's value there.
547 /* Resolve trampoline entries */
548 if (S->Flags & SF_TRAMPOLINE) {
552 /* Check for constness */
553 return (SymHasExpr (S) && IsConstExpr (S->V.Expr, Val));
558 int SymHasExpr (const SymEntry* S)
559 /* Return true if the given symbol has an associated expression */
561 /* Resolve trampoline entries */
562 if (S->Flags & SF_TRAMPOLINE) {
566 /* Check the expression */
567 return ((S->Flags & (SF_DEFINED|SF_IMPORT)) == SF_DEFINED);
572 void SymMarkUser (SymEntry* S)
573 /* Set a user mark on the specified symbol */
575 /* Resolve trampoline entries */
576 if (S->Flags & SF_TRAMPOLINE) {
586 void SymUnmarkUser (SymEntry* S)
587 /* Remove a user mark from the specified symbol */
589 /* Resolve trampoline entries */
590 if (S->Flags & SF_TRAMPOLINE) {
595 S->Flags &= ~SF_USER;
600 int SymHasUserMark (SymEntry* S)
601 /* Return the state of the user mark for the specified symbol */
603 /* Resolve trampoline entries */
604 if (S->Flags & SF_TRAMPOLINE) {
609 return (S->Flags & SF_USER) != 0;
614 struct ExprNode* GetSymExpr (SymEntry* S)
615 /* Get the expression for a non-const symbol */
617 /* Resolve trampoline entries */
618 if (S->Flags & SF_TRAMPOLINE) {
622 PRECONDITION (S != 0 && SymHasExpr (S));
628 const struct ExprNode* SymResolve (const SymEntry* S)
629 /* Helper function for DumpExpr. Resolves a symbol into an expression or return
630 * NULL. Do not call in other contexts!
633 /* Resolve trampoline entries */
634 if (S->Flags & SF_TRAMPOLINE) {
638 return SymHasExpr (S)? S->V.Expr : 0;
643 const char* GetSymName (const SymEntry* S)
644 /* Return the name of the symbol */
646 /* Resolve trampoline entries */
647 if (S->Flags & SF_TRAMPOLINE) {
650 return GetString (S->Name);
655 unsigned char GetSymAddrSize (const SymEntry* S)
656 /* Return the address size of the symbol. Beware: This function will just
657 * return the AddrSize member, it will not look at the expression!
660 if (S->Flags & SF_TRAMPOLINE) {
668 long GetSymVal (SymEntry* S)
669 /* Return the value of a symbol assuming it's constant. FAIL will be called
670 * in case the symbol is undefined or not constant.
674 CHECK (S != 0 && SymHasExpr (S) && IsConstExpr (GetSymExpr (S), &Val));
680 unsigned GetSymIndex (const SymEntry* S)
681 /* Return the symbol index for the given symbol */
683 /* Resolve trampoline entries */
684 if (S->Flags & SF_TRAMPOLINE) {
687 PRECONDITION (S != 0 && (S->Flags & SF_INDEXED) != 0);
693 const FilePos* GetSymPos (const SymEntry* S)
694 /* Return the position of first occurence in the source for the given symbol */
696 /* Resolve trampoline entries */
697 if (S->Flags & SF_TRAMPOLINE) {
700 PRECONDITION (S != 0);