]> git.sur5r.net Git - cc65/blob - src/ca65/symentry.c
6f67ec015d4b4df607f26d9ef228b267164ce8ef
[cc65] / src / ca65 / symentry.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                symentry.c                                 */
4 /*                                                                           */
5 /*          Symbol table entry forward for the ca65 macroassembler           */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 1998-2003 Ullrich von Bassewitz                                       */
10 /*               Römerstraße 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 "xmalloc.h"
41
42 /* ca65 */
43 #include "error.h"
44 #include "expr.h"
45 #include "global.h"
46 #include "scanner.h"
47 #include "segment.h"
48 #include "spool.h"
49 #include "symentry.h"
50 #include "symtab.h"
51
52
53
54 /*****************************************************************************/
55 /*                                   Data                                    */
56 /*****************************************************************************/
57
58
59
60 /* List of all symbol table entries */
61 SymEntry* SymList = 0;
62
63 /* Pointer to last defined symbol */
64 SymEntry* SymLast = 0;
65
66
67
68 /*****************************************************************************/
69 /*                                   Code                                    */
70 /*****************************************************************************/
71
72
73
74 int IsLocalName (const char* Name)
75 /* Return true if Name is the name of a local symbol */
76 {
77     return (*Name == LocalStart);
78 }
79
80
81
82 int IsLocalNameId (unsigned Name)
83 /* Return true if Name is the name of a local symbol */
84 {
85     return (*GetString (Name) == LocalStart);
86 }
87
88
89
90 static unsigned SymAddrSize (const SymEntry* S)
91 /* Get the default address size for a symbol. */
92 {
93     /* Local symbols are always near (is this ok?) */
94     if (IsLocalNameId (S->Name)) {
95         return ADDR_SIZE_ABS;
96     }
97
98     /* Return the address size of the segment */
99     return GetCurrentSegAddrSize ();
100 }
101
102
103
104 SymEntry* NewSymEntry (const char* Name)
105 /* Allocate a symbol table entry, initialize and return it */
106 {
107     /* Allocate memory */
108     SymEntry* S = xmalloc (sizeof (SymEntry));
109
110     /* Initialize the entry */
111     S->Left       = 0;
112     S->Right      = 0;
113     S->Locals     = 0;
114     S->SymTab     = 0;
115     S->Pos        = CurPos;
116     S->Flags      = 0;
117     S->V.Expr     = 0;
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);
123
124     /* Insert it into the list of all entries */
125     S->List = SymList;
126     SymList = S;
127
128     /* Return the initialized entry */
129     return S;
130 }
131
132
133
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.
141  */
142 {
143     /* Is there a tree? */
144     if (T == 0) {
145         *E = 0;
146         return 1;
147     }
148
149     /* We have a table, search it */
150     while (1) {
151
152         /* Get the symbol name */
153         const char* SymName = GetString (T->Name);
154
155         /* Choose next entry */
156         int Cmp = strcmp (Name, SymName);
157         if (Cmp < 0 && T->Left) {
158             T = T->Left;
159         } else if (Cmp > 0&& T->Right) {
160             T = T->Right;
161         } else {
162             /* Found or end of search, return the result */
163             *E = T;
164             return Cmp;
165         }
166     }
167 }
168
169
170
171 void SymRef (SymEntry* S)
172 /* Mark the given symbol as referenced */
173 {
174     /* Mark the symbol as referenced */
175     S->Flags |= SF_REFERENCED;
176 }
177
178
179
180 void SymDef (SymEntry* S, ExprNode* Expr, unsigned char AddrSize, unsigned Flags)
181 /* Define a new symbol */
182 {
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));
186         return;
187     }
188     if (S->Flags & SF_DEFINED) {
189         /* Multiple definition */
190         Error ("Symbol `%s' is already defined", GetSymName (S));
191         S->Flags |= SF_MULTDEF;
192         return;
193     }
194
195     /* Map a default address size to a real value */
196     if (AddrSize == ADDR_SIZE_DEFAULT) {
197         long Val;
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;
205             } else {
206                 AddrSize = ADDR_SIZE_LONG;
207             }
208         } else {
209             AddrSize = SymAddrSize (S);
210         }
211     }
212
213     /* Set the symbol value */
214     S->V.Expr = Expr;
215
216     /* If the symbol is marked as global, export it. Address size is checked
217      * below.
218      */
219     if (S->Flags & SF_GLOBAL) {
220         S->Flags = (S->Flags & ~SF_GLOBAL) | SF_EXPORT;
221     }
222
223     /* Mark the symbol as defined and use the given address size */
224     S->Flags |= (SF_DEFINED | Flags);
225     S->AddrSize = AddrSize;
226
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));
237         }
238     }
239
240     /* If this is not a local symbol, remember it as the last global one */
241     if (!IsLocalNameId (S->Name)) {
242         SymLast = S;
243     }
244 }
245
246
247
248 void SymImport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
249 /* Mark the given symbol as an imported symbol */
250 {
251     /* Don't accept local symbols */
252     if (IsLocalNameId (S->Name)) {
253         Error ("Illegal use of a local symbol");
254         return;
255     }
256
257     if (S->Flags & SF_DEFINED) {
258         Error ("Symbol `%s' is already defined", GetSymName (S));
259         S->Flags |= SF_MULTDEF;
260         return;
261     }
262     if (S->Flags & SF_EXPORT) {
263         /* The symbol is already marked as exported symbol */
264         Error ("Cannot import exported symbol `%s'", GetSymName (S));
265         return;
266     }
267
268     /* If no address size is given, use the address size of the enclosing
269      * segment.
270      */
271     if (AddrSize == ADDR_SIZE_DEFAULT) {
272         AddrSize = GetCurrentSegAddrSize ();
273     }
274
275     /* If the symbol is marked as import or global, check the address size,
276      * then do silently remove the global flag.
277      */
278     if (S->Flags & SF_IMPORT) {
279         if ((Flags & SF_FORCED) != (S->Flags & SF_FORCED)) {
280             Error ("Redeclaration mismatch for symbol `%s'", GetSymName (S));
281         }
282         if (AddrSize != S->AddrSize) {
283             Error ("Address size mismatch for symbol `%s'", GetSymName (S));
284         }
285     }
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));
290         }
291     }
292
293     /* Set the symbol data */
294     S->Flags |= (SF_IMPORT | Flags);
295     S->AddrSize = AddrSize;
296 }
297
298
299
300 void SymExport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
301 /* Mark the given symbol as an exported symbol */
302 {
303     /* Don't accept local symbols */
304     if (IsLocalNameId (S->Name)) {
305         Error ("Illegal use of a local symbol");
306         return;
307     }
308
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));
313         return;
314     }
315
316     /* If the symbol was marked as global before, remove the global flag and
317      * proceed, but check the address size.
318      */
319     if (S->Flags & SF_GLOBAL) {
320         if (AddrSize != S->ExportSize) {
321             Error ("Address size mismatch for symbol `%s'", GetSymName (S));
322         }
323         S->Flags &= ~SF_GLOBAL;
324     }
325
326     /* If the symbol was already marked as an export, but wasn't defined
327      * before, the address sizes in both definitions must match.
328      */
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));
332         }
333     }
334     S->ExportSize = AddrSize;
335
336     /* If the symbol is already defined, check symbol size against the
337      * exported size.
338      */
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));
348         }
349     }
350
351     /* Set the symbol data */
352     S->Flags |= (SF_EXPORT | SF_REFERENCED | Flags);
353 }
354
355
356
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.
360  */
361 {
362     /* Don't accept local symbols */
363     if (IsLocalNameId (S->Name)) {
364         Error ("Illegal use of a local symbol");
365         return;
366     }
367
368     /* If the symbol is already marked as import, the address size must match.
369      * Apart from that, ignore the global declaration.
370      */
371     if (S->Flags & SF_IMPORT) {
372         if (AddrSize == ADDR_SIZE_DEFAULT) {
373             /* Use the size of the current segment */
374             AddrSize = GetCurrentSegAddrSize ();
375         }
376         if (AddrSize != S->AddrSize) {
377             Error ("Address size mismatch for symbol `%s'", GetSymName (S));
378         }
379         return;
380     }
381
382     /* If the symbol is already an export: If it is not defined, the address
383      * sizes must match.
384      */
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));
390             }
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));
395             }
396         }
397         return;
398     }
399
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.
403      */
404     if (S->Flags & SF_GLOBAL) {
405         if (AddrSize != S->ExportSize) {
406             Error ("Address size mismatch for symbol `%s'", GetSymName (S));
407         }
408         return;
409     }
410
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.
415      */
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));
427         }
428         S->Flags |= (SF_EXPORT | Flags);
429     } else {
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.
433          */
434         S->AddrSize = AddrSize;
435         if (S->AddrSize == ADDR_SIZE_DEFAULT) {
436             /* Use the size of the current segment */
437             S->AddrSize = GetCurrentSegAddrSize ();
438         }
439         S->ExportSize = AddrSize;
440         S->Flags |= (SF_GLOBAL | Flags);
441     }
442 }
443
444
445
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.
449  */
450 {
451     /* Check the parameters */
452 #if (CD_TYPE_MIN != 0)
453     CHECK (Type >= CD_TYPE_MIN && Type <= CD_TYPE_MAX);
454 #else
455     CHECK (Type <= CD_TYPE_MAX);
456 #endif
457     CHECK (Prio >= CD_PRIO_MIN && Prio <= CD_PRIO_MAX);
458
459     /* Don't accept local symbols */
460     if (IsLocalNameId (S->Name)) {
461         Error ("Illegal use of a local symbol");
462         return;
463     }
464
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));
469         return;
470     }
471
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.
475      */
476     if (S->Flags & (SF_EXPORT | SF_GLOBAL)) {
477         if (S->ExportSize != AddrSize) {
478             Error ("Address size mismatch for symbol `%s'", GetSymName (S));
479         }
480         S->Flags &= ~SF_GLOBAL;
481     }
482     S->ExportSize = AddrSize;
483
484     /* If the symbol is already defined, check symbol size against the
485      * exported size.
486      */
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));
493         }
494     }
495
496     /* If the symbol was already declared as a condes, check if the new
497      * priority value is the same as the old one.
498      */
499     if (S->ConDesPrio[Type] != CD_PRIO_NONE) {
500         if (S->ConDesPrio[Type] != Prio) {
501             Error ("Redeclaration mismatch for symbol `%s'", GetSymName (S));
502         }
503     }
504     S->ConDesPrio[Type] = Prio;
505
506     /* Set the symbol data */
507     S->Flags |= (SF_EXPORT | SF_REFERENCED);
508 }
509
510
511
512 int SymIsDef (const SymEntry* S)
513 /* Return true if the given symbol is already defined */
514 {
515     return (S->Flags & SF_DEFINED) != 0;
516 }
517
518
519
520 int SymIsRef (const SymEntry* S)
521 /* Return true if the given symbol has been referenced */
522 {
523     return (S->Flags & SF_REFERENCED) != 0;
524 }
525
526
527
528 int SymIsImport (const SymEntry* S)
529 /* Return true if the given symbol is marked as import */
530 {
531     /* Resolve trampoline entries */
532     if (S->Flags & SF_TRAMPOLINE) {
533         S = S->V.Sym;
534     }
535
536     /* Check the import flag */
537     return (S->Flags & SF_IMPORT) != 0;
538 }
539
540
541
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.
545  */
546 {
547     /* Resolve trampoline entries */
548     if (S->Flags & SF_TRAMPOLINE) {
549         S = S->V.Sym;
550     }
551
552     /* Check for constness */
553     return (SymHasExpr (S) && IsConstExpr (S->V.Expr, Val));
554 }
555
556
557
558 int SymHasExpr (const SymEntry* S)
559 /* Return true if the given symbol has an associated expression */
560 {
561     /* Resolve trampoline entries */
562     if (S->Flags & SF_TRAMPOLINE) {
563         S = S->V.Sym;
564     }
565
566     /* Check the expression */
567     return ((S->Flags & (SF_DEFINED|SF_IMPORT)) == SF_DEFINED);
568 }
569
570
571
572 void SymMarkUser (SymEntry* S)
573 /* Set a user mark on the specified symbol */
574 {
575     /* Resolve trampoline entries */
576     if (S->Flags & SF_TRAMPOLINE) {
577         S = S->V.Sym;
578     }
579
580     /* Set the bit */
581     S->Flags |= SF_USER;
582 }
583
584
585
586 void SymUnmarkUser (SymEntry* S)
587 /* Remove a user mark from the specified symbol */
588 {
589     /* Resolve trampoline entries */
590     if (S->Flags & SF_TRAMPOLINE) {
591         S = S->V.Sym;
592     }
593
594     /* Reset the bit */
595     S->Flags &= ~SF_USER;
596 }
597
598
599
600 int SymHasUserMark (SymEntry* S)
601 /* Return the state of the user mark for the specified symbol */
602 {
603     /* Resolve trampoline entries */
604     if (S->Flags & SF_TRAMPOLINE) {
605         S = S->V.Sym;
606     }
607
608     /* Check the bit */
609     return (S->Flags & SF_USER) != 0;
610 }
611
612
613
614 struct ExprNode* GetSymExpr (SymEntry* S)
615 /* Get the expression for a non-const symbol */
616 {
617     /* Resolve trampoline entries */
618     if (S->Flags & SF_TRAMPOLINE) {
619         S = S->V.Sym;
620     }
621
622     PRECONDITION (S != 0 && SymHasExpr (S));
623     return S->V.Expr;
624 }
625
626
627
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!
631  */
632 {
633     /* Resolve trampoline entries */
634     if (S->Flags & SF_TRAMPOLINE) {
635         S = S->V.Sym;
636     }
637
638     return SymHasExpr (S)? S->V.Expr : 0;
639 }
640
641
642
643 const char* GetSymName (const SymEntry* S)
644 /* Return the name of the symbol */
645 {
646     /* Resolve trampoline entries */
647     if (S->Flags & SF_TRAMPOLINE) {
648         S = S->V.Sym;
649     }
650     return GetString (S->Name);
651 }
652
653
654
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!
658  */
659 {
660     if (S->Flags & SF_TRAMPOLINE) {
661         S = S->V.Sym;
662     }
663     return S->AddrSize;
664 }
665
666
667
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.
671  */
672 {
673     long Val;
674     CHECK (S != 0 && SymHasExpr (S) && IsConstExpr (GetSymExpr (S), &Val));
675     return Val;
676 }
677
678
679
680 unsigned GetSymIndex (const SymEntry* S)
681 /* Return the symbol index for the given symbol */
682 {
683     /* Resolve trampoline entries */
684     if (S->Flags & SF_TRAMPOLINE) {
685         S = S->V.Sym;
686     }
687     PRECONDITION (S != 0 && (S->Flags & SF_INDEXED) != 0);
688     return S->Index;
689 }
690
691
692
693 const FilePos* GetSymPos (const SymEntry* S)
694 /* Return the position of first occurence in the source for the given symbol */
695 {
696     /* Resolve trampoline entries */
697     if (S->Flags & SF_TRAMPOLINE) {
698         S = S->V.Sym;
699     }
700     PRECONDITION (S != 0);
701     return &S->Pos;
702 }
703
704
705
706