]> git.sur5r.net Git - cc65/blob - src/ca65/symentry.c
Remember where each symbol was defined and where it was referenced. Write this
[cc65] / src / ca65 / symentry.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                symentry.c                                 */
4 /*                                                                           */
5 /*              Symbol table entry for the ca65 macroassembler               */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 1998-2011, Ullrich von Bassewitz                                      */
10 /*                Roemerstrasse 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 "symdefs.h"
41 #include "xmalloc.h"
42
43 /* ca65 */
44 #include "error.h"
45 #include "expr.h"
46 #include "global.h"
47 #include "scanner.h"
48 #include "segment.h"
49 #include "spool.h"
50 #include "studyexpr.h"          /* ### */
51 #include "symentry.h"
52 #include "symtab.h"
53
54
55
56 /*****************************************************************************/
57 /*                                   Data                                    */
58 /*****************************************************************************/
59
60
61
62 /* List of all symbol table entries */
63 SymEntry* SymList = 0;
64
65 /* Pointer to last defined symbol */
66 SymEntry* SymLast = 0;
67
68
69
70 /*****************************************************************************/
71 /*                                   Code                                    */
72 /*****************************************************************************/
73
74
75
76 SymEntry* NewSymEntry (const StrBuf* Name, unsigned Flags)
77 /* Allocate a symbol table entry, initialize and return it */
78 {
79     unsigned I;
80
81     /* Allocate memory */
82     SymEntry* S = xmalloc (sizeof (SymEntry));
83
84     /* Initialize the entry */
85     S->Left       = 0;
86     S->Right      = 0;
87     S->Locals     = 0;
88     S->Sym.Tab    = 0;
89     S->DefLines   = EmptyCollection;
90     S->RefLines   = EmptyCollection;
91     for (I = 0; I < sizeof (S->GuessedUse) / sizeof (S->GuessedUse[0]); ++I) {
92         S->GuessedUse[I] = 0;
93     }
94     S->Flags      = Flags;
95     S->DebugSymId = ~0U;
96     S->ImportId   = ~0U;
97     S->ExportId   = ~0U;
98     S->Expr       = 0;
99     S->ExprRefs   = AUTO_COLLECTION_INITIALIZER;
100     S->ExportSize = ADDR_SIZE_DEFAULT;
101     S->AddrSize   = ADDR_SIZE_DEFAULT;
102     memset (S->ConDesPrio, 0, sizeof (S->ConDesPrio));
103     S->Name       = GetStrBufId (Name);
104
105     /* Insert it into the list of all entries */
106     S->List = SymList;
107     SymList = S;
108
109     /* Return the initialized entry */
110     return S;
111 }
112
113
114
115 int SymSearchTree (SymEntry* T, const StrBuf* Name, SymEntry** E)
116 /* Search in the given tree for a name. If we find the symbol, the function
117  * will return 0 and put the entry pointer into E. If we did not find the
118  * symbol, and the tree is empty, E is set to NULL. If the tree is not empty,
119  * E will be set to the last entry, and the result of the function is <0 if
120  * the entry should be inserted on the left side, and >0 if it should get
121  * inserted on the right side.
122  */
123 {
124     /* Is there a tree? */
125     if (T == 0) {
126         *E = 0;
127         return 1;
128     }
129
130     /* We have a table, search it */
131     while (1) {
132
133         /* Get the symbol name */
134         const StrBuf* SymName = GetStrBuf (T->Name);
135
136         /* Choose next entry */
137         int Cmp = SB_Compare (Name, SymName);
138         if (Cmp < 0 && T->Left) {
139             T = T->Left;
140         } else if (Cmp > 0&& T->Right) {
141             T = T->Right;
142         } else {
143             /* Found or end of search, return the result */
144             *E = T;
145             return Cmp;
146         }
147     }
148 }
149
150
151
152 void SymTransferExprRefs (SymEntry* From, SymEntry* To)
153 /* Transfer all expression references from one symbol to another. */
154 {
155     unsigned I;
156
157     for (I = 0; I < CollCount (&From->ExprRefs); ++I) {
158
159         /* Get the expression node */
160         ExprNode* E = CollAtUnchecked (&From->ExprRefs, I);
161
162         /* Safety */
163         CHECK (E->Op == EXPR_SYMBOL && E->V.Sym == From);
164
165         /* Replace the symbol reference */
166         E->V.Sym = To;
167
168         /* Add the expression reference */
169         SymAddExprRef (To, E);
170     }
171
172     /* Remove all symbol references from the old symbol */
173     CollDeleteAll (&From->ExprRefs);
174 }
175
176
177
178 static void SymReplaceExprRefs (SymEntry* S)
179 /* Replace the references to this symbol by a copy of the symbol expression */
180 {
181     unsigned I;
182     long     Val;
183
184     /* Check if the expression is const and get its value */
185     int IsConst = IsConstExpr (S->Expr, &Val);
186     CHECK (IsConst);
187
188     /* Loop over all references */
189     for (I = 0; I < CollCount (&S->ExprRefs); ++I) {
190
191         /* Get the expression node */
192         ExprNode* E = CollAtUnchecked (&S->ExprRefs, I);
193
194         /* Safety */
195         CHECK (E->Op == EXPR_SYMBOL && E->V.Sym == S);
196
197         /* We cannot touch the root node, since there are pointers to it.
198          * Replace it by a literal node.
199          */
200         E->Op = EXPR_LITERAL;
201         E->V.IVal = Val;
202     }
203
204     /* Remove all symbol references from the symbol */
205     CollDeleteAll (&S->ExprRefs);
206 }
207
208
209
210 void SymDef (SymEntry* S, ExprNode* Expr, unsigned char AddrSize, unsigned Flags)
211 /* Define a new symbol */
212 {
213     if (S->Flags & SF_IMPORT) {
214         /* Defined symbol is marked as imported external symbol */
215         Error ("Symbol `%m%p' is already an import", GetSymName (S));
216         return;
217     }
218     if ((Flags & SF_VAR) != 0 && (S->Flags & (SF_EXPORT | SF_GLOBAL))) {
219         /* Variable symbols cannot be exports or globals */
220         Error ("Var symbol `%m%p' cannot be an export or global symbol", GetSymName (S));
221         return;
222     }
223     if (S->Flags & SF_DEFINED) {
224         /* Multiple definition. In case of a variable, this is legal. */
225         if ((S->Flags & SF_VAR) == 0) {
226             Error ("Symbol `%m%p' is already defined", GetSymName (S));
227             S->Flags |= SF_MULTDEF;
228             return;
229         } else {
230             /* Redefinition must also be a variable symbol */
231             if ((Flags & SF_VAR) == 0) {
232                 Error ("Symbol `%m%p' is already different kind", GetSymName (S));
233                 return;
234             }
235             /* Delete the current symbol expression, since it will get
236              * replaced
237              */
238             FreeExpr (S->Expr);
239             S->Expr = 0;
240         }
241     }
242
243     /* Map a default address size to a real value */
244     if (AddrSize == ADDR_SIZE_DEFAULT) {
245         /* ### Must go! Delay address size calculation until end of assembly! */
246         ExprDesc ED;
247         ED_Init (&ED);
248         StudyExpr (Expr, &ED);
249         AddrSize = ED.AddrSize;
250         ED_Done (&ED);
251     }
252
253     /* Set the symbol value */
254     S->Expr = Expr;
255
256     /* In case of a variable symbol, walk over all expressions containing
257      * this symbol and replace the (sub-)expression by the literal value of
258      * the tree. Be sure to replace the expression node in place, since there
259      * may be pointers to it.
260      */
261     if (Flags & SF_VAR) {
262         SymReplaceExprRefs (S);
263     }
264
265     /* If the symbol is marked as global, export it. Address size is checked
266      * below.
267      */
268     if (S->Flags & SF_GLOBAL) {
269         S->Flags = (S->Flags & ~SF_GLOBAL) | SF_EXPORT;
270         ReleaseFullLineInfo (&S->DefLines);
271     }
272
273     /* Mark the symbol as defined and use the given address size */
274     S->Flags |= (SF_DEFINED | Flags);
275     S->AddrSize = AddrSize;
276
277     /* Remember the line info of the symbol definition */
278     GetFullLineInfo (&S->DefLines);
279
280     /* If the symbol is exported, check the address sizes */
281     if (S->Flags & SF_EXPORT) {
282         if (S->ExportSize == ADDR_SIZE_DEFAULT) {
283             /* Use the real size of the symbol */
284             S->ExportSize = S->AddrSize;
285         } else if (S->AddrSize > S->ExportSize) {
286             /* We're exporting a symbol smaller than it actually is */
287             Warning (1, "Symbol `%m%p' is %s but exported %s",
288                      GetSymName (S), AddrSizeToStr (S->AddrSize),
289                      AddrSizeToStr (S->ExportSize));
290         }
291     }
292
293     /* If this is not a local symbol, remember it as the last global one */
294     if ((S->Flags & SF_LOCAL) == 0) {
295         SymLast = S;
296     }
297 }
298
299
300
301 void SymRef (SymEntry* S)
302 /* Mark the given symbol as referenced */
303 {
304     /* Mark the symbol as referenced */
305     S->Flags |= SF_REFERENCED;
306
307     /* Remember the current location */
308     CollAppend (&S->RefLines, GetAsmLineInfo ());
309 }
310
311
312
313 void SymImport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
314 /* Mark the given symbol as an imported symbol */
315 {
316     if (S->Flags & SF_DEFINED) {
317         Error ("Symbol `%m%p' is already defined", GetSymName (S));
318         S->Flags |= SF_MULTDEF;
319         return;
320     }
321     if (S->Flags & SF_EXPORT) {
322         /* The symbol is already marked as exported symbol */
323         Error ("Cannot import exported symbol `%m%p'", GetSymName (S));
324         return;
325     }
326
327     /* If no address size is given, use the address size of the enclosing
328      * segment.
329      */
330     if (AddrSize == ADDR_SIZE_DEFAULT) {
331         AddrSize = GetCurrentSegAddrSize ();
332     }
333
334     /* If the symbol is marked as import or global, check the address size,
335      * then do silently remove the global flag.
336      */
337     if (S->Flags & SF_IMPORT) {
338         if ((Flags & SF_FORCED) != (S->Flags & SF_FORCED)) {
339             Error ("Redeclaration mismatch for symbol `%m%p'", GetSymName (S));
340         }
341         if (AddrSize != S->AddrSize) {
342             Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
343         }
344     }
345     if (S->Flags & SF_GLOBAL) {
346         S->Flags &= ~SF_GLOBAL;
347         if (AddrSize != S->AddrSize) {
348             Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
349         }
350     }
351
352     /* Set the symbol data */
353     S->Flags |= (SF_IMPORT | Flags);
354     S->AddrSize = AddrSize;
355
356     /* Mark the position of the import as the position of the definition.
357      * Please note: In case of multiple .global or .import statements, the line
358      * infos add up.
359      */
360     GetFullLineInfo (&S->DefLines);
361 }
362
363
364
365 void SymExport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
366 /* Mark the given symbol as an exported symbol */
367 {
368     /* Check if it's ok to export the symbol */
369     if (S->Flags & SF_IMPORT) {
370         /* The symbol is already marked as imported external symbol */
371         Error ("Symbol `%m%p' is already an import", GetSymName (S));
372         return;
373     }
374     if (S->Flags & SF_VAR) {
375         /* Variable symbols cannot be exported */
376         Error ("Var symbol `%m%p' cannot be exported", GetSymName (S));
377         return;
378     }
379
380     /* If the symbol was marked as global before, remove the global flag and
381      * proceed, but check the address size.
382      */
383     if (S->Flags & SF_GLOBAL) {
384         if (AddrSize != S->ExportSize) {
385             Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
386         }
387         S->Flags &= ~SF_GLOBAL;
388
389         /* .GLOBAL remembers line infos in case an .IMPORT follows. We have
390          * to remove these here.
391          */
392         ReleaseFullLineInfo (&S->DefLines);
393     }
394
395     /* If the symbol was already marked as an export, but wasn't defined
396      * before, the address sizes in both definitions must match.
397      */
398     if ((S->Flags & (SF_EXPORT|SF_DEFINED)) == SF_EXPORT) {
399         if (S->ExportSize != AddrSize) {
400             Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
401         }
402     }
403     S->ExportSize = AddrSize;
404
405     /* If the symbol is already defined, check symbol size against the
406      * exported size.
407      */
408     if (S->Flags & SF_DEFINED) {
409         if (S->ExportSize == ADDR_SIZE_DEFAULT) {
410             /* No export size given, use the real size of the symbol */
411             S->ExportSize = S->AddrSize;
412         } else if (S->AddrSize > S->ExportSize) {
413             /* We're exporting a symbol smaller than it actually is */
414             Warning (1, "Symbol `%m%p' is %s but exported %s",
415                      GetSymName (S), AddrSizeToStr (S->AddrSize),
416                      AddrSizeToStr (S->ExportSize));
417         }
418     }
419
420     /* Set the symbol data */
421     S->Flags |= (SF_EXPORT | SF_REFERENCED | Flags);
422 }
423
424
425
426 void SymGlobal (SymEntry* S, unsigned char AddrSize, unsigned Flags)
427 /* Mark the given symbol as a global symbol, that is, as a symbol that is
428  * either imported or exported.
429  */
430 {
431     if (S->Flags & SF_VAR) {
432         /* Variable symbols cannot be exported or imported */
433         Error ("Var symbol `%m%p' cannot be made global", GetSymName (S));
434         return;
435     }
436
437     /* If the symbol is already marked as import, the address size must match.
438      * Apart from that, ignore the global declaration.
439      */
440     if (S->Flags & SF_IMPORT) {
441         if (AddrSize == ADDR_SIZE_DEFAULT) {
442             /* Use the size of the current segment */
443             AddrSize = GetCurrentSegAddrSize ();
444         }
445         if (AddrSize != S->AddrSize) {
446             Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
447         }
448         return;
449     }
450
451     /* If the symbol is already an export: If it is not defined, the address
452      * sizes must match.
453      */
454     if (S->Flags & SF_EXPORT) {
455         if ((S->Flags & SF_DEFINED) == 0) {
456             /* Symbol is undefined */
457             if (AddrSize != S->ExportSize) {
458                 Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
459             }
460         } else if (AddrSize != ADDR_SIZE_DEFAULT) {
461             /* Symbol is defined and address size given */
462             if (AddrSize != S->ExportSize) {
463                 Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
464             }
465         }
466         return;
467     }
468
469     /* If the symbol is already marked as global, the address size must match.
470      * Use the ExportSize here, since it contains the actual address size
471      * passed to this function.
472      */
473     if (S->Flags & SF_GLOBAL) {
474         if (AddrSize != S->ExportSize) {
475             Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
476         }
477         return;
478     }
479
480     /* If we come here, the symbol was neither declared as export, import or
481      * global before. Check if it is already defined, in which case it will
482      * become an export. If it is not defined, mark it as global and remember
483      * the given address sizes.
484      */
485     if (S->Flags & SF_DEFINED) {
486         /* The symbol is defined, export it */
487         S->ExportSize = AddrSize;
488         if (S->ExportSize == ADDR_SIZE_DEFAULT) {
489             /* No export size given, use the real size of the symbol */
490             S->ExportSize = S->AddrSize;
491         } else if (S->AddrSize > S->ExportSize) {
492             /* We're exporting a symbol smaller than it actually is */
493             Warning (1, "Symbol `%m%p' is %s but exported %s",
494                      GetSymName (S), AddrSizeToStr (S->AddrSize),
495                      AddrSizeToStr (S->ExportSize));
496         }
497         S->Flags |= (SF_EXPORT | Flags);
498     } else {
499         /* Since we don't know if the symbol will get exported or imported,
500          * remember two different address sizes: One for an import in AddrSize,
501          * and the other one for an export in ExportSize.
502          */
503         S->AddrSize = AddrSize;
504         if (S->AddrSize == ADDR_SIZE_DEFAULT) {
505             /* Use the size of the current segment */
506             S->AddrSize = GetCurrentSegAddrSize ();
507         }
508         S->ExportSize = AddrSize;
509         S->Flags |= (SF_GLOBAL | Flags);
510
511         /* Remember the current location as location of definition in case
512          * an .IMPORT follows later.
513          */
514         GetFullLineInfo (&S->DefLines);
515     }
516 }
517
518
519
520 void SymConDes (SymEntry* S, unsigned char AddrSize, unsigned Type, unsigned Prio)
521 /* Mark the given symbol as a module constructor/destructor. This will also
522  * mark the symbol as an export. Initializers may never be zero page symbols.
523  */
524 {
525     /* Check the parameters */
526 #if (CD_TYPE_MIN != 0)
527     CHECK (Type >= CD_TYPE_MIN && Type <= CD_TYPE_MAX);
528 #else
529     CHECK (Type <= CD_TYPE_MAX);
530 #endif
531     CHECK (Prio >= CD_PRIO_MIN && Prio <= CD_PRIO_MAX);
532
533     /* Check for errors */
534     if (S->Flags & SF_IMPORT) {
535         /* The symbol is already marked as imported external symbol */
536         Error ("Symbol `%m%p' is already an import", GetSymName (S));
537         return;
538     }
539     if (S->Flags & SF_VAR) {
540         /* Variable symbols cannot be exported or imported */
541         Error ("Var symbol `%m%p' cannot be exported", GetSymName (S));
542         return;
543     }
544
545     /* If the symbol was already marked as an export or global, check if
546      * this was done specifiying the same address size. In case of a global
547      * declaration, silently remove the global flag.
548      */
549     if (S->Flags & (SF_EXPORT | SF_GLOBAL)) {
550         if (S->ExportSize != AddrSize) {
551             Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
552         }
553         S->Flags &= ~SF_GLOBAL;
554     }
555     S->ExportSize = AddrSize;
556
557     /* If the symbol is already defined, check symbol size against the
558      * exported size.
559      */
560     if (S->Flags & SF_DEFINED) {
561         if (S->ExportSize == ADDR_SIZE_DEFAULT) {
562             /* Use the real size of the symbol */
563             S->ExportSize = S->AddrSize;
564         } else if (S->AddrSize != S->ExportSize) {
565             Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
566         }
567     }
568
569     /* If the symbol was already declared as a condes, check if the new
570      * priority value is the same as the old one.
571      */
572     if (S->ConDesPrio[Type] != CD_PRIO_NONE) {
573         if (S->ConDesPrio[Type] != Prio) {
574             Error ("Redeclaration mismatch for symbol `%m%p'", GetSymName (S));
575         }
576     }
577     S->ConDesPrio[Type] = Prio;
578
579     /* Set the symbol data */
580     S->Flags |= (SF_EXPORT | SF_REFERENCED);
581
582     /* In case we have no line info for the definition, record it now */
583     if (CollCount (&S->DefLines) == 0) {
584         GetFullLineInfo (&S->DefLines);
585     }
586 }
587
588
589
590 void SymGuessedAddrSize (SymEntry* Sym, unsigned char AddrSize)
591 /* Mark the address size of the given symbol as guessed. The address size
592  * passed as argument is the one NOT used, because the actual address size
593  * wasn't known. Example: Zero page addressing was not used because symbol
594  * is undefined, and absolute addressing was available.
595  */
596 {
597     /* We must have a valid address size passed */
598     PRECONDITION (AddrSize != ADDR_SIZE_DEFAULT);
599
600     /* We do not support all address sizes currently */
601     if (AddrSize > sizeof (Sym->GuessedUse) / sizeof (Sym->GuessedUse[0])) {
602         return;
603     }
604
605     /* We can only remember one such occurance */
606     if (Sym->GuessedUse[AddrSize-1]) {
607         return;
608     }
609
610     /* Ok, remember the file position */
611     Sym->GuessedUse[AddrSize-1] = xdup (&CurTok.Pos, sizeof (CurTok.Pos));
612 }
613
614
615
616 void SymExportFromGlobal (SymEntry* S)
617 /* Called at the end of assembly. Converts a global symbol that is defined
618  * into an export.
619  */
620 {
621     /* Remove the global flag and make the symbol an export */
622     S->Flags &= ~SF_GLOBAL;
623     S->Flags |= SF_EXPORT;
624 }
625
626
627
628 void SymImportFromGlobal (SymEntry* S)
629 /* Called at the end of assembly. Converts a global symbol that is undefined
630  * into an import.
631  */
632 {
633     /* Remove the global flag and make it an import */
634     S->Flags &= ~SF_GLOBAL;
635     S->Flags |= SF_IMPORT;
636 }
637
638
639
640 int SymIsConst (const SymEntry* S, long* Val)
641 /* Return true if the given symbol has a constant value. If Val is not NULL
642  * and the symbol has a constant value, store it's value there.
643  */
644 {
645     /* Check for constness */
646     return (SymHasExpr (S) && IsConstExpr (S->Expr, Val));
647 }
648
649
650
651 SymTable* GetSymParentScope (SymEntry* S)
652 /* Get the parent scope of the symbol (not the one it is defined in). Return
653  * NULL if the symbol is a cheap local, or defined on global level.
654  */
655 {
656     if ((S->Flags & SF_LOCAL) != 0) {
657         /* This is a cheap local symbol */
658         return 0;
659     } else if (S->Sym.Tab == 0) {
660         /* Symbol not in a table. This may happen if there have been errors
661          * before. Return NULL in this case to avoid further errors.
662          */
663         return 0;
664     } else {
665         /* This is a global symbol */
666         return S->Sym.Tab->Parent;
667     }
668 }
669
670
671
672 struct ExprNode* GetSymExpr (SymEntry* S)
673 /* Get the expression for a non-const symbol */
674 {
675     PRECONDITION (S != 0 && SymHasExpr (S));
676     return S->Expr;
677 }
678
679
680
681 const struct ExprNode* SymResolve (const SymEntry* S)
682 /* Helper function for DumpExpr. Resolves a symbol into an expression or return
683  * NULL. Do not call in other contexts!
684  */
685 {
686     return SymHasExpr (S)? S->Expr : 0;
687 }
688
689
690
691 long GetSymVal (SymEntry* S)
692 /* Return the value of a symbol assuming it's constant. FAIL will be called
693  * in case the symbol is undefined or not constant.
694  */
695 {
696     long Val;
697     CHECK (S != 0 && SymHasExpr (S) && IsConstExpr (GetSymExpr (S), &Val));
698     return Val;
699 }
700
701
702
703 unsigned GetSymImportId (const SymEntry* S)
704 /* Return the import id for the given symbol */
705 {
706     PRECONDITION (S != 0 && (S->Flags & SF_IMPORT) && S->ImportId != ~0U);
707     return S->ImportId;
708 }
709
710
711
712 unsigned GetSymExportId (const SymEntry* S)
713 /* Return the export id for the given symbol */
714 {
715     PRECONDITION (S != 0 && (S->Flags & SF_EXPORT) && S->ExportId != ~0U);
716     return S->ExportId;
717 }
718
719
720
721 unsigned GetSymInfoFlags (const SymEntry* S, long* ConstVal)
722 /* Return a set of flags used when writing symbol information into a file.
723  * If the SYM_CONST bit is set, ConstVal will contain the constant value
724  * of the symbol. The result does not include the condes count.
725  * See common/symdefs.h for more information.
726  */
727 {
728     /* Setup info flags */
729     unsigned Flags = 0;
730     Flags |= SymIsConst (S, ConstVal)? SYM_CONST : SYM_EXPR;
731     Flags |= (S->Flags & SF_LABEL)? SYM_LABEL : SYM_EQUATE;
732     Flags |= (S->Flags & SF_LOCAL)? SYM_CHEAP_LOCAL : SYM_STD;
733     if (S->Flags & SF_EXPORT) {
734         Flags |= SYM_EXPORT;
735     }
736     if (S->Flags & SF_IMPORT) {
737         Flags |= SYM_IMPORT;
738     }
739
740     /* Return the result */
741     return Flags;
742 }
743
744
745