]> git.sur5r.net Git - cc65/blob - src/ca65/symentry.c
New DefAddrSize variable
[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 */
217     if (S->Flags & SF_GLOBAL) {
218         S->ExportSize = S->AddrSize;
219         S->Flags = (S->Flags & ~SF_GLOBAL) | SF_EXPORT;
220     }
221
222     /* Mark the symbol as defined and use the given address size */
223     S->Flags |= (SF_DEFINED | Flags);
224     S->AddrSize = AddrSize;
225
226     /* If the symbol is exported, check the address sizes */
227     if (S->Flags & SF_EXPORT) {
228         if (S->ExportSize == ADDR_SIZE_DEFAULT) {
229             /* Use the real size of the symbol */
230             S->ExportSize = S->AddrSize;
231         } else if (S->AddrSize > S->ExportSize) {
232             PWarning (GetSymPos (S), 1, "Symbol `%s' is %s but exported as %s",
233                       GetSymName (S), AddrSizeToStr (S->AddrSize),
234                       AddrSizeToStr (S->ExportSize));
235         }
236     }
237
238     /* If the symbol is a ZP symbol, check if the value is in correct range */
239     if (S->AddrSize == ADDR_SIZE_ZP) {
240         /* Already marked as ZP symbol by some means */
241         if (!IsByteExpr (Expr)) {
242             Error ("Range error");
243         }
244     }
245
246     /* If this is not a local symbol, remember it as the last global one */
247     if (!IsLocalNameId (S->Name)) {
248         SymLast = S;
249     }
250 }
251
252
253
254 void SymImport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
255 /* Mark the given symbol as an imported symbol */
256 {
257     /* Don't accept local symbols */
258     if (IsLocalNameId (S->Name)) {
259         Error ("Illegal use of a local symbol");
260         return;
261     }
262
263     if (S->Flags & SF_DEFINED) {
264         Error ("Symbol `%s' is already defined", GetSymName (S));
265         S->Flags |= SF_MULTDEF;
266         return;
267     }
268     if (S->Flags & SF_EXPORT) {
269         /* The symbol is already marked as exported symbol */
270         Error ("Cannot import exported symbol `%s'", GetSymName (S));
271         return;
272     }
273
274     /* If no address size is given, use the default address size */
275     if (AddrSize == ADDR_SIZE_DEFAULT) {
276         AddrSize = DefAddrSize;
277     }
278
279     /* If the symbol is marked as import or global, check the symbol flags,
280      * then do silently remove the global flag
281      */
282     if (S->Flags & SF_IMPORT) {
283         if ((Flags & SF_FORCED) != (S->Flags & SF_FORCED)) {
284             Error ("Redeclaration mismatch for symbol `%s'", GetSymName (S));
285         }
286         if (AddrSize != S->AddrSize) {
287             Error ("Address size mismatch for symbol `%s'", GetSymName (S));
288         }
289     }
290     if (S->Flags & SF_GLOBAL) {
291         if (S->AddrSize != ADDR_SIZE_DEFAULT && S->AddrSize != AddrSize) {
292             Error ("Address size mismatch for symbol `%s'", GetSymName (S));
293         }
294         S->Flags &= ~SF_GLOBAL;
295     }
296
297     /* Set the symbol data */
298     S->Flags |= (SF_IMPORT | Flags);
299     S->AddrSize = AddrSize;
300 }
301
302
303
304 void SymExport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
305 /* Mark the given symbol as an exported symbol */
306 {
307     /* Don't accept local symbols */
308     if (IsLocalNameId (S->Name)) {
309         Error ("Illegal use of a local symbol");
310         return;
311     }
312
313     /* Check if it's ok to export the symbol */
314     if (S->Flags & SF_IMPORT) {
315         /* The symbol is already marked as imported external symbol */
316         Error ("Symbol `%s' is already an import", GetSymName (S));
317         return;
318     }
319
320     /* If the symbol was marked as global before, make it an export */
321     if (S->Flags & SF_GLOBAL) {
322         S->ExportSize = S->AddrSize;
323         S->Flags &= ~SF_GLOBAL;
324     }
325
326     /* If the symbol was already marked as an export, check if this was done
327      * specifiying the same address size. If the old spec had no explicit
328      * address size, use the new one.
329      */
330     if (S->Flags & SF_EXPORT) {
331         if (S->ExportSize == ADDR_SIZE_DEFAULT) {
332             S->ExportSize = AddrSize;
333         } else if (AddrSize == ADDR_SIZE_DEFAULT) {
334             AddrSize = S->ExportSize;
335         }
336         if (S->ExportSize != ADDR_SIZE_DEFAULT && S->ExportSize != AddrSize) {
337             Error ("Address size mismatch for symbol `%s'", GetSymName (S));
338         }
339     }
340     S->ExportSize = AddrSize;
341
342     /* If the symbol is already defined, check symbol size against the
343      * exported size.
344      */
345     if (S->Flags & SF_DEFINED) {
346         if (S->ExportSize == ADDR_SIZE_DEFAULT) {
347             /* No export size given, use the real size of the symbol */
348             S->ExportSize = S->AddrSize;
349         } else if (S->AddrSize > S->ExportSize) {
350             Warning (1, "Symbol `%s' is %s but exported as %s",
351                      GetSymName (S), AddrSizeToStr (S->AddrSize),
352                      AddrSizeToStr (S->ExportSize));
353         }
354     }
355
356     /* Set the symbol data */
357     S->Flags |= (SF_EXPORT | SF_REFERENCED | Flags);
358 }
359
360
361
362 void SymGlobal (SymEntry* S, unsigned char AddrSize, unsigned Flags)
363 /* Mark the given symbol as a global symbol, that is, as a symbol that is
364  * either imported or exported.
365  */
366 {
367     /* Don't accept local symbols */
368     if (IsLocalNameId (S->Name)) {
369         Error ("Illegal use of a local symbol");
370         return;
371     }
372
373     /* If the symbol is already marked as import or export, check the
374      * size of the definition, then bail out.
375      */
376     if (S->Flags & SF_IMPORT) {
377         if (AddrSize != ADDR_SIZE_DEFAULT && AddrSize != S->AddrSize) {
378             Error ("Address size mismatch for symbol `%s'", GetSymName (S));
379         }
380         return;
381     }
382     if (S->Flags & SF_EXPORT) {
383         /* If the old symbol had no explicit address size spec, use the
384          * new one.
385          */
386         if (S->ExportSize == ADDR_SIZE_DEFAULT) {
387             S->ExportSize = AddrSize;
388         }
389         if (AddrSize != S->ExportSize) {
390             Error ("Address size mismatch for symbol `%s'", GetSymName (S));
391         }
392         return;
393     }
394
395     /* If the symbol is already defined, export it. Otherwise mark it as
396      * global.
397      */
398     if (S->Flags & SF_DEFINED) {
399         /* The symbol is defined, export it */
400         S->ExportSize = AddrSize;
401         if (S->ExportSize == ADDR_SIZE_DEFAULT) {
402             /* No export size given, use the real size of the symbol */
403             S->ExportSize = S->AddrSize;
404         } else if (S->AddrSize > S->ExportSize) {
405             Warning (1, "Symbol `%s' is %s but exported as %s",
406                      GetSymName (S), AddrSizeToStr (S->AddrSize),
407                      AddrSizeToStr (S->ExportSize));
408         }
409         S->Flags |= (SF_EXPORT | Flags);
410         S->ExportSize = AddrSize;
411     } else {
412         S->Flags |= (SF_GLOBAL | Flags);
413         S->AddrSize = AddrSize;
414     }
415 }
416
417
418
419 void SymConDes (SymEntry* S, unsigned char AddrSize, unsigned Type, unsigned Prio)
420 /* Mark the given symbol as a module constructor/destructor. This will also
421  * mark the symbol as an export. Initializers may never be zero page symbols.
422  */
423 {
424     /* Check the parameters */
425 #if (CD_TYPE_MIN != 0)
426     CHECK (Type >= CD_TYPE_MIN && Type <= CD_TYPE_MAX);
427 #else
428     CHECK (Type <= CD_TYPE_MAX);
429 #endif
430     CHECK (Prio >= CD_PRIO_MIN && Prio <= CD_PRIO_MAX);
431
432     /* Don't accept local symbols */
433     if (IsLocalNameId (S->Name)) {
434         Error ("Illegal use of a local symbol");
435         return;
436     }
437
438     /* Check for errors */
439     if (S->Flags & SF_IMPORT) {
440         /* The symbol is already marked as imported external symbol */
441         Error ("Symbol `%s' is already an import", GetSymName (S));
442         return;
443     }
444
445     /* If the symbol was already marked as an export or global, check if
446      * this was done specifiying the same address size. In case of a global
447      * declaration, silently remove the global flag.
448      */
449     if (S->Flags & (SF_EXPORT | SF_GLOBAL)) {
450         if (S->ExportSize != AddrSize) {
451             Error ("Address size mismatch for symbol `%s'", GetSymName (S));
452         }
453         S->Flags &= ~SF_GLOBAL;
454     }
455     S->ExportSize = AddrSize;
456
457     /* If the symbol is already defined, check symbol size against the
458      * exported size.
459      */
460     if (S->Flags & SF_DEFINED) {
461         if (S->ExportSize == ADDR_SIZE_DEFAULT) {
462             /* Use the real size of the symbol */
463             S->ExportSize = S->AddrSize;
464         } else if (S->AddrSize != S->ExportSize) {
465             Error ("Address size mismatch for symbol `%s'", GetSymName (S));
466         }
467     }
468
469     /* If the symbol was already declared as a condes, check if the new
470      * priority value is the same as the old one.
471      */
472     if (S->ConDesPrio[Type] != CD_PRIO_NONE) {
473         if (S->ConDesPrio[Type] != Prio) {
474             Error ("Redeclaration mismatch for symbol `%s'", GetSymName (S));
475         }
476     }
477     S->ConDesPrio[Type] = Prio;
478
479     /* Set the symbol data */
480     S->Flags |= (SF_EXPORT | SF_REFERENCED);
481 }
482
483
484
485 int SymIsDef (const SymEntry* S)
486 /* Return true if the given symbol is already defined */
487 {
488     return (S->Flags & SF_DEFINED) != 0;
489 }
490
491
492
493 int SymIsRef (const SymEntry* S)
494 /* Return true if the given symbol has been referenced */
495 {
496     return (S->Flags & SF_REFERENCED) != 0;
497 }
498
499
500
501 int SymIsImport (const SymEntry* S)
502 /* Return true if the given symbol is marked as import */
503 {
504     /* Resolve trampoline entries */
505     if (S->Flags & SF_TRAMPOLINE) {
506         S = S->V.Sym;
507     }
508
509     /* Check the import flag */
510     return (S->Flags & SF_IMPORT) != 0;
511 }
512
513
514
515 int SymIsConst (SymEntry* S, long* Val)
516 /* Return true if the given symbol has a constant value. If Val is not NULL
517  * and the symbol has a constant value, store it's value there.
518  */
519 {
520     /* Resolve trampoline entries */
521     if (S->Flags & SF_TRAMPOLINE) {
522         S = S->V.Sym;
523     }
524
525     /* Check for constness */
526     return (SymHasExpr (S) && IsConstExpr (S->V.Expr, Val));
527 }
528
529
530
531 int SymHasExpr (const SymEntry* S)
532 /* Return true if the given symbol has an associated expression */
533 {
534     /* Resolve trampoline entries */
535     if (S->Flags & SF_TRAMPOLINE) {
536         S = S->V.Sym;
537     }
538
539     /* Check the expression */
540     return ((S->Flags & (SF_DEFINED|SF_IMPORT)) == SF_DEFINED);
541 }
542
543
544
545 void SymMarkUser (SymEntry* S)
546 /* Set a user mark on the specified symbol */
547 {
548     /* Resolve trampoline entries */
549     if (S->Flags & SF_TRAMPOLINE) {
550         S = S->V.Sym;
551     }
552
553     /* Set the bit */
554     S->Flags |= SF_USER;
555 }
556
557
558
559 void SymUnmarkUser (SymEntry* S)
560 /* Remove a user mark from the specified symbol */
561 {
562     /* Resolve trampoline entries */
563     if (S->Flags & SF_TRAMPOLINE) {
564         S = S->V.Sym;
565     }
566
567     /* Reset the bit */
568     S->Flags &= ~SF_USER;
569 }
570
571
572
573 int SymHasUserMark (SymEntry* S)
574 /* Return the state of the user mark for the specified symbol */
575 {
576     /* Resolve trampoline entries */
577     if (S->Flags & SF_TRAMPOLINE) {
578         S = S->V.Sym;
579     }
580
581     /* Check the bit */
582     return (S->Flags & SF_USER) != 0;
583 }
584
585
586
587 struct ExprNode* GetSymExpr (SymEntry* S)
588 /* Get the expression for a non-const symbol */
589 {
590     /* Resolve trampoline entries */
591     if (S->Flags & SF_TRAMPOLINE) {
592         S = S->V.Sym;
593     }
594
595     PRECONDITION (S != 0 && SymHasExpr (S));
596     return S->V.Expr;
597 }
598
599
600
601 const struct ExprNode* SymResolve (const SymEntry* S)
602 /* Helper function for DumpExpr. Resolves a symbol into an expression or return
603  * NULL. Do not call in other contexts!
604  */
605 {
606     /* Resolve trampoline entries */
607     if (S->Flags & SF_TRAMPOLINE) {
608         S = S->V.Sym;
609     }
610
611     return SymHasExpr (S)? S->V.Expr : 0;
612 }
613
614
615
616 const char* GetSymName (const SymEntry* S)
617 /* Return the name of the symbol */
618 {
619     /* Resolve trampoline entries */
620     if (S->Flags & SF_TRAMPOLINE) {
621         S = S->V.Sym;
622     }
623     return GetString (S->Name);
624 }
625
626
627
628 unsigned char GetSymAddrSize (const SymEntry* S)
629 /* Return the address size of the symbol. Beware: This function will just
630  * return the AddrSize member, it will not look at the expression!
631  */
632 {
633     if (S->Flags & SF_TRAMPOLINE) {
634         S = S->V.Sym;
635     }
636     return S->AddrSize;
637 }
638
639
640
641 long GetSymVal (SymEntry* S)
642 /* Return the value of a symbol assuming it's constant. FAIL will be called
643  * in case the symbol is undefined or not constant.
644  */
645 {
646     long Val;
647     CHECK (S != 0 && SymHasExpr (S) && IsConstExpr (GetSymExpr (S), &Val));
648     return Val;
649 }
650
651
652
653 unsigned GetSymIndex (const SymEntry* S)
654 /* Return the symbol index for the given symbol */
655 {
656     /* Resolve trampoline entries */
657     if (S->Flags & SF_TRAMPOLINE) {
658         S = S->V.Sym;
659     }
660     PRECONDITION (S != 0 && (S->Flags & SF_INDEXED) != 0);
661     return S->Index;
662 }
663
664
665
666 const FilePos* GetSymPos (const SymEntry* S)
667 /* Return the position of first occurence in the source for the given symbol */
668 {
669     /* Resolve trampoline entries */
670     if (S->Flags & SF_TRAMPOLINE) {
671         S = S->V.Sym;
672     }
673     PRECONDITION (S != 0);
674     return &S->Pos;
675 }
676
677
678
679