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