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 */
217 if (S->Flags & SF_GLOBAL) {
218 S->ExportSize = S->AddrSize;
219 S->Flags = (S->Flags & ~SF_GLOBAL) | SF_EXPORT;
222 /* Mark the symbol as defined and use the given address size */
223 S->Flags |= (SF_DEFINED | Flags);
224 S->AddrSize = AddrSize;
226 /* If the symbol is exported, check the address sizes */
227 if (S->Flags & SF_EXPORT) {
228 if (S->ExportSize == ADDR_SIZE_DEFAULT) {
229 /* Use the real size of the symbol */
230 S->ExportSize = S->AddrSize;
231 } else if (S->AddrSize > S->ExportSize) {
232 PWarning (GetSymPos (S), 1, "Symbol `%s' is %s but exported as %s",
233 GetSymName (S), AddrSizeToStr (S->AddrSize),
234 AddrSizeToStr (S->ExportSize));
238 /* If the symbol is a ZP symbol, check if the value is in correct range */
239 if (S->AddrSize == ADDR_SIZE_ZP) {
240 /* Already marked as ZP symbol by some means */
241 if (!IsByteExpr (Expr)) {
242 Error ("Range error");
246 /* If this is not a local symbol, remember it as the last global one */
247 if (!IsLocalNameId (S->Name)) {
254 void SymImport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
255 /* Mark the given symbol as an imported symbol */
257 /* Don't accept local symbols */
258 if (IsLocalNameId (S->Name)) {
259 Error ("Illegal use of a local symbol");
263 if (S->Flags & SF_DEFINED) {
264 Error ("Symbol `%s' is already defined", GetSymName (S));
265 S->Flags |= SF_MULTDEF;
268 if (S->Flags & SF_EXPORT) {
269 /* The symbol is already marked as exported symbol */
270 Error ("Cannot import exported symbol `%s'", GetSymName (S));
274 /* If no address size is given, use the default address size */
275 if (AddrSize == ADDR_SIZE_DEFAULT) {
276 AddrSize = DefAddrSize;
279 /* If the symbol is marked as import or global, check the symbol flags,
280 * then do silently remove the global flag
282 if (S->Flags & SF_IMPORT) {
283 if ((Flags & SF_FORCED) != (S->Flags & SF_FORCED)) {
284 Error ("Redeclaration mismatch for symbol `%s'", GetSymName (S));
286 if (AddrSize != S->AddrSize) {
287 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
290 if (S->Flags & SF_GLOBAL) {
291 if (S->AddrSize != ADDR_SIZE_DEFAULT && S->AddrSize != AddrSize) {
292 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
294 S->Flags &= ~SF_GLOBAL;
297 /* Set the symbol data */
298 S->Flags |= (SF_IMPORT | Flags);
299 S->AddrSize = AddrSize;
304 void SymExport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
305 /* Mark the given symbol as an exported symbol */
307 /* Don't accept local symbols */
308 if (IsLocalNameId (S->Name)) {
309 Error ("Illegal use of a local symbol");
313 /* Check if it's ok to export the symbol */
314 if (S->Flags & SF_IMPORT) {
315 /* The symbol is already marked as imported external symbol */
316 Error ("Symbol `%s' is already an import", GetSymName (S));
320 /* If the symbol was marked as global before, make it an export */
321 if (S->Flags & SF_GLOBAL) {
322 S->ExportSize = S->AddrSize;
323 S->Flags &= ~SF_GLOBAL;
326 /* If the symbol was already marked as an export, check if this was done
327 * specifiying the same address size. If the old spec had no explicit
328 * address size, use the new one.
330 if (S->Flags & SF_EXPORT) {
331 if (S->ExportSize == ADDR_SIZE_DEFAULT) {
332 S->ExportSize = AddrSize;
333 } else if (AddrSize == ADDR_SIZE_DEFAULT) {
334 AddrSize = S->ExportSize;
336 if (S->ExportSize != ADDR_SIZE_DEFAULT && S->ExportSize != AddrSize) {
337 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
340 S->ExportSize = AddrSize;
342 /* If the symbol is already defined, check symbol size against the
345 if (S->Flags & SF_DEFINED) {
346 if (S->ExportSize == ADDR_SIZE_DEFAULT) {
347 /* No export size given, use the real size of the symbol */
348 S->ExportSize = S->AddrSize;
349 } else if (S->AddrSize > S->ExportSize) {
350 Warning (1, "Symbol `%s' is %s but exported as %s",
351 GetSymName (S), AddrSizeToStr (S->AddrSize),
352 AddrSizeToStr (S->ExportSize));
356 /* Set the symbol data */
357 S->Flags |= (SF_EXPORT | SF_REFERENCED | Flags);
362 void SymGlobal (SymEntry* S, unsigned char AddrSize, unsigned Flags)
363 /* Mark the given symbol as a global symbol, that is, as a symbol that is
364 * either imported or exported.
367 /* Don't accept local symbols */
368 if (IsLocalNameId (S->Name)) {
369 Error ("Illegal use of a local symbol");
373 /* If the symbol is already marked as import or export, check the
374 * size of the definition, then bail out.
376 if (S->Flags & SF_IMPORT) {
377 if (AddrSize != ADDR_SIZE_DEFAULT && AddrSize != S->AddrSize) {
378 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
382 if (S->Flags & SF_EXPORT) {
383 /* If the old symbol had no explicit address size spec, use the
386 if (S->ExportSize == ADDR_SIZE_DEFAULT) {
387 S->ExportSize = AddrSize;
389 if (AddrSize != S->ExportSize) {
390 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
395 /* If the symbol is already defined, export it. Otherwise mark it as
398 if (S->Flags & SF_DEFINED) {
399 /* The symbol is defined, export it */
400 S->ExportSize = AddrSize;
401 if (S->ExportSize == ADDR_SIZE_DEFAULT) {
402 /* No export size given, use the real size of the symbol */
403 S->ExportSize = S->AddrSize;
404 } else if (S->AddrSize > S->ExportSize) {
405 Warning (1, "Symbol `%s' is %s but exported as %s",
406 GetSymName (S), AddrSizeToStr (S->AddrSize),
407 AddrSizeToStr (S->ExportSize));
409 S->Flags |= (SF_EXPORT | Flags);
410 S->ExportSize = AddrSize;
412 S->Flags |= (SF_GLOBAL | Flags);
413 S->AddrSize = AddrSize;
419 void SymConDes (SymEntry* S, unsigned char AddrSize, unsigned Type, unsigned Prio)
420 /* Mark the given symbol as a module constructor/destructor. This will also
421 * mark the symbol as an export. Initializers may never be zero page symbols.
424 /* Check the parameters */
425 #if (CD_TYPE_MIN != 0)
426 CHECK (Type >= CD_TYPE_MIN && Type <= CD_TYPE_MAX);
428 CHECK (Type <= CD_TYPE_MAX);
430 CHECK (Prio >= CD_PRIO_MIN && Prio <= CD_PRIO_MAX);
432 /* Don't accept local symbols */
433 if (IsLocalNameId (S->Name)) {
434 Error ("Illegal use of a local symbol");
438 /* Check for errors */
439 if (S->Flags & SF_IMPORT) {
440 /* The symbol is already marked as imported external symbol */
441 Error ("Symbol `%s' is already an import", GetSymName (S));
445 /* If the symbol was already marked as an export or global, check if
446 * this was done specifiying the same address size. In case of a global
447 * declaration, silently remove the global flag.
449 if (S->Flags & (SF_EXPORT | SF_GLOBAL)) {
450 if (S->ExportSize != AddrSize) {
451 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
453 S->Flags &= ~SF_GLOBAL;
455 S->ExportSize = AddrSize;
457 /* If the symbol is already defined, check symbol size against the
460 if (S->Flags & SF_DEFINED) {
461 if (S->ExportSize == ADDR_SIZE_DEFAULT) {
462 /* Use the real size of the symbol */
463 S->ExportSize = S->AddrSize;
464 } else if (S->AddrSize != S->ExportSize) {
465 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
469 /* If the symbol was already declared as a condes, check if the new
470 * priority value is the same as the old one.
472 if (S->ConDesPrio[Type] != CD_PRIO_NONE) {
473 if (S->ConDesPrio[Type] != Prio) {
474 Error ("Redeclaration mismatch for symbol `%s'", GetSymName (S));
477 S->ConDesPrio[Type] = Prio;
479 /* Set the symbol data */
480 S->Flags |= (SF_EXPORT | SF_REFERENCED);
485 int SymIsDef (const SymEntry* S)
486 /* Return true if the given symbol is already defined */
488 return (S->Flags & SF_DEFINED) != 0;
493 int SymIsRef (const SymEntry* S)
494 /* Return true if the given symbol has been referenced */
496 return (S->Flags & SF_REFERENCED) != 0;
501 int SymIsImport (const SymEntry* S)
502 /* Return true if the given symbol is marked as import */
504 /* Resolve trampoline entries */
505 if (S->Flags & SF_TRAMPOLINE) {
509 /* Check the import flag */
510 return (S->Flags & SF_IMPORT) != 0;
515 int SymIsConst (SymEntry* S, long* Val)
516 /* Return true if the given symbol has a constant value. If Val is not NULL
517 * and the symbol has a constant value, store it's value there.
520 /* Resolve trampoline entries */
521 if (S->Flags & SF_TRAMPOLINE) {
525 /* Check for constness */
526 return (SymHasExpr (S) && IsConstExpr (S->V.Expr, Val));
531 int SymHasExpr (const SymEntry* S)
532 /* Return true if the given symbol has an associated expression */
534 /* Resolve trampoline entries */
535 if (S->Flags & SF_TRAMPOLINE) {
539 /* Check the expression */
540 return ((S->Flags & (SF_DEFINED|SF_IMPORT)) == SF_DEFINED);
545 void SymMarkUser (SymEntry* S)
546 /* Set a user mark on the specified symbol */
548 /* Resolve trampoline entries */
549 if (S->Flags & SF_TRAMPOLINE) {
559 void SymUnmarkUser (SymEntry* S)
560 /* Remove a user mark from the specified symbol */
562 /* Resolve trampoline entries */
563 if (S->Flags & SF_TRAMPOLINE) {
568 S->Flags &= ~SF_USER;
573 int SymHasUserMark (SymEntry* S)
574 /* Return the state of the user mark for the specified symbol */
576 /* Resolve trampoline entries */
577 if (S->Flags & SF_TRAMPOLINE) {
582 return (S->Flags & SF_USER) != 0;
587 struct ExprNode* GetSymExpr (SymEntry* S)
588 /* Get the expression for a non-const symbol */
590 /* Resolve trampoline entries */
591 if (S->Flags & SF_TRAMPOLINE) {
595 PRECONDITION (S != 0 && SymHasExpr (S));
601 const struct ExprNode* SymResolve (const SymEntry* S)
602 /* Helper function for DumpExpr. Resolves a symbol into an expression or return
603 * NULL. Do not call in other contexts!
606 /* Resolve trampoline entries */
607 if (S->Flags & SF_TRAMPOLINE) {
611 return SymHasExpr (S)? S->V.Expr : 0;
616 const char* GetSymName (const SymEntry* S)
617 /* Return the name of the symbol */
619 /* Resolve trampoline entries */
620 if (S->Flags & SF_TRAMPOLINE) {
623 return GetString (S->Name);
628 unsigned char GetSymAddrSize (const SymEntry* S)
629 /* Return the address size of the symbol. Beware: This function will just
630 * return the AddrSize member, it will not look at the expression!
633 if (S->Flags & SF_TRAMPOLINE) {
641 long GetSymVal (SymEntry* S)
642 /* Return the value of a symbol assuming it's constant. FAIL will be called
643 * in case the symbol is undefined or not constant.
647 CHECK (S != 0 && SymHasExpr (S) && IsConstExpr (GetSymExpr (S), &Val));
653 unsigned GetSymIndex (const SymEntry* S)
654 /* Return the symbol index for the given symbol */
656 /* Resolve trampoline entries */
657 if (S->Flags & SF_TRAMPOLINE) {
660 PRECONDITION (S != 0 && (S->Flags & SF_INDEXED) != 0);
666 const FilePos* GetSymPos (const SymEntry* S)
667 /* Return the position of first occurence in the source for the given symbol */
669 /* Resolve trampoline entries */
670 if (S->Flags & SF_TRAMPOLINE) {
673 PRECONDITION (S != 0);