]> git.sur5r.net Git - cc65/blob - src/ca65/symtab.c
f6055591e40ba683f41789f489f61a99f67e8c5a
[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ömerstraße 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 "addrsize.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 "segment.h"
52 #include "spool.h"
53 #include "symtab.h"
54
55
56
57 /*****************************************************************************/
58 /*                                   Data                                    */
59 /*****************************************************************************/
60
61
62
63 /* Combined symbol entry flags used within this module */
64 #define SF_UNDEFMASK    (SF_REFERENCED | SF_DEFINED | SF_IMPORT)
65 #define SF_UNDEFVAL     (SF_REFERENCED)
66 #define SF_EXPMASK      (SF_TRAMPOLINE | SF_EXPORT)
67 #define SF_EXPVAL       (SF_EXPORT)
68 #define SF_DBGINFOMASK  (SF_TRAMPOLINE | SF_DEFINED | SF_EXPORT | SF_IMPORT)
69 #define SF_DBGINFOVAL   (SF_DEFINED)
70
71 /* Symbol tables */
72 SymTable*       CurrentScope = 0;       /* Pointer to current symbol table */
73 SymTable*       RootScope    = 0;       /* Root symbol table */
74
75 /* Symbol table variables */
76 static unsigned         ImportCount = 0;/* Counter for import symbols */
77 static unsigned         ExportCount = 0;/* Counter for export symbols */
78
79
80
81 /*****************************************************************************/
82 /*                         Internally used functions                         */
83 /*****************************************************************************/
84
85
86
87 static unsigned ScopeTableSize (unsigned Level)
88 /* Get the size of a table for the given lexical level */
89 {
90     switch (Level) {
91         case 0:         return 213;
92         case 1:         return  53;
93         default:        return  29;
94     }
95 }
96
97
98
99 static SymTable* NewSymTable (SymTable* Parent, const char* Name)
100 /* Allocate a symbol table on the heap and return it */
101 {
102     /* Determine the lexical level and the number of table slots */
103     unsigned Level = Parent? Parent->Level + 1 : 0;
104     unsigned Slots = ScopeTableSize (Level);
105
106     /* Allocate memory */
107     SymTable* S = xmalloc (sizeof (SymTable) + (Slots-1) * sizeof (SymEntry*));
108
109     /* Set variables and clear hash table entries */
110     S->Left         = 0;
111     S->Right        = 0;
112     S->Childs       = 0;
113     S->Flags        = ST_NONE;
114     S->AddrSize     = ADDR_SIZE_DEFAULT;
115     S->Type         = 0;
116     S->Level        = Level;
117     S->TableSlots   = Slots;
118     S->TableEntries = 0;
119     S->Parent       = Parent;
120     S->Name         = GetStringId (Name);
121     while (Slots--) {
122         S->Table[Slots] = 0;
123     }
124
125     /* Insert the symbol table into the child tree of the parent */
126     if (Parent) {
127         SymTable* T = Parent->Childs;
128         if (T == 0) {
129             /* First entry */
130             Parent->Childs = S;
131         } else {
132             while (1) {
133                 /* Choose next entry */
134                 int Cmp = strcmp (Name, GetString (T->Name));
135                 if (Cmp < 0) {
136                     if (T->Left) {
137                         T = T->Left;
138                     } else {
139                         T->Left = S;
140                         break;
141                     }
142                 } else if (Cmp > 0) {
143                     if (T->Right) {
144                         T = T->Right;
145                     } else {
146                         T->Right = S;
147                         break;
148                     }
149                 } else {
150                     /* Duplicate scope name */
151                     Internal ("Duplicate scope name: `%s'", Name);
152                 }
153             }
154         }
155     }
156
157     /* Return the prepared struct */
158     return S;
159 }
160
161
162
163 static int SearchSymTree (SymEntry* T, const char* Name, SymEntry** E)
164 /* Search in the given tree for a name. If we find the symbol, the function
165  * will return 0 and put the entry pointer into E. If we did not find the
166  * symbol, and the tree is empty, E is set to NULL. If the tree is not empty,
167  * E will be set to the last entry, and the result of the function is <0 if
168  * the entry should be inserted on the left side, and >0 if it should get
169  * inserted on the right side.
170  */
171 {
172     /* Is there a tree? */
173     if (T == 0) {
174         *E = 0;
175         return 1;
176     }
177
178     /* We have a table, search it */
179     while (1) {
180
181         /* Get the symbol name */
182         const char* SymName = GetString (T->Name);
183
184         /* Choose next entry */
185         int Cmp = strcmp (Name, SymName);
186         if (Cmp < 0 && T->Left) {
187             T = T->Left;
188         } else if (Cmp > 0&& T->Right) {
189             T = T->Right;
190         } else {
191             /* Found or end of search, return the result */
192             *E = T;
193             return Cmp;
194         }
195     }
196 }
197
198
199
200 /*****************************************************************************/
201 /*                                   Code                                    */
202 /*****************************************************************************/
203
204
205
206 void SymEnterLevel (const char* ScopeName, unsigned AddrSize)
207 /* Enter a new lexical level */
208 {
209     /* Map a default address size to something real */
210     if (AddrSize == ADDR_SIZE_DEFAULT) {
211         /* Use the segment address size */
212         AddrSize = GetCurrentSegAddrSize ();
213     }
214
215     /* If we have a current scope, search for the given name and create a
216      * new one if it doesn't exist. If this is the root scope, just create it.
217      */
218     if (CurrentScope) {
219         CurrentScope = SymFindScope (CurrentScope, ScopeName, SYM_ALLOC_NEW);
220
221         /* Check if the scope has been defined before */
222         if (CurrentScope->Flags & ST_DEFINED) {
223             Error ("Duplicate scope `%s'", ScopeName);
224         }
225     } else {
226         CurrentScope = RootScope = NewSymTable (0, ScopeName);
227     }
228
229     /* Mark the scope as defined */
230     CurrentScope->Flags |= ST_DEFINED;
231 }
232
233
234
235 void SymLeaveLevel (void)
236 /* Leave the current lexical level */
237 {
238     CurrentScope = CurrentScope->Parent;
239 }
240
241
242
243 SymTable* SymFindScope (SymTable* Parent, const char* Name, int AllocNew)
244 /* Find a scope in the given enclosing scope */
245 {
246     SymTable** T = &Parent->Childs;
247     while (*T) {
248         int Cmp = strcmp (Name, GetString ((*T)->Name));
249         if (Cmp < 0) {
250             T = &(*T)->Left;
251         } else if (Cmp > 0) {
252             T = &(*T)->Right;
253         } else {
254             /* Found the scope */
255             return *T;
256         }
257     }
258
259     /* Create a new scope if requested and we didn't find one */
260     if (*T == 0 && AllocNew) {
261         *T = NewSymTable (Parent, Name);
262     }
263
264     /* Return the scope */
265     return *T;
266 }
267
268
269
270 SymEntry* SymFind (SymTable* Scope, const char* Name, int AllocNew)
271 /* Find a new symbol table entry in the given table. If AllocNew is given and
272  * the entry is not found, create a new one. Return the entry found, or the
273  * new entry created, or - in case AllocNew is zero - return 0.
274  */
275 {
276     SymEntry* S;
277     int Cmp;
278
279     if (IsLocalName (Name)) {
280
281         /* Local symbol, get the table */
282         if (!SymLast) {
283             /* No last global, so there's no local table */
284             Error ("No preceeding global symbol");
285             if (AllocNew) {
286                 return NewSymEntry (Name);
287             } else {
288                 return 0;
289             }
290         }
291
292         /* Search for the symbol if we have a table */
293         Cmp = SearchSymTree (SymLast->Locals, Name, &S);
294
295         /* If we found an entry, return it */
296         if (Cmp == 0) {
297             return S;
298         }
299
300         if (AllocNew) {
301
302             /* Otherwise create a new entry, insert and return it */
303             SymEntry* N = NewSymEntry (Name);
304             if (S == 0) {
305                 SymLast->Locals = N;
306             } else if (Cmp < 0) {
307                 S->Left = N;
308             } else {
309                 S->Right = N;
310             }
311             return N;
312         }
313
314     } else {
315
316         /* Global symbol: Get the hash value for the name */
317         unsigned Hash = HashStr (Name) % Scope->TableSlots;
318
319         /* Search for the entry */
320         Cmp = SearchSymTree (Scope->Table[Hash], Name, &S);
321
322         /* If we found an entry, return it */
323         if (Cmp == 0) {
324             /* Check for a trampoline entry, in this case return the real
325              * symbol.
326              */
327             while (S->Flags & SF_TRAMPOLINE) {
328                 S = S->V.Sym;
329             }
330             return S;
331         }
332
333         if (AllocNew) {
334
335             /* Otherwise create a new entry, insert and return it */
336             SymEntry* N = NewSymEntry (Name);
337             if (S == 0) {
338                 Scope->Table[Hash] = N;
339             } else if (Cmp < 0) {
340                 S->Left = N;
341             } else {
342                 S->Right = N;
343             }
344             N->SymTab = Scope;
345             ++Scope->TableEntries;
346             return N;
347
348         }
349     }
350
351     /* We did not find the entry and AllocNew is false. */
352     return 0;
353 }
354
355
356
357 static SymEntry* SymFindAny (SymTable* Scope, const char* Name)
358 /* Find a symbol in the given or any of its parent scopes. The function will
359  * never create a new symbol, since this can only be done in one specific
360  * scope.
361  */
362 {
363     SymEntry* Sym;
364     do {
365         /* Search in the current table */
366         Sym = SymFind (Scope, Name, SYM_FIND_EXISTING);
367         if (Sym) {
368             /* Found, return it */
369             return Sym;
370         } else {
371             /* Not found, search in the parent scope, if we have one */
372             Scope = Scope->Parent;
373         }
374     } while (Sym == 0 && Scope != 0);
375
376     /* Not found */
377     return 0;
378 }
379
380
381
382 void SymConDes (const char* Name, unsigned Type, unsigned Prio)
383 /* Mark the given symbol as a module constructor/destructor. This will also
384  * mark the symbol as an export. Initializers may never be zero page symbols.
385  */
386 {
387     SymEntry* S;
388
389     /* Check the parameters */
390 #if (CD_TYPE_MIN != 0)
391     CHECK (Type >= CD_TYPE_MIN && Type <= CD_TYPE_MAX);
392 #else
393     CHECK (Type <= CD_TYPE_MAX);
394 #endif
395     CHECK (Prio >= CD_PRIO_MIN && Prio <= CD_PRIO_MAX);
396
397     /* Don't accept local symbols */
398     if (IsLocalName (Name)) {
399         Error ("Illegal use of a local symbol");
400         return;
401     }
402
403     /* Do we have such a symbol? */
404     S = SymFind (CurrentScope, Name, SYM_ALLOC_NEW);
405     if (S->Flags & SF_IMPORT) {
406         /* The symbol is already marked as imported external symbol */
407         Error ("Symbol `%s' is already an import", Name);
408         return;
409     }
410
411     /* If the symbol is marked as global, silently remove the global flag */
412     if (S->Flags & SF_GLOBAL) {
413         S->Flags &= ~SF_GLOBAL;
414     }
415
416     /* Check if the symbol was not already defined as ZP symbol */
417     if (S->AddrSize == ADDR_SIZE_ZP) {
418         Error ("Redeclaration mismatch for symbol `%s'", Name);
419     }
420
421     /* If the symbol was already declared as a condes, check if the new
422      * priority value is the same as the old one.
423      */
424     if (S->ConDesPrio[Type] != CD_PRIO_NONE) {
425         if (S->ConDesPrio[Type] != Prio) {
426             Error ("Redeclaration mismatch for symbol `%s'", Name);
427         }
428     }
429     S->ConDesPrio[Type] = Prio;
430
431     /* Set the symbol data */
432     S->Flags |= SF_EXPORT | SF_REFERENCED;
433 }
434
435
436
437 int SymIsConst (SymEntry* S)
438 /* Return true if the given symbol has a constant value */
439 {
440     /* Resolve trampoline entries */
441     if (S->Flags & SF_TRAMPOLINE) {
442         S = S->V.Sym;
443     }
444
445     /* Check for constness */
446     if (S->Flags & SF_CONST) {
447         return 1;
448     } else if ((S->Flags & SF_DEFINED) && IsConstExpr (S->V.Expr)) {
449         /* Constant expression, remember the value */
450         ExprNode* Expr = S->V.Expr;
451         S->Flags |= SF_CONST;
452         S->V.Val = GetExprVal (Expr);
453         FreeExpr (Expr);
454         return 1;
455     }
456     return 0;
457 }
458
459
460
461 int SymIsZP (SymEntry* S)
462 /* Return true if the symbol is explicitly marked as zeropage symbol */
463 {
464     /* Resolve trampoline entries */
465     if (S->Flags & SF_TRAMPOLINE) {
466         S = S->V.Sym;
467     }
468
469     /* If the symbol is not a global symbol, was not defined before, check the
470      * enclosing scope for a symbol with the same name, and return the ZP
471      * attribute of this symbol if we find one.
472      */
473     if (!IsLocalNameId (S->Name) && (S->Flags & (SF_DEFINED | SF_IMPORT)) == 0 &&
474         S->SymTab->Parent != 0) {
475
476         /* Try to find a symbol with the same name in the enclosing scope */
477         SymEntry* E = SymFindAny (S->SymTab->Parent, GetString (S->Name));
478
479         /* If we found one, use the ZP flag */
480         if (E && E->AddrSize == ADDR_SIZE_ZP) {
481             S->AddrSize = ADDR_SIZE_ZP;
482         }
483     }
484
485     /* Check the ZP flag */
486     return (S->AddrSize == ADDR_SIZE_ZP);
487 }
488
489
490
491 static void SymCheckUndefined (SymEntry* S)
492 /* Handle an undefined symbol */
493 {
494     /* Undefined symbol. It may be...
495      *
496      *   - An undefined symbol in a nested lexical level. In this
497      *     case, search for the symbol in the higher levels and
498      *     make the entry a trampoline entry if we find one.
499      *
500      *   - If the symbol is not found, it is a real undefined symbol.
501      *     If the AutoImport flag is set, make it an import. If the
502      *     AutoImport flag is not set, it's an error.
503      */
504     SymEntry* Sym = 0;
505     if (S->SymTab) {
506         /* It's a global symbol, get the higher level table */
507         SymTable* Tab = S->SymTab->Parent;
508         while (Tab) {
509             Sym = SymFindAny (Tab, GetString (S->Name));
510             if (Sym) {
511                 if (Sym->Flags & (SF_DEFINED | SF_IMPORT)) {
512                     /* We've found a symbol in a higher level that is
513                      * either defined in the source, or an import.
514                      */
515                      break;
516                 } else {
517                     /* The symbol found is undefined itself. Look further */
518                     Tab = Sym->SymTab->Parent;
519                 }
520             } else {
521                 /* No symbol found */
522                 break;
523             }
524         }
525     }
526     if (Sym) {
527         /* We found the symbol in a higher level. Make S a trampoline
528          * symbol. Beware: We have to transfer the symbol attributes to
529          * the real symbol and check for any conflicts.
530          */
531         S->Flags |= SF_TRAMPOLINE;
532         S->V.Sym = Sym;
533
534         /* Transfer the flags. Note: S may not be imported, since in that
535          * case it wouldn't be undefined.
536          */
537         if (S->Flags & SF_EXPORT) {
538             if (Sym->Flags & SF_IMPORT) {
539                 /* The symbol is already marked as imported external symbol */
540                 PError (&S->Pos, "Symbol `%s' is already an import", GetString (S->Name));
541             }
542             Sym->Flags |= (S->Flags & SF_EXPORT);
543             Sym->ExportSize = S->ExportSize;
544         }
545
546         /* Transfer the referenced flag */
547         Sym->Flags |= (S->Flags & SF_REFERENCED);
548
549     } else {
550         /* The symbol is definitely undefined */
551         if (S->Flags & SF_EXPORT) {
552             /* We will not auto-import an export */
553             PError (&S->Pos, "Exported symbol `%s' was never defined",
554                     GetString (S->Name));
555         } else {
556             if (AutoImport) {
557                 /* Mark as import, will be indexed later */
558                 S->Flags |= SF_IMPORT;
559             } else {
560                 /* Error */
561                 PError (&S->Pos, "Symbol `%s' is undefined", GetString (S->Name));
562             }
563         }
564     }
565 }
566
567
568
569 void SymCheck (void)
570 /* Run through all symbols and check for anomalies and errors */
571 {
572     SymEntry* S;
573
574     /* Check for open scopes */
575     if (CurrentScope->Parent != 0) {
576         Error ("Local scope was not closed");
577     }
578
579     /* First pass: Walk through all symbols, checking for undefined's and
580      * changing them to trampoline symbols or make them imports.
581      */
582     S = SymList;
583     while (S) {
584         /* If the symbol is marked as global, mark it as export, if it is
585          * already defined, otherwise mark it as import.
586          */
587         if (S->Flags & SF_GLOBAL) {
588             S->Flags &= ~SF_GLOBAL;
589             if (S->Flags & SF_DEFINED) {
590                 S->Flags |= SF_EXPORT;
591             } else {
592                 S->Flags |= SF_IMPORT;
593             }
594         }
595
596         /* Handle undefined symbols */
597         if ((S->Flags & SF_UNDEFMASK) == SF_UNDEFVAL) {
598             /* This is an undefined symbol. Handle it. */
599             SymCheckUndefined (S);
600         }
601
602         /* Next symbol */
603         S = S->List;
604     }
605
606     /* Second pass: Walk again through the symbols. Ignore undefined's, since
607      * we handled them in the last pass, and ignore trampoline symbols, since
608      * we handled them in the last pass, too.
609      */
610     S = SymList;
611     while (S) {
612         if ((S->Flags & SF_TRAMPOLINE) == 0 &&
613             (S->Flags & SF_UNDEFMASK) != SF_UNDEFVAL) {
614             if ((S->Flags & SF_DEFINED) != 0 && (S->Flags & SF_REFERENCED) == 0) {
615                 /* Symbol was defined but never referenced */
616                 PWarning (&S->Pos, 2,
617                           "Symbol `%s' is defined but never used",
618                           GetString (S->Name));
619             }
620             if (S->Flags & SF_IMPORT) {
621                 if ((S->Flags & (SF_REFERENCED | SF_FORCED)) == SF_NONE) {
622                     /* Imported symbol is not referenced */
623                     PWarning (&S->Pos, 2,
624                               "Symbol `%s' is imported but never used",
625                               GetString (S->Name));
626                 } else {
627                     /* Give the import an index, count imports */
628                     S->Index = ImportCount++;
629                     S->Flags |= SF_INDEXED;
630                 }
631             }
632             if (S->Flags & SF_EXPORT) {
633                 /* Give the export an index, count exports */
634                 S->Index = ExportCount++;
635                 S->Flags |= SF_INDEXED;
636             }
637         }
638
639         /* Next symbol */
640         S = S->List;
641     }
642 }
643
644
645
646 void SymDump (FILE* F)
647 /* Dump the symbol table */
648 {
649     SymEntry* S = SymList;
650
651     while (S) {
652         /* Ignore trampoline symbols */
653         if ((S->Flags & SF_TRAMPOLINE) != 0) {
654             fprintf (F,
655                      "%-24s %s %s %s %s %s\n",
656                      GetString (S->Name),
657                      (S->Flags & SF_DEFINED)? "DEF" : "---",
658                      (S->Flags & SF_REFERENCED)? "REF" : "---",
659                      (S->Flags & SF_IMPORT)? "IMP" : "---",
660                      (S->Flags & SF_EXPORT)? "EXP" : "---",
661                      AddrSizeToStr (S->AddrSize));
662         }
663         /* Next symbol */
664         S = S->List;
665     }
666 }
667
668
669
670 void WriteImports (void)
671 /* Write the imports list to the object file */
672 {
673     SymEntry* S;
674
675     /* Tell the object file module that we're about to start the imports */
676     ObjStartImports ();
677
678     /* Write the import count to the list */
679     ObjWriteVar (ImportCount);
680
681     /* Walk throught list and write all valid imports to the file. An import
682      * is considered valid, if it is either referenced, or the forced bit is
683      * set. Otherwise, the import is ignored (no need to link in something
684      * that isn't used).
685      */
686     S = SymList;
687     while (S) {
688         if ((S->Flags & (SF_TRAMPOLINE | SF_IMPORT)) == SF_IMPORT &&
689             (S->Flags & (SF_REFERENCED | SF_FORCED)) != 0) {
690
691             if (S->AddrSize == ADDR_SIZE_ZP) {
692                 ObjWrite8 (IMP_ZP);
693             } else {
694                 ObjWrite8 (IMP_ABS);
695             }
696             ObjWriteVar (S->Name);
697             ObjWritePos (&S->Pos);
698         }
699         S = S->List;
700     }
701
702     /* Done writing imports */
703     ObjEndImports ();
704 }
705
706
707
708 static unsigned char GetExportExprMask (SymEntry* S)
709 /* Return the expression bits for the given symbol table entry */
710 {
711     unsigned char ExprMask;
712
713     /* Check if the symbol is const */
714     ExprMask = (SymIsConst (S))? EXP_CONST : EXP_EXPR;
715
716     /* Add zeropage/abs bits */
717     ExprMask |= (S->ExportSize == ADDR_SIZE_ZP)? EXP_ZP : EXP_ABS;
718
719     /* Add the label/equate bits */
720     ExprMask |= (S->Flags & SF_LABEL)? EXP_LABEL : EXP_EQUATE;
721
722     /* Return the mask */
723     return ExprMask;
724 }
725
726
727
728 void WriteExports (void)
729 /* Write the exports list to the object file */
730 {
731     SymEntry* S;
732     unsigned Type;
733
734     /* Tell the object file module that we're about to start the exports */
735     ObjStartExports ();
736
737     /* Write the export count to the list */
738     ObjWriteVar (ExportCount);
739
740     /* Walk throught list and write all exports to the file */
741     S = SymList;
742     while (S) {
743         if ((S->Flags & SF_EXPMASK) == SF_EXPVAL) {
744             unsigned char ExprMask;
745
746             /* Finalize an associated expression if we have one */
747             SymFinalize (S);
748
749             /* Get the expression bits */
750             ExprMask = GetExportExprMask (S);
751
752             /* Count the number of ConDes types */
753             for (Type = 0; Type < CD_TYPE_COUNT; ++Type) {
754                 if (S->ConDesPrio[Type] != CD_PRIO_NONE) {
755                     INC_EXP_CONDES_COUNT (ExprMask);
756                 }
757             }
758
759             /* Write the type */
760             ObjWrite8 (ExprMask);
761
762             /* Write any ConDes declarations */
763             if (GET_EXP_CONDES_COUNT (ExprMask) > 0) {
764                 for (Type = 0; Type < CD_TYPE_COUNT; ++Type) {
765                     unsigned char Prio = S->ConDesPrio[Type];
766                     if (Prio != CD_PRIO_NONE) {
767                         ObjWrite8 (CD_BUILD (Type, Prio));
768                     }
769                 }
770             }
771
772             /* Write the name */
773             ObjWriteVar (S->Name);
774
775             /* Write the value */
776             if ((ExprMask & EXP_MASK_VAL) == EXP_CONST) {
777                 /* Constant value */
778                 ObjWrite32 (S->V.Val);
779             } else {
780                 /* Expression involved */
781                 WriteExpr (S->V.Expr);
782             }
783
784             /* Write the source file position */
785             ObjWritePos (&S->Pos);
786         }
787         S = S->List;
788     }
789
790     /* Done writing exports */
791     ObjEndExports ();
792 }
793
794
795
796 static unsigned char GetDbgExprMask (SymEntry* S)
797 /* Return the expression bits for the given symbol table entry */
798 {
799     unsigned char ExprMask;
800
801     /* Check if the symbol is const */
802     ExprMask = (SymIsConst (S))? EXP_CONST : EXP_EXPR;
803
804     /* Add zeropage/abs bits */
805     ExprMask |= (S->AddrSize == ADDR_SIZE_ZP)? EXP_ZP : EXP_ABS;
806
807     /* Add the label/equate bits */
808     ExprMask |= (S->Flags & SF_LABEL)? EXP_LABEL : EXP_EQUATE;
809
810     /* Return the mask */
811     return ExprMask;
812 }
813
814
815
816 void WriteDbgSyms (void)
817 /* Write a list of all symbols to the object file */
818 {
819     unsigned Count;
820     SymEntry* S;
821
822     /* Tell the object file module that we're about to start the debug info */
823     ObjStartDbgSyms ();
824
825     /* Check if debug info is requested */
826     if (DbgSyms) {
827
828         /* Walk through the list and count the symbols */
829         Count = 0;
830         S = SymList;
831         while (S) {
832             if ((S->Flags & SF_DBGINFOMASK) == SF_DBGINFOVAL) {
833                 ++Count;
834             }
835             S = S->List;
836         }
837
838         /* Write the symbol count to the list */
839         ObjWriteVar (Count);
840
841         /* Walk through list and write all symbols to the file */
842         S = SymList;
843         while (S) {
844             if ((S->Flags & SF_DBGINFOMASK) == SF_DBGINFOVAL) {
845                 unsigned char ExprMask;
846
847                 /* Finalize an associated expression if we have one */
848                 SymFinalize (S);
849
850                 /* Get the expression bits */
851                 ExprMask = GetDbgExprMask (S);
852
853                 /* Write the type */
854                 ObjWrite8 (ExprMask);
855
856                 /* Write the name */
857                 ObjWriteVar (S->Name);
858
859                 /* Write the value */
860                 if ((ExprMask & EXP_MASK_VAL) == EXP_CONST) {
861                     /* Constant value */
862                     ObjWrite32 (S->V.Val);
863                 } else {
864                     /* Expression involved */
865                     WriteExpr (S->V.Expr);
866                 }
867
868                 /* Write the source file position */
869                 ObjWritePos (&S->Pos);
870             }
871             S = S->List;
872         }
873
874     } else {
875
876         /* No debug symbols */
877         ObjWriteVar (0);
878
879     }
880
881     /* Done writing debug symbols */
882     ObjEndDbgSyms ();
883 }
884
885
886
887