]> git.sur5r.net Git - cc65/blob - src/ca65/symtab.c
7af07dbfedeb847d14c62066126f01a27363a1f0
[cc65] / src / ca65 / symtab.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 symtab.c                                  */
4 /*                                                                           */
5 /*                 Symbol table for the ca65 macroassembler                  */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 1998-2000 Ullrich von Bassewitz                                       */
10 /*               Wacholderweg 14                                             */
11 /*               D-70597 Stuttgart                                           */
12 /* EMail:        uz@musoftware.de                                            */
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 "cddefs.h"
40 #include "check.h"
41 #include "hashstr.h"
42 #include "symdefs.h"
43 #include "xmalloc.h"
44
45 /* ca65 */
46 #include "global.h"
47 #include "error.h"
48 #include "expr.h"
49 #include "objfile.h"
50 #include "scanner.h"
51 #include "symtab.h"
52
53
54
55 /*****************************************************************************/
56 /*                                   Data                                    */
57 /*****************************************************************************/
58
59
60
61 /* Bits for the Flags value in SymEntry */
62 #define SF_USER         0x0001          /* User bit */
63 #define SF_TRAMPOLINE   0x0002          /* Trampoline entry */
64 #define SF_EXPORT       0x0004          /* Export this symbol */
65 #define SF_IMPORT       0x0008          /* Import this symbol */
66 #define SF_GLOBAL       0x0010          /* Global symbol */
67 #define SF_ZP           0x0020          /* Declared as zeropage symbol */
68 #define SF_ABS          0x0040          /* Declared as absolute symbol */
69 #define SF_LABEL        0x0080          /* Used as a label */
70 #define SF_INDEXED      0x0800          /* Index is valid */
71 #define SF_CONST        0x1000          /* The symbol has a constant value */
72 #define SF_MULTDEF      0x2000          /* Multiply defined symbol */
73 #define SF_DEFINED      0x4000          /* Defined */
74 #define SF_REFERENCED   0x8000          /* Referenced */
75
76 /* Combined stuff */
77 #define SF_UNDEFMASK    (SF_REFERENCED | SF_DEFINED | SF_IMPORT)
78 #define SF_UNDEFVAL     (SF_REFERENCED)
79 #define SF_IMPMASK      (SF_TRAMPOLINE | SF_IMPORT | SF_REFERENCED)
80 #define SF_IMPVAL       (SF_IMPORT | SF_REFERENCED)
81 #define SF_EXPMASK      (SF_TRAMPOLINE | SF_EXPORT)
82 #define SF_EXPVAL       (SF_EXPORT)
83 #define SF_DBGINFOMASK  (SF_TRAMPOLINE | SF_DEFINED | SF_EXPORT | SF_IMPORT)
84 #define SF_DBGINFOVAL   (SF_DEFINED)
85
86 /* Structure of a symbol table entry */
87 struct SymEntry {
88     SymEntry*               Left;       /* Lexically smaller entry */
89     SymEntry*               Right;      /* Lexically larger entry */
90     SymEntry*               List;       /* List of all entries */
91     SymEntry*               Locals;     /* Root of subtree for local symbols */
92     struct SymTable*        SymTab;     /* Table this symbol is in, 0 for locals */
93     FilePos                 Pos;        /* File position for this symbol */
94     unsigned                Flags;      /* Symbol flags */
95     unsigned                Index;      /* Index of import/export entries */
96     union {
97         struct ExprNode*    Expr;       /* Expression if CONST not set */
98         long                Val;        /* Value (if CONST set) */
99         SymEntry*           Sym;        /* Symbol (if trampoline entry) */
100     } V;
101     unsigned char           ConDesPrio[CD_TYPE_COUNT];  /* ConDes priorities... */
102                                         /* ...actually value+1 (used as flag) */
103     char                    Name [1];   /* Dynamic allocation */
104 };
105
106
107
108 /* Definitions for the hash table */
109 #define MAIN_HASHTAB_SIZE       213
110 #define SUB_HASHTAB_SIZE        53
111 typedef struct SymTable SymTable;
112 struct SymTable {
113     unsigned            TableSlots;     /* Number of hash table slots */
114     unsigned            TableEntries;   /* Number of entries in the table */
115     SymTable*           BackLink;       /* Link to enclosing scope if any */
116     SymEntry*           Table [1];      /* Dynamic allocation */
117 };
118
119
120
121 /* Arguments for SymFind */
122 #define SF_FIND_EXISTING        0
123 #define SF_ALLOC_NEW            1
124
125
126
127 /* Symbol table variables */
128 static SymEntry*        SymList = 0;    /* List of all symbol table entries */
129 static SymEntry*        SymLast = 0;    /* Pointer to last defined symbol */
130 static SymTable*        SymTab  = 0;    /* Pointer to current symbol table */
131 static SymTable*        RootTab = 0;    /* Root symbol table */
132 static unsigned         ImportCount = 0;/* Counter for import symbols */
133 static unsigned         ExportCount = 0;/* Counter for export symbols */
134
135
136
137 /*****************************************************************************/
138 /*                         Internally used functions                         */
139 /*****************************************************************************/
140
141
142
143 static int IsLocal (const char* Name)
144 /* Return true if Name is the name of a local symbol */
145 {
146     return (*Name == LocalStart);
147 }
148
149
150
151 static SymEntry* NewSymEntry (const char* Name)
152 /* Allocate a symbol table entry, initialize and return it */
153 {
154     SymEntry* S;
155     unsigned Len;
156
157     /* Get the length of the name */
158     Len = strlen (Name);
159
160     /* Allocate memory */
161     S = xmalloc (sizeof (SymEntry) + Len);
162
163     /* Initialize the entry */
164     S->Left     = 0;
165     S->Right    = 0;
166     S->Locals   = 0;
167     S->SymTab   = 0;
168     S->Pos      = CurPos;
169     S->Flags    = 0;
170     S->V.Expr   = 0;
171     memset (S->ConDesPrio, 0, sizeof (S->ConDesPrio));
172     memcpy (S->Name, Name, Len+1);
173
174     /* Insert it into the list of all entries */
175     S->List = SymList;
176     SymList = S;
177
178     /* Return the initialized entry */
179     return S;
180 }
181
182
183
184 static SymTable* NewSymTable (unsigned Size)
185 /* Allocate a symbol table on the heap and return it */
186 {
187     SymTable* S;
188
189     /* Allocate memory */
190     S = xmalloc (sizeof (SymTable) + (Size-1) * sizeof (SymEntry*));
191
192     /* Set variables and clear hash table entries */
193     S->TableSlots   = Size;
194     S->TableEntries = 0;
195     S->BackLink     = 0;
196     while (Size--) {
197         S->Table [Size] = 0;
198     }
199
200     /* Return the prepared struct */
201     return S;
202 }
203
204
205
206 static int SearchSymTab (SymEntry* T, const char* Name, SymEntry** E)
207 /* Search in the given table for a name (Hash is the hash value of Name and
208  * is given as parameter so that it will not get calculated twice if we search
209  * in more than one table). If we find the symbol, the function will return 0
210  * and put the entry pointer into E. If we did not find the symbol, and the
211  * tree is empty, E is set to NULL. If the tree is not empty, E will be set to
212  * the last entry, and the result of the function is <0 if the entry should
213  * be inserted on the left side, and >0 if it should get inserted on the right
214  * side.
215  */
216 {
217     int Cmp;
218
219     /* Is there a tree? */
220     if (T == 0) {
221         *E = 0;
222         return 1;
223     }
224
225     /* We have a table, search it */
226     while (1) {
227         /* Choose next entry */
228         Cmp = strcmp (Name, T->Name);
229         if (Cmp < 0 && T->Left) {
230             T = T->Left;
231         } else if (Cmp > 0 && T->Right) {
232             T = T->Right;
233         } else {
234             /* Found or end of search */
235             break;
236         }
237     }
238
239     /* Return the search result */
240     *E = T;
241     return Cmp;
242 }
243
244
245
246 /*****************************************************************************/
247 /*                                   Code                                    */
248 /*****************************************************************************/
249
250
251
252 static SymEntry* SymFind (SymTable* Tab, const char* Name, int AllocNew)
253 /* Find a new symbol table entry in the given table. If AllocNew is given and
254  * the entry is not found, create a new one. Return the entry found, or the
255  * new entry created, or - in case AllocNew is zero - return 0.
256  */
257 {
258     SymEntry* S;
259     int Cmp;
260     unsigned Hash;
261
262     if (IsLocal (Name)) {
263
264         /* Local symbol, get the table */
265         if (!SymLast) {
266             /* No last global, so there's no local table */
267             Error (ERR_ILLEGAL_LOCAL_USE);
268             if (AllocNew) {
269                 return NewSymEntry (Name);
270             } else {
271                 return 0;
272             }
273         }
274
275         /* Search for the symbol if we have a table */
276         Cmp = SearchSymTab (SymLast->Locals, Name, &S);
277
278         /* If we found an entry, return it */
279         if (Cmp == 0) {
280             return S;
281         }
282
283         if (AllocNew) {
284
285             /* Otherwise create a new entry, insert and return it */
286             SymEntry* N = NewSymEntry (Name);
287             if (S == 0) {
288                 SymLast->Locals = N;
289             } else if (Cmp < 0) {
290                 S->Left = N;
291             } else {
292                 S->Right = N;
293             }
294             return N;
295         }
296
297     } else {
298
299         /* Global symbol: Get the hash value for the name */
300         Hash = HashStr (Name) % Tab->TableSlots;
301
302         /* Search for the entry */
303         Cmp = SearchSymTab (Tab->Table [Hash], Name, &S);
304
305         /* If we found an entry, return it */
306         if (Cmp == 0) {
307             /* Check for a trampoline entry, in this case return the real
308              * symbol.
309              */
310             if (S->Flags & SF_TRAMPOLINE) {
311                 return S->V.Sym;
312             } else {
313                 return S;
314             }
315         }
316
317         if (AllocNew) {
318
319             /* Otherwise create a new entry, insert and return it */
320             SymEntry* N = NewSymEntry (Name);
321             if (S == 0) {
322                 Tab->Table [Hash] = N;
323             } else if (Cmp < 0) {
324                 S->Left = N;
325             } else {
326                 S->Right = N;
327             }
328             N->SymTab = Tab;
329             ++Tab->TableEntries;
330             return N;
331
332         }
333     }
334
335     /* We did not find the entry and AllocNew is false. */
336     return 0;
337 }
338
339
340
341 static SymEntry* SymFindAny (SymTable* Tab, const char* Name)
342 /* Find a symbol in any table */
343 {
344     SymEntry* Sym;
345     do {
346         /* Search in the current table */
347         Sym = SymFind (Tab, Name, 0);
348         if (Sym) {
349             /* Found, return it */
350             return Sym;
351         } else {
352             /* Not found, search in the backlink, if we have one */
353             Tab = Tab->BackLink;
354         }
355     } while (Sym == 0 && Tab != 0);
356
357     /* Not found */
358     return 0;
359 }
360
361
362
363 static SymEntry* SymRefInternal (SymTable* Table, const char* Name)
364 /* Search for the symbol in the given table and return it */
365 {
366     /* Try to find the symbol, create a new one if the symbol does not exist */
367     SymEntry* S = SymFind (Table, Name, SF_ALLOC_NEW);
368
369     /* Mark the symbol as referenced */
370     S->Flags |= SF_REFERENCED;
371
372     /* Return it */
373     return S;
374 }
375
376
377
378 void SymEnterLevel (void)
379 /* Enter a new lexical level */
380 {
381     if (RootTab == 0) {
382         /* Create the main symbol table */
383         RootTab = SymTab = NewSymTable (MAIN_HASHTAB_SIZE);
384     } else {
385         /* Create a local symbol table */
386         SymTable* LocalSyms;
387         LocalSyms = NewSymTable (SUB_HASHTAB_SIZE);
388         LocalSyms->BackLink = SymTab;
389         SymTab = LocalSyms;
390     }
391 }
392
393
394
395 void SymLeaveLevel (void)
396 /* Leave the current lexical level */
397 {
398     SymTab = SymTab->BackLink;
399 }
400
401
402
403 void SymDef (const char* Name, ExprNode* Expr, int ZP, int Label)
404 /* Define a new symbol */
405 {
406     /* Do we have such a symbol? */
407     SymEntry* S = SymFind (SymTab, Name, SF_ALLOC_NEW);
408     if (S->Flags & SF_IMPORT) {
409         /* Defined symbol is marked as imported external symbol */
410         Error (ERR_SYM_ALREADY_IMPORT, Name);
411         return;
412     }
413     if (S->Flags & SF_DEFINED) {
414         /* Multiple definition */
415         Error (ERR_SYM_ALREADY_DEFINED, Name);
416         S->Flags |= SF_MULTDEF;
417         return;
418     }
419
420     /* Set the symbol data */
421     if (IsConstExpr (Expr)) {
422         /* Expression is const, store the value */
423         S->Flags |= SF_CONST;
424         S->V.Val = GetExprVal (Expr);
425         FreeExpr (Expr);
426     } else {
427         /* Not const, store the expression */
428         S->V.Expr  = Expr;
429     }
430     S->Flags |= SF_DEFINED;
431     if (ZP) {
432         S->Flags |= SF_ZP;
433     }
434     if (Label) {
435         S->Flags |= SF_LABEL;
436     }
437
438     /* If the symbol is a ZP symbol, check if the value is in correct range */
439     if (S->Flags & SF_ZP) {
440         /* Already marked as ZP symbol by some means */
441         if (!IsByteExpr (Expr)) {
442             Error (ERR_RANGE);
443         }
444     }
445
446     /* If this is not a local symbol, remember it as the last global one */
447     if (!IsLocal (Name)) {
448         SymLast = S;
449     }
450 }
451
452
453
454 SymEntry* SymRef (const char* Name)
455 /* Search for the symbol and return it */
456 {
457     /* Reference the symbol in the current table */
458     return SymRefInternal (SymTab, Name);
459 }
460
461
462
463 SymEntry* SymRefGlobal (const char* Name)
464 /* Search for the symbol in the global namespace and return it */
465 {
466     /* Reference the symbol in the current table */
467     return SymRefInternal (RootTab, Name);
468 }
469
470
471
472 void SymImport (const char* Name, int ZP)
473 /* Mark the given symbol as an imported symbol */
474 {
475     SymEntry* S;
476
477     /* Don't accept local symbols */
478     if (IsLocal (Name)) {
479         Error (ERR_ILLEGAL_LOCAL_USE);
480         return;
481     }
482
483     /* Do we have such a symbol? */
484     S = SymFind (SymTab, Name, SF_ALLOC_NEW);
485     if (S->Flags & SF_DEFINED) {
486         Error (ERR_SYM_ALREADY_DEFINED, Name);
487         S->Flags |= SF_MULTDEF;
488         return;
489     }
490     if (S->Flags & SF_EXPORT) {
491         /* The symbol is already marked as exported symbol */
492         Error (ERR_SYM_ALREADY_EXPORT, Name);
493         return;
494     }
495
496     /* If the symbol is marked as global, check the symbol size, then do
497      * silently remove the global flag
498      */
499     if (S->Flags & SF_GLOBAL) {
500         if ((ZP != 0) != ((S->Flags & SF_ZP) != 0)) {
501             Error (ERR_SYM_REDECL_MISMATCH);
502         }
503         S->Flags &= ~SF_GLOBAL;
504     }
505
506     /* Set the symbol data */
507     S->Flags |= SF_IMPORT;
508     if (ZP) {
509         S->Flags |= SF_ZP;
510     }
511 }
512
513
514
515 void SymExport (const char* Name, int ZP)
516 /* Mark the given symbol as an exported symbol */
517 {
518     SymEntry* S;
519
520     /* Don't accept local symbols */
521     if (IsLocal (Name)) {
522         Error (ERR_ILLEGAL_LOCAL_USE);
523         return;
524     }
525
526     /* Do we have such a symbol? */
527     S = SymFind (SymTab, Name, SF_ALLOC_NEW);
528     if (S->Flags & SF_IMPORT) {
529         /* The symbol is already marked as imported external symbol */
530         Error (ERR_SYM_ALREADY_IMPORT, Name);
531         return;
532     }
533
534     /* If the symbol is marked as global, check the symbol size, then do
535      * silently remove the global flag
536      */
537     if (S->Flags & SF_GLOBAL) {
538         if ((ZP != 0) != ((S->Flags & SF_ZP) != 0)) {
539             Error (ERR_SYM_REDECL_MISMATCH);
540         }
541         S->Flags &= ~SF_GLOBAL;
542     }
543
544     /* Set the symbol data */
545     S->Flags |= SF_EXPORT | SF_REFERENCED;
546     if (ZP) {
547         S->Flags |= SF_ZP;
548     }
549 }
550
551
552
553 void SymGlobal (const char* Name, int ZP)
554 /* Mark the given symbol as a global symbol, that is, as a symbol that is
555  * either imported or exported.
556  */
557 {
558     SymEntry* S;
559
560     /* Don't accept local symbols */
561     if (IsLocal (Name)) {
562         Error (ERR_ILLEGAL_LOCAL_USE);
563         return;
564     }
565
566     /* Search for this symbol, create a new entry if needed */
567     S = SymFind (SymTab, Name, SF_ALLOC_NEW);
568
569     /* If the symbol is already marked as import or export, check the
570      * size of the definition, then bail out. */
571     if (S->Flags & SF_IMPORT || S->Flags & SF_EXPORT) {
572         if ((ZP != 0) != ((S->Flags & SF_ZP) != 0)) {
573             Error (ERR_SYM_REDECL_MISMATCH);
574         }
575         return;
576     }
577
578     /* Mark the symbol */
579     S->Flags |= SF_GLOBAL;
580     if (ZP) {
581         S->Flags |= SF_ZP;
582     }
583 }
584
585
586
587 void SymConDes (const char* Name, unsigned Type, unsigned Prio)
588 /* Mark the given symbol as a module constructor/destructor. This will also
589  * mark the symbol as an export. Initializers may never be zero page symbols.
590  */
591 {
592     SymEntry* S;
593
594     /* Check the parameters */
595     CHECK (Type >= CD_TYPE_MIN && Type <= CD_TYPE_MAX);
596     CHECK (Prio >= CD_PRIO_MIN && Prio <= CD_PRIO_MAX);
597
598     /* Don't accept local symbols */
599     if (IsLocal (Name)) {
600         Error (ERR_ILLEGAL_LOCAL_USE);
601         return;
602     }
603
604     /* Do we have such a symbol? */
605     S = SymFind (SymTab, Name, SF_ALLOC_NEW);
606     if (S->Flags & SF_IMPORT) {
607         /* The symbol is already marked as imported external symbol */
608         Error (ERR_SYM_ALREADY_IMPORT, Name);
609         return;
610     }
611
612     /* If the symbol is marked as global, silently remove the global flag */
613     if (S->Flags & SF_GLOBAL) {
614         S->Flags &= ~SF_GLOBAL;
615     }
616
617     /* Check if the symbol was not already defined as ZP symbol */
618     if ((S->Flags & SF_ZP) != 0) {
619         Error (ERR_SYM_REDECL_MISMATCH);
620     }
621
622     /* If the symbol was already declared as a condes, check if the new
623      * priority value is the same as the old one.
624      */
625     if (S->ConDesPrio[Type] != CD_PRIO_NONE) {
626         if (S->ConDesPrio[Type] != Prio) {
627             Error (ERR_SYM_REDECL_MISMATCH);
628         }
629     }
630     S->ConDesPrio[Type] = Prio;
631
632     /* Set the symbol data */
633     S->Flags |= SF_EXPORT | SF_REFERENCED;
634 }
635
636
637
638 int SymIsDef (const char* Name)
639 /* Return true if the given symbol is already defined */
640 {
641     SymEntry* S = SymFindAny (SymTab, Name);
642     return S != 0 && (S->Flags & SF_DEFINED) != 0;
643 }
644
645
646
647 int SymIsRef (const char* Name)
648 /* Return true if the given symbol has been referenced */
649 {
650     SymEntry* S = SymFindAny (SymTab, Name);
651     return S != 0 && (S->Flags & SF_REFERENCED) != 0;
652 }
653
654
655
656 int SymIsConst (SymEntry* S)
657 /* Return true if the given symbol has a constant value */
658 {
659     /* Resolve trampoline entries */
660     if (S->Flags & SF_TRAMPOLINE) {
661         S = S->V.Sym;
662     }
663
664     /* Check for constness */
665     if (S->Flags & SF_CONST) {
666         return 1;
667     } else if ((S->Flags & SF_DEFINED) && IsConstExpr (S->V.Expr)) {
668         /* Constant expression, remember the value */
669         ExprNode* Expr = S->V.Expr;
670         S->Flags |= SF_CONST;
671         S->V.Val = GetExprVal (Expr);
672         FreeExpr (Expr);
673         return 1;
674     }
675     return 0;
676 }
677
678
679
680 int SymIsZP (SymEntry* S)
681 /* Return true if the symbol is explicitly marked as zeropage symbol */
682 {
683     /* Resolve trampoline entries */
684     if (S->Flags & SF_TRAMPOLINE) {
685         S = S->V.Sym;
686     }
687
688     /* If the symbol is not a global symbol, was not defined before, check the
689      * enclosing scope for a symbol with the same name, and return the ZP
690      * attribute of this symbol if we find one.
691      */
692     if (!IsLocal (S->Name)                                              &&
693         (S->Flags & (SF_ZP | SF_ABS | SF_DEFINED | SF_IMPORT)) == 0     &&
694         S->SymTab->BackLink != 0) {
695
696         /* Try to find a symbol with the same name in the enclosing scope */
697         SymEntry* E = SymFindAny (S->SymTab->BackLink, S->Name);
698
699         /* If we found one, use the ZP flag */
700         if (E && (E->Flags & SF_ZP) != 0) {
701             S->Flags |= SF_ZP;
702         }
703     }
704
705     /* Check the ZP flag */
706     return (S->Flags & SF_ZP) != 0;
707 }
708
709
710
711 int SymIsImport (SymEntry* S)
712 /* Return true if the given symbol is marked as import */
713 {
714     /* Resolve trampoline entries */
715     if (S->Flags & SF_TRAMPOLINE) {
716         S = S->V.Sym;
717     }
718
719     /* Check the import flag */
720     return (S->Flags & SF_IMPORT) != 0;
721 }
722
723
724
725 int SymHasExpr (SymEntry* S)
726 /* Return true if the given symbol has an associated expression */
727 {
728     /* Resolve trampoline entries */
729     if (S->Flags & SF_TRAMPOLINE) {
730         S = S->V.Sym;
731     }
732
733     /* Check the expression */
734     return ((S->Flags & SF_DEFINED) != 0 &&
735             (S->Flags & SF_IMPORT)  == 0 &&
736             (S->Flags & SF_CONST)   == 0);
737 }
738
739
740
741 void SymFinalize (SymEntry* S)
742 /* Finalize a symbol expression if there is one */
743 {
744     /* Resolve trampoline entries */
745     if (S->Flags & SF_TRAMPOLINE) {
746         S = S->V.Sym;
747     }
748
749     /* Check if we have an expression */
750     if (SymHasExpr (S)) {
751         S->V.Expr = FinalizeExpr (S->V.Expr);
752     }
753 }
754
755
756
757 void SymMarkUser (SymEntry* S)
758 /* Set a user mark on the specified symbol */
759 {
760     /* Resolve trampoline entries */
761     if (S->Flags & SF_TRAMPOLINE) {
762         S = S->V.Sym;
763     }
764
765     /* Set the bit */
766     S->Flags |= SF_USER;
767 }
768
769
770
771 void SymUnmarkUser (SymEntry* S)
772 /* Remove a user mark from the specified symbol */
773 {
774     /* Resolve trampoline entries */
775     if (S->Flags & SF_TRAMPOLINE) {
776         S = S->V.Sym;
777     }
778
779     /* Reset the bit */
780     S->Flags &= ~SF_USER;
781 }
782
783
784
785 int SymHasUserMark (SymEntry* S)
786 /* Return the state of the user mark for the specified symbol */
787 {
788     /* Resolve trampoline entries */
789     if (S->Flags & SF_TRAMPOLINE) {
790         S = S->V.Sym;
791     }
792
793     /* Check the bit */
794     return (S->Flags & SF_USER) != 0;
795 }
796
797
798
799 long GetSymVal (SymEntry* S)
800 /* Return the symbol value */
801 {
802     /* Resolve trampoline entries */
803     if (S->Flags & SF_TRAMPOLINE) {
804         S = S->V.Sym;
805     }
806
807     PRECONDITION ((S->Flags & SF_DEFINED) != 0 && (S->Flags & SF_CONST) != 0);
808     return S->V.Val;
809 }
810
811
812
813 ExprNode* GetSymExpr (SymEntry* S)
814 /* Get the expression for a non-const symbol */
815 {
816     /* Resolve trampoline entries */
817     if (S->Flags & SF_TRAMPOLINE) {
818         S = S->V.Sym;
819     }
820
821     PRECONDITION (S != 0 && (S->Flags & SF_CONST) == 0);
822     return S->V.Expr;
823 }
824
825
826
827 const char* GetSymName (SymEntry* S)
828 /* Return the name of the symbol */
829 {
830     /* Resolve trampoline entries */
831     if (S->Flags & SF_TRAMPOLINE) {
832         S = S->V.Sym;
833     }
834     return S->Name;
835 }
836
837
838
839 unsigned GetSymIndex (SymEntry* S)
840 /* Return the symbol index for the given symbol */
841 {
842     /* Resolve trampoline entries */
843     if (S->Flags & SF_TRAMPOLINE) {
844         S = S->V.Sym;
845     }
846     PRECONDITION (S != 0 && (S->Flags & SF_INDEXED));
847     return S->Index;
848 }
849
850
851
852 const FilePos* GetSymPos (SymEntry* S)
853 /* Return the position of first occurence in the source for the given symbol */
854 {
855     /* Resolve trampoline entries */
856     if (S->Flags & SF_TRAMPOLINE) {
857         S = S->V.Sym;
858     }
859     PRECONDITION (S != 0);
860     return &S->Pos;
861 }
862
863
864
865 static void SymCheckUndefined (SymEntry* S)
866 /* Handle an undefined symbol */
867 {
868     /* Undefined symbol. It may be...
869      *
870      *   - An undefined symbol in a nested lexical level. In this
871      *     case, search for the symbol in the higher levels and
872      *     make the entry a trampoline entry if we find one.
873      *
874      *   - If the symbol is not found, it is a real undefined symbol.
875      *     If the AutoImport flag is set, make it an import. If the
876      *     AutoImport flag is not set, it's an error.
877      */
878     SymEntry* Sym = 0;
879     if (S->SymTab) {
880         /* It's a global symbol, get the higher level table */
881         SymTable* Tab = S->SymTab->BackLink;
882         while (Tab) {
883             Sym = SymFindAny (Tab, S->Name);
884             if (Sym) {
885                 if (Sym->Flags & (SF_DEFINED | SF_IMPORT)) {
886                     /* We've found a symbol in a higher level that is
887                      * either defined in the source, or an import.
888                      */
889                      break;
890                 } else {
891                     /* The symbol found is undefined itself. Look further */
892                     Tab = Sym->SymTab->BackLink;
893                 }
894             } else {
895                 /* No symbol found */
896                 break;
897             }
898         }
899     }
900     if (Sym) {
901         /* We found the symbol in a higher level. Make S a trampoline
902          * symbol. Beware: We have to transfer the symbol attributes to
903          * the real symbol and check for any conflicts.
904          */
905         S->Flags |= SF_TRAMPOLINE;
906         S->V.Sym = Sym;
907
908         /* Transfer the flags. Note: S may not be imported, since in that
909          * case it wouldn't be undefined.
910          */
911         if (S->Flags & SF_EXPORT) {
912             if (Sym->Flags & SF_IMPORT) {
913                 /* The symbol is already marked as imported external symbol */
914                 PError (&S->Pos, ERR_SYM_ALREADY_IMPORT, S->Name);
915             }
916             Sym->Flags |= S->Flags & (SF_EXPORT | SF_ZP);
917         }
918
919         /* Transfer the referenced flag */
920         Sym->Flags |= (S->Flags & SF_REFERENCED);
921
922     } else {
923         /* The symbol is definitely undefined */
924         if (S->Flags & SF_EXPORT) {
925             /* We will not auto-import an export */
926             PError (&S->Pos, ERR_EXPORT_UNDEFINED, S->Name);
927         } else {
928             if (AutoImport) {
929                 /* Mark as import, will be indexed later */
930                 S->Flags |= SF_IMPORT;
931             } else {
932                 /* Error */
933                 PError (&S->Pos, ERR_SYM_UNDEFINED, S->Name);
934             }
935         }
936     }
937 }
938
939
940
941 void SymCheck (void)
942 /* Run through all symbols and check for anomalies and errors */
943 {
944     SymEntry* S;
945
946     /* Check for open lexical levels */
947     if (SymTab->BackLink != 0) {
948         Error (ERR_OPEN_PROC);
949     }
950
951     /* First pass: Walk through all symbols, checking for undefined's and
952      * changing them to trampoline symbols or make them imports.
953      */
954     S = SymList;
955     while (S) {
956         /* If the symbol is marked as global, mark it as export, if it is
957          * already defined, otherwise mark it as import.
958          */
959         if (S->Flags & SF_GLOBAL) {
960             S->Flags &= ~SF_GLOBAL;
961             if (S->Flags & SF_DEFINED) {
962                 S->Flags |= SF_EXPORT;
963             } else {
964                 S->Flags |= SF_IMPORT;
965             }
966         }
967
968         /* Handle undefined symbols */
969         if ((S->Flags & SF_UNDEFMASK) == SF_UNDEFVAL) {
970             /* This is an undefined symbol. Handle it. */
971             SymCheckUndefined (S);
972         }
973
974         /* Next symbol */
975         S = S->List;
976     }
977
978     /* Second pass: Walk again through the symbols. Ignore undefined's, since
979      * we handled them in the last pass, and ignore trampoline symbols, since
980      * we handled them in the last pass, too.
981      */
982     S = SymList;
983     while (S) {
984         if ((S->Flags & SF_TRAMPOLINE) == 0 &&
985             (S->Flags & SF_UNDEFMASK) != SF_UNDEFVAL) {
986             if ((S->Flags & SF_DEFINED) != 0 && (S->Flags & SF_REFERENCED) == 0) {
987                 /* Symbol was defined but never referenced */
988                 PWarning (&S->Pos, WARN_SYM_NOT_REFERENCED, S->Name);
989             }
990             if (S->Flags & SF_IMPORT) {
991                 if ((S->Flags & SF_REFERENCED) == 0) {
992                     /* Imported symbol is not referenced */
993                     PWarning (&S->Pos, WARN_IMPORT_NOT_REFERENCED, S->Name);
994                 } else {
995                     /* Give the import an index, count imports */
996                     S->Index = ImportCount++;
997                     S->Flags |= SF_INDEXED;
998                 }
999             }
1000             if (S->Flags & SF_EXPORT) {
1001                 /* Give the export an index, count exports */
1002                 S->Index = ExportCount++;
1003                 S->Flags |= SF_INDEXED;
1004             }
1005         }
1006
1007         /* Next symbol */
1008         S = S->List;
1009     }
1010 }
1011
1012
1013
1014 void SymDump (FILE* F)
1015 /* Dump the symbol table */
1016 {
1017     SymEntry* S = SymList;
1018
1019     while (S) {
1020         /* Ignore trampoline symbols */
1021         if ((S->Flags & SF_TRAMPOLINE) != 0) {
1022             printf ("%-24s %s %s %s %s %s\n",
1023                     S->Name,
1024                     (S->Flags & SF_DEFINED)? "DEF" : "---",
1025                     (S->Flags & SF_REFERENCED)? "REF" : "---",
1026                     (S->Flags & SF_IMPORT)? "IMP" : "---",
1027                     (S->Flags & SF_EXPORT)? "EXP" : "---",
1028                     (S->Flags & SF_ZP)? "ZP" : "--");
1029         }
1030         /* Next symbol */
1031         S = S->List;
1032     }
1033 }
1034
1035
1036
1037 void WriteImports (void)
1038 /* Write the imports list to the object file */
1039 {
1040     SymEntry* S;
1041
1042     /* Tell the object file module that we're about to start the imports */
1043     ObjStartImports ();
1044
1045     /* Write the import count to the list */
1046     ObjWriteVar (ImportCount);
1047
1048     /* Walk throught list and write all imports to the file */
1049     S = SymList;
1050     while (S) {
1051         if ((S->Flags & SF_IMPMASK) == SF_IMPVAL) {
1052             if (S->Flags & SF_ZP) {
1053                 ObjWrite8 (IMP_ZP);
1054             } else {
1055                 ObjWrite8 (IMP_ABS);
1056             }
1057             ObjWriteStr (S->Name);
1058             ObjWritePos (&S->Pos);
1059         }
1060         S = S->List;
1061     }
1062
1063     /* Done writing imports */
1064     ObjEndImports ();
1065 }
1066
1067
1068
1069 static unsigned char GetExprMask (SymEntry* S)
1070 /* Return the expression bits for the given symbol table entry */
1071 {
1072     unsigned char ExprMask;
1073
1074     /* Check if the symbol is const */
1075     ExprMask = (SymIsConst (S))? EXP_CONST : EXP_EXPR;
1076
1077     /* Add zeropage/abs bits */
1078     ExprMask |= (S->Flags & SF_ZP)? EXP_ZP : EXP_ABS;
1079
1080     /* Add the label/equate bits */
1081     ExprMask |= (S->Flags & SF_LABEL)? EXP_LABEL : EXP_EQUATE;
1082
1083     /* Return the mask */
1084     return ExprMask;
1085 }
1086
1087
1088
1089 void WriteExports (void)
1090 /* Write the exports list to the object file */
1091 {
1092     SymEntry* S;
1093     unsigned Type;
1094
1095     /* Tell the object file module that we're about to start the exports */
1096     ObjStartExports ();
1097
1098     /* Write the export count to the list */
1099     ObjWriteVar (ExportCount);
1100
1101     /* Walk throught list and write all exports to the file */
1102     S = SymList;
1103     while (S) {
1104         if ((S->Flags & SF_EXPMASK) == SF_EXPVAL) {
1105             unsigned char ExprMask;
1106
1107             /* Finalize an associated expression if we have one */
1108             SymFinalize (S);
1109
1110             /* Get the expression bits */
1111             ExprMask = GetExprMask (S);
1112
1113             /* Count the number of ConDes types */
1114             for (Type = 0; Type < CD_TYPE_COUNT; ++Type) {
1115                 if (S->ConDesPrio[Type] != CD_PRIO_NONE) {
1116                     INC_EXP_CONDES_COUNT (ExprMask);
1117                 }
1118             }
1119
1120             /* Write the type */
1121             ObjWrite8 (ExprMask);
1122
1123             /* Write any ConDes declarations */
1124             if (GET_EXP_CONDES_COUNT (ExprMask) > 0) {
1125                 for (Type = 0; Type < CD_TYPE_COUNT; ++Type) {
1126                     unsigned char Prio = S->ConDesPrio[Type];
1127                     if (Prio != CD_PRIO_NONE) {
1128                         ObjWrite8 (CD_BUILD (Type, Prio));
1129                     }
1130                 }
1131             }
1132
1133             /* Write the name */
1134             ObjWriteStr (S->Name);
1135
1136             /* Write the value */
1137             if ((ExprMask & EXP_MASK_VAL) == EXP_CONST) {
1138                 /* Constant value */
1139                 ObjWrite32 (S->V.Val);
1140             } else {
1141                 /* Expression involved */
1142                 WriteExpr (S->V.Expr);
1143             }
1144
1145             /* Write the source file position */
1146             ObjWritePos (&S->Pos);
1147         }
1148         S = S->List;
1149     }
1150
1151     /* Done writing exports */
1152     ObjEndExports ();
1153 }
1154
1155
1156
1157 void WriteDbgSyms (void)
1158 /* Write a list of all symbols to the object file */
1159 {
1160     unsigned Count;
1161     SymEntry* S;
1162
1163     /* Tell the object file module that we're about to start the debug info */
1164     ObjStartDbgSyms ();
1165
1166     /* Check if debug info is requested */
1167     if (DbgSyms) {
1168
1169         /* Walk through the list and count the symbols */
1170         Count = 0;
1171         S = SymList;
1172         while (S) {
1173             if ((S->Flags & SF_DBGINFOMASK) == SF_DBGINFOVAL) {
1174                 ++Count;
1175             }
1176             S = S->List;
1177         }
1178
1179         /* Write the symbol count to the list */
1180         ObjWriteVar (Count);
1181
1182         /* Walk through list and write all symbols to the file */
1183         S = SymList;
1184         while (S) {
1185             if ((S->Flags & SF_DBGINFOMASK) == SF_DBGINFOVAL) {
1186                 unsigned char ExprMask;
1187
1188                 /* Finalize an associated expression if we have one */
1189                 SymFinalize (S);
1190
1191                 /* Get the expression bits */
1192                 ExprMask = GetExprMask (S);
1193
1194                 /* Write the type */
1195                 ObjWrite8 (ExprMask);
1196
1197                 /* Write the name */
1198                 ObjWriteStr (S->Name);
1199
1200                 /* Write the value */
1201                 if ((ExprMask & EXP_MASK_VAL) == EXP_CONST) {
1202                     /* Constant value */
1203                     ObjWrite32 (S->V.Val);
1204                 } else {
1205                     /* Expression involved */
1206                     WriteExpr (S->V.Expr);
1207                 }
1208
1209                 /* Write the source file position */
1210                 ObjWritePos (&S->Pos);
1211             }
1212             S = S->List;
1213         }
1214
1215     } else {
1216
1217         /* No debug symbols */
1218         ObjWriteVar (0);
1219
1220     }
1221
1222     /* Done writing debug symbols */
1223     ObjEndDbgSyms ();
1224 }
1225
1226
1227