1 /*****************************************************************************/
5 /* Symbol table entry forward for the ca65 macroassembler */
9 /* (C) 1998-2003 Ullrich von Bassewitz */
11 /* D-70794 Filderstadt */
12 /* EMail: uz@cc65.org */
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. */
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: */
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 */
32 /*****************************************************************************/
54 /*****************************************************************************/
56 /*****************************************************************************/
60 /* List of all symbol table entries */
61 SymEntry* SymList = 0;
63 /* Pointer to last defined symbol */
64 SymEntry* SymLast = 0;
68 /*****************************************************************************/
70 /*****************************************************************************/
74 int IsLocalName (const char* Name)
75 /* Return true if Name is the name of a local symbol */
77 return (*Name == LocalStart);
82 int IsLocalNameId (unsigned Name)
83 /* Return true if Name is the name of a local symbol */
85 return (*GetString (Name) == LocalStart);
90 static unsigned SymAddrSize (const SymEntry* S)
91 /* Get the default address size for a symbol. */
93 /* Local symbols are always near (is this ok?) */
94 if (IsLocalNameId (S->Name)) {
98 /* Return the address size of the segment */
99 return GetCurrentSegAddrSize ();
104 SymEntry* NewSymEntry (const char* Name)
105 /* Allocate a symbol table entry, initialize and return it */
107 /* Allocate memory */
108 SymEntry* S = xmalloc (sizeof (SymEntry));
110 /* Initialize the entry */
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);
124 /* Insert it into the list of all entries */
128 /* Return the initialized entry */
134 void SymRef (SymEntry* S)
135 /* Mark the given symbol as referenced */
137 /* Mark the symbol as referenced */
138 S->Flags |= SF_REFERENCED;
143 void SymDef (SymEntry* S, ExprNode* Expr, unsigned char AddrSize, unsigned Flags)
144 /* Define a new symbol */
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));
151 if (S->Flags & SF_DEFINED) {
152 /* Multiple definition */
153 Error ("Symbol `%s' is already defined", GetSymName (S));
154 S->Flags |= SF_MULTDEF;
158 /* Map a default address size to a real value */
159 if (AddrSize == ADDR_SIZE_DEFAULT) {
161 if (IsConstExpr (Expr, &Val) && IsByteRange (Val)) {
162 AddrSize = ADDR_SIZE_ZP;
164 AddrSize = SymAddrSize (S);
168 /* Set the symbol value */
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;
177 /* Mark the symbol as defined and use the given address size */
178 S->Flags |= (SF_DEFINED | Flags);
179 S->AddrSize = AddrSize;
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));
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");
201 /* If this is not a local symbol, remember it as the last global one */
202 if (!IsLocalNameId (S->Name)) {
209 void SymImport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
210 /* Mark the given symbol as an imported symbol */
212 /* Don't accept local symbols */
213 if (IsLocalNameId (S->Name)) {
214 Error ("Illegal use of a local symbol");
218 if (S->Flags & SF_DEFINED) {
219 Error ("Symbol `%s' is already defined", GetSymName (S));
220 S->Flags |= SF_MULTDEF;
223 if (S->Flags & SF_EXPORT) {
224 /* The symbol is already marked as exported symbol */
225 Error ("Cannot import exported symbol `%s'", GetSymName (S));
229 /* Map a default address size to a real value */
230 if (AddrSize == ADDR_SIZE_DEFAULT) {
231 AddrSize = SymAddrSize (S);
234 /* If the symbol is marked as import or global, check the symbol flags,
235 * then do silently remove the global flag
237 if (S->Flags & SF_IMPORT) {
238 if ((Flags & SF_FORCED) != (S->Flags & SF_FORCED)) {
239 Error ("Redeclaration mismatch for symbol `%s'", GetSymName (S));
241 if (AddrSize != S->AddrSize) {
242 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
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));
249 S->Flags &= ~SF_GLOBAL;
252 /* Set the symbol data */
253 S->Flags |= (SF_IMPORT | Flags);
254 S->AddrSize = AddrSize;
259 void SymExport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
260 /* Mark the given symbol as an exported symbol */
262 /* Don't accept local symbols */
263 if (IsLocalNameId (S->Name)) {
264 Error ("Illegal use of a local symbol");
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));
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;
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.
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;
291 if (S->ExportSize != ADDR_SIZE_DEFAULT && S->ExportSize != AddrSize) {
292 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
295 S->ExportSize = AddrSize;
297 /* If the symbol is already defined, check symbol size against the
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));
311 /* Set the symbol data */
312 S->Flags |= (SF_EXPORT | SF_REFERENCED | Flags);
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.
322 /* Don't accept local symbols */
323 if (IsLocalNameId (S->Name)) {
324 Error ("Illegal use of a local symbol");
328 /* If the symbol is already marked as import or export, check the
329 * size of the definition, then bail out.
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));
337 if (S->Flags & SF_EXPORT) {
338 /* If the old symbol had no explicit address size spec, use the
341 if (S->ExportSize == ADDR_SIZE_DEFAULT) {
342 S->ExportSize = AddrSize;
344 if (AddrSize != S->ExportSize) {
345 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
350 /* If the symbol is already defined, export it. Otherwise mark it as
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));
364 S->Flags |= (SF_EXPORT | Flags);
365 S->ExportSize = AddrSize;
367 S->Flags |= (SF_GLOBAL | Flags);
368 S->AddrSize = AddrSize;
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.
379 /* Check the parameters */
380 #if (CD_TYPE_MIN != 0)
381 CHECK (Type >= CD_TYPE_MIN && Type <= CD_TYPE_MAX);
383 CHECK (Type <= CD_TYPE_MAX);
385 CHECK (Prio >= CD_PRIO_MIN && Prio <= CD_PRIO_MAX);
387 /* Don't accept local symbols */
388 if (IsLocalNameId (S->Name)) {
389 Error ("Illegal use of a local symbol");
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));
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.
404 if (S->Flags & (SF_EXPORT | SF_GLOBAL)) {
405 if (S->ExportSize != AddrSize) {
406 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
408 S->Flags &= ~SF_GLOBAL;
410 S->ExportSize = AddrSize;
412 /* If the symbol is already defined, check symbol size against the
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));
424 /* If the symbol was already declared as a condes, check if the new
425 * priority value is the same as the old one.
427 if (S->ConDesPrio[Type] != CD_PRIO_NONE) {
428 if (S->ConDesPrio[Type] != Prio) {
429 Error ("Redeclaration mismatch for symbol `%s'", GetSymName (S));
432 S->ConDesPrio[Type] = Prio;
434 /* Set the symbol data */
435 S->Flags |= (SF_EXPORT | SF_REFERENCED);
440 int SymIsDef (const SymEntry* S)
441 /* Return true if the given symbol is already defined */
443 return (S->Flags & SF_DEFINED) != 0;
448 int SymIsRef (const SymEntry* S)
449 /* Return true if the given symbol has been referenced */
451 return (S->Flags & SF_REFERENCED) != 0;
456 int SymIsImport (const SymEntry* S)
457 /* Return true if the given symbol is marked as import */
459 /* Resolve trampoline entries */
460 if (S->Flags & SF_TRAMPOLINE) {
464 /* Check the import flag */
465 return (S->Flags & SF_IMPORT) != 0;
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.
475 /* Resolve trampoline entries */
476 if (S->Flags & SF_TRAMPOLINE) {
480 /* Check for constness */
481 return (SymHasExpr (S) && IsConstExpr (S->V.Expr, Val));
486 int SymHasExpr (const SymEntry* S)
487 /* Return true if the given symbol has an associated expression */
489 /* Resolve trampoline entries */
490 if (S->Flags & SF_TRAMPOLINE) {
494 /* Check the expression */
495 return ((S->Flags & (SF_DEFINED|SF_IMPORT)) == SF_DEFINED);
500 void SymMarkUser (SymEntry* S)
501 /* Set a user mark on the specified symbol */
503 /* Resolve trampoline entries */
504 if (S->Flags & SF_TRAMPOLINE) {
514 void SymUnmarkUser (SymEntry* S)
515 /* Remove a user mark from the specified symbol */
517 /* Resolve trampoline entries */
518 if (S->Flags & SF_TRAMPOLINE) {
523 S->Flags &= ~SF_USER;
528 int SymHasUserMark (SymEntry* S)
529 /* Return the state of the user mark for the specified symbol */
531 /* Resolve trampoline entries */
532 if (S->Flags & SF_TRAMPOLINE) {
537 return (S->Flags & SF_USER) != 0;
542 struct ExprNode* GetSymExpr (SymEntry* S)
543 /* Get the expression for a non-const symbol */
545 /* Resolve trampoline entries */
546 if (S->Flags & SF_TRAMPOLINE) {
550 PRECONDITION (S != 0 && SymHasExpr (S));
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!
561 /* Resolve trampoline entries */
562 if (S->Flags & SF_TRAMPOLINE) {
566 return SymHasExpr (S)? S->V.Expr : 0;
571 const char* GetSymName (const SymEntry* S)
572 /* Return the name of the symbol */
574 /* Resolve trampoline entries */
575 if (S->Flags & SF_TRAMPOLINE) {
578 return GetString (S->Name);
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!
588 if (S->Flags & SF_TRAMPOLINE) {
596 unsigned GetSymIndex (const SymEntry* S)
597 /* Return the symbol index for the given symbol */
599 /* Resolve trampoline entries */
600 if (S->Flags & SF_TRAMPOLINE) {
603 PRECONDITION (S != 0 && (S->Flags & SF_INDEXED) != 0);
609 const FilePos* GetSymPos (const SymEntry* S)
610 /* Return the position of first occurence in the source for the given symbol */
612 /* Resolve trampoline entries */
613 if (S->Flags & SF_TRAMPOLINE) {
616 PRECONDITION (S != 0);