]> git.sur5r.net Git - cc65/blob - src/ca65/symentry.c
Allow conditional directives within .STRUCT7:UNION and .ENUM
[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) && IsByteRange (Val)) {
199             AddrSize = ADDR_SIZE_ZP;
200         } else {
201             AddrSize = SymAddrSize (S);
202         }
203     }
204
205     /* Set the symbol value */
206     S->V.Expr = Expr;
207
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;
212     }
213
214     /* Mark the symbol as defined and use the given address size */
215     S->Flags |= (SF_DEFINED | Flags);
216     S->AddrSize = AddrSize;
217
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));
227         }
228     }
229
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");
235         }
236     }
237
238     /* If this is not a local symbol, remember it as the last global one */
239     if (!IsLocalNameId (S->Name)) {
240         SymLast = S;
241     }
242 }
243
244
245
246 void SymImport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
247 /* Mark the given symbol as an imported symbol */
248 {
249     /* Don't accept local symbols */
250     if (IsLocalNameId (S->Name)) {
251         Error ("Illegal use of a local symbol");
252         return;
253     }
254
255     if (S->Flags & SF_DEFINED) {
256         Error ("Symbol `%s' is already defined", GetSymName (S));
257         S->Flags |= SF_MULTDEF;
258         return;
259     }
260     if (S->Flags & SF_EXPORT) {
261         /* The symbol is already marked as exported symbol */
262         Error ("Cannot import exported symbol `%s'", GetSymName (S));
263         return;
264     }
265
266     /* Map a default address size to a real value */
267     if (AddrSize == ADDR_SIZE_DEFAULT) {
268         AddrSize = SymAddrSize (S);
269     }
270
271     /* If the symbol is marked as import or global, check the symbol flags,
272      * then do silently remove the global flag
273      */
274     if (S->Flags & SF_IMPORT) {
275         if ((Flags & SF_FORCED) != (S->Flags & SF_FORCED)) {
276             Error ("Redeclaration mismatch for symbol `%s'", GetSymName (S));
277         }
278         if (AddrSize != S->AddrSize) {
279             Error ("Address size mismatch for symbol `%s'", GetSymName (S));
280         }
281     }
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));
285         }
286         S->Flags &= ~SF_GLOBAL;
287     }
288
289     /* Set the symbol data */
290     S->Flags |= (SF_IMPORT | Flags);
291     S->AddrSize = AddrSize;
292 }
293
294
295
296 void SymExport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
297 /* Mark the given symbol as an exported symbol */
298 {
299     /* Don't accept local symbols */
300     if (IsLocalNameId (S->Name)) {
301         Error ("Illegal use of a local symbol");
302         return;
303     }
304
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));
309         return;
310     }
311
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;
316     }
317
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.
321      */
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;
327         }
328         if (S->ExportSize != ADDR_SIZE_DEFAULT && S->ExportSize != AddrSize) {
329             Error ("Address size mismatch for symbol `%s'", GetSymName (S));
330         }
331     }
332     S->ExportSize = AddrSize;
333
334     /* If the symbol is already defined, check symbol size against the
335      * exported size.
336      */
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));
345         }
346     }
347
348     /* Set the symbol data */
349     S->Flags |= (SF_EXPORT | SF_REFERENCED | Flags);
350 }
351
352
353
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.
357  */
358 {
359     /* Don't accept local symbols */
360     if (IsLocalNameId (S->Name)) {
361         Error ("Illegal use of a local symbol");
362         return;
363     }
364
365     /* If the symbol is already marked as import or export, check the
366      * size of the definition, then bail out.
367      */
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));
371         }
372         return;
373     }
374     if (S->Flags & SF_EXPORT) {
375         /* If the old symbol had no explicit address size spec, use the
376          * new one.
377          */
378         if (S->ExportSize == ADDR_SIZE_DEFAULT) {
379             S->ExportSize = AddrSize;
380         }
381         if (AddrSize != S->ExportSize) {
382             Error ("Address size mismatch for symbol `%s'", GetSymName (S));
383         }
384         return;
385     }
386
387     /* If the symbol is already defined, export it. Otherwise mark it as
388      * global.
389      */
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));
400         }
401         S->Flags |= (SF_EXPORT | Flags);
402         S->ExportSize = AddrSize;
403     } else {
404         S->Flags |= (SF_GLOBAL | Flags);
405         S->AddrSize = AddrSize;
406     }
407 }
408
409
410
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.
414  */
415 {
416     /* Check the parameters */
417 #if (CD_TYPE_MIN != 0)
418     CHECK (Type >= CD_TYPE_MIN && Type <= CD_TYPE_MAX);
419 #else
420     CHECK (Type <= CD_TYPE_MAX);
421 #endif
422     CHECK (Prio >= CD_PRIO_MIN && Prio <= CD_PRIO_MAX);
423
424     /* Don't accept local symbols */
425     if (IsLocalNameId (S->Name)) {
426         Error ("Illegal use of a local symbol");
427         return;
428     }
429
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));
434         return;
435     }
436
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.
440      */
441     if (S->Flags & (SF_EXPORT | SF_GLOBAL)) {
442         if (S->ExportSize != AddrSize) {
443             Error ("Address size mismatch for symbol `%s'", GetSymName (S));
444         }
445         S->Flags &= ~SF_GLOBAL;
446     }
447     S->ExportSize = AddrSize;
448
449     /* If the symbol is already defined, check symbol size against the
450      * exported size.
451      */
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));
458         }
459     }
460
461     /* If the symbol was already declared as a condes, check if the new
462      * priority value is the same as the old one.
463      */
464     if (S->ConDesPrio[Type] != CD_PRIO_NONE) {
465         if (S->ConDesPrio[Type] != Prio) {
466             Error ("Redeclaration mismatch for symbol `%s'", GetSymName (S));
467         }
468     }
469     S->ConDesPrio[Type] = Prio;
470
471     /* Set the symbol data */
472     S->Flags |= (SF_EXPORT | SF_REFERENCED);
473 }
474
475
476
477 int SymIsDef (const SymEntry* S)
478 /* Return true if the given symbol is already defined */
479 {
480     return (S->Flags & SF_DEFINED) != 0;
481 }
482
483
484
485 int SymIsRef (const SymEntry* S)
486 /* Return true if the given symbol has been referenced */
487 {
488     return (S->Flags & SF_REFERENCED) != 0;
489 }
490
491
492
493 int SymIsImport (const SymEntry* S)
494 /* Return true if the given symbol is marked as import */
495 {
496     /* Resolve trampoline entries */
497     if (S->Flags & SF_TRAMPOLINE) {
498         S = S->V.Sym;
499     }
500
501     /* Check the import flag */
502     return (S->Flags & SF_IMPORT) != 0;
503 }
504
505
506
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.
510  */
511 {
512     /* Resolve trampoline entries */
513     if (S->Flags & SF_TRAMPOLINE) {
514         S = S->V.Sym;
515     }
516
517     /* Check for constness */
518     return (SymHasExpr (S) && IsConstExpr (S->V.Expr, Val));
519 }
520
521
522
523 int SymHasExpr (const SymEntry* S)
524 /* Return true if the given symbol has an associated expression */
525 {
526     /* Resolve trampoline entries */
527     if (S->Flags & SF_TRAMPOLINE) {
528         S = S->V.Sym;
529     }
530
531     /* Check the expression */
532     return ((S->Flags & (SF_DEFINED|SF_IMPORT)) == SF_DEFINED);
533 }
534
535
536
537 void SymMarkUser (SymEntry* S)
538 /* Set a user mark on the specified symbol */
539 {
540     /* Resolve trampoline entries */
541     if (S->Flags & SF_TRAMPOLINE) {
542         S = S->V.Sym;
543     }
544
545     /* Set the bit */
546     S->Flags |= SF_USER;
547 }
548
549
550
551 void SymUnmarkUser (SymEntry* S)
552 /* Remove a user mark from the specified symbol */
553 {
554     /* Resolve trampoline entries */
555     if (S->Flags & SF_TRAMPOLINE) {
556         S = S->V.Sym;
557     }
558
559     /* Reset the bit */
560     S->Flags &= ~SF_USER;
561 }
562
563
564
565 int SymHasUserMark (SymEntry* S)
566 /* Return the state of the user mark for the specified symbol */
567 {
568     /* Resolve trampoline entries */
569     if (S->Flags & SF_TRAMPOLINE) {
570         S = S->V.Sym;
571     }
572
573     /* Check the bit */
574     return (S->Flags & SF_USER) != 0;
575 }
576
577
578
579 struct ExprNode* GetSymExpr (SymEntry* S)
580 /* Get the expression for a non-const symbol */
581 {
582     /* Resolve trampoline entries */
583     if (S->Flags & SF_TRAMPOLINE) {
584         S = S->V.Sym;
585     }
586
587     PRECONDITION (S != 0 && SymHasExpr (S));
588     return S->V.Expr;
589 }
590
591
592
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!
596  */
597 {
598     /* Resolve trampoline entries */
599     if (S->Flags & SF_TRAMPOLINE) {
600         S = S->V.Sym;
601     }
602
603     return SymHasExpr (S)? S->V.Expr : 0;
604 }
605
606
607
608 const char* GetSymName (const SymEntry* S)
609 /* Return the name of the symbol */
610 {
611     /* Resolve trampoline entries */
612     if (S->Flags & SF_TRAMPOLINE) {
613         S = S->V.Sym;
614     }
615     return GetString (S->Name);
616 }
617
618
619
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!
623  */
624 {
625     if (S->Flags & SF_TRAMPOLINE) {
626         S = S->V.Sym;
627     }
628     return S->AddrSize;
629 }
630
631
632
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.
636  */
637 {
638     long Val;
639     CHECK (S != 0 && SymHasExpr (S) && IsConstExpr (GetSymExpr (S), &Val));
640     return Val;
641 }
642
643
644
645 unsigned GetSymIndex (const SymEntry* S)
646 /* Return the symbol index for the given symbol */
647 {
648     /* Resolve trampoline entries */
649     if (S->Flags & SF_TRAMPOLINE) {
650         S = S->V.Sym;
651     }
652     PRECONDITION (S != 0 && (S->Flags & SF_INDEXED) != 0);
653     return S->Index;
654 }
655
656
657
658 const FilePos* GetSymPos (const SymEntry* S)
659 /* Return the position of first occurence in the source for the given symbol */
660 {
661     /* Resolve trampoline entries */
662     if (S->Flags & SF_TRAMPOLINE) {
663         S = S->V.Sym;
664     }
665     PRECONDITION (S != 0);
666     return &S->Pos;
667 }
668
669
670
671