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