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