]> git.sur5r.net Git - cc65/blob - src/ca65/symentry.c
Added variable symbols using .set
[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-2004 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 "studyexpr.h"          /* ### */
50 #include "symentry.h"
51 #include "symtab.h"
52
53
54
55 /*****************************************************************************/
56 /*                                   Data                                    */
57 /*****************************************************************************/
58
59
60
61 /* List of all symbol table entries */
62 SymEntry* SymList = 0;
63
64 /* Pointer to last defined symbol */
65 SymEntry* SymLast = 0;
66
67
68
69 /*****************************************************************************/
70 /*                                   Code                                    */
71 /*****************************************************************************/
72
73
74
75 SymEntry* NewSymEntry (const char* Name, unsigned Flags)
76 /* Allocate a symbol table entry, initialize and return it */
77 {
78     /* Allocate memory */
79     SymEntry* S = xmalloc (sizeof (SymEntry));
80
81     /* Initialize the entry */
82     S->Left       = 0;
83     S->Right      = 0;
84     S->Locals     = 0;
85     S->SymTab     = 0;
86     S->Pos        = CurPos;
87     S->Flags      = Flags;
88     S->Expr       = 0;
89     S->ExprRefs   = AUTO_COLLECTION_INITIALIZER;
90     S->ExportSize = ADDR_SIZE_DEFAULT;
91     S->AddrSize   = ADDR_SIZE_DEFAULT;
92     memset (S->ConDesPrio, 0, sizeof (S->ConDesPrio));
93     S->Name       = GetStringId (Name);
94
95     /* Insert it into the list of all entries */
96     S->List = SymList;
97     SymList = S;
98
99     /* Return the initialized entry */
100     return S;
101 }
102
103
104
105 int SymSearchTree (SymEntry* T, const char* Name, SymEntry** E)
106 /* Search in the given tree for a name. If we find the symbol, the function
107  * will return 0 and put the entry pointer into E. If we did not find the
108  * symbol, and the tree is empty, E is set to NULL. If the tree is not empty,
109  * E will be set to the last entry, and the result of the function is <0 if
110  * the entry should be inserted on the left side, and >0 if it should get
111  * inserted on the right side.
112  */
113 {
114     /* Is there a tree? */
115     if (T == 0) {
116         *E = 0;
117         return 1;
118     }
119
120     /* We have a table, search it */
121     while (1) {
122
123         /* Get the symbol name */
124         const char* SymName = GetString (T->Name);
125
126         /* Choose next entry */
127         int Cmp = strcmp (Name, SymName);
128         if (Cmp < 0 && T->Left) {
129             T = T->Left;
130         } else if (Cmp > 0&& T->Right) {
131             T = T->Right;
132         } else {
133             /* Found or end of search, return the result */
134             *E = T;
135             return Cmp;
136         }
137     }
138 }
139
140
141
142 void SymRef (SymEntry* S)
143 /* Mark the given symbol as referenced */
144 {
145     /* Mark the symbol as referenced */
146     S->Flags |= SF_REFERENCED;
147 }
148
149
150
151 void SymTransferExprRefs (SymEntry* From, SymEntry* To)
152 /* Transfer all expression references from one symbol to another. */
153 {
154     unsigned I;
155
156     for (I = 0; I < CollCount (&From->ExprRefs); ++I) {
157
158         /* Get the expression node */
159         ExprNode* E = CollAtUnchecked (&From->ExprRefs, I);
160
161         /* Safety */
162         CHECK (E->Op == EXPR_SYMBOL && E->V.Sym == From);
163
164         /* Replace the symbol reference */
165         E->V.Sym = To;
166
167         /* Add the expression reference */
168         SymAddExprRef (To, E);
169     }
170
171     /* Remove all symbol references from the old symbol */
172     CollDeleteAll (&From->ExprRefs);
173 }
174
175
176
177 static void SymReplaceExprRefs (SymEntry* S)
178 /* Replace the references to this symbol by a copy of the symbol expression */
179 {
180     unsigned I;
181     long     Val;
182
183     /* Check if the expression is const and get its value */
184     int IsConst = IsConstExpr (S->Expr, &Val);
185     CHECK (IsConst);
186
187     /* Loop over all references */
188     for (I = 0; I < CollCount (&S->ExprRefs); ++I) {
189
190         /* Get the expression node */
191         ExprNode* E = CollAtUnchecked (&S->ExprRefs, I);
192
193         /* Safety */
194         CHECK (E->Op == EXPR_SYMBOL && E->V.Sym == S);
195
196         /* We cannot touch the root node, since there are pointers to it. 
197          * Replace it by a literal node.
198          */
199         E->Op = EXPR_LITERAL;
200         E->V.Val = Val;
201     }
202
203     /* Remove all symbol references from the symbol */
204     CollDeleteAll (&S->ExprRefs);
205 }
206
207
208
209 void SymDef (SymEntry* S, ExprNode* Expr, unsigned char AddrSize, unsigned Flags)
210 /* Define a new symbol */
211 {
212     if (S->Flags & SF_IMPORT) {
213         /* Defined symbol is marked as imported external symbol */
214         Error ("Symbol `%s' is already an import", GetSymName (S));
215         return;
216     }
217     if ((Flags & SF_VAR) != 0 && (S->Flags & (SF_EXPORT | SF_GLOBAL))) {
218         /* Variable symbols cannot be exports or globals */
219         Error ("Var symbol `%s' cannot be an export or global symbol", GetSymName (S));
220         return;
221     }
222     if (S->Flags & SF_DEFINED) {
223         /* Multiple definition. In case of a variable, this is legal. */
224         if ((S->Flags & SF_VAR) == 0) {
225             Error ("Symbol `%s' is already defined", GetSymName (S));
226             S->Flags |= SF_MULTDEF;
227             return;
228         } else {
229             /* Redefinition must also be a variable symbol */
230             if ((Flags & SF_VAR) == 0) {
231                 Error ("Symbol `%s' is already different kind", GetSymName (S));
232                 return;
233             }
234             /* Delete the current symbol expression, since it will get
235              * replaced
236              */
237             FreeExpr (S->Expr);
238             S->Expr = 0;
239         }
240     }
241
242     /* Map a default address size to a real value */
243     if (AddrSize == ADDR_SIZE_DEFAULT) {
244         /* ### Must go! Delay address size calculation until end of assembly! */
245         ExprDesc ED;
246         ED_Init (&ED);
247         StudyExpr (Expr, &ED);
248         AddrSize = ED.AddrSize;
249         ED_Done (&ED);
250     }
251
252     /* Set the symbol value */
253     S->Expr = Expr;
254
255     /* In case of a variable symbol, walk over all expressions containing 
256      * this symbol and replace the (sub-)expression by the literal value of
257      * the tree. Be sure to replace the expression node in place, since there
258      * may be pointers to it.
259      */
260     if (Flags & SF_VAR) {
261         SymReplaceExprRefs (S);
262     }
263
264     /* If the symbol is marked as global, export it. Address size is checked
265      * below.
266      */
267     if (S->Flags & SF_GLOBAL) {
268         S->Flags = (S->Flags & ~SF_GLOBAL) | SF_EXPORT;
269     }
270
271     /* Mark the symbol as defined and use the given address size */
272     S->Flags |= (SF_DEFINED | Flags);
273     S->AddrSize = AddrSize;
274
275     /* If the symbol is exported, check the address sizes */
276     if (S->Flags & SF_EXPORT) {
277         if (S->ExportSize == ADDR_SIZE_DEFAULT) {
278             /* Use the real size of the symbol */
279             S->ExportSize = S->AddrSize;
280         } else if (S->AddrSize > S->ExportSize) {
281             /* We're exporting a symbol smaller than it actually is */
282             PWarning (GetSymPos (S), 1, "Symbol `%s' is %s but exported %s",
283                       GetSymName (S), AddrSizeToStr (S->AddrSize),
284                       AddrSizeToStr (S->ExportSize));
285         }
286     }
287
288     /* If this is not a local symbol, remember it as the last global one */
289     if ((S->Flags & SF_LOCAL) == 0) {
290         SymLast = S;
291     }
292 }
293
294
295
296 void SymImport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
297 /* Mark the given symbol as an imported symbol */
298 {
299     if (S->Flags & SF_DEFINED) {
300         Error ("Symbol `%s' is already defined", GetSymName (S));
301         S->Flags |= SF_MULTDEF;
302         return;
303     }
304     if (S->Flags & SF_EXPORT) {
305         /* The symbol is already marked as exported symbol */
306         Error ("Cannot import exported symbol `%s'", GetSymName (S));
307         return;
308     }
309
310     /* If no address size is given, use the address size of the enclosing
311      * segment.
312      */
313     if (AddrSize == ADDR_SIZE_DEFAULT) {
314         AddrSize = GetCurrentSegAddrSize ();
315     }
316
317     /* If the symbol is marked as import or global, check the address size,
318      * then do silently remove the global flag.
319      */
320     if (S->Flags & SF_IMPORT) {
321         if ((Flags & SF_FORCED) != (S->Flags & SF_FORCED)) {
322             Error ("Redeclaration mismatch for symbol `%s'", GetSymName (S));
323         }
324         if (AddrSize != S->AddrSize) {
325             Error ("Address size mismatch for symbol `%s'", GetSymName (S));
326         }
327     }
328     if (S->Flags & SF_GLOBAL) {
329         S->Flags &= ~SF_GLOBAL;
330         if (AddrSize != S->AddrSize) {
331             Error ("Address size mismatch for symbol `%s'", GetSymName (S));
332         }
333     }
334
335     /* Set the symbol data */
336     S->Flags |= (SF_IMPORT | Flags);
337     S->AddrSize = AddrSize;
338 }
339
340
341
342 void SymExport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
343 /* Mark the given symbol as an exported symbol */
344 {
345     /* Check if it's ok to export the symbol */
346     if (S->Flags & SF_IMPORT) {
347         /* The symbol is already marked as imported external symbol */
348         Error ("Symbol `%s' is already an import", GetSymName (S));
349         return;
350     }
351     if (S->Flags & SF_VAR) {
352         /* Variable symbols cannot be exported */
353         Error ("Var symbol `%s' cannot be exported", GetSymName (S));
354         return;
355     }
356
357     /* If the symbol was marked as global before, remove the global flag and
358      * proceed, but check the address size.
359      */
360     if (S->Flags & SF_GLOBAL) {
361         if (AddrSize != S->ExportSize) {
362             Error ("Address size mismatch for symbol `%s'", GetSymName (S));
363         }
364         S->Flags &= ~SF_GLOBAL;
365     }
366
367     /* If the symbol was already marked as an export, but wasn't defined
368      * before, the address sizes in both definitions must match.
369      */
370     if ((S->Flags & (SF_EXPORT|SF_DEFINED)) == SF_EXPORT) {
371         if (S->ExportSize != AddrSize) {
372             Error ("Address size mismatch for symbol `%s'", GetSymName (S));
373         }
374     }
375     S->ExportSize = AddrSize;
376
377     /* If the symbol is already defined, check symbol size against the
378      * exported size.
379      */
380     if (S->Flags & SF_DEFINED) {
381         if (S->ExportSize == ADDR_SIZE_DEFAULT) {
382             /* No export size given, use the real size of the symbol */
383             S->ExportSize = S->AddrSize;
384         } else if (S->AddrSize > S->ExportSize) {
385             /* We're exporting a symbol smaller than it actually is */
386             Warning (1, "Symbol `%s' is %s but exported %s",
387                      GetSymName (S), AddrSizeToStr (S->AddrSize),
388                      AddrSizeToStr (S->ExportSize));
389         }
390     }
391
392     /* Set the symbol data */
393     S->Flags |= (SF_EXPORT | SF_REFERENCED | Flags);
394 }
395
396
397
398 void SymGlobal (SymEntry* S, unsigned char AddrSize, unsigned Flags)
399 /* Mark the given symbol as a global symbol, that is, as a symbol that is
400  * either imported or exported.
401  */
402 {
403     if (S->Flags & SF_VAR) {
404         /* Variable symbols cannot be exported or imported */
405         Error ("Var symbol `%s' cannot be made global", GetSymName (S));
406         return;
407     }
408
409     /* If the symbol is already marked as import, the address size must match.
410      * Apart from that, ignore the global declaration.
411      */
412     if (S->Flags & SF_IMPORT) {
413         if (AddrSize == ADDR_SIZE_DEFAULT) {
414             /* Use the size of the current segment */
415             AddrSize = GetCurrentSegAddrSize ();
416         }
417         if (AddrSize != S->AddrSize) {
418             Error ("Address size mismatch for symbol `%s'", GetSymName (S));
419         }
420         return;
421     }
422
423     /* If the symbol is already an export: If it is not defined, the address
424      * sizes must match.
425      */
426     if (S->Flags & SF_EXPORT) {
427         if ((S->Flags & SF_DEFINED) == 0) {
428             /* Symbol is undefined */
429             if (AddrSize != S->ExportSize) {
430                 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
431             }
432         } else if (AddrSize != ADDR_SIZE_DEFAULT) {
433             /* Symbol is defined and address size given */
434             if (AddrSize != S->ExportSize) {
435                 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
436             }
437         }
438         return;
439     }
440
441     /* If the symbol is already marked as global, the address size must match.
442      * Use the ExportSize here, since it contains the actual address size
443      * passed to this function.
444      */
445     if (S->Flags & SF_GLOBAL) {
446         if (AddrSize != S->ExportSize) {
447             Error ("Address size mismatch for symbol `%s'", GetSymName (S));
448         }
449         return;
450     }
451
452     /* If we come here, the symbol was neither declared as export, import or
453      * global before. Check if it is already defined, in which case it will
454      * become an export. If it is not defined, mark it as global and remember
455      * the given address sizes.
456      */
457     if (S->Flags & SF_DEFINED) {
458         /* The symbol is defined, export it */
459         S->ExportSize = AddrSize;
460         if (S->ExportSize == ADDR_SIZE_DEFAULT) {
461             /* No export size given, use the real size of the symbol */
462             S->ExportSize = S->AddrSize;
463         } else if (S->AddrSize > S->ExportSize) {
464             /* We're exporting a symbol smaller than it actually is */
465             Warning (1, "Symbol `%s' is %s but exported %s",
466                      GetSymName (S), AddrSizeToStr (S->AddrSize),
467                      AddrSizeToStr (S->ExportSize));
468         }
469         S->Flags |= (SF_EXPORT | Flags);
470     } else {
471         /* Since we don't know if the symbol will get exported or imported,
472          * remember two different address sizes: One for an import in AddrSize,
473          * and the other one for an export in ExportSize.
474          */
475         S->AddrSize = AddrSize;
476         if (S->AddrSize == ADDR_SIZE_DEFAULT) {
477             /* Use the size of the current segment */
478             S->AddrSize = GetCurrentSegAddrSize ();
479         }
480         S->ExportSize = AddrSize;
481         S->Flags |= (SF_GLOBAL | Flags);
482     }
483 }
484
485
486
487 void SymConDes (SymEntry* S, unsigned char AddrSize, unsigned Type, unsigned Prio)
488 /* Mark the given symbol as a module constructor/destructor. This will also
489  * mark the symbol as an export. Initializers may never be zero page symbols.
490  */
491 {
492     /* Check the parameters */
493 #if (CD_TYPE_MIN != 0)
494     CHECK (Type >= CD_TYPE_MIN && Type <= CD_TYPE_MAX);
495 #else
496     CHECK (Type <= CD_TYPE_MAX);
497 #endif
498     CHECK (Prio >= CD_PRIO_MIN && Prio <= CD_PRIO_MAX);
499
500     /* Check for errors */
501     if (S->Flags & SF_IMPORT) {
502         /* The symbol is already marked as imported external symbol */
503         Error ("Symbol `%s' is already an import", GetSymName (S));
504         return;
505     }
506     if (S->Flags & SF_VAR) {
507         /* Variable symbols cannot be exported or imported */
508         Error ("Var symbol `%s' cannot be exported", GetSymName (S));
509         return;
510     }
511
512     /* If the symbol was already marked as an export or global, check if
513      * this was done specifiying the same address size. In case of a global
514      * declaration, silently remove the global flag.
515      */
516     if (S->Flags & (SF_EXPORT | SF_GLOBAL)) {
517         if (S->ExportSize != AddrSize) {
518             Error ("Address size mismatch for symbol `%s'", GetSymName (S));
519         }
520         S->Flags &= ~SF_GLOBAL;
521     }
522     S->ExportSize = AddrSize;
523
524     /* If the symbol is already defined, check symbol size against the
525      * exported size.
526      */
527     if (S->Flags & SF_DEFINED) {
528         if (S->ExportSize == ADDR_SIZE_DEFAULT) {
529             /* Use the real size of the symbol */
530             S->ExportSize = S->AddrSize;
531         } else if (S->AddrSize != S->ExportSize) {
532             Error ("Address size mismatch for symbol `%s'", GetSymName (S));
533         }
534     }
535
536     /* If the symbol was already declared as a condes, check if the new
537      * priority value is the same as the old one.
538      */
539     if (S->ConDesPrio[Type] != CD_PRIO_NONE) {
540         if (S->ConDesPrio[Type] != Prio) {
541             Error ("Redeclaration mismatch for symbol `%s'", GetSymName (S));
542         }
543     }
544     S->ConDesPrio[Type] = Prio;
545
546     /* Set the symbol data */
547     S->Flags |= (SF_EXPORT | SF_REFERENCED);
548 }
549
550
551
552 void SymExportFromGlobal (SymEntry* S)
553 /* Called at the end of assembly. Converts a global symbol that is defined
554  * into an export.
555  */
556 {
557     /* Remove the global flag and make the symbol an export */
558     S->Flags &= ~SF_GLOBAL;
559     S->Flags |= SF_EXPORT;
560 }
561
562
563
564 void SymImportFromGlobal (SymEntry* S)
565 /* Called at the end of assembly. Converts a global symbol that is undefined
566  * into an import.
567  */
568 {
569     /* Remove the global flag and make it an import */
570     S->Flags &= ~SF_GLOBAL;
571     S->Flags |= SF_IMPORT;
572 }
573
574
575
576 int SymIsConst (SymEntry* S, long* Val)
577 /* Return true if the given symbol has a constant value. If Val is not NULL
578  * and the symbol has a constant value, store it's value there.
579  */
580 {
581     /* Check for constness */
582     return (SymHasExpr (S) && IsConstExpr (S->Expr, Val));
583 }
584
585
586
587 SymTable* GetSymParentScope (SymEntry* S)
588 /* Get the parent scope of the symbol (not the one it is defined in). Return
589  * NULL if the symbol is a cheap local, or defined on global level.
590  */
591 {
592     return (S->SymTab && S->SymTab->Parent)? S->SymTab->Parent : 0;
593 }
594
595
596
597 struct ExprNode* GetSymExpr (SymEntry* S)
598 /* Get the expression for a non-const symbol */
599 {
600     PRECONDITION (S != 0 && SymHasExpr (S));
601     return S->Expr;
602 }
603
604
605
606 const struct ExprNode* SymResolve (const SymEntry* S)
607 /* Helper function for DumpExpr. Resolves a symbol into an expression or return
608  * NULL. Do not call in other contexts!
609  */
610 {
611     return SymHasExpr (S)? S->Expr : 0;
612 }
613
614
615
616 long GetSymVal (SymEntry* S)
617 /* Return the value of a symbol assuming it's constant. FAIL will be called
618  * in case the symbol is undefined or not constant.
619  */
620 {
621     long Val;
622     CHECK (S != 0 && SymHasExpr (S) && IsConstExpr (GetSymExpr (S), &Val));
623     return Val;
624 }
625
626
627
628 unsigned GetSymIndex (const SymEntry* S)
629 /* Return the symbol index for the given symbol */
630 {
631     PRECONDITION (S != 0 && (S->Flags & SF_INDEXED) != 0);
632     return S->Index;
633 }
634
635
636