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