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