]> git.sur5r.net Git - cc65/blob - src/ca65/symentry.c
Don't use SF_TRAMPOLINE, change symbol references instead.
[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 int SymSearchTree (SymEntry* T, const char* Name, SymEntry** E)
135 /* Search in the given tree for a name. If we find the symbol, the function
136  * will return 0 and put the entry pointer into E. If we did not find the
137  * symbol, and the tree is empty, E is set to NULL. If the tree is not empty,
138  * E will be set to the last entry, and the result of the function is <0 if
139  * the entry should be inserted on the left side, and >0 if it should get
140  * inserted on the right side.
141  */
142 {
143     /* Is there a tree? */
144     if (T == 0) {
145         *E = 0;
146         return 1;
147     }
148
149     /* We have a table, search it */
150     while (1) {
151
152         /* Get the symbol name */
153         const char* SymName = GetString (T->Name);
154
155         /* Choose next entry */
156         int Cmp = strcmp (Name, SymName);
157         if (Cmp < 0 && T->Left) {
158             T = T->Left;
159         } else if (Cmp > 0&& T->Right) {
160             T = T->Right;
161         } else {
162             /* Found or end of search, return the result */
163             *E = T;
164             return Cmp;
165         }
166     }
167 }
168
169
170
171 void SymRef (SymEntry* S)
172 /* Mark the given symbol as referenced */
173 {
174     /* Mark the symbol as referenced */
175     S->Flags |= SF_REFERENCED;
176 }
177
178
179
180 void SymTransferExprRefs (SymEntry* From, SymEntry* To)
181 /* Transfer all expression references from one symbol to another. */
182 {
183     unsigned I;
184
185     for (I = 0; I < CollCount (&From->ExprRefs); ++I) {
186
187         /* Get the expression node */
188         ExprNode* E = CollAtUnchecked (&From->ExprRefs, I);
189
190         /* Safety */
191         CHECK (E->Op == EXPR_SYMBOL && E->V.Sym == From);
192
193         /* Replace the symbol reference */
194         E->V.Sym = To;
195
196         /* Add the expression reference */
197         SymAddExprRef (To, E);
198     }
199
200     /* Remove all symbol references from the old symbol */
201     CollDeleteAll (&From->ExprRefs);
202 }
203
204
205
206 void SymDef (SymEntry* S, ExprNode* Expr, unsigned char AddrSize, unsigned Flags)
207 /* Define a new symbol */
208 {
209     if (S->Flags & SF_IMPORT) {
210         /* Defined symbol is marked as imported external symbol */
211         Error ("Symbol `%s' is already an import", GetSymName (S));
212         return;
213     }
214     if (S->Flags & SF_DEFINED) {
215         /* Multiple definition */
216         Error ("Symbol `%s' is already defined", GetSymName (S));
217         S->Flags |= SF_MULTDEF;
218         return;
219     }
220
221     /* Map a default address size to a real value */
222     if (AddrSize == ADDR_SIZE_DEFAULT) {
223         long Val;
224         if (IsConstExpr (Expr, &Val)) {
225             if (IsByteRange (Val)) {
226                 AddrSize = ADDR_SIZE_ZP;
227             } else if (IsWordRange (Val)) {
228                 AddrSize = ADDR_SIZE_ABS;
229             } else if (IsFarRange (Val)) {
230                 AddrSize = ADDR_SIZE_FAR;
231             } else {
232                 AddrSize = ADDR_SIZE_LONG;
233             }
234         } else {
235             AddrSize = SymAddrSize (S);
236         }
237     }
238
239     /* Set the symbol value */
240     S->V.Expr = Expr;
241
242     /* If the symbol is marked as global, export it. Address size is checked
243      * below.
244      */
245     if (S->Flags & SF_GLOBAL) {
246         S->Flags = (S->Flags & ~SF_GLOBAL) | SF_EXPORT;
247     }
248
249     /* Mark the symbol as defined and use the given address size */
250     S->Flags |= (SF_DEFINED | Flags);
251     S->AddrSize = AddrSize;
252
253     /* If the symbol is exported, check the address sizes */
254     if (S->Flags & SF_EXPORT) {
255         if (S->ExportSize == ADDR_SIZE_DEFAULT) {
256             /* Use the real size of the symbol */
257             S->ExportSize = S->AddrSize;
258         } else if (S->AddrSize > S->ExportSize) {
259             /* We're exporting a symbol smaller than it actually is */
260             PWarning (GetSymPos (S), 1, "Symbol `%s' is %s but exported %s",
261                       GetSymName (S), AddrSizeToStr (S->AddrSize),
262                       AddrSizeToStr (S->ExportSize));
263         }
264     }
265
266     /* If this is not a local symbol, remember it as the last global one */
267     if (!IsLocalNameId (S->Name)) {
268         SymLast = S;
269     }
270 }
271
272
273
274 void SymImport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
275 /* Mark the given symbol as an imported symbol */
276 {
277     if (S->Flags & SF_DEFINED) {
278         Error ("Symbol `%s' is already defined", GetSymName (S));
279         S->Flags |= SF_MULTDEF;
280         return;
281     }
282     if (S->Flags & SF_EXPORT) {
283         /* The symbol is already marked as exported symbol */
284         Error ("Cannot import exported symbol `%s'", GetSymName (S));
285         return;
286     }
287
288     /* If no address size is given, use the address size of the enclosing
289      * segment.
290      */
291     if (AddrSize == ADDR_SIZE_DEFAULT) {
292         AddrSize = GetCurrentSegAddrSize ();
293     }
294
295     /* If the symbol is marked as import or global, check the address size,
296      * then do silently remove the global flag.
297      */
298     if (S->Flags & SF_IMPORT) {
299         if ((Flags & SF_FORCED) != (S->Flags & SF_FORCED)) {
300             Error ("Redeclaration mismatch for symbol `%s'", GetSymName (S));
301         }
302         if (AddrSize != S->AddrSize) {
303             Error ("Address size mismatch for symbol `%s'", GetSymName (S));
304         }
305     }
306     if (S->Flags & SF_GLOBAL) {
307         S->Flags &= ~SF_GLOBAL;
308         if (AddrSize != S->AddrSize) {
309             Error ("Address size mismatch for symbol `%s'", GetSymName (S));
310         }
311     }
312
313     /* Set the symbol data */
314     S->Flags |= (SF_IMPORT | Flags);
315     S->AddrSize = AddrSize;
316 }
317
318
319
320 void SymExport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
321 /* Mark the given symbol as an exported symbol */
322 {
323     /* Check if it's ok to export the symbol */
324     if (S->Flags & SF_IMPORT) {
325         /* The symbol is already marked as imported external symbol */
326         Error ("Symbol `%s' is already an import", GetSymName (S));
327         return;
328     }
329
330     /* If the symbol was marked as global before, remove the global flag and
331      * proceed, but check the address size.
332      */
333     if (S->Flags & SF_GLOBAL) {
334         if (AddrSize != S->ExportSize) {
335             Error ("Address size mismatch for symbol `%s'", GetSymName (S));
336         }
337         S->Flags &= ~SF_GLOBAL;
338     }
339
340     /* If the symbol was already marked as an export, but wasn't defined
341      * before, the address sizes in both definitions must match.
342      */
343     if ((S->Flags & (SF_EXPORT|SF_DEFINED)) == SF_EXPORT) {
344         if (S->ExportSize != AddrSize) {
345             Error ("Address size mismatch for symbol `%s'", GetSymName (S));
346         }
347     }
348     S->ExportSize = AddrSize;
349
350     /* If the symbol is already defined, check symbol size against the
351      * exported size.
352      */
353     if (S->Flags & SF_DEFINED) {
354         if (S->ExportSize == ADDR_SIZE_DEFAULT) {
355             /* No export size given, use the real size of the symbol */
356             S->ExportSize = S->AddrSize;
357         } else if (S->AddrSize > S->ExportSize) {
358             /* We're exporting a symbol smaller than it actually is */
359             Warning (1, "Symbol `%s' is %s but exported %s",
360                      GetSymName (S), AddrSizeToStr (S->AddrSize),
361                      AddrSizeToStr (S->ExportSize));
362         }
363     }
364
365     /* Set the symbol data */
366     S->Flags |= (SF_EXPORT | SF_REFERENCED | Flags);
367 }
368
369
370
371 void SymGlobal (SymEntry* S, unsigned char AddrSize, unsigned Flags)
372 /* Mark the given symbol as a global symbol, that is, as a symbol that is
373  * either imported or exported.
374  */
375 {
376     /* If the symbol is already marked as import, the address size must match.
377      * Apart from that, ignore the global declaration.
378      */
379     if (S->Flags & SF_IMPORT) {
380         if (AddrSize == ADDR_SIZE_DEFAULT) {
381             /* Use the size of the current segment */
382             AddrSize = GetCurrentSegAddrSize ();
383         }
384         if (AddrSize != S->AddrSize) {
385             Error ("Address size mismatch for symbol `%s'", GetSymName (S));
386         }
387         return;
388     }
389
390     /* If the symbol is already an export: If it is not defined, the address
391      * sizes must match.
392      */
393     if (S->Flags & SF_EXPORT) {
394         if ((S->Flags & SF_DEFINED) == 0) {
395             /* Symbol is undefined */
396             if (AddrSize != S->ExportSize) {
397                 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
398             }
399         } else if (AddrSize != ADDR_SIZE_DEFAULT) {
400             /* Symbol is defined and address size given */
401             if (AddrSize != S->ExportSize) {
402                 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
403             }
404         }
405         return;
406     }
407
408     /* If the symbol is already marked as global, the address size must match.
409      * Use the ExportSize here, since it contains the actual address size
410      * passed to this function.
411      */
412     if (S->Flags & SF_GLOBAL) {
413         if (AddrSize != S->ExportSize) {
414             Error ("Address size mismatch for symbol `%s'", GetSymName (S));
415         }
416         return;
417     }
418
419     /* If we come here, the symbol was neither declared as export, import or
420      * global before. Check if it is already defined, in which case it will
421      * become an export. If it is not defined, mark it as global and remember
422      * the given address sizes.
423      */
424     if (S->Flags & SF_DEFINED) {
425         /* The symbol is defined, export it */
426         S->ExportSize = AddrSize;
427         if (S->ExportSize == ADDR_SIZE_DEFAULT) {
428             /* No export size given, use the real size of the symbol */
429             S->ExportSize = S->AddrSize;
430         } else if (S->AddrSize > S->ExportSize) {
431             /* We're exporting a symbol smaller than it actually is */
432             Warning (1, "Symbol `%s' is %s but exported %s",
433                      GetSymName (S), AddrSizeToStr (S->AddrSize),
434                      AddrSizeToStr (S->ExportSize));
435         }
436         S->Flags |= (SF_EXPORT | Flags);
437     } else {
438         /* Since we don't know if the symbol will get exported or imported,
439          * remember two different address sizes: One for an import in AddrSize,
440          * and the other one for an export in ExportSize.
441          */
442         S->AddrSize = AddrSize;
443         if (S->AddrSize == ADDR_SIZE_DEFAULT) {
444             /* Use the size of the current segment */
445             S->AddrSize = GetCurrentSegAddrSize ();
446         }
447         S->ExportSize = AddrSize;
448         S->Flags |= (SF_GLOBAL | Flags);
449     }
450 }
451
452
453
454 void SymConDes (SymEntry* S, unsigned char AddrSize, unsigned Type, unsigned Prio)
455 /* Mark the given symbol as a module constructor/destructor. This will also
456  * mark the symbol as an export. Initializers may never be zero page symbols.
457  */
458 {
459     /* Check the parameters */
460 #if (CD_TYPE_MIN != 0)
461     CHECK (Type >= CD_TYPE_MIN && Type <= CD_TYPE_MAX);
462 #else
463     CHECK (Type <= CD_TYPE_MAX);
464 #endif
465     CHECK (Prio >= CD_PRIO_MIN && Prio <= CD_PRIO_MAX);
466
467     /* Check for errors */
468     if (S->Flags & SF_IMPORT) {
469         /* The symbol is already marked as imported external symbol */
470         Error ("Symbol `%s' is already an import", GetSymName (S));
471         return;
472     }
473
474     /* If the symbol was already marked as an export or global, check if
475      * this was done specifiying the same address size. In case of a global
476      * declaration, silently remove the global flag.
477      */
478     if (S->Flags & (SF_EXPORT | SF_GLOBAL)) {
479         if (S->ExportSize != AddrSize) {
480             Error ("Address size mismatch for symbol `%s'", GetSymName (S));
481         }
482         S->Flags &= ~SF_GLOBAL;
483     }
484     S->ExportSize = AddrSize;
485
486     /* If the symbol is already defined, check symbol size against the
487      * exported size.
488      */
489     if (S->Flags & SF_DEFINED) {
490         if (S->ExportSize == ADDR_SIZE_DEFAULT) {
491             /* Use the real size of the symbol */
492             S->ExportSize = S->AddrSize;
493         } else if (S->AddrSize != S->ExportSize) {
494             Error ("Address size mismatch for symbol `%s'", GetSymName (S));
495         }
496     }
497
498     /* If the symbol was already declared as a condes, check if the new
499      * priority value is the same as the old one.
500      */
501     if (S->ConDesPrio[Type] != CD_PRIO_NONE) {
502         if (S->ConDesPrio[Type] != Prio) {
503             Error ("Redeclaration mismatch for symbol `%s'", GetSymName (S));
504         }
505     }
506     S->ConDesPrio[Type] = Prio;
507
508     /* Set the symbol data */
509     S->Flags |= (SF_EXPORT | SF_REFERENCED);
510 }
511
512
513
514 int SymIsConst (SymEntry* S, long* Val)
515 /* Return true if the given symbol has a constant value. If Val is not NULL
516  * and the symbol has a constant value, store it's value there.
517  */
518 {
519     /* Check for constness */
520     return (SymHasExpr (S) && IsConstExpr (S->V.Expr, Val));
521 }
522
523
524
525 struct ExprNode* GetSymExpr (SymEntry* S)
526 /* Get the expression for a non-const symbol */
527 {
528     PRECONDITION (S != 0 && SymHasExpr (S));
529     return S->V.Expr;
530 }
531
532
533
534 const struct ExprNode* SymResolve (const SymEntry* S)
535 /* Helper function for DumpExpr. Resolves a symbol into an expression or return
536  * NULL. Do not call in other contexts!
537  */
538 {
539     return SymHasExpr (S)? S->V.Expr : 0;
540 }
541
542
543
544 long GetSymVal (SymEntry* S)
545 /* Return the value of a symbol assuming it's constant. FAIL will be called
546  * in case the symbol is undefined or not constant.
547  */
548 {
549     long Val;
550     CHECK (S != 0 && SymHasExpr (S) && IsConstExpr (GetSymExpr (S), &Val));
551     return Val;
552 }
553
554
555
556 unsigned GetSymIndex (const SymEntry* S)
557 /* Return the symbol index for the given symbol */
558 {
559     PRECONDITION (S != 0 && (S->Flags & SF_INDEXED) != 0);
560     return S->Index;
561 }
562
563
564