]> git.sur5r.net Git - cc65/blob - src/ca65/symentry.c
3df040d28e0ccbca0c7f6c8ddd284663d4d908d9
[cc65] / src / ca65 / symentry.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                symentry.c                                 */
4 /*                                                                           */
5 /*              Symbol table entry for the ca65 macroassembler               */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 1998-2010, Ullrich von Bassewitz                                      */
10 /*                Roemerstrasse 52                                           */
11 /*                D-70794 Filderstadt                                        */
12 /* EMail:         uz@cc65.org                                                */
13 /*                                                                           */
14 /*                                                                           */
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.                                    */
18 /*                                                                           */
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:                            */
22 /*                                                                           */
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              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 #include <string.h>
37
38 /* common */
39 #include "addrsize.h"
40 #include "symdefs.h"
41 #include "xmalloc.h"
42
43 /* ca65 */
44 #include "error.h"
45 #include "expr.h"
46 #include "global.h"
47 #include "scanner.h"
48 #include "segment.h"
49 #include "spool.h"
50 #include "studyexpr.h"          /* ### */
51 #include "symentry.h"
52 #include "symtab.h"
53
54
55
56 /*****************************************************************************/
57 /*                                   Data                                    */
58 /*****************************************************************************/
59
60
61
62 /* List of all symbol table entries */
63 SymEntry* SymList = 0;
64
65 /* Pointer to last defined symbol */
66 SymEntry* SymLast = 0;
67
68
69
70 /*****************************************************************************/
71 /*                                   Code                                    */
72 /*****************************************************************************/
73
74
75
76 SymEntry* NewSymEntry (const StrBuf* Name, unsigned Flags)
77 /* Allocate a symbol table entry, initialize and return it */
78 {
79     unsigned I;
80
81     /* Allocate memory */
82     SymEntry* S = xmalloc (sizeof (SymEntry));
83
84     /* Initialize the entry */
85     S->Left       = 0;
86     S->Right      = 0;
87     S->Locals     = 0;
88     S->Sym.Tab    = 0;
89     S->Pos        = CurPos;
90     for (I = 0; I < sizeof (S->GuessedUse) / sizeof (S->GuessedUse[0]); ++I) {
91         S->GuessedUse[I] = 0;
92     }
93     S->Flags      = Flags;
94     S->DebugSymId = ~0U;
95     S->ImportId   = ~0U;
96     S->Expr       = 0;
97     S->ExprRefs   = AUTO_COLLECTION_INITIALIZER;
98     S->ExportSize = ADDR_SIZE_DEFAULT;
99     S->AddrSize   = ADDR_SIZE_DEFAULT;
100     memset (S->ConDesPrio, 0, sizeof (S->ConDesPrio));
101     S->Name       = GetStrBufId (Name);
102
103     /* Insert it into the list of all entries */
104     S->List = SymList;
105     SymList = S;
106
107     /* Return the initialized entry */
108     return S;
109 }
110
111
112
113 int SymSearchTree (SymEntry* T, const StrBuf* Name, SymEntry** E)
114 /* Search in the given tree for a name. If we find the symbol, the function
115  * will return 0 and put the entry pointer into E. If we did not find the
116  * symbol, and the tree is empty, E is set to NULL. If the tree is not empty,
117  * E will be set to the last entry, and the result of the function is <0 if
118  * the entry should be inserted on the left side, and >0 if it should get
119  * inserted on the right side.
120  */
121 {
122     /* Is there a tree? */
123     if (T == 0) {
124         *E = 0;
125         return 1;
126     }
127
128     /* We have a table, search it */
129     while (1) {
130
131         /* Get the symbol name */
132         const StrBuf* SymName = GetStrBuf (T->Name);
133
134         /* Choose next entry */
135         int Cmp = SB_Compare (Name, SymName);
136         if (Cmp < 0 && T->Left) {
137             T = T->Left;
138         } else if (Cmp > 0&& T->Right) {
139             T = T->Right;
140         } else {
141             /* Found or end of search, return the result */
142             *E = T;
143             return Cmp;
144         }
145     }
146 }
147
148
149
150 void SymRef (SymEntry* S)
151 /* Mark the given symbol as referenced */
152 {
153     /* Mark the symbol as referenced */
154     S->Flags |= SF_REFERENCED;
155 }
156
157
158
159 void SymTransferExprRefs (SymEntry* From, SymEntry* To)
160 /* Transfer all expression references from one symbol to another. */
161 {
162     unsigned I;
163
164     for (I = 0; I < CollCount (&From->ExprRefs); ++I) {
165
166         /* Get the expression node */
167         ExprNode* E = CollAtUnchecked (&From->ExprRefs, I);
168
169         /* Safety */
170         CHECK (E->Op == EXPR_SYMBOL && E->V.Sym == From);
171
172         /* Replace the symbol reference */
173         E->V.Sym = To;
174
175         /* Add the expression reference */
176         SymAddExprRef (To, E);
177     }
178
179     /* Remove all symbol references from the old symbol */
180     CollDeleteAll (&From->ExprRefs);
181 }
182
183
184
185 static void SymReplaceExprRefs (SymEntry* S)
186 /* Replace the references to this symbol by a copy of the symbol expression */
187 {
188     unsigned I;
189     long     Val;
190
191     /* Check if the expression is const and get its value */
192     int IsConst = IsConstExpr (S->Expr, &Val);
193     CHECK (IsConst);
194
195     /* Loop over all references */
196     for (I = 0; I < CollCount (&S->ExprRefs); ++I) {
197
198         /* Get the expression node */
199         ExprNode* E = CollAtUnchecked (&S->ExprRefs, I);
200
201         /* Safety */
202         CHECK (E->Op == EXPR_SYMBOL && E->V.Sym == S);
203
204         /* We cannot touch the root node, since there are pointers to it.
205          * Replace it by a literal node.
206          */
207         E->Op = EXPR_LITERAL;
208         E->V.IVal = Val;
209     }
210
211     /* Remove all symbol references from the symbol */
212     CollDeleteAll (&S->ExprRefs);
213 }
214
215
216
217 void SymDef (SymEntry* S, ExprNode* Expr, unsigned char AddrSize, unsigned Flags)
218 /* Define a new symbol */
219 {
220     if (S->Flags & SF_IMPORT) {
221         /* Defined symbol is marked as imported external symbol */
222         Error ("Symbol `%m%p' is already an import", GetSymName (S));
223         return;
224     }
225     if ((Flags & SF_VAR) != 0 && (S->Flags & (SF_EXPORT | SF_GLOBAL))) {
226         /* Variable symbols cannot be exports or globals */
227         Error ("Var symbol `%m%p' cannot be an export or global symbol", GetSymName (S));
228         return;
229     }
230     if (S->Flags & SF_DEFINED) {
231         /* Multiple definition. In case of a variable, this is legal. */
232         if ((S->Flags & SF_VAR) == 0) {
233             Error ("Symbol `%m%p' is already defined", GetSymName (S));
234             S->Flags |= SF_MULTDEF;
235             return;
236         } else {
237             /* Redefinition must also be a variable symbol */
238             if ((Flags & SF_VAR) == 0) {
239                 Error ("Symbol `%m%p' is already different kind", GetSymName (S));
240                 return;
241             }
242             /* Delete the current symbol expression, since it will get
243              * replaced
244              */
245             FreeExpr (S->Expr);
246             S->Expr = 0;
247         }
248     }
249
250     /* Map a default address size to a real value */
251     if (AddrSize == ADDR_SIZE_DEFAULT) {
252         /* ### Must go! Delay address size calculation until end of assembly! */
253         ExprDesc ED;
254         ED_Init (&ED);
255         StudyExpr (Expr, &ED);
256         AddrSize = ED.AddrSize;
257         ED_Done (&ED);
258     }
259
260     /* Set the symbol value */
261     S->Expr = Expr;
262
263     /* In case of a variable symbol, walk over all expressions containing
264      * this symbol and replace the (sub-)expression by the literal value of
265      * the tree. Be sure to replace the expression node in place, since there
266      * may be pointers to it.
267      */
268     if (Flags & SF_VAR) {
269         SymReplaceExprRefs (S);
270     }
271
272     /* If the symbol is marked as global, export it. Address size is checked
273      * below.
274      */
275     if (S->Flags & SF_GLOBAL) {
276         S->Flags = (S->Flags & ~SF_GLOBAL) | SF_EXPORT;
277     }
278
279     /* Mark the symbol as defined and use the given address size */
280     S->Flags |= (SF_DEFINED | Flags);
281     S->AddrSize = AddrSize;
282
283     /* If the symbol is exported, check the address sizes */
284     if (S->Flags & SF_EXPORT) {
285         if (S->ExportSize == ADDR_SIZE_DEFAULT) {
286             /* Use the real size of the symbol */
287             S->ExportSize = S->AddrSize;
288         } else if (S->AddrSize > S->ExportSize) {
289             /* We're exporting a symbol smaller than it actually is */
290             PWarning (GetSymPos (S), 1, "Symbol `%m%p' is %s but exported %s",
291                       GetSymName (S), AddrSizeToStr (S->AddrSize),
292                       AddrSizeToStr (S->ExportSize));
293         }
294     }
295
296     /* If this is not a local symbol, remember it as the last global one */
297     if ((S->Flags & SF_LOCAL) == 0) {
298         SymLast = S;
299     }
300 }
301
302
303
304 void SymImport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
305 /* Mark the given symbol as an imported symbol */
306 {
307     if (S->Flags & SF_DEFINED) {
308         Error ("Symbol `%m%p' is already defined", GetSymName (S));
309         S->Flags |= SF_MULTDEF;
310         return;
311     }
312     if (S->Flags & SF_EXPORT) {
313         /* The symbol is already marked as exported symbol */
314         Error ("Cannot import exported symbol `%m%p'", GetSymName (S));
315         return;
316     }
317
318     /* If no address size is given, use the address size of the enclosing
319      * segment.
320      */
321     if (AddrSize == ADDR_SIZE_DEFAULT) {
322         AddrSize = GetCurrentSegAddrSize ();
323     }
324
325     /* If the symbol is marked as import or global, check the address size,
326      * then do silently remove the global flag.
327      */
328     if (S->Flags & SF_IMPORT) {
329         if ((Flags & SF_FORCED) != (S->Flags & SF_FORCED)) {
330             Error ("Redeclaration mismatch for symbol `%m%p'", GetSymName (S));
331         }
332         if (AddrSize != S->AddrSize) {
333             Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
334         }
335     }
336     if (S->Flags & SF_GLOBAL) {
337         S->Flags &= ~SF_GLOBAL;
338         if (AddrSize != S->AddrSize) {
339             Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
340         }
341     }
342
343     /* Set the symbol data */
344     S->Flags |= (SF_IMPORT | Flags);
345     S->AddrSize = AddrSize;
346 }
347
348
349
350 void SymExport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
351 /* Mark the given symbol as an exported symbol */
352 {
353     /* Check if it's ok to export the symbol */
354     if (S->Flags & SF_IMPORT) {
355         /* The symbol is already marked as imported external symbol */
356         Error ("Symbol `%m%p' is already an import", GetSymName (S));
357         return;
358     }
359     if (S->Flags & SF_VAR) {
360         /* Variable symbols cannot be exported */
361         Error ("Var symbol `%m%p' cannot be exported", GetSymName (S));
362         return;
363     }
364
365     /* If the symbol was marked as global before, remove the global flag and
366      * proceed, but check the address size.
367      */
368     if (S->Flags & SF_GLOBAL) {
369         if (AddrSize != S->ExportSize) {
370             Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
371         }
372         S->Flags &= ~SF_GLOBAL;
373     }
374
375     /* If the symbol was already marked as an export, but wasn't defined
376      * before, the address sizes in both definitions must match.
377      */
378     if ((S->Flags & (SF_EXPORT|SF_DEFINED)) == SF_EXPORT) {
379         if (S->ExportSize != AddrSize) {
380             Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
381         }
382     }
383     S->ExportSize = AddrSize;
384
385     /* If the symbol is already defined, check symbol size against the
386      * exported size.
387      */
388     if (S->Flags & SF_DEFINED) {
389         if (S->ExportSize == ADDR_SIZE_DEFAULT) {
390             /* No export size given, use the real size of the symbol */
391             S->ExportSize = S->AddrSize;
392         } else if (S->AddrSize > S->ExportSize) {
393             /* We're exporting a symbol smaller than it actually is */
394             Warning (1, "Symbol `%m%p' is %s but exported %s",
395                      GetSymName (S), AddrSizeToStr (S->AddrSize),
396                      AddrSizeToStr (S->ExportSize));
397         }
398     }
399
400     /* Set the symbol data */
401     S->Flags |= (SF_EXPORT | SF_REFERENCED | Flags);
402 }
403
404
405
406 void SymGlobal (SymEntry* S, unsigned char AddrSize, unsigned Flags)
407 /* Mark the given symbol as a global symbol, that is, as a symbol that is
408  * either imported or exported.
409  */
410 {
411     if (S->Flags & SF_VAR) {
412         /* Variable symbols cannot be exported or imported */
413         Error ("Var symbol `%m%p' cannot be made global", GetSymName (S));
414         return;
415     }
416
417     /* If the symbol is already marked as import, the address size must match.
418      * Apart from that, ignore the global declaration.
419      */
420     if (S->Flags & SF_IMPORT) {
421         if (AddrSize == ADDR_SIZE_DEFAULT) {
422             /* Use the size of the current segment */
423             AddrSize = GetCurrentSegAddrSize ();
424         }
425         if (AddrSize != S->AddrSize) {
426             Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
427         }
428         return;
429     }
430
431     /* If the symbol is already an export: If it is not defined, the address
432      * sizes must match.
433      */
434     if (S->Flags & SF_EXPORT) {
435         if ((S->Flags & SF_DEFINED) == 0) {
436             /* Symbol is undefined */
437             if (AddrSize != S->ExportSize) {
438                 Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
439             }
440         } else if (AddrSize != ADDR_SIZE_DEFAULT) {
441             /* Symbol is defined and address size given */
442             if (AddrSize != S->ExportSize) {
443                 Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
444             }
445         }
446         return;
447     }
448
449     /* If the symbol is already marked as global, the address size must match.
450      * Use the ExportSize here, since it contains the actual address size
451      * passed to this function.
452      */
453     if (S->Flags & SF_GLOBAL) {
454         if (AddrSize != S->ExportSize) {
455             Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
456         }
457         return;
458     }
459
460     /* If we come here, the symbol was neither declared as export, import or
461      * global before. Check if it is already defined, in which case it will
462      * become an export. If it is not defined, mark it as global and remember
463      * the given address sizes.
464      */
465     if (S->Flags & SF_DEFINED) {
466         /* The symbol is defined, export it */
467         S->ExportSize = AddrSize;
468         if (S->ExportSize == ADDR_SIZE_DEFAULT) {
469             /* No export size given, use the real size of the symbol */
470             S->ExportSize = S->AddrSize;
471         } else if (S->AddrSize > S->ExportSize) {
472             /* We're exporting a symbol smaller than it actually is */
473             Warning (1, "Symbol `%m%p' is %s but exported %s",
474                      GetSymName (S), AddrSizeToStr (S->AddrSize),
475                      AddrSizeToStr (S->ExportSize));
476         }
477         S->Flags |= (SF_EXPORT | Flags);
478     } else {
479         /* Since we don't know if the symbol will get exported or imported,
480          * remember two different address sizes: One for an import in AddrSize,
481          * and the other one for an export in ExportSize.
482          */
483         S->AddrSize = AddrSize;
484         if (S->AddrSize == ADDR_SIZE_DEFAULT) {
485             /* Use the size of the current segment */
486             S->AddrSize = GetCurrentSegAddrSize ();
487         }
488         S->ExportSize = AddrSize;
489         S->Flags |= (SF_GLOBAL | Flags);
490     }
491 }
492
493
494
495 void SymConDes (SymEntry* S, unsigned char AddrSize, unsigned Type, unsigned Prio)
496 /* Mark the given symbol as a module constructor/destructor. This will also
497  * mark the symbol as an export. Initializers may never be zero page symbols.
498  */
499 {
500     /* Check the parameters */
501 #if (CD_TYPE_MIN != 0)
502     CHECK (Type >= CD_TYPE_MIN && Type <= CD_TYPE_MAX);
503 #else
504     CHECK (Type <= CD_TYPE_MAX);
505 #endif
506     CHECK (Prio >= CD_PRIO_MIN && Prio <= CD_PRIO_MAX);
507
508     /* Check for errors */
509     if (S->Flags & SF_IMPORT) {
510         /* The symbol is already marked as imported external symbol */
511         Error ("Symbol `%m%p' is already an import", GetSymName (S));
512         return;
513     }
514     if (S->Flags & SF_VAR) {
515         /* Variable symbols cannot be exported or imported */
516         Error ("Var symbol `%m%p' cannot be exported", GetSymName (S));
517         return;
518     }
519
520     /* If the symbol was already marked as an export or global, check if
521      * this was done specifiying the same address size. In case of a global
522      * declaration, silently remove the global flag.
523      */
524     if (S->Flags & (SF_EXPORT | SF_GLOBAL)) {
525         if (S->ExportSize != AddrSize) {
526             Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
527         }
528         S->Flags &= ~SF_GLOBAL;
529     }
530     S->ExportSize = AddrSize;
531
532     /* If the symbol is already defined, check symbol size against the
533      * exported size.
534      */
535     if (S->Flags & SF_DEFINED) {
536         if (S->ExportSize == ADDR_SIZE_DEFAULT) {
537             /* Use the real size of the symbol */
538             S->ExportSize = S->AddrSize;
539         } else if (S->AddrSize != S->ExportSize) {
540             Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
541         }
542     }
543
544     /* If the symbol was already declared as a condes, check if the new
545      * priority value is the same as the old one.
546      */
547     if (S->ConDesPrio[Type] != CD_PRIO_NONE) {
548         if (S->ConDesPrio[Type] != Prio) {
549             Error ("Redeclaration mismatch for symbol `%m%p'", GetSymName (S));
550         }
551     }
552     S->ConDesPrio[Type] = Prio;
553
554     /* Set the symbol data */
555     S->Flags |= (SF_EXPORT | SF_REFERENCED);
556 }
557
558
559
560 void SymGuessedAddrSize (SymEntry* Sym, unsigned char AddrSize)
561 /* Mark the address size of the given symbol as guessed. The address size
562  * passed as argument is the one NOT used, because the actual address size
563  * wasn't known. Example: Zero page addressing was not used because symbol
564  * is undefined, and absolute addressing was available.
565  */
566 {
567     /* We must have a valid address size passed */
568     PRECONDITION (AddrSize != ADDR_SIZE_DEFAULT);
569
570     /* We do not support all address sizes currently */
571     if (AddrSize > sizeof (Sym->GuessedUse) / sizeof (Sym->GuessedUse[0])) {
572         return;
573     }
574
575     /* We can only remember one such occurance */
576     if (Sym->GuessedUse[AddrSize-1]) {
577         return;
578     }
579
580     /* Ok, remember the file position */
581     Sym->GuessedUse[AddrSize-1] = xdup (&CurPos, sizeof (CurPos));
582 }
583
584
585
586 void SymExportFromGlobal (SymEntry* S)
587 /* Called at the end of assembly. Converts a global symbol that is defined
588  * into an export.
589  */
590 {
591     /* Remove the global flag and make the symbol an export */
592     S->Flags &= ~SF_GLOBAL;
593     S->Flags |= SF_EXPORT;
594 }
595
596
597
598 void SymImportFromGlobal (SymEntry* S)
599 /* Called at the end of assembly. Converts a global symbol that is undefined
600  * into an import.
601  */
602 {
603     /* Remove the global flag and make it an import */
604     S->Flags &= ~SF_GLOBAL;
605     S->Flags |= SF_IMPORT;
606 }
607
608
609
610 int SymIsConst (const SymEntry* S, long* Val)
611 /* Return true if the given symbol has a constant value. If Val is not NULL
612  * and the symbol has a constant value, store it's value there.
613  */
614 {
615     /* Check for constness */
616     return (SymHasExpr (S) && IsConstExpr (S->Expr, Val));
617 }
618
619
620
621 SymTable* GetSymParentScope (SymEntry* S)
622 /* Get the parent scope of the symbol (not the one it is defined in). Return
623  * NULL if the symbol is a cheap local, or defined on global level.
624  */
625 {
626     if ((S->Flags & SF_LOCAL) != 0) {
627         /* This is a cheap local symbol */
628         return 0;
629     } else {
630         /* This is a global symbol */
631         return S->Sym.Tab->Parent;
632     }
633 }
634
635
636
637 struct ExprNode* GetSymExpr (SymEntry* S)
638 /* Get the expression for a non-const symbol */
639 {
640     PRECONDITION (S != 0 && SymHasExpr (S));
641     return S->Expr;
642 }
643
644
645
646 const struct ExprNode* SymResolve (const SymEntry* S)
647 /* Helper function for DumpExpr. Resolves a symbol into an expression or return
648  * NULL. Do not call in other contexts!
649  */
650 {
651     return SymHasExpr (S)? S->Expr : 0;
652 }
653
654
655
656 long GetSymVal (SymEntry* S)
657 /* Return the value of a symbol assuming it's constant. FAIL will be called
658  * in case the symbol is undefined or not constant.
659  */
660 {
661     long Val;
662     CHECK (S != 0 && SymHasExpr (S) && IsConstExpr (GetSymExpr (S), &Val));
663     return Val;
664 }
665
666
667
668 unsigned GetSymImportId (const SymEntry* S)
669 /* Return the import id for the given symbol */
670 {
671     PRECONDITION (S != 0 && (S->Flags & SF_IMPORT) && S->ImportId != ~0U);
672     return S->ImportId;
673 }
674
675
676
677 unsigned GetSymInfoFlags (const SymEntry* S, long* ConstVal)
678 /* Return a set of flags used when writing symbol information into a file.
679  * If the SYM_CONST bit is set, ConstVal will contain the constant value
680  * of the symbol. The result does not include the condes count.
681  * See common/symdefs.h for more information.
682  */
683 {
684     /* Setup info flags */
685     unsigned Flags = 0;
686     Flags |= SymIsConst (S, ConstVal)? SYM_CONST : SYM_EXPR;
687     Flags |= (S->Flags & SF_LABEL)? SYM_LABEL : SYM_EQUATE;
688     Flags |= (S->Flags & SF_LOCAL)? SYM_CHEAP_LOCAL : SYM_STD;
689
690     /* Return the result */
691     return Flags;
692 }
693
694
695