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) {
160 AddrSize = SymAddrSize (S);
163 /* Set the symbol value */
166 /* If the symbol is marked as global, export it */
167 if (S->Flags & SF_GLOBAL) {
168 S->ExportSize = S->AddrSize;
169 S->Flags = (S->Flags & ~SF_GLOBAL) | SF_EXPORT;
172 /* Mark the symbol as defined and use the given address size */
173 S->Flags |= (SF_DEFINED | Flags);
174 S->AddrSize = AddrSize;
176 /* If the symbol is exported, check the address sizes */
177 if (S->Flags & SF_EXPORT) {
178 if (S->ExportSize == ADDR_SIZE_DEFAULT) {
179 /* Use the real size of the symbol */
180 S->ExportSize = S->AddrSize;
181 } else if (S->AddrSize > S->ExportSize) {
182 PWarning (GetSymPos (S), 1, "Symbol `%s' is %s but exported as %s",
183 GetSymName (S), AddrSizeToStr (S->AddrSize),
184 AddrSizeToStr (S->ExportSize));
188 /* If the symbol is a ZP symbol, check if the value is in correct range */
189 if (S->AddrSize == ADDR_SIZE_ZP) {
190 /* Already marked as ZP symbol by some means */
191 if (!IsByteExpr (Expr)) {
192 Error ("Range error");
196 /* If this is not a local symbol, remember it as the last global one */
197 if (!IsLocalNameId (S->Name)) {
204 void SymImport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
205 /* Mark the given symbol as an imported symbol */
207 /* Don't accept local symbols */
208 if (IsLocalNameId (S->Name)) {
209 Error ("Illegal use of a local symbol");
213 if (S->Flags & SF_DEFINED) {
214 Error ("Symbol `%s' is already defined", GetSymName (S));
215 S->Flags |= SF_MULTDEF;
218 if (S->Flags & SF_EXPORT) {
219 /* The symbol is already marked as exported symbol */
220 Error ("Cannot import exported symbol `%s'", GetSymName (S));
224 /* Map a default address size to a real value */
225 if (AddrSize == ADDR_SIZE_DEFAULT) {
226 AddrSize = SymAddrSize (S);
229 /* If the symbol is marked as import or global, check the symbol flags,
230 * then do silently remove the global flag
232 if (S->Flags & SF_IMPORT) {
233 if ((Flags & SF_FORCED) != (S->Flags & SF_FORCED)) {
234 Error ("Redeclaration mismatch for symbol `%s'", GetSymName (S));
236 if (AddrSize != S->AddrSize) {
237 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
240 if (S->Flags & SF_GLOBAL) {
241 if (S->AddrSize != ADDR_SIZE_DEFAULT && S->AddrSize != AddrSize) {
242 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
244 S->Flags &= ~SF_GLOBAL;
247 /* Set the symbol data */
248 S->Flags |= (SF_IMPORT | Flags);
249 S->AddrSize = AddrSize;
254 void SymExport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
255 /* Mark the given symbol as an exported symbol */
257 /* Don't accept local symbols */
258 if (IsLocalNameId (S->Name)) {
259 Error ("Illegal use of a local symbol");
263 /* Check if it's ok to export the symbol */
264 if (S->Flags & SF_IMPORT) {
265 /* The symbol is already marked as imported external symbol */
266 Error ("Symbol `%s' is already an import", GetSymName (S));
270 /* If the symbol was marked as global before, make it an export */
271 if (S->Flags & SF_GLOBAL) {
272 S->ExportSize = S->AddrSize;
273 S->Flags &= ~SF_GLOBAL;
276 /* If the symbol was already marked as an export, check if this was done
277 * specifiying the same address size. If the old spec had no explicit
278 * address size, use the new one.
280 if (S->Flags & SF_EXPORT) {
281 if (S->ExportSize == ADDR_SIZE_DEFAULT) {
282 S->ExportSize = AddrSize;
283 } else if (AddrSize == ADDR_SIZE_DEFAULT) {
284 AddrSize = S->ExportSize;
286 if (S->ExportSize != ADDR_SIZE_DEFAULT && S->ExportSize != AddrSize) {
287 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
290 S->ExportSize = AddrSize;
292 /* If the symbol is already defined, check symbol size against the
295 if (S->Flags & SF_DEFINED) {
296 if (S->ExportSize == ADDR_SIZE_DEFAULT) {
297 /* No export size given, use the real size of the symbol */
298 S->ExportSize = S->AddrSize;
299 } else if (S->AddrSize > S->ExportSize) {
300 Warning (1, "Symbol `%s' is %s but exported as %s",
301 GetSymName (S), AddrSizeToStr (S->AddrSize),
302 AddrSizeToStr (S->ExportSize));
306 /* Set the symbol data */
307 S->Flags |= (SF_EXPORT | SF_REFERENCED | Flags);
312 void SymGlobal (SymEntry* S, unsigned char AddrSize, unsigned Flags)
313 /* Mark the given symbol as a global symbol, that is, as a symbol that is
314 * either imported or exported.
317 /* Don't accept local symbols */
318 if (IsLocalNameId (S->Name)) {
319 Error ("Illegal use of a local symbol");
323 /* If the symbol is already marked as import or export, check the
324 * size of the definition, then bail out.
326 if (S->Flags & SF_IMPORT) {
327 if (AddrSize != ADDR_SIZE_DEFAULT && AddrSize != S->AddrSize) {
328 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
332 if (S->Flags & SF_EXPORT) {
333 /* If the old symbol had no explicit address size spec, use the
336 if (S->ExportSize == ADDR_SIZE_DEFAULT) {
337 S->ExportSize = AddrSize;
339 if (AddrSize != S->ExportSize) {
340 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
345 /* If the symbol is already defined, export it. Otherwise mark it as
348 if (S->Flags & SF_DEFINED) {
349 /* The symbol is defined, export it */
350 S->ExportSize = AddrSize;
351 if (S->ExportSize == ADDR_SIZE_DEFAULT) {
352 /* No export size given, use the real size of the symbol */
353 S->ExportSize = S->AddrSize;
354 } else if (S->AddrSize > S->ExportSize) {
355 Warning (1, "Symbol `%s' is %s but exported as %s",
356 GetSymName (S), AddrSizeToStr (S->AddrSize),
357 AddrSizeToStr (S->ExportSize));
359 S->Flags |= (SF_EXPORT | Flags);
360 S->ExportSize = AddrSize;
362 S->Flags |= (SF_GLOBAL | Flags);
363 S->AddrSize = AddrSize;
369 void SymConDes (SymEntry* S, unsigned char AddrSize, unsigned Type, unsigned Prio)
370 /* Mark the given symbol as a module constructor/destructor. This will also
371 * mark the symbol as an export. Initializers may never be zero page symbols.
374 /* Check the parameters */
375 #if (CD_TYPE_MIN != 0)
376 CHECK (Type >= CD_TYPE_MIN && Type <= CD_TYPE_MAX);
378 CHECK (Type <= CD_TYPE_MAX);
380 CHECK (Prio >= CD_PRIO_MIN && Prio <= CD_PRIO_MAX);
382 /* Don't accept local symbols */
383 if (IsLocalNameId (S->Name)) {
384 Error ("Illegal use of a local symbol");
388 /* Check for errors */
389 if (S->Flags & SF_IMPORT) {
390 /* The symbol is already marked as imported external symbol */
391 Error ("Symbol `%s' is already an import", GetSymName (S));
395 /* If the symbol was already marked as an export or global, check if
396 * this was done specifiying the same address size. In case of a global
397 * declaration, silently remove the global flag.
399 if (S->Flags & (SF_EXPORT | SF_GLOBAL)) {
400 if (S->ExportSize != AddrSize) {
401 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
403 S->Flags &= ~SF_GLOBAL;
405 S->ExportSize = AddrSize;
407 /* If the symbol is already defined, check symbol size against the
410 if (S->Flags & SF_DEFINED) {
411 if (S->ExportSize == ADDR_SIZE_DEFAULT) {
412 /* Use the real size of the symbol */
413 S->ExportSize = S->AddrSize;
414 } else if (S->AddrSize != S->ExportSize) {
415 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
419 /* If the symbol was already declared as a condes, check if the new
420 * priority value is the same as the old one.
422 if (S->ConDesPrio[Type] != CD_PRIO_NONE) {
423 if (S->ConDesPrio[Type] != Prio) {
424 Error ("Redeclaration mismatch for symbol `%s'", GetSymName (S));
427 S->ConDesPrio[Type] = Prio;
429 /* Set the symbol data */
430 S->Flags |= (SF_EXPORT | SF_REFERENCED);
435 int SymIsDef (const SymEntry* S)
436 /* Return true if the given symbol is already defined */
438 return (S->Flags & SF_DEFINED) != 0;
443 int SymIsRef (const SymEntry* S)
444 /* Return true if the given symbol has been referenced */
446 return (S->Flags & SF_REFERENCED) != 0;
451 int SymIsImport (const SymEntry* S)
452 /* Return true if the given symbol is marked as import */
454 /* Resolve trampoline entries */
455 if (S->Flags & SF_TRAMPOLINE) {
459 /* Check the import flag */
460 return (S->Flags & SF_IMPORT) != 0;
465 int SymIsConst (SymEntry* S, long* Val)
466 /* Return true if the given symbol has a constant value. If Val is not NULL
467 * and the symbol has a constant value, store it's value there.
470 /* Resolve trampoline entries */
471 if (S->Flags & SF_TRAMPOLINE) {
475 /* Check for constness */
476 return (SymHasExpr (S) && IsConstExpr (S->V.Expr, Val));
481 int SymHasExpr (const SymEntry* S)
482 /* Return true if the given symbol has an associated expression */
484 /* Resolve trampoline entries */
485 if (S->Flags & SF_TRAMPOLINE) {
489 /* Check the expression */
490 return ((S->Flags & (SF_DEFINED|SF_IMPORT)) == SF_DEFINED);
495 void SymMarkUser (SymEntry* S)
496 /* Set a user mark on the specified symbol */
498 /* Resolve trampoline entries */
499 if (S->Flags & SF_TRAMPOLINE) {
509 void SymUnmarkUser (SymEntry* S)
510 /* Remove a user mark from the specified symbol */
512 /* Resolve trampoline entries */
513 if (S->Flags & SF_TRAMPOLINE) {
518 S->Flags &= ~SF_USER;
523 int SymHasUserMark (SymEntry* S)
524 /* Return the state of the user mark for the specified symbol */
526 /* Resolve trampoline entries */
527 if (S->Flags & SF_TRAMPOLINE) {
532 return (S->Flags & SF_USER) != 0;
537 struct ExprNode* GetSymExpr (SymEntry* S)
538 /* Get the expression for a non-const symbol */
540 /* Resolve trampoline entries */
541 if (S->Flags & SF_TRAMPOLINE) {
545 PRECONDITION (S != 0 && SymHasExpr (S));
551 const struct ExprNode* SymResolve (const SymEntry* S)
552 /* Helper function for DumpExpr. Resolves a symbol into an expression or return
553 * NULL. Do not call in other contexts!
556 /* Resolve trampoline entries */
557 if (S->Flags & SF_TRAMPOLINE) {
561 return SymHasExpr (S)? S->V.Expr : 0;
566 const char* GetSymName (const SymEntry* S)
567 /* Return the name of the symbol */
569 /* Resolve trampoline entries */
570 if (S->Flags & SF_TRAMPOLINE) {
573 return GetString (S->Name);
578 unsigned GetSymAddrSize (const SymEntry* S)
579 /* Return the address size of the symbol. Beware: This function will just
580 * return the AddrSize member, it will not look at the expression!
583 if (S->Flags & SF_TRAMPOLINE) {
591 unsigned GetSymIndex (const SymEntry* S)
592 /* Return the symbol index for the given symbol */
594 /* Resolve trampoline entries */
595 if (S->Flags & SF_TRAMPOLINE) {
598 PRECONDITION (S != 0 && (S->Flags & SF_INDEXED) != 0);
604 const FilePos* GetSymPos (const SymEntry* S)
605 /* Return the position of first occurence in the source for the given symbol */
607 /* Resolve trampoline entries */
608 if (S->Flags & SF_TRAMPOLINE) {
611 PRECONDITION (S != 0);