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