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) && IsByteRange (Val)) {
199 AddrSize = ADDR_SIZE_ZP;
201 AddrSize = SymAddrSize (S);
205 /* Set the symbol value */
208 /* If the symbol is marked as global, export it */
209 if (S->Flags & SF_GLOBAL) {
210 S->ExportSize = S->AddrSize;
211 S->Flags = (S->Flags & ~SF_GLOBAL) | SF_EXPORT;
214 /* Mark the symbol as defined and use the given address size */
215 S->Flags |= (SF_DEFINED | Flags);
216 S->AddrSize = AddrSize;
218 /* If the symbol is exported, check the address sizes */
219 if (S->Flags & SF_EXPORT) {
220 if (S->ExportSize == ADDR_SIZE_DEFAULT) {
221 /* Use the real size of the symbol */
222 S->ExportSize = S->AddrSize;
223 } else if (S->AddrSize > S->ExportSize) {
224 PWarning (GetSymPos (S), 1, "Symbol `%s' is %s but exported as %s",
225 GetSymName (S), AddrSizeToStr (S->AddrSize),
226 AddrSizeToStr (S->ExportSize));
230 /* If the symbol is a ZP symbol, check if the value is in correct range */
231 if (S->AddrSize == ADDR_SIZE_ZP) {
232 /* Already marked as ZP symbol by some means */
233 if (!IsByteExpr (Expr)) {
234 Error ("Range error");
238 /* If this is not a local symbol, remember it as the last global one */
239 if (!IsLocalNameId (S->Name)) {
246 void SymImport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
247 /* Mark the given symbol as an imported symbol */
249 /* Don't accept local symbols */
250 if (IsLocalNameId (S->Name)) {
251 Error ("Illegal use of a local symbol");
255 if (S->Flags & SF_DEFINED) {
256 Error ("Symbol `%s' is already defined", GetSymName (S));
257 S->Flags |= SF_MULTDEF;
260 if (S->Flags & SF_EXPORT) {
261 /* The symbol is already marked as exported symbol */
262 Error ("Cannot import exported symbol `%s'", GetSymName (S));
266 /* Map a default address size to a real value */
267 if (AddrSize == ADDR_SIZE_DEFAULT) {
268 AddrSize = SymAddrSize (S);
271 /* If the symbol is marked as import or global, check the symbol flags,
272 * then do silently remove the global flag
274 if (S->Flags & SF_IMPORT) {
275 if ((Flags & SF_FORCED) != (S->Flags & SF_FORCED)) {
276 Error ("Redeclaration mismatch for symbol `%s'", GetSymName (S));
278 if (AddrSize != S->AddrSize) {
279 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
282 if (S->Flags & SF_GLOBAL) {
283 if (S->AddrSize != ADDR_SIZE_DEFAULT && S->AddrSize != AddrSize) {
284 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
286 S->Flags &= ~SF_GLOBAL;
289 /* Set the symbol data */
290 S->Flags |= (SF_IMPORT | Flags);
291 S->AddrSize = AddrSize;
296 void SymExport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
297 /* Mark the given symbol as an exported symbol */
299 /* Don't accept local symbols */
300 if (IsLocalNameId (S->Name)) {
301 Error ("Illegal use of a local symbol");
305 /* Check if it's ok to export the symbol */
306 if (S->Flags & SF_IMPORT) {
307 /* The symbol is already marked as imported external symbol */
308 Error ("Symbol `%s' is already an import", GetSymName (S));
312 /* If the symbol was marked as global before, make it an export */
313 if (S->Flags & SF_GLOBAL) {
314 S->ExportSize = S->AddrSize;
315 S->Flags &= ~SF_GLOBAL;
318 /* If the symbol was already marked as an export, check if this was done
319 * specifiying the same address size. If the old spec had no explicit
320 * address size, use the new one.
322 if (S->Flags & SF_EXPORT) {
323 if (S->ExportSize == ADDR_SIZE_DEFAULT) {
324 S->ExportSize = AddrSize;
325 } else if (AddrSize == ADDR_SIZE_DEFAULT) {
326 AddrSize = S->ExportSize;
328 if (S->ExportSize != ADDR_SIZE_DEFAULT && S->ExportSize != AddrSize) {
329 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
332 S->ExportSize = AddrSize;
334 /* If the symbol is already defined, check symbol size against the
337 if (S->Flags & SF_DEFINED) {
338 if (S->ExportSize == ADDR_SIZE_DEFAULT) {
339 /* No export size given, use the real size of the symbol */
340 S->ExportSize = S->AddrSize;
341 } else if (S->AddrSize > S->ExportSize) {
342 Warning (1, "Symbol `%s' is %s but exported as %s",
343 GetSymName (S), AddrSizeToStr (S->AddrSize),
344 AddrSizeToStr (S->ExportSize));
348 /* Set the symbol data */
349 S->Flags |= (SF_EXPORT | SF_REFERENCED | Flags);
354 void SymGlobal (SymEntry* S, unsigned char AddrSize, unsigned Flags)
355 /* Mark the given symbol as a global symbol, that is, as a symbol that is
356 * either imported or exported.
359 /* Don't accept local symbols */
360 if (IsLocalNameId (S->Name)) {
361 Error ("Illegal use of a local symbol");
365 /* If the symbol is already marked as import or export, check the
366 * size of the definition, then bail out.
368 if (S->Flags & SF_IMPORT) {
369 if (AddrSize != ADDR_SIZE_DEFAULT && AddrSize != S->AddrSize) {
370 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
374 if (S->Flags & SF_EXPORT) {
375 /* If the old symbol had no explicit address size spec, use the
378 if (S->ExportSize == ADDR_SIZE_DEFAULT) {
379 S->ExportSize = AddrSize;
381 if (AddrSize != S->ExportSize) {
382 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
387 /* If the symbol is already defined, export it. Otherwise mark it as
390 if (S->Flags & SF_DEFINED) {
391 /* The symbol is defined, export it */
392 S->ExportSize = AddrSize;
393 if (S->ExportSize == ADDR_SIZE_DEFAULT) {
394 /* No export size given, use the real size of the symbol */
395 S->ExportSize = S->AddrSize;
396 } else if (S->AddrSize > S->ExportSize) {
397 Warning (1, "Symbol `%s' is %s but exported as %s",
398 GetSymName (S), AddrSizeToStr (S->AddrSize),
399 AddrSizeToStr (S->ExportSize));
401 S->Flags |= (SF_EXPORT | Flags);
402 S->ExportSize = AddrSize;
404 S->Flags |= (SF_GLOBAL | Flags);
405 S->AddrSize = AddrSize;
411 void SymConDes (SymEntry* S, unsigned char AddrSize, unsigned Type, unsigned Prio)
412 /* Mark the given symbol as a module constructor/destructor. This will also
413 * mark the symbol as an export. Initializers may never be zero page symbols.
416 /* Check the parameters */
417 #if (CD_TYPE_MIN != 0)
418 CHECK (Type >= CD_TYPE_MIN && Type <= CD_TYPE_MAX);
420 CHECK (Type <= CD_TYPE_MAX);
422 CHECK (Prio >= CD_PRIO_MIN && Prio <= CD_PRIO_MAX);
424 /* Don't accept local symbols */
425 if (IsLocalNameId (S->Name)) {
426 Error ("Illegal use of a local symbol");
430 /* Check for errors */
431 if (S->Flags & SF_IMPORT) {
432 /* The symbol is already marked as imported external symbol */
433 Error ("Symbol `%s' is already an import", GetSymName (S));
437 /* If the symbol was already marked as an export or global, check if
438 * this was done specifiying the same address size. In case of a global
439 * declaration, silently remove the global flag.
441 if (S->Flags & (SF_EXPORT | SF_GLOBAL)) {
442 if (S->ExportSize != AddrSize) {
443 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
445 S->Flags &= ~SF_GLOBAL;
447 S->ExportSize = AddrSize;
449 /* If the symbol is already defined, check symbol size against the
452 if (S->Flags & SF_DEFINED) {
453 if (S->ExportSize == ADDR_SIZE_DEFAULT) {
454 /* Use the real size of the symbol */
455 S->ExportSize = S->AddrSize;
456 } else if (S->AddrSize != S->ExportSize) {
457 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
461 /* If the symbol was already declared as a condes, check if the new
462 * priority value is the same as the old one.
464 if (S->ConDesPrio[Type] != CD_PRIO_NONE) {
465 if (S->ConDesPrio[Type] != Prio) {
466 Error ("Redeclaration mismatch for symbol `%s'", GetSymName (S));
469 S->ConDesPrio[Type] = Prio;
471 /* Set the symbol data */
472 S->Flags |= (SF_EXPORT | SF_REFERENCED);
477 int SymIsDef (const SymEntry* S)
478 /* Return true if the given symbol is already defined */
480 return (S->Flags & SF_DEFINED) != 0;
485 int SymIsRef (const SymEntry* S)
486 /* Return true if the given symbol has been referenced */
488 return (S->Flags & SF_REFERENCED) != 0;
493 int SymIsImport (const SymEntry* S)
494 /* Return true if the given symbol is marked as import */
496 /* Resolve trampoline entries */
497 if (S->Flags & SF_TRAMPOLINE) {
501 /* Check the import flag */
502 return (S->Flags & SF_IMPORT) != 0;
507 int SymIsConst (SymEntry* S, long* Val)
508 /* Return true if the given symbol has a constant value. If Val is not NULL
509 * and the symbol has a constant value, store it's value there.
512 /* Resolve trampoline entries */
513 if (S->Flags & SF_TRAMPOLINE) {
517 /* Check for constness */
518 return (SymHasExpr (S) && IsConstExpr (S->V.Expr, Val));
523 int SymHasExpr (const SymEntry* S)
524 /* Return true if the given symbol has an associated expression */
526 /* Resolve trampoline entries */
527 if (S->Flags & SF_TRAMPOLINE) {
531 /* Check the expression */
532 return ((S->Flags & (SF_DEFINED|SF_IMPORT)) == SF_DEFINED);
537 void SymMarkUser (SymEntry* S)
538 /* Set a user mark on the specified symbol */
540 /* Resolve trampoline entries */
541 if (S->Flags & SF_TRAMPOLINE) {
551 void SymUnmarkUser (SymEntry* S)
552 /* Remove a user mark from the specified symbol */
554 /* Resolve trampoline entries */
555 if (S->Flags & SF_TRAMPOLINE) {
560 S->Flags &= ~SF_USER;
565 int SymHasUserMark (SymEntry* S)
566 /* Return the state of the user mark for the specified symbol */
568 /* Resolve trampoline entries */
569 if (S->Flags & SF_TRAMPOLINE) {
574 return (S->Flags & SF_USER) != 0;
579 struct ExprNode* GetSymExpr (SymEntry* S)
580 /* Get the expression for a non-const symbol */
582 /* Resolve trampoline entries */
583 if (S->Flags & SF_TRAMPOLINE) {
587 PRECONDITION (S != 0 && SymHasExpr (S));
593 const struct ExprNode* SymResolve (const SymEntry* S)
594 /* Helper function for DumpExpr. Resolves a symbol into an expression or return
595 * NULL. Do not call in other contexts!
598 /* Resolve trampoline entries */
599 if (S->Flags & SF_TRAMPOLINE) {
603 return SymHasExpr (S)? S->V.Expr : 0;
608 const char* GetSymName (const SymEntry* S)
609 /* Return the name of the symbol */
611 /* Resolve trampoline entries */
612 if (S->Flags & SF_TRAMPOLINE) {
615 return GetString (S->Name);
620 unsigned char GetSymAddrSize (const SymEntry* S)
621 /* Return the address size of the symbol. Beware: This function will just
622 * return the AddrSize member, it will not look at the expression!
625 if (S->Flags & SF_TRAMPOLINE) {
633 long GetSymVal (SymEntry* S)
634 /* Return the value of a symbol assuming it's constant. FAIL will be called
635 * in case the symbol is undefined or not constant.
639 CHECK (S != 0 && SymHasExpr (S) && IsConstExpr (GetSymExpr (S), &Val));
645 unsigned GetSymIndex (const SymEntry* S)
646 /* Return the symbol index for the given symbol */
648 /* Resolve trampoline entries */
649 if (S->Flags & SF_TRAMPOLINE) {
652 PRECONDITION (S != 0 && (S->Flags & SF_INDEXED) != 0);
658 const FilePos* GetSymPos (const SymEntry* S)
659 /* Return the position of first occurence in the source for the given symbol */
661 /* Resolve trampoline entries */
662 if (S->Flags & SF_TRAMPOLINE) {
665 PRECONDITION (S != 0);