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 int IsLocalName (const char* Name)
76 /* Return true if Name is the name of a local symbol */
78 return (*Name == LocalStart);
83 int IsLocalNameId (unsigned Name)
84 /* Return true if Name is the name of a local symbol */
86 return (*GetString (Name) == LocalStart);
91 SymEntry* NewSymEntry (const char* Name)
92 /* Allocate a symbol table entry, initialize and return it */
95 SymEntry* S = xmalloc (sizeof (SymEntry));
97 /* Initialize the entry */
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);
111 /* Insert it into the list of all entries */
115 /* Return the initialized entry */
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.
130 /* Is there a tree? */
136 /* We have a table, search it */
139 /* Get the symbol name */
140 const char* SymName = GetString (T->Name);
142 /* Choose next entry */
143 int Cmp = strcmp (Name, SymName);
144 if (Cmp < 0 && T->Left) {
146 } else if (Cmp > 0&& T->Right) {
149 /* Found or end of search, return the result */
158 void SymRef (SymEntry* S)
159 /* Mark the given symbol as referenced */
161 /* Mark the symbol as referenced */
162 S->Flags |= SF_REFERENCED;
167 void SymTransferExprRefs (SymEntry* From, SymEntry* To)
168 /* Transfer all expression references from one symbol to another. */
172 for (I = 0; I < CollCount (&From->ExprRefs); ++I) {
174 /* Get the expression node */
175 ExprNode* E = CollAtUnchecked (&From->ExprRefs, I);
178 CHECK (E->Op == EXPR_SYMBOL && E->V.Sym == From);
180 /* Replace the symbol reference */
183 /* Add the expression reference */
184 SymAddExprRef (To, E);
187 /* Remove all symbol references from the old symbol */
188 CollDeleteAll (&From->ExprRefs);
193 void SymDef (SymEntry* S, ExprNode* Expr, unsigned char AddrSize, unsigned Flags)
194 /* Define a new symbol */
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));
201 if (S->Flags & SF_DEFINED) {
202 /* Multiple definition */
203 Error ("Symbol `%s' is already defined", GetSymName (S));
204 S->Flags |= SF_MULTDEF;
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! */
213 StudyExpr (Expr, &ED);
214 AddrSize = ED.AddrSize;
218 /* Set the symbol value */
221 /* If the symbol is marked as global, export it. Address size is checked
224 if (S->Flags & SF_GLOBAL) {
225 S->Flags = (S->Flags & ~SF_GLOBAL) | SF_EXPORT;
228 /* Mark the symbol as defined and use the given address size */
229 S->Flags |= (SF_DEFINED | Flags);
230 S->AddrSize = AddrSize;
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));
245 /* If this is not a local symbol, remember it as the last global one */
246 if (!IsLocalNameId (S->Name)) {
253 void SymImport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
254 /* Mark the given symbol as an imported symbol */
256 if (S->Flags & SF_DEFINED) {
257 Error ("Symbol `%s' is already defined", GetSymName (S));
258 S->Flags |= SF_MULTDEF;
261 if (S->Flags & SF_EXPORT) {
262 /* The symbol is already marked as exported symbol */
263 Error ("Cannot import exported symbol `%s'", GetSymName (S));
267 /* If no address size is given, use the address size of the enclosing
270 if (AddrSize == ADDR_SIZE_DEFAULT) {
271 AddrSize = GetCurrentSegAddrSize ();
274 /* If the symbol is marked as import or global, check the address size,
275 * then do silently remove the global flag.
277 if (S->Flags & SF_IMPORT) {
278 if ((Flags & SF_FORCED) != (S->Flags & SF_FORCED)) {
279 Error ("Redeclaration mismatch for symbol `%s'", GetSymName (S));
281 if (AddrSize != S->AddrSize) {
282 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
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));
292 /* Set the symbol data */
293 S->Flags |= (SF_IMPORT | Flags);
294 S->AddrSize = AddrSize;
299 void SymExport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
300 /* Mark the given symbol as an exported symbol */
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));
309 /* If the symbol was marked as global before, remove the global flag and
310 * proceed, but check the address size.
312 if (S->Flags & SF_GLOBAL) {
313 if (AddrSize != S->ExportSize) {
314 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
316 S->Flags &= ~SF_GLOBAL;
319 /* If the symbol was already marked as an export, but wasn't defined
320 * before, the address sizes in both definitions must match.
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));
327 S->ExportSize = AddrSize;
329 /* If the symbol is already defined, check symbol size against the
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));
344 /* Set the symbol data */
345 S->Flags |= (SF_EXPORT | SF_REFERENCED | Flags);
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.
355 /* If the symbol is already marked as import, the address size must match.
356 * Apart from that, ignore the global declaration.
358 if (S->Flags & SF_IMPORT) {
359 if (AddrSize == ADDR_SIZE_DEFAULT) {
360 /* Use the size of the current segment */
361 AddrSize = GetCurrentSegAddrSize ();
363 if (AddrSize != S->AddrSize) {
364 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
369 /* If the symbol is already an export: If it is not defined, the address
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));
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));
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.
391 if (S->Flags & SF_GLOBAL) {
392 if (AddrSize != S->ExportSize) {
393 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
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.
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));
415 S->Flags |= (SF_EXPORT | Flags);
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.
421 S->AddrSize = AddrSize;
422 if (S->AddrSize == ADDR_SIZE_DEFAULT) {
423 /* Use the size of the current segment */
424 S->AddrSize = GetCurrentSegAddrSize ();
426 S->ExportSize = AddrSize;
427 S->Flags |= (SF_GLOBAL | Flags);
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.
438 /* Check the parameters */
439 #if (CD_TYPE_MIN != 0)
440 CHECK (Type >= CD_TYPE_MIN && Type <= CD_TYPE_MAX);
442 CHECK (Type <= CD_TYPE_MAX);
444 CHECK (Prio >= CD_PRIO_MIN && Prio <= CD_PRIO_MAX);
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));
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.
457 if (S->Flags & (SF_EXPORT | SF_GLOBAL)) {
458 if (S->ExportSize != AddrSize) {
459 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
461 S->Flags &= ~SF_GLOBAL;
463 S->ExportSize = AddrSize;
465 /* If the symbol is already defined, check symbol size against the
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));
477 /* If the symbol was already declared as a condes, check if the new
478 * priority value is the same as the old one.
480 if (S->ConDesPrio[Type] != CD_PRIO_NONE) {
481 if (S->ConDesPrio[Type] != Prio) {
482 Error ("Redeclaration mismatch for symbol `%s'", GetSymName (S));
485 S->ConDesPrio[Type] = Prio;
487 /* Set the symbol data */
488 S->Flags |= (SF_EXPORT | SF_REFERENCED);
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.
498 /* Check for constness */
499 return (SymHasExpr (S) && IsConstExpr (S->V.Expr, Val));
504 struct ExprNode* GetSymExpr (SymEntry* S)
505 /* Get the expression for a non-const symbol */
507 PRECONDITION (S != 0 && SymHasExpr (S));
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!
518 return SymHasExpr (S)? S->V.Expr : 0;
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.
529 CHECK (S != 0 && SymHasExpr (S) && IsConstExpr (GetSymExpr (S), &Val));
535 unsigned GetSymIndex (const SymEntry* S)
536 /* Return the symbol index for the given symbol */
538 PRECONDITION (S != 0 && (S->Flags & SF_INDEXED) != 0);