]> git.sur5r.net Git - cc65/blob - src/ca65/symtab.c
Add co65 utility
[cc65] / src / ca65 / symtab.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 symtab.c                                  */
4 /*                                                                           */
5 /*                 Symbol table for the ca65 macroassembler                  */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 1998-2002 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, SF_FIND_EXISTING);
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 void SymEnterLevel (void)
364 /* Enter a new lexical level */
365 {
366     if (RootTab == 0) {
367         /* Create the main symbol table */
368         RootTab = SymTab = NewSymTable (MAIN_HASHTAB_SIZE);
369     } else {
370         /* Create a local symbol table */
371         SymTable* LocalSyms;
372         LocalSyms = NewSymTable (SUB_HASHTAB_SIZE);
373         LocalSyms->BackLink = SymTab;
374         SymTab = LocalSyms;
375     }
376 }
377
378
379
380 void SymLeaveLevel (void)
381 /* Leave the current lexical level */
382 {
383     SymTab = SymTab->BackLink;
384 }
385
386
387
388 void SymDef (const char* Name, ExprNode* Expr, int ZP, int Label)
389 /* Define a new symbol */
390 {
391     /* Do we have such a symbol? */
392     SymEntry* S = SymFind (SymTab, Name, SF_ALLOC_NEW);
393     if (S->Flags & SF_IMPORT) {
394         /* Defined symbol is marked as imported external symbol */
395         Error (ERR_SYM_ALREADY_IMPORT, Name);
396         return;
397     }
398     if (S->Flags & SF_DEFINED) {
399         /* Multiple definition */
400         Error (ERR_SYM_ALREADY_DEFINED, Name);
401         S->Flags |= SF_MULTDEF;
402         return;
403     }
404
405     /* Set the symbol data */
406     if (IsConstExpr (Expr)) {
407         /* Expression is const, store the value */
408         S->Flags |= SF_CONST;
409         S->V.Val = GetExprVal (Expr);
410         FreeExpr (Expr);
411     } else {
412         /* Not const, store the expression */
413         S->V.Expr  = Expr;
414     }
415     S->Flags |= SF_DEFINED;
416     if (ZP) {
417         S->Flags |= SF_ZP;
418     }
419     if (Label) {
420         S->Flags |= SF_LABEL;
421     }
422
423     /* If the symbol is a ZP symbol, check if the value is in correct range */
424     if (S->Flags & SF_ZP) {
425         /* Already marked as ZP symbol by some means */
426         if (!IsByteExpr (Expr)) {
427             Error (ERR_RANGE);
428         }
429     }
430
431     /* If this is not a local symbol, remember it as the last global one */
432     if (!IsLocal (Name)) {
433         SymLast = S;
434     }
435 }
436
437
438
439 SymEntry* SymRef (const char* Name, int Scope)
440 /* Search for the symbol and return it */
441 {
442     SymEntry* S;
443
444     switch (Scope) {
445         case SCOPE_GLOBAL:  S = SymFind (RootTab, Name, SF_ALLOC_NEW);  break;
446         case SCOPE_LOCAL:   S = SymFind (SymTab, Name, SF_ALLOC_NEW);   break;
447
448         /* Others are not allowed */
449         case SCOPE_ANY:
450         default:
451             Internal ("Invalid scope in SymRef: %d", Scope);
452             /* NOTREACHED */
453             S = 0;
454     }
455
456     /* Mark the symbol as referenced */
457     S->Flags |= SF_REFERENCED;
458
459     /* Return it */
460     return S;
461 }
462
463
464
465 void SymImport (const char* Name, int ZP)
466 /* Mark the given symbol as an imported symbol */
467 {
468     SymEntry* S;
469
470     /* Don't accept local symbols */
471     if (IsLocal (Name)) {
472         Error (ERR_ILLEGAL_LOCAL_USE);
473         return;
474     }
475
476     /* Do we have such a symbol? */
477     S = SymFind (SymTab, Name, SF_ALLOC_NEW);
478     if (S->Flags & SF_DEFINED) {
479         Error (ERR_SYM_ALREADY_DEFINED, Name);
480         S->Flags |= SF_MULTDEF;
481         return;
482     }
483     if (S->Flags & SF_EXPORT) {
484         /* The symbol is already marked as exported symbol */
485         Error (ERR_SYM_ALREADY_EXPORT, Name);
486         return;
487     }
488
489     /* If the symbol is marked as global, check the symbol size, then do
490      * silently remove the global flag
491      */
492     if (S->Flags & SF_GLOBAL) {
493         if ((ZP != 0) != ((S->Flags & SF_ZP) != 0)) {
494             Error (ERR_SYM_REDECL_MISMATCH, Name);
495         }
496         S->Flags &= ~SF_GLOBAL;
497     }
498
499     /* Set the symbol data */
500     S->Flags |= SF_IMPORT;
501     if (ZP) {
502         S->Flags |= SF_ZP;
503     }
504 }
505
506
507
508 void SymExport (const char* Name, int ZP)
509 /* Mark the given symbol as an exported symbol */
510 {
511     SymEntry* S;
512
513     /* Don't accept local symbols */
514     if (IsLocal (Name)) {
515         Error (ERR_ILLEGAL_LOCAL_USE);
516         return;
517     }
518
519     /* Do we have such a symbol? */
520     S = SymFind (SymTab, Name, SF_ALLOC_NEW);
521     if (S->Flags & SF_IMPORT) {
522         /* The symbol is already marked as imported external symbol */
523         Error (ERR_SYM_ALREADY_IMPORT, Name);
524         return;
525     }
526
527     /* If the symbol is marked as global, check the symbol size, then do
528      * silently remove the global flag
529      */
530     if (S->Flags & SF_GLOBAL) {
531         if ((ZP != 0) != ((S->Flags & SF_ZP) != 0)) {
532             Error (ERR_SYM_REDECL_MISMATCH, Name);
533         }
534         S->Flags &= ~SF_GLOBAL;
535     }
536
537     /* Set the symbol data */
538     S->Flags |= SF_EXPORT | SF_REFERENCED;
539     if (ZP) {
540         S->Flags |= SF_ZP;
541     }
542 }
543
544
545
546 void SymGlobal (const char* Name, int ZP)
547 /* Mark the given symbol as a global symbol, that is, as a symbol that is
548  * either imported or exported.
549  */
550 {
551     SymEntry* S;
552
553     /* Don't accept local symbols */
554     if (IsLocal (Name)) {
555         Error (ERR_ILLEGAL_LOCAL_USE);
556         return;
557     }
558
559     /* Search for this symbol, create a new entry if needed */
560     S = SymFind (SymTab, Name, SF_ALLOC_NEW);
561
562     /* If the symbol is already marked as import or export, check the
563      * size of the definition, then bail out. */
564     if (S->Flags & SF_IMPORT || S->Flags & SF_EXPORT) {
565         if ((ZP != 0) != ((S->Flags & SF_ZP) != 0)) {
566             Error (ERR_SYM_REDECL_MISMATCH, Name);
567         }
568         return;
569     }
570
571     /* Mark the symbol */
572     S->Flags |= SF_GLOBAL;
573     if (ZP) {
574         S->Flags |= SF_ZP;
575     }
576 }
577
578
579
580 void SymConDes (const char* Name, unsigned Type, unsigned Prio)
581 /* Mark the given symbol as a module constructor/destructor. This will also
582  * mark the symbol as an export. Initializers may never be zero page symbols.
583  */
584 {
585     SymEntry* S;
586
587     /* Check the parameters */
588 #if (CD_TYPE_MIN != 0)
589     CHECK (Type >= CD_TYPE_MIN && Type <= CD_TYPE_MAX);
590 #else
591     CHECK (Type <= CD_TYPE_MAX);
592 #endif
593     CHECK (Prio >= CD_PRIO_MIN && Prio <= CD_PRIO_MAX);
594
595     /* Don't accept local symbols */
596     if (IsLocal (Name)) {
597         Error (ERR_ILLEGAL_LOCAL_USE);
598         return;
599     }
600
601     /* Do we have such a symbol? */
602     S = SymFind (SymTab, Name, SF_ALLOC_NEW);
603     if (S->Flags & SF_IMPORT) {
604         /* The symbol is already marked as imported external symbol */
605         Error (ERR_SYM_ALREADY_IMPORT, Name);
606         return;
607     }
608
609     /* If the symbol is marked as global, silently remove the global flag */
610     if (S->Flags & SF_GLOBAL) {
611         S->Flags &= ~SF_GLOBAL;
612     }
613
614     /* Check if the symbol was not already defined as ZP symbol */
615     if ((S->Flags & SF_ZP) != 0) {
616         Error (ERR_SYM_REDECL_MISMATCH, Name);
617     }
618
619     /* If the symbol was already declared as a condes, check if the new
620      * priority value is the same as the old one.
621      */
622     if (S->ConDesPrio[Type] != CD_PRIO_NONE) {
623         if (S->ConDesPrio[Type] != Prio) {
624             Error (ERR_SYM_REDECL_MISMATCH, Name);
625         }
626     }
627     S->ConDesPrio[Type] = Prio;
628
629     /* Set the symbol data */
630     S->Flags |= SF_EXPORT | SF_REFERENCED;
631 }
632
633
634
635 int SymIsDef (const char* Name, int Scope)
636 /* Return true if the given symbol is already defined */
637 {
638     SymEntry* S = 0;
639
640     /* Search for the symbol */
641     switch (Scope) {
642         case SCOPE_ANY:    S = SymFindAny (SymTab, Name);                 break;
643         case SCOPE_GLOBAL: S = SymFind (RootTab, Name, SF_FIND_EXISTING); break;
644         case SCOPE_LOCAL:  S = SymFind (SymTab, Name, SF_FIND_EXISTING);  break;
645         default:           Internal ("Invalid scope in SymIsDef: %d", Scope);
646     }
647
648     /* Check if it's defined */
649     return S != 0 && (S->Flags & SF_DEFINED) != 0;
650 }
651
652
653
654 int SymIsRef (const char* Name, int Scope)
655 /* Return true if the given symbol has been referenced */
656 {
657     SymEntry* S = 0;
658
659     /* Search for the symbol */
660     switch (Scope) {
661         case SCOPE_ANY:    S = SymFindAny (SymTab, Name);                 break;
662         case SCOPE_GLOBAL: S = SymFind (RootTab, Name, SF_FIND_EXISTING); break;
663         case SCOPE_LOCAL:  S = SymFind (SymTab, Name, SF_FIND_EXISTING);  break;
664         default:           Internal ("Invalid scope in SymIsRef: %d", Scope);
665     }
666
667     /* Check if it's defined */
668     return S != 0 && (S->Flags & SF_REFERENCED) != 0;
669 }
670
671
672
673 int SymIsConst (SymEntry* S)
674 /* Return true if the given symbol has a constant value */
675 {
676     /* Resolve trampoline entries */
677     if (S->Flags & SF_TRAMPOLINE) {
678         S = S->V.Sym;
679     }
680
681     /* Check for constness */
682     if (S->Flags & SF_CONST) {
683         return 1;
684     } else if ((S->Flags & SF_DEFINED) && IsConstExpr (S->V.Expr)) {
685         /* Constant expression, remember the value */
686         ExprNode* Expr = S->V.Expr;
687         S->Flags |= SF_CONST;
688         S->V.Val = GetExprVal (Expr);
689         FreeExpr (Expr);
690         return 1;
691     }
692     return 0;
693 }
694
695
696
697 int SymIsZP (SymEntry* S)
698 /* Return true if the symbol is explicitly marked as zeropage symbol */
699 {
700     /* Resolve trampoline entries */
701     if (S->Flags & SF_TRAMPOLINE) {
702         S = S->V.Sym;
703     }
704
705     /* If the symbol is not a global symbol, was not defined before, check the
706      * enclosing scope for a symbol with the same name, and return the ZP
707      * attribute of this symbol if we find one.
708      */
709     if (!IsLocal (S->Name)                                              &&
710         (S->Flags & (SF_ZP | SF_ABS | SF_DEFINED | SF_IMPORT)) == 0     &&
711         S->SymTab->BackLink != 0) {
712
713         /* Try to find a symbol with the same name in the enclosing scope */
714         SymEntry* E = SymFindAny (S->SymTab->BackLink, S->Name);
715
716         /* If we found one, use the ZP flag */
717         if (E && (E->Flags & SF_ZP) != 0) {
718             S->Flags |= SF_ZP;
719         }
720     }
721
722     /* Check the ZP flag */
723     return (S->Flags & SF_ZP) != 0;
724 }
725
726
727
728 int SymIsImport (SymEntry* S)
729 /* Return true if the given symbol is marked as import */
730 {
731     /* Resolve trampoline entries */
732     if (S->Flags & SF_TRAMPOLINE) {
733         S = S->V.Sym;
734     }
735
736     /* Check the import flag */
737     return (S->Flags & SF_IMPORT) != 0;
738 }
739
740
741
742 int SymHasExpr (SymEntry* S)
743 /* Return true if the given symbol has an associated expression */
744 {
745     /* Resolve trampoline entries */
746     if (S->Flags & SF_TRAMPOLINE) {
747         S = S->V.Sym;
748     }
749
750     /* Check the expression */
751     return ((S->Flags & SF_DEFINED) != 0 &&
752             (S->Flags & SF_IMPORT)  == 0 &&
753             (S->Flags & SF_CONST)   == 0);
754 }
755
756
757
758 void SymFinalize (SymEntry* S)
759 /* Finalize a symbol expression if there is one */
760 {
761     /* Resolve trampoline entries */
762     if (S->Flags & SF_TRAMPOLINE) {
763         S = S->V.Sym;
764     }
765
766     /* Check if we have an expression */
767     if (SymHasExpr (S)) {
768         S->V.Expr = FinalizeExpr (S->V.Expr);
769     }
770 }
771
772
773
774 void SymMarkUser (SymEntry* S)
775 /* Set a user mark on the specified symbol */
776 {
777     /* Resolve trampoline entries */
778     if (S->Flags & SF_TRAMPOLINE) {
779         S = S->V.Sym;
780     }
781
782     /* Set the bit */
783     S->Flags |= SF_USER;
784 }
785
786
787
788 void SymUnmarkUser (SymEntry* S)
789 /* Remove a user mark from the specified symbol */
790 {
791     /* Resolve trampoline entries */
792     if (S->Flags & SF_TRAMPOLINE) {
793         S = S->V.Sym;
794     }
795
796     /* Reset the bit */
797     S->Flags &= ~SF_USER;
798 }
799
800
801
802 int SymHasUserMark (SymEntry* S)
803 /* Return the state of the user mark for the specified symbol */
804 {
805     /* Resolve trampoline entries */
806     if (S->Flags & SF_TRAMPOLINE) {
807         S = S->V.Sym;
808     }
809
810     /* Check the bit */
811     return (S->Flags & SF_USER) != 0;
812 }
813
814
815
816 long GetSymVal (SymEntry* S)
817 /* Return the symbol value */
818 {
819     /* Resolve trampoline entries */
820     if (S->Flags & SF_TRAMPOLINE) {
821         S = S->V.Sym;
822     }
823
824     PRECONDITION ((S->Flags & SF_DEFINED) != 0 && (S->Flags & SF_CONST) != 0);
825     return S->V.Val;
826 }
827
828
829
830 ExprNode* GetSymExpr (SymEntry* S)
831 /* Get the expression for a non-const symbol */
832 {
833     /* Resolve trampoline entries */
834     if (S->Flags & SF_TRAMPOLINE) {
835         S = S->V.Sym;
836     }
837
838     PRECONDITION (S != 0 && (S->Flags & SF_CONST) == 0);
839     return S->V.Expr;
840 }
841
842
843
844 const char* GetSymName (SymEntry* S)
845 /* Return the name of the symbol */
846 {
847     /* Resolve trampoline entries */
848     if (S->Flags & SF_TRAMPOLINE) {
849         S = S->V.Sym;
850     }
851     return S->Name;
852 }
853
854
855
856 unsigned GetSymIndex (SymEntry* S)
857 /* Return the symbol index for the given symbol */
858 {
859     /* Resolve trampoline entries */
860     if (S->Flags & SF_TRAMPOLINE) {
861         S = S->V.Sym;
862     }
863     PRECONDITION (S != 0 && (S->Flags & SF_INDEXED));
864     return S->Index;
865 }
866
867
868
869 const FilePos* GetSymPos (SymEntry* S)
870 /* Return the position of first occurence in the source for the given symbol */
871 {
872     /* Resolve trampoline entries */
873     if (S->Flags & SF_TRAMPOLINE) {
874         S = S->V.Sym;
875     }
876     PRECONDITION (S != 0);
877     return &S->Pos;
878 }
879
880
881
882 static void SymCheckUndefined (SymEntry* S)
883 /* Handle an undefined symbol */
884 {
885     /* Undefined symbol. It may be...
886      *
887      *   - An undefined symbol in a nested lexical level. In this
888      *     case, search for the symbol in the higher levels and
889      *     make the entry a trampoline entry if we find one.
890      *
891      *   - If the symbol is not found, it is a real undefined symbol.
892      *     If the AutoImport flag is set, make it an import. If the
893      *     AutoImport flag is not set, it's an error.
894      */
895     SymEntry* Sym = 0;
896     if (S->SymTab) {
897         /* It's a global symbol, get the higher level table */
898         SymTable* Tab = S->SymTab->BackLink;
899         while (Tab) {
900             Sym = SymFindAny (Tab, S->Name);
901             if (Sym) {
902                 if (Sym->Flags & (SF_DEFINED | SF_IMPORT)) {
903                     /* We've found a symbol in a higher level that is
904                      * either defined in the source, or an import.
905                      */
906                      break;
907                 } else {
908                     /* The symbol found is undefined itself. Look further */
909                     Tab = Sym->SymTab->BackLink;
910                 }
911             } else {
912                 /* No symbol found */
913                 break;
914             }
915         }
916     }
917     if (Sym) {
918         /* We found the symbol in a higher level. Make S a trampoline
919          * symbol. Beware: We have to transfer the symbol attributes to
920          * the real symbol and check for any conflicts.
921          */
922         S->Flags |= SF_TRAMPOLINE;
923         S->V.Sym = Sym;
924
925         /* Transfer the flags. Note: S may not be imported, since in that
926          * case it wouldn't be undefined.
927          */
928         if (S->Flags & SF_EXPORT) {
929             if (Sym->Flags & SF_IMPORT) {
930                 /* The symbol is already marked as imported external symbol */
931                 PError (&S->Pos, ERR_SYM_ALREADY_IMPORT, S->Name);
932             }
933             Sym->Flags |= S->Flags & (SF_EXPORT | SF_ZP);
934         }
935
936         /* Transfer the referenced flag */
937         Sym->Flags |= (S->Flags & SF_REFERENCED);
938
939     } else {
940         /* The symbol is definitely undefined */
941         if (S->Flags & SF_EXPORT) {
942             /* We will not auto-import an export */
943             PError (&S->Pos, ERR_EXPORT_UNDEFINED, S->Name);
944         } else {
945             if (AutoImport) {
946                 /* Mark as import, will be indexed later */
947                 S->Flags |= SF_IMPORT;
948             } else {
949                 /* Error */
950                 PError (&S->Pos, ERR_SYM_UNDEFINED, S->Name);
951             }
952         }
953     }
954 }
955
956
957
958 void SymCheck (void)
959 /* Run through all symbols and check for anomalies and errors */
960 {
961     SymEntry* S;
962
963     /* Check for open lexical levels */
964     if (SymTab->BackLink != 0) {
965         Error (ERR_OPEN_PROC);
966     }
967
968     /* First pass: Walk through all symbols, checking for undefined's and
969      * changing them to trampoline symbols or make them imports.
970      */
971     S = SymList;
972     while (S) {
973         /* If the symbol is marked as global, mark it as export, if it is
974          * already defined, otherwise mark it as import.
975          */
976         if (S->Flags & SF_GLOBAL) {
977             S->Flags &= ~SF_GLOBAL;
978             if (S->Flags & SF_DEFINED) {
979                 S->Flags |= SF_EXPORT;
980             } else {
981                 S->Flags |= SF_IMPORT;
982             }
983         }
984
985         /* Handle undefined symbols */
986         if ((S->Flags & SF_UNDEFMASK) == SF_UNDEFVAL) {
987             /* This is an undefined symbol. Handle it. */
988             SymCheckUndefined (S);
989         }
990
991         /* Next symbol */
992         S = S->List;
993     }
994
995     /* Second pass: Walk again through the symbols. Ignore undefined's, since
996      * we handled them in the last pass, and ignore trampoline symbols, since
997      * we handled them in the last pass, too.
998      */
999     S = SymList;
1000     while (S) {
1001         if ((S->Flags & SF_TRAMPOLINE) == 0 &&
1002             (S->Flags & SF_UNDEFMASK) != SF_UNDEFVAL) {
1003             if ((S->Flags & SF_DEFINED) != 0 && (S->Flags & SF_REFERENCED) == 0) {
1004                 /* Symbol was defined but never referenced */
1005                 PWarning (&S->Pos, WARN_SYM_NOT_REFERENCED, S->Name);
1006             }
1007             if (S->Flags & SF_IMPORT) {
1008                 if ((S->Flags & SF_REFERENCED) == 0) {
1009                     /* Imported symbol is not referenced */
1010                     PWarning (&S->Pos, WARN_IMPORT_NOT_REFERENCED, S->Name);
1011                 } else {
1012                     /* Give the import an index, count imports */
1013                     S->Index = ImportCount++;
1014                     S->Flags |= SF_INDEXED;
1015                 }
1016             }
1017             if (S->Flags & SF_EXPORT) {
1018                 /* Give the export an index, count exports */
1019                 S->Index = ExportCount++;
1020                 S->Flags |= SF_INDEXED;
1021             }
1022         }
1023
1024         /* Next symbol */
1025         S = S->List;
1026     }
1027 }
1028
1029
1030
1031 void SymDump (FILE* F)
1032 /* Dump the symbol table */
1033 {
1034     SymEntry* S = SymList;
1035
1036     while (S) {
1037         /* Ignore trampoline symbols */
1038         if ((S->Flags & SF_TRAMPOLINE) != 0) {
1039             fprintf (F,
1040                      "%-24s %s %s %s %s %s\n",
1041                      S->Name,
1042                      (S->Flags & SF_DEFINED)? "DEF" : "---",
1043                      (S->Flags & SF_REFERENCED)? "REF" : "---",
1044                      (S->Flags & SF_IMPORT)? "IMP" : "---",
1045                      (S->Flags & SF_EXPORT)? "EXP" : "---",
1046                      (S->Flags & SF_ZP)? "ZP" : "--");
1047         }
1048         /* Next symbol */
1049         S = S->List;
1050     }
1051 }
1052
1053
1054
1055 void WriteImports (void)
1056 /* Write the imports list to the object file */
1057 {
1058     SymEntry* S;
1059
1060     /* Tell the object file module that we're about to start the imports */
1061     ObjStartImports ();
1062
1063     /* Write the import count to the list */
1064     ObjWriteVar (ImportCount);
1065
1066     /* Walk throught list and write all imports to the file */
1067     S = SymList;
1068     while (S) {
1069         if ((S->Flags & SF_IMPMASK) == SF_IMPVAL) {
1070             if (S->Flags & SF_ZP) {
1071                 ObjWrite8 (IMP_ZP);
1072             } else {
1073                 ObjWrite8 (IMP_ABS);
1074             }
1075             ObjWriteStr (S->Name);
1076             ObjWritePos (&S->Pos);
1077         }
1078         S = S->List;
1079     }
1080
1081     /* Done writing imports */
1082     ObjEndImports ();
1083 }
1084
1085
1086
1087 static unsigned char GetExprMask (SymEntry* S)
1088 /* Return the expression bits for the given symbol table entry */
1089 {
1090     unsigned char ExprMask;
1091
1092     /* Check if the symbol is const */
1093     ExprMask = (SymIsConst (S))? EXP_CONST : EXP_EXPR;
1094
1095     /* Add zeropage/abs bits */
1096     ExprMask |= (S->Flags & SF_ZP)? EXP_ZP : EXP_ABS;
1097
1098     /* Add the label/equate bits */
1099     ExprMask |= (S->Flags & SF_LABEL)? EXP_LABEL : EXP_EQUATE;
1100
1101     /* Return the mask */
1102     return ExprMask;
1103 }
1104
1105
1106
1107 void WriteExports (void)
1108 /* Write the exports list to the object file */
1109 {
1110     SymEntry* S;
1111     unsigned Type;
1112
1113     /* Tell the object file module that we're about to start the exports */
1114     ObjStartExports ();
1115
1116     /* Write the export count to the list */
1117     ObjWriteVar (ExportCount);
1118
1119     /* Walk throught list and write all exports to the file */
1120     S = SymList;
1121     while (S) {
1122         if ((S->Flags & SF_EXPMASK) == SF_EXPVAL) {
1123             unsigned char ExprMask;
1124
1125             /* Finalize an associated expression if we have one */
1126             SymFinalize (S);
1127
1128             /* Get the expression bits */
1129             ExprMask = GetExprMask (S);
1130
1131             /* Count the number of ConDes types */
1132             for (Type = 0; Type < CD_TYPE_COUNT; ++Type) {
1133                 if (S->ConDesPrio[Type] != CD_PRIO_NONE) {
1134                     INC_EXP_CONDES_COUNT (ExprMask);
1135                 }
1136             }
1137
1138             /* Write the type */
1139             ObjWrite8 (ExprMask);
1140
1141             /* Write any ConDes declarations */
1142             if (GET_EXP_CONDES_COUNT (ExprMask) > 0) {
1143                 for (Type = 0; Type < CD_TYPE_COUNT; ++Type) {
1144                     unsigned char Prio = S->ConDesPrio[Type];
1145                     if (Prio != CD_PRIO_NONE) {
1146                         ObjWrite8 (CD_BUILD (Type, Prio));
1147                     }
1148                 }
1149             }
1150
1151             /* Write the name */
1152             ObjWriteStr (S->Name);
1153
1154             /* Write the value */
1155             if ((ExprMask & EXP_MASK_VAL) == EXP_CONST) {
1156                 /* Constant value */
1157                 ObjWrite32 (S->V.Val);
1158             } else {
1159                 /* Expression involved */
1160                 WriteExpr (S->V.Expr);
1161             }
1162
1163             /* Write the source file position */
1164             ObjWritePos (&S->Pos);
1165         }
1166         S = S->List;
1167     }
1168
1169     /* Done writing exports */
1170     ObjEndExports ();
1171 }
1172
1173
1174
1175 void WriteDbgSyms (void)
1176 /* Write a list of all symbols to the object file */
1177 {
1178     unsigned Count;
1179     SymEntry* S;
1180
1181     /* Tell the object file module that we're about to start the debug info */
1182     ObjStartDbgSyms ();
1183
1184     /* Check if debug info is requested */
1185     if (DbgSyms) {
1186
1187         /* Walk through the list and count the symbols */
1188         Count = 0;
1189         S = SymList;
1190         while (S) {
1191             if ((S->Flags & SF_DBGINFOMASK) == SF_DBGINFOVAL) {
1192                 ++Count;
1193             }
1194             S = S->List;
1195         }
1196
1197         /* Write the symbol count to the list */
1198         ObjWriteVar (Count);
1199
1200         /* Walk through list and write all symbols to the file */
1201         S = SymList;
1202         while (S) {
1203             if ((S->Flags & SF_DBGINFOMASK) == SF_DBGINFOVAL) {
1204                 unsigned char ExprMask;
1205
1206                 /* Finalize an associated expression if we have one */
1207                 SymFinalize (S);
1208
1209                 /* Get the expression bits */
1210                 ExprMask = GetExprMask (S);
1211
1212                 /* Write the type */
1213                 ObjWrite8 (ExprMask);
1214
1215                 /* Write the name */
1216                 ObjWriteStr (S->Name);
1217
1218                 /* Write the value */
1219                 if ((ExprMask & EXP_MASK_VAL) == EXP_CONST) {
1220                     /* Constant value */
1221                     ObjWrite32 (S->V.Val);
1222                 } else {
1223                     /* Expression involved */
1224                     WriteExpr (S->V.Expr);
1225                 }
1226
1227                 /* Write the source file position */
1228                 ObjWritePos (&S->Pos);
1229             }
1230             S = S->List;
1231         }
1232
1233     } else {
1234
1235         /* No debug symbols */
1236         ObjWriteVar (0);
1237
1238     }
1239
1240     /* Done writing debug symbols */
1241     ObjEndDbgSyms ();
1242 }
1243
1244
1245