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