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