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