]> git.sur5r.net Git - cc65/blob - src/ca65/symentry.c
f716e3288852ab7e8272c61dade5922079b9f980
[cc65] / src / ca65 / symentry.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                symentry.c                                 */
4 /*                                                                           */
5 /*          Symbol table entry forward 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 "xmalloc.h"
41
42 /* ca65 */
43 #include "error.h"
44 #include "expr.h"
45 #include "global.h"
46 #include "scanner.h"
47 #include "segment.h"
48 #include "spool.h"
49 #include "symentry.h"
50 #include "symtab.h"
51
52
53
54 /*****************************************************************************/
55 /*                                   Data                                    */
56 /*****************************************************************************/
57
58
59
60 /* List of all symbol table entries */
61 SymEntry* SymList = 0;
62
63 /* Pointer to last defined symbol */
64 SymEntry* SymLast = 0;
65
66
67
68 /*****************************************************************************/
69 /*                                   Code                                    */
70 /*****************************************************************************/
71
72
73
74 int IsLocalName (const char* Name)
75 /* Return true if Name is the name of a local symbol */
76 {
77     return (*Name == LocalStart);
78 }
79
80
81
82 int IsLocalNameId (unsigned Name)
83 /* Return true if Name is the name of a local symbol */
84 {
85     return (*GetString (Name) == LocalStart);
86 }
87
88
89
90 static unsigned SymAddrSize (const SymEntry* S)
91 /* Get the default address size for a symbol. */
92 {
93     /* Local symbols are always near (is this ok?) */
94     if (IsLocalNameId (S->Name)) {
95         return ADDR_SIZE_ABS;
96     }
97
98     /* Return the address size of the segment */
99     return GetCurrentSegAddrSize ();
100 }
101
102
103
104 SymEntry* NewSymEntry (const char* Name)
105 /* Allocate a symbol table entry, initialize and return it */
106 {
107     /* Allocate memory */
108     SymEntry* S = xmalloc (sizeof (SymEntry));
109
110     /* Initialize the entry */
111     S->Left       = 0;
112     S->Right      = 0;
113     S->Locals     = 0;
114     S->SymTab     = 0;
115     S->Pos        = CurPos;
116     S->Flags      = 0;
117     S->V.Expr     = 0;
118     S->ExprRefs   = AUTO_COLLECTION_INITIALIZER;
119     S->ExportSize = ADDR_SIZE_DEFAULT;
120     S->AddrSize   = ADDR_SIZE_DEFAULT;
121     memset (S->ConDesPrio, 0, sizeof (S->ConDesPrio));
122     S->Name       = GetStringId (Name);
123
124     /* Insert it into the list of all entries */
125     S->List = SymList;
126     SymList = S;
127
128     /* Return the initialized entry */
129     return S;
130 }
131
132
133
134 void SymRef (SymEntry* S)
135 /* Mark the given symbol as referenced */
136 {
137     /* Mark the symbol as referenced */
138     S->Flags |= SF_REFERENCED;
139 }
140
141
142
143 void SymDef (SymEntry* S, ExprNode* Expr, unsigned char AddrSize, unsigned Flags)
144 /* Define a new symbol */
145 {
146     if (S->Flags & SF_IMPORT) {
147         /* Defined symbol is marked as imported external symbol */
148         Error ("Symbol `%s' is already an import", GetSymName (S));
149         return;
150     }
151     if (S->Flags & SF_DEFINED) {
152         /* Multiple definition */
153         Error ("Symbol `%s' is already defined", GetSymName (S));
154         S->Flags |= SF_MULTDEF;
155         return;
156     }
157
158     /* Map a default address size to a real value */
159     if (AddrSize == ADDR_SIZE_DEFAULT) {
160         AddrSize = SymAddrSize (S);
161     }
162
163     /* Set the symbol value */
164     S->V.Expr = Expr;
165
166     /* If the symbol is marked as global, export it */
167     if (S->Flags & SF_GLOBAL) {
168         S->ExportSize = S->AddrSize;
169         S->Flags = (S->Flags & ~SF_GLOBAL) | SF_EXPORT;
170     }
171
172     /* Mark the symbol as defined and use the given address size */
173     S->Flags |= (SF_DEFINED | Flags);
174     S->AddrSize = AddrSize;
175
176     /* If the symbol is exported, check the address sizes */
177     if (S->Flags & SF_EXPORT) {
178         if (S->ExportSize == ADDR_SIZE_DEFAULT) {
179             /* Use the real size of the symbol */
180             S->ExportSize = S->AddrSize;
181         } else if (S->AddrSize > S->ExportSize) {
182             PWarning (GetSymPos (S), 1, "Symbol `%s' is %s but exported as %s",
183                       GetSymName (S), AddrSizeToStr (S->AddrSize),
184                       AddrSizeToStr (S->ExportSize));
185         }
186     }
187
188     /* If the symbol is a ZP symbol, check if the value is in correct range */
189     if (S->AddrSize == ADDR_SIZE_ZP) {
190         /* Already marked as ZP symbol by some means */
191         if (!IsByteExpr (Expr)) {
192             Error ("Range error");
193         }
194     }
195
196     /* If this is not a local symbol, remember it as the last global one */
197     if (!IsLocalNameId (S->Name)) {
198         SymLast = S;
199     }
200 }
201
202
203
204 void SymImport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
205 /* Mark the given symbol as an imported symbol */
206 {
207     /* Don't accept local symbols */
208     if (IsLocalNameId (S->Name)) {
209         Error ("Illegal use of a local symbol");
210         return;
211     }
212
213     if (S->Flags & SF_DEFINED) {
214         Error ("Symbol `%s' is already defined", GetSymName (S));
215         S->Flags |= SF_MULTDEF;
216         return;
217     }
218     if (S->Flags & SF_EXPORT) {
219         /* The symbol is already marked as exported symbol */
220         Error ("Cannot import exported symbol `%s'", GetSymName (S));
221         return;
222     }
223
224     /* Map a default address size to a real value */
225     if (AddrSize == ADDR_SIZE_DEFAULT) {
226         AddrSize = SymAddrSize (S);
227     }
228
229     /* If the symbol is marked as import or global, check the symbol flags,
230      * then do silently remove the global flag
231      */
232     if (S->Flags & SF_IMPORT) {
233         if ((Flags & SF_FORCED) != (S->Flags & SF_FORCED)) {
234             Error ("Redeclaration mismatch for symbol `%s'", GetSymName (S));
235         }
236         if (AddrSize != S->AddrSize) {
237             Error ("Address size mismatch for symbol `%s'", GetSymName (S));
238         }
239     }
240     if (S->Flags & SF_GLOBAL) {
241         if (S->AddrSize != ADDR_SIZE_DEFAULT && S->AddrSize != AddrSize) {
242             Error ("Address size mismatch for symbol `%s'", GetSymName (S));
243         }
244         S->Flags &= ~SF_GLOBAL;
245     }
246
247     /* Set the symbol data */
248     S->Flags |= (SF_IMPORT | Flags);
249     S->AddrSize = AddrSize;
250 }
251
252
253
254 void SymExport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
255 /* Mark the given symbol as an exported symbol */
256 {
257     /* Don't accept local symbols */
258     if (IsLocalNameId (S->Name)) {
259         Error ("Illegal use of a local symbol");
260         return;
261     }
262
263     /* Check if it's ok to export the symbol */
264     if (S->Flags & SF_IMPORT) {
265         /* The symbol is already marked as imported external symbol */
266         Error ("Symbol `%s' is already an import", GetSymName (S));
267         return;
268     }
269
270     /* If the symbol was marked as global before, make it an export */
271     if (S->Flags & SF_GLOBAL) {
272         S->ExportSize = S->AddrSize;
273         S->Flags &= ~SF_GLOBAL;
274     }
275
276     /* If the symbol was already marked as an export, check if this was done
277      * specifiying the same address size. If the old spec had no explicit
278      * address size, use the new one.
279      */
280     if (S->Flags & SF_EXPORT) {
281         if (S->ExportSize == ADDR_SIZE_DEFAULT) {
282             S->ExportSize = AddrSize;
283         } else if (AddrSize == ADDR_SIZE_DEFAULT) {
284             AddrSize = S->ExportSize;
285         }
286         if (S->ExportSize != ADDR_SIZE_DEFAULT && S->ExportSize != AddrSize) {
287             Error ("Address size mismatch for symbol `%s'", GetSymName (S));
288         }
289     }
290     S->ExportSize = AddrSize;
291
292     /* If the symbol is already defined, check symbol size against the
293      * exported size.
294      */
295     if (S->Flags & SF_DEFINED) {
296         if (S->ExportSize == ADDR_SIZE_DEFAULT) {
297             /* No export size given, use the real size of the symbol */
298             S->ExportSize = S->AddrSize;
299         } else if (S->AddrSize > S->ExportSize) {
300             Warning (1, "Symbol `%s' is %s but exported as %s",
301                      GetSymName (S), AddrSizeToStr (S->AddrSize),
302                      AddrSizeToStr (S->ExportSize));
303         }
304     }
305
306     /* Set the symbol data */
307     S->Flags |= (SF_EXPORT | SF_REFERENCED | Flags);
308 }
309
310
311
312 void SymGlobal (SymEntry* S, unsigned char AddrSize, unsigned Flags)
313 /* Mark the given symbol as a global symbol, that is, as a symbol that is
314  * either imported or exported.
315  */
316 {
317     /* Don't accept local symbols */
318     if (IsLocalNameId (S->Name)) {
319         Error ("Illegal use of a local symbol");
320         return;
321     }
322
323     /* If the symbol is already marked as import or export, check the
324      * size of the definition, then bail out.
325      */
326     if (S->Flags & SF_IMPORT) {
327         if (AddrSize != ADDR_SIZE_DEFAULT && AddrSize != S->AddrSize) {
328             Error ("Address size mismatch for symbol `%s'", GetSymName (S));
329         }
330         return;
331     }
332     if (S->Flags & SF_EXPORT) {
333         /* If the old symbol had no explicit address size spec, use the
334          * new one.
335          */
336         if (S->ExportSize == ADDR_SIZE_DEFAULT) {
337             S->ExportSize = AddrSize;
338         }
339         if (AddrSize != S->ExportSize) {
340             Error ("Address size mismatch for symbol `%s'", GetSymName (S));
341         }
342         return;
343     }
344
345     /* If the symbol is already defined, export it. Otherwise mark it as
346      * global.
347      */
348     if (S->Flags & SF_DEFINED) {
349         /* The symbol is defined, export it */
350         S->ExportSize = AddrSize;
351         if (S->ExportSize == ADDR_SIZE_DEFAULT) {
352             /* No export size given, use the real size of the symbol */
353             S->ExportSize = S->AddrSize;
354         } else if (S->AddrSize > S->ExportSize) {
355             Warning (1, "Symbol `%s' is %s but exported as %s",
356                      GetSymName (S), AddrSizeToStr (S->AddrSize),
357                      AddrSizeToStr (S->ExportSize));
358         }
359         S->Flags |= (SF_EXPORT | Flags);
360         S->ExportSize = AddrSize;
361     } else {
362         S->Flags |= (SF_GLOBAL | Flags);
363         S->AddrSize = AddrSize;
364     }
365 }
366
367
368
369 void SymConDes (SymEntry* S, unsigned char AddrSize, unsigned Type, unsigned Prio)
370 /* Mark the given symbol as a module constructor/destructor. This will also
371  * mark the symbol as an export. Initializers may never be zero page symbols.
372  */
373 {
374     /* Check the parameters */
375 #if (CD_TYPE_MIN != 0)
376     CHECK (Type >= CD_TYPE_MIN && Type <= CD_TYPE_MAX);
377 #else
378     CHECK (Type <= CD_TYPE_MAX);
379 #endif
380     CHECK (Prio >= CD_PRIO_MIN && Prio <= CD_PRIO_MAX);
381
382     /* Don't accept local symbols */
383     if (IsLocalNameId (S->Name)) {
384         Error ("Illegal use of a local symbol");
385         return;
386     }
387
388     /* Check for errors */
389     if (S->Flags & SF_IMPORT) {
390         /* The symbol is already marked as imported external symbol */
391         Error ("Symbol `%s' is already an import", GetSymName (S));
392         return;
393     }
394
395     /* If the symbol was already marked as an export or global, check if
396      * this was done specifiying the same address size. In case of a global
397      * declaration, silently remove the global flag.
398      */
399     if (S->Flags & (SF_EXPORT | SF_GLOBAL)) {
400         if (S->ExportSize != AddrSize) {
401             Error ("Address size mismatch for symbol `%s'", GetSymName (S));
402         }
403         S->Flags &= ~SF_GLOBAL;
404     }
405     S->ExportSize = AddrSize;
406
407     /* If the symbol is already defined, check symbol size against the
408      * exported size.
409      */
410     if (S->Flags & SF_DEFINED) {
411         if (S->ExportSize == ADDR_SIZE_DEFAULT) {
412             /* Use the real size of the symbol */
413             S->ExportSize = S->AddrSize;
414         } else if (S->AddrSize != S->ExportSize) {
415             Error ("Address size mismatch for symbol `%s'", GetSymName (S));
416         }
417     }
418
419     /* If the symbol was already declared as a condes, check if the new
420      * priority value is the same as the old one.
421      */
422     if (S->ConDesPrio[Type] != CD_PRIO_NONE) {
423         if (S->ConDesPrio[Type] != Prio) {
424             Error ("Redeclaration mismatch for symbol `%s'", GetSymName (S));
425         }
426     }
427     S->ConDesPrio[Type] = Prio;
428
429     /* Set the symbol data */
430     S->Flags |= (SF_EXPORT | SF_REFERENCED);
431 }
432
433
434
435 int SymIsDef (const SymEntry* S)
436 /* Return true if the given symbol is already defined */
437 {
438     return (S->Flags & SF_DEFINED) != 0;
439 }
440
441
442
443 int SymIsRef (const SymEntry* S)
444 /* Return true if the given symbol has been referenced */
445 {
446     return (S->Flags & SF_REFERENCED) != 0;
447 }
448
449
450
451 int SymIsImport (const SymEntry* S)
452 /* Return true if the given symbol is marked as import */
453 {
454     /* Resolve trampoline entries */
455     if (S->Flags & SF_TRAMPOLINE) {
456         S = S->V.Sym;
457     }
458
459     /* Check the import flag */
460     return (S->Flags & SF_IMPORT) != 0;
461 }
462
463
464
465 int SymIsConst (SymEntry* S, long* Val)
466 /* Return true if the given symbol has a constant value. If Val is not NULL
467  * and the symbol has a constant value, store it's value there.
468  */
469 {
470     /* Resolve trampoline entries */
471     if (S->Flags & SF_TRAMPOLINE) {
472         S = S->V.Sym;
473     }
474
475     /* Check for constness */
476     return (SymHasExpr (S) && IsConstExpr (S->V.Expr, Val));
477 }
478
479
480
481 int SymHasExpr (const SymEntry* S)
482 /* Return true if the given symbol has an associated expression */
483 {
484     /* Resolve trampoline entries */
485     if (S->Flags & SF_TRAMPOLINE) {
486         S = S->V.Sym;
487     }
488
489     /* Check the expression */
490     return ((S->Flags & (SF_DEFINED|SF_IMPORT)) == SF_DEFINED);
491 }
492
493
494
495 void SymMarkUser (SymEntry* S)
496 /* Set a user mark on the specified symbol */
497 {
498     /* Resolve trampoline entries */
499     if (S->Flags & SF_TRAMPOLINE) {
500         S = S->V.Sym;
501     }
502
503     /* Set the bit */
504     S->Flags |= SF_USER;
505 }
506
507
508
509 void SymUnmarkUser (SymEntry* S)
510 /* Remove a user mark from the specified symbol */
511 {
512     /* Resolve trampoline entries */
513     if (S->Flags & SF_TRAMPOLINE) {
514         S = S->V.Sym;
515     }
516
517     /* Reset the bit */
518     S->Flags &= ~SF_USER;
519 }
520
521
522
523 int SymHasUserMark (SymEntry* S)
524 /* Return the state of the user mark for the specified symbol */
525 {
526     /* Resolve trampoline entries */
527     if (S->Flags & SF_TRAMPOLINE) {
528         S = S->V.Sym;
529     }
530
531     /* Check the bit */
532     return (S->Flags & SF_USER) != 0;
533 }
534
535
536
537 struct ExprNode* GetSymExpr (SymEntry* S)
538 /* Get the expression for a non-const symbol */
539 {
540     /* Resolve trampoline entries */
541     if (S->Flags & SF_TRAMPOLINE) {
542         S = S->V.Sym;
543     }
544
545     PRECONDITION (S != 0 && SymHasExpr (S));
546     return S->V.Expr;
547 }
548
549
550
551 const struct ExprNode* SymResolve (const SymEntry* S)
552 /* Helper function for DumpExpr. Resolves a symbol into an expression or return
553  * NULL. Do not call in other contexts!
554  */
555 {
556     /* Resolve trampoline entries */
557     if (S->Flags & SF_TRAMPOLINE) {
558         S = S->V.Sym;
559     }
560
561     return SymHasExpr (S)? S->V.Expr : 0;
562 }
563
564
565
566 const char* GetSymName (const SymEntry* S)
567 /* Return the name of the symbol */
568 {
569     /* Resolve trampoline entries */
570     if (S->Flags & SF_TRAMPOLINE) {
571         S = S->V.Sym;
572     }
573     return GetString (S->Name);
574 }
575
576
577
578 unsigned GetSymAddrSize (const SymEntry* S)
579 /* Return the address size of the symbol. Beware: This function will just
580  * return the AddrSize member, it will not look at the expression!
581  */
582 {
583     if (S->Flags & SF_TRAMPOLINE) {
584         S = S->V.Sym;
585     }
586     return S->AddrSize;
587 }
588
589
590
591 unsigned GetSymIndex (const SymEntry* S)
592 /* Return the symbol index for the given symbol */
593 {
594     /* Resolve trampoline entries */
595     if (S->Flags & SF_TRAMPOLINE) {
596         S = S->V.Sym;
597     }
598     PRECONDITION (S != 0 && (S->Flags & SF_INDEXED) != 0);
599     return S->Index;
600 }
601
602
603
604 const FilePos* GetSymPos (const SymEntry* S)
605 /* Return the position of first occurence in the source for the given symbol */
606 {
607     /* Resolve trampoline entries */
608     if (S->Flags & SF_TRAMPOLINE) {
609         S = S->V.Sym;
610     }
611     PRECONDITION (S != 0);
612     return &S->Pos;
613 }
614
615
616
617