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