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