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 /*****************************************************************************/
49 #include "studyexpr.h" /* ### */
55 /*****************************************************************************/
57 /*****************************************************************************/
61 /* List of all symbol table entries */
62 SymEntry* SymList = 0;
64 /* Pointer to last defined symbol */
65 SymEntry* SymLast = 0;
69 /*****************************************************************************/
71 /*****************************************************************************/
75 SymEntry* NewSymEntry (const char* Name, unsigned Flags)
76 /* Allocate a symbol table entry, initialize and return it */
79 SymEntry* S = xmalloc (sizeof (SymEntry));
81 /* Initialize the entry */
89 S->ExprRefs = AUTO_COLLECTION_INITIALIZER;
90 S->ExportSize = ADDR_SIZE_DEFAULT;
91 S->AddrSize = ADDR_SIZE_DEFAULT;
92 memset (S->ConDesPrio, 0, sizeof (S->ConDesPrio));
93 S->Name = GetStringId (Name);
95 /* Insert it into the list of all entries */
99 /* Return the initialized entry */
105 int SymSearchTree (SymEntry* T, const char* Name, SymEntry** E)
106 /* Search in the given tree for a name. If we find the symbol, the function
107 * will return 0 and put the entry pointer into E. If we did not find the
108 * symbol, and the tree is empty, E is set to NULL. If the tree is not empty,
109 * E will be set to the last entry, and the result of the function is <0 if
110 * the entry should be inserted on the left side, and >0 if it should get
111 * inserted on the right side.
114 /* Is there a tree? */
120 /* We have a table, search it */
123 /* Get the symbol name */
124 const char* SymName = GetString (T->Name);
126 /* Choose next entry */
127 int Cmp = strcmp (Name, SymName);
128 if (Cmp < 0 && T->Left) {
130 } else if (Cmp > 0&& T->Right) {
133 /* Found or end of search, return the result */
142 void SymRef (SymEntry* S)
143 /* Mark the given symbol as referenced */
145 /* Mark the symbol as referenced */
146 S->Flags |= SF_REFERENCED;
151 void SymTransferExprRefs (SymEntry* From, SymEntry* To)
152 /* Transfer all expression references from one symbol to another. */
156 for (I = 0; I < CollCount (&From->ExprRefs); ++I) {
158 /* Get the expression node */
159 ExprNode* E = CollAtUnchecked (&From->ExprRefs, I);
162 CHECK (E->Op == EXPR_SYMBOL && E->V.Sym == From);
164 /* Replace the symbol reference */
167 /* Add the expression reference */
168 SymAddExprRef (To, E);
171 /* Remove all symbol references from the old symbol */
172 CollDeleteAll (&From->ExprRefs);
177 void SymDef (SymEntry* S, ExprNode* Expr, unsigned char AddrSize, unsigned Flags)
178 /* Define a new symbol */
180 if (S->Flags & SF_IMPORT) {
181 /* Defined symbol is marked as imported external symbol */
182 Error ("Symbol `%s' is already an import", GetSymName (S));
185 if (S->Flags & SF_DEFINED) {
186 /* Multiple definition */
187 Error ("Symbol `%s' is already defined", GetSymName (S));
188 S->Flags |= SF_MULTDEF;
192 /* Map a default address size to a real value */
193 if (AddrSize == ADDR_SIZE_DEFAULT) {
194 /* ### Must go! Delay address size calculation until end of assembly! */
197 StudyExpr (Expr, &ED);
198 AddrSize = ED.AddrSize;
202 /* Set the symbol value */
205 /* If the symbol is marked as global, export it. Address size is checked
208 if (S->Flags & SF_GLOBAL) {
209 S->Flags = (S->Flags & ~SF_GLOBAL) | SF_EXPORT;
212 /* Mark the symbol as defined and use the given address size */
213 S->Flags |= (SF_DEFINED | Flags);
214 S->AddrSize = AddrSize;
216 /* If the symbol is exported, check the address sizes */
217 if (S->Flags & SF_EXPORT) {
218 if (S->ExportSize == ADDR_SIZE_DEFAULT) {
219 /* Use the real size of the symbol */
220 S->ExportSize = S->AddrSize;
221 } else if (S->AddrSize > S->ExportSize) {
222 /* We're exporting a symbol smaller than it actually is */
223 PWarning (GetSymPos (S), 1, "Symbol `%s' is %s but exported %s",
224 GetSymName (S), AddrSizeToStr (S->AddrSize),
225 AddrSizeToStr (S->ExportSize));
229 /* If this is not a local symbol, remember it as the last global one */
230 if ((S->Flags & SF_LOCAL) == 0) {
237 void SymImport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
238 /* Mark the given symbol as an imported symbol */
240 if (S->Flags & SF_DEFINED) {
241 Error ("Symbol `%s' is already defined", GetSymName (S));
242 S->Flags |= SF_MULTDEF;
245 if (S->Flags & SF_EXPORT) {
246 /* The symbol is already marked as exported symbol */
247 Error ("Cannot import exported symbol `%s'", GetSymName (S));
251 /* If no address size is given, use the address size of the enclosing
254 if (AddrSize == ADDR_SIZE_DEFAULT) {
255 AddrSize = GetCurrentSegAddrSize ();
258 /* If the symbol is marked as import or global, check the address size,
259 * then do silently remove the global flag.
261 if (S->Flags & SF_IMPORT) {
262 if ((Flags & SF_FORCED) != (S->Flags & SF_FORCED)) {
263 Error ("Redeclaration mismatch for symbol `%s'", GetSymName (S));
265 if (AddrSize != S->AddrSize) {
266 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
269 if (S->Flags & SF_GLOBAL) {
270 S->Flags &= ~SF_GLOBAL;
271 if (AddrSize != S->AddrSize) {
272 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
276 /* Set the symbol data */
277 S->Flags |= (SF_IMPORT | Flags);
278 S->AddrSize = AddrSize;
283 void SymExport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
284 /* Mark the given symbol as an exported symbol */
286 /* Check if it's ok to export the symbol */
287 if (S->Flags & SF_IMPORT) {
288 /* The symbol is already marked as imported external symbol */
289 Error ("Symbol `%s' is already an import", GetSymName (S));
293 /* If the symbol was marked as global before, remove the global flag and
294 * proceed, but check the address size.
296 if (S->Flags & SF_GLOBAL) {
297 if (AddrSize != S->ExportSize) {
298 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
300 S->Flags &= ~SF_GLOBAL;
303 /* If the symbol was already marked as an export, but wasn't defined
304 * before, the address sizes in both definitions must match.
306 if ((S->Flags & (SF_EXPORT|SF_DEFINED)) == SF_EXPORT) {
307 if (S->ExportSize != AddrSize) {
308 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
311 S->ExportSize = AddrSize;
313 /* If the symbol is already defined, check symbol size against the
316 if (S->Flags & SF_DEFINED) {
317 if (S->ExportSize == ADDR_SIZE_DEFAULT) {
318 /* No export size given, use the real size of the symbol */
319 S->ExportSize = S->AddrSize;
320 } else if (S->AddrSize > S->ExportSize) {
321 /* We're exporting a symbol smaller than it actually is */
322 Warning (1, "Symbol `%s' is %s but exported %s",
323 GetSymName (S), AddrSizeToStr (S->AddrSize),
324 AddrSizeToStr (S->ExportSize));
328 /* Set the symbol data */
329 S->Flags |= (SF_EXPORT | SF_REFERENCED | Flags);
334 void SymGlobal (SymEntry* S, unsigned char AddrSize, unsigned Flags)
335 /* Mark the given symbol as a global symbol, that is, as a symbol that is
336 * either imported or exported.
339 /* If the symbol is already marked as import, the address size must match.
340 * Apart from that, ignore the global declaration.
342 if (S->Flags & SF_IMPORT) {
343 if (AddrSize == ADDR_SIZE_DEFAULT) {
344 /* Use the size of the current segment */
345 AddrSize = GetCurrentSegAddrSize ();
347 if (AddrSize != S->AddrSize) {
348 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
353 /* If the symbol is already an export: If it is not defined, the address
356 if (S->Flags & SF_EXPORT) {
357 if ((S->Flags & SF_DEFINED) == 0) {
358 /* Symbol is undefined */
359 if (AddrSize != S->ExportSize) {
360 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
362 } else if (AddrSize != ADDR_SIZE_DEFAULT) {
363 /* Symbol is defined and address size given */
364 if (AddrSize != S->ExportSize) {
365 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
371 /* If the symbol is already marked as global, the address size must match.
372 * Use the ExportSize here, since it contains the actual address size
373 * passed to this function.
375 if (S->Flags & SF_GLOBAL) {
376 if (AddrSize != S->ExportSize) {
377 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
382 /* If we come here, the symbol was neither declared as export, import or
383 * global before. Check if it is already defined, in which case it will
384 * become an export. If it is not defined, mark it as global and remember
385 * the given address sizes.
387 if (S->Flags & SF_DEFINED) {
388 /* The symbol is defined, export it */
389 S->ExportSize = AddrSize;
390 if (S->ExportSize == ADDR_SIZE_DEFAULT) {
391 /* No export size given, use the real size of the symbol */
392 S->ExportSize = S->AddrSize;
393 } else if (S->AddrSize > S->ExportSize) {
394 /* We're exporting a symbol smaller than it actually is */
395 Warning (1, "Symbol `%s' is %s but exported %s",
396 GetSymName (S), AddrSizeToStr (S->AddrSize),
397 AddrSizeToStr (S->ExportSize));
399 S->Flags |= (SF_EXPORT | Flags);
401 /* Since we don't know if the symbol will get exported or imported,
402 * remember two different address sizes: One for an import in AddrSize,
403 * and the other one for an export in ExportSize.
405 S->AddrSize = AddrSize;
406 if (S->AddrSize == ADDR_SIZE_DEFAULT) {
407 /* Use the size of the current segment */
408 S->AddrSize = GetCurrentSegAddrSize ();
410 S->ExportSize = AddrSize;
411 S->Flags |= (SF_GLOBAL | Flags);
417 void SymConDes (SymEntry* S, unsigned char AddrSize, unsigned Type, unsigned Prio)
418 /* Mark the given symbol as a module constructor/destructor. This will also
419 * mark the symbol as an export. Initializers may never be zero page symbols.
422 /* Check the parameters */
423 #if (CD_TYPE_MIN != 0)
424 CHECK (Type >= CD_TYPE_MIN && Type <= CD_TYPE_MAX);
426 CHECK (Type <= CD_TYPE_MAX);
428 CHECK (Prio >= CD_PRIO_MIN && Prio <= CD_PRIO_MAX);
430 /* Check for errors */
431 if (S->Flags & SF_IMPORT) {
432 /* The symbol is already marked as imported external symbol */
433 Error ("Symbol `%s' is already an import", GetSymName (S));
437 /* If the symbol was already marked as an export or global, check if
438 * this was done specifiying the same address size. In case of a global
439 * declaration, silently remove the global flag.
441 if (S->Flags & (SF_EXPORT | SF_GLOBAL)) {
442 if (S->ExportSize != AddrSize) {
443 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
445 S->Flags &= ~SF_GLOBAL;
447 S->ExportSize = AddrSize;
449 /* If the symbol is already defined, check symbol size against the
452 if (S->Flags & SF_DEFINED) {
453 if (S->ExportSize == ADDR_SIZE_DEFAULT) {
454 /* Use the real size of the symbol */
455 S->ExportSize = S->AddrSize;
456 } else if (S->AddrSize != S->ExportSize) {
457 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
461 /* If the symbol was already declared as a condes, check if the new
462 * priority value is the same as the old one.
464 if (S->ConDesPrio[Type] != CD_PRIO_NONE) {
465 if (S->ConDesPrio[Type] != Prio) {
466 Error ("Redeclaration mismatch for symbol `%s'", GetSymName (S));
469 S->ConDesPrio[Type] = Prio;
471 /* Set the symbol data */
472 S->Flags |= (SF_EXPORT | SF_REFERENCED);
477 int SymIsConst (SymEntry* S, long* Val)
478 /* Return true if the given symbol has a constant value. If Val is not NULL
479 * and the symbol has a constant value, store it's value there.
482 /* Check for constness */
483 return (SymHasExpr (S) && IsConstExpr (S->Expr, Val));
488 SymTable* GetSymParentScope (SymEntry* S)
489 /* Get the parent scope of the symbol (not the one it is defined in). Return
490 * NULL if the symbol is a cheap local, or defined on global level.
493 return (S->SymTab && S->SymTab->Parent)? S->SymTab->Parent : 0;
498 struct ExprNode* GetSymExpr (SymEntry* S)
499 /* Get the expression for a non-const symbol */
501 PRECONDITION (S != 0 && SymHasExpr (S));
507 const struct ExprNode* SymResolve (const SymEntry* S)
508 /* Helper function for DumpExpr. Resolves a symbol into an expression or return
509 * NULL. Do not call in other contexts!
512 return SymHasExpr (S)? S->Expr : 0;
517 long GetSymVal (SymEntry* S)
518 /* Return the value of a symbol assuming it's constant. FAIL will be called
519 * in case the symbol is undefined or not constant.
523 CHECK (S != 0 && SymHasExpr (S) && IsConstExpr (GetSymExpr (S), &Val));
529 unsigned GetSymIndex (const SymEntry* S)
530 /* Return the symbol index for the given symbol */
532 PRECONDITION (S != 0 && (S->Flags & SF_INDEXED) != 0);