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