]> git.sur5r.net Git - cc65/blob - src/ca65/symentry.c
Use CollTransfer where possible.
[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     /* Remember line info for this reference */
424     CollAppend (&S->RefLines, GetAsmLineInfo ());
425 }
426
427
428
429 void SymGlobal (SymEntry* S, unsigned char AddrSize, unsigned Flags)
430 /* Mark the given symbol as a global symbol, that is, as a symbol that is
431  * either imported or exported.
432  */
433 {
434     if (S->Flags & SF_VAR) {
435         /* Variable symbols cannot be exported or imported */
436         Error ("Var symbol `%m%p' cannot be made global", GetSymName (S));
437         return;
438     }
439
440     /* If the symbol is already marked as import, the address size must match.
441      * Apart from that, ignore the global declaration.
442      */
443     if (S->Flags & SF_IMPORT) {
444         if (AddrSize == ADDR_SIZE_DEFAULT) {
445             /* Use the size of the current segment */
446             AddrSize = GetCurrentSegAddrSize ();
447         }
448         if (AddrSize != S->AddrSize) {
449             Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
450         }
451         return;
452     }
453
454     /* If the symbol is already an export: If it is not defined, the address
455      * sizes must match.
456      */
457     if (S->Flags & SF_EXPORT) {
458         if ((S->Flags & SF_DEFINED) == 0) {
459             /* Symbol is undefined */
460             if (AddrSize != S->ExportSize) {
461                 Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
462             }
463         } else if (AddrSize != ADDR_SIZE_DEFAULT) {
464             /* Symbol is defined and address size given */
465             if (AddrSize != S->ExportSize) {
466                 Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
467             }
468         }
469         return;
470     }
471
472     /* If the symbol is already marked as global, the address size must match.
473      * Use the ExportSize here, since it contains the actual address size
474      * passed to this function.
475      */
476     if (S->Flags & SF_GLOBAL) {
477         if (AddrSize != S->ExportSize) {
478             Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
479         }
480         return;
481     }
482
483     /* If we come here, the symbol was neither declared as export, import or
484      * global before. Check if it is already defined, in which case it will
485      * become an export. If it is not defined, mark it as global and remember
486      * the given address sizes.
487      */
488     if (S->Flags & SF_DEFINED) {
489         /* The symbol is defined, export it */
490         S->ExportSize = AddrSize;
491         if (S->ExportSize == ADDR_SIZE_DEFAULT) {
492             /* No export size given, use the real size of the symbol */
493             S->ExportSize = S->AddrSize;
494         } else if (S->AddrSize > S->ExportSize) {
495             /* We're exporting a symbol smaller than it actually is */
496             Warning (1, "Symbol `%m%p' is %s but exported %s",
497                      GetSymName (S), AddrSizeToStr (S->AddrSize),
498                      AddrSizeToStr (S->ExportSize));
499         }
500         S->Flags |= (SF_EXPORT | Flags);
501     } else {
502         /* Since we don't know if the symbol will get exported or imported,
503          * remember two different address sizes: One for an import in AddrSize,
504          * and the other one for an export in ExportSize.
505          */
506         S->AddrSize = AddrSize;
507         if (S->AddrSize == ADDR_SIZE_DEFAULT) {
508             /* Use the size of the current segment */
509             S->AddrSize = GetCurrentSegAddrSize ();
510         }
511         S->ExportSize = AddrSize;
512         S->Flags |= (SF_GLOBAL | Flags);
513
514         /* Remember the current location as location of definition in case
515          * an .IMPORT follows later.
516          */
517         GetFullLineInfo (&S->DefLines);
518     }
519 }
520
521
522
523 void SymConDes (SymEntry* S, unsigned char AddrSize, unsigned Type, unsigned Prio)
524 /* Mark the given symbol as a module constructor/destructor. This will also
525  * mark the symbol as an export. Initializers may never be zero page symbols.
526  */
527 {
528     /* Check the parameters */
529 #if (CD_TYPE_MIN != 0)
530     CHECK (Type >= CD_TYPE_MIN && Type <= CD_TYPE_MAX);
531 #else
532     CHECK (Type <= CD_TYPE_MAX);
533 #endif
534     CHECK (Prio >= CD_PRIO_MIN && Prio <= CD_PRIO_MAX);
535
536     /* Check for errors */
537     if (S->Flags & SF_IMPORT) {
538         /* The symbol is already marked as imported external symbol */
539         Error ("Symbol `%m%p' is already an import", GetSymName (S));
540         return;
541     }
542     if (S->Flags & SF_VAR) {
543         /* Variable symbols cannot be exported or imported */
544         Error ("Var symbol `%m%p' cannot be exported", GetSymName (S));
545         return;
546     }
547
548     /* If the symbol was already marked as an export or global, check if
549      * this was done specifiying the same address size. In case of a global
550      * declaration, silently remove the global flag.
551      */
552     if (S->Flags & (SF_EXPORT | SF_GLOBAL)) {
553         if (S->ExportSize != AddrSize) {
554             Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
555         }
556         S->Flags &= ~SF_GLOBAL;
557     }
558     S->ExportSize = AddrSize;
559
560     /* If the symbol is already defined, check symbol size against the
561      * exported size.
562      */
563     if (S->Flags & SF_DEFINED) {
564         if (S->ExportSize == ADDR_SIZE_DEFAULT) {
565             /* Use the real size of the symbol */
566             S->ExportSize = S->AddrSize;
567         } else if (S->AddrSize != S->ExportSize) {
568             Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
569         }
570     }
571
572     /* If the symbol was already declared as a condes, check if the new
573      * priority value is the same as the old one.
574      */
575     if (S->ConDesPrio[Type] != CD_PRIO_NONE) {
576         if (S->ConDesPrio[Type] != Prio) {
577             Error ("Redeclaration mismatch for symbol `%m%p'", GetSymName (S));
578         }
579     }
580     S->ConDesPrio[Type] = Prio;
581
582     /* Set the symbol data */
583     S->Flags |= (SF_EXPORT | SF_REFERENCED);
584
585     /* In case we have no line info for the definition, record it now */
586     if (CollCount (&S->DefLines) == 0) {
587         GetFullLineInfo (&S->DefLines);
588     }
589 }
590
591
592
593 void SymGuessedAddrSize (SymEntry* Sym, unsigned char AddrSize)
594 /* Mark the address size of the given symbol as guessed. The address size
595  * passed as argument is the one NOT used, because the actual address size
596  * wasn't known. Example: Zero page addressing was not used because symbol
597  * is undefined, and absolute addressing was available.
598  */
599 {
600     /* We must have a valid address size passed */
601     PRECONDITION (AddrSize != ADDR_SIZE_DEFAULT);
602
603     /* We do not support all address sizes currently */
604     if (AddrSize > sizeof (Sym->GuessedUse) / sizeof (Sym->GuessedUse[0])) {
605         return;
606     }
607
608     /* We can only remember one such occurance */
609     if (Sym->GuessedUse[AddrSize-1]) {
610         return;
611     }
612
613     /* Ok, remember the file position */
614     Sym->GuessedUse[AddrSize-1] = xdup (&CurTok.Pos, sizeof (CurTok.Pos));
615 }
616
617
618
619 void SymExportFromGlobal (SymEntry* S)
620 /* Called at the end of assembly. Converts a global symbol that is defined
621  * into an export.
622  */
623 {
624     /* Remove the global flag and make the symbol an export */
625     S->Flags &= ~SF_GLOBAL;
626     S->Flags |= SF_EXPORT;
627 }
628
629
630
631 void SymImportFromGlobal (SymEntry* S)
632 /* Called at the end of assembly. Converts a global symbol that is undefined
633  * into an import.
634  */
635 {
636     /* Remove the global flag and make it an import */
637     S->Flags &= ~SF_GLOBAL;
638     S->Flags |= SF_IMPORT;
639 }
640
641
642
643 int SymIsConst (const SymEntry* S, long* Val)
644 /* Return true if the given symbol has a constant value. If Val is not NULL
645  * and the symbol has a constant value, store it's value there.
646  */
647 {
648     /* Check for constness */
649     return (SymHasExpr (S) && IsConstExpr (S->Expr, Val));
650 }
651
652
653
654 SymTable* GetSymParentScope (SymEntry* S)
655 /* Get the parent scope of the symbol (not the one it is defined in). Return
656  * NULL if the symbol is a cheap local, or defined on global level.
657  */
658 {
659     if ((S->Flags & SF_LOCAL) != 0) {
660         /* This is a cheap local symbol */
661         return 0;
662     } else if (S->Sym.Tab == 0) {
663         /* Symbol not in a table. This may happen if there have been errors
664          * before. Return NULL in this case to avoid further errors.
665          */
666         return 0;
667     } else {
668         /* This is a global symbol */
669         return S->Sym.Tab->Parent;
670     }
671 }
672
673
674
675 struct ExprNode* GetSymExpr (SymEntry* S)
676 /* Get the expression for a non-const symbol */
677 {
678     PRECONDITION (S != 0 && SymHasExpr (S));
679     return S->Expr;
680 }
681
682
683
684 const struct ExprNode* SymResolve (const SymEntry* S)
685 /* Helper function for DumpExpr. Resolves a symbol into an expression or return
686  * NULL. Do not call in other contexts!
687  */
688 {
689     return SymHasExpr (S)? S->Expr : 0;
690 }
691
692
693
694 long GetSymVal (SymEntry* S)
695 /* Return the value of a symbol assuming it's constant. FAIL will be called
696  * in case the symbol is undefined or not constant.
697  */
698 {
699     long Val;
700     CHECK (S != 0 && SymHasExpr (S) && IsConstExpr (GetSymExpr (S), &Val));
701     return Val;
702 }
703
704
705
706 unsigned GetSymImportId (const SymEntry* S)
707 /* Return the import id for the given symbol */
708 {
709     PRECONDITION (S != 0 && (S->Flags & SF_IMPORT) && S->ImportId != ~0U);
710     return S->ImportId;
711 }
712
713
714
715 unsigned GetSymExportId (const SymEntry* S)
716 /* Return the export id for the given symbol */
717 {
718     PRECONDITION (S != 0 && (S->Flags & SF_EXPORT) && S->ExportId != ~0U);
719     return S->ExportId;
720 }
721
722
723
724 unsigned GetSymInfoFlags (const SymEntry* S, long* ConstVal)
725 /* Return a set of flags used when writing symbol information into a file.
726  * If the SYM_CONST bit is set, ConstVal will contain the constant value
727  * of the symbol. The result does not include the condes count.
728  * See common/symdefs.h for more information.
729  */
730 {
731     /* Setup info flags */
732     unsigned Flags = 0;
733     Flags |= SymIsConst (S, ConstVal)? SYM_CONST : SYM_EXPR;
734     Flags |= (S->Flags & SF_LABEL)? SYM_LABEL : SYM_EQUATE;
735     Flags |= (S->Flags & SF_LOCAL)? SYM_CHEAP_LOCAL : SYM_STD;
736     if (S->Flags & SF_EXPORT) {
737         Flags |= SYM_EXPORT;
738     }
739     if (S->Flags & SF_IMPORT) {
740         Flags |= SYM_IMPORT;
741     }
742
743     /* Return the result */
744     return Flags;
745 }
746
747
748