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