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 int SymSearchTree (SymEntry* T, const char* Name, SymEntry** E)
135 /* Search in the given tree for a name. If we find the symbol, the function
136 * will return 0 and put the entry pointer into E. If we did not find the
137 * symbol, and the tree is empty, E is set to NULL. If the tree is not empty,
138 * E will be set to the last entry, and the result of the function is <0 if
139 * the entry should be inserted on the left side, and >0 if it should get
140 * inserted on the right side.
143 /* Is there a tree? */
149 /* We have a table, search it */
152 /* Get the symbol name */
153 const char* SymName = GetString (T->Name);
155 /* Choose next entry */
156 int Cmp = strcmp (Name, SymName);
157 if (Cmp < 0 && T->Left) {
159 } else if (Cmp > 0&& T->Right) {
162 /* Found or end of search, return the result */
171 void SymRef (SymEntry* S)
172 /* Mark the given symbol as referenced */
174 /* Mark the symbol as referenced */
175 S->Flags |= SF_REFERENCED;
180 void SymTransferExprRefs (SymEntry* From, SymEntry* To)
181 /* Transfer all expression references from one symbol to another. */
185 for (I = 0; I < CollCount (&From->ExprRefs); ++I) {
187 /* Get the expression node */
188 ExprNode* E = CollAtUnchecked (&From->ExprRefs, I);
191 CHECK (E->Op == EXPR_SYMBOL && E->V.Sym == From);
193 /* Replace the symbol reference */
196 /* Add the expression reference */
197 SymAddExprRef (To, E);
200 /* Remove all symbol references from the old symbol */
201 CollDeleteAll (&From->ExprRefs);
206 void SymDef (SymEntry* S, ExprNode* Expr, unsigned char AddrSize, unsigned Flags)
207 /* Define a new symbol */
209 if (S->Flags & SF_IMPORT) {
210 /* Defined symbol is marked as imported external symbol */
211 Error ("Symbol `%s' is already an import", GetSymName (S));
214 if (S->Flags & SF_DEFINED) {
215 /* Multiple definition */
216 Error ("Symbol `%s' is already defined", GetSymName (S));
217 S->Flags |= SF_MULTDEF;
221 /* Map a default address size to a real value */
222 if (AddrSize == ADDR_SIZE_DEFAULT) {
224 if (IsConstExpr (Expr, &Val)) {
225 if (IsByteRange (Val)) {
226 AddrSize = ADDR_SIZE_ZP;
227 } else if (IsWordRange (Val)) {
228 AddrSize = ADDR_SIZE_ABS;
229 } else if (IsFarRange (Val)) {
230 AddrSize = ADDR_SIZE_FAR;
232 AddrSize = ADDR_SIZE_LONG;
235 AddrSize = SymAddrSize (S);
239 /* Set the symbol value */
242 /* If the symbol is marked as global, export it. Address size is checked
245 if (S->Flags & SF_GLOBAL) {
246 S->Flags = (S->Flags & ~SF_GLOBAL) | SF_EXPORT;
249 /* Mark the symbol as defined and use the given address size */
250 S->Flags |= (SF_DEFINED | Flags);
251 S->AddrSize = AddrSize;
253 /* If the symbol is exported, check the address sizes */
254 if (S->Flags & SF_EXPORT) {
255 if (S->ExportSize == ADDR_SIZE_DEFAULT) {
256 /* Use the real size of the symbol */
257 S->ExportSize = S->AddrSize;
258 } else if (S->AddrSize > S->ExportSize) {
259 /* We're exporting a symbol smaller than it actually is */
260 PWarning (GetSymPos (S), 1, "Symbol `%s' is %s but exported %s",
261 GetSymName (S), AddrSizeToStr (S->AddrSize),
262 AddrSizeToStr (S->ExportSize));
266 /* If this is not a local symbol, remember it as the last global one */
267 if (!IsLocalNameId (S->Name)) {
274 void SymImport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
275 /* Mark the given symbol as an imported symbol */
277 if (S->Flags & SF_DEFINED) {
278 Error ("Symbol `%s' is already defined", GetSymName (S));
279 S->Flags |= SF_MULTDEF;
282 if (S->Flags & SF_EXPORT) {
283 /* The symbol is already marked as exported symbol */
284 Error ("Cannot import exported symbol `%s'", GetSymName (S));
288 /* If no address size is given, use the address size of the enclosing
291 if (AddrSize == ADDR_SIZE_DEFAULT) {
292 AddrSize = GetCurrentSegAddrSize ();
295 /* If the symbol is marked as import or global, check the address size,
296 * then do silently remove the global flag.
298 if (S->Flags & SF_IMPORT) {
299 if ((Flags & SF_FORCED) != (S->Flags & SF_FORCED)) {
300 Error ("Redeclaration mismatch for symbol `%s'", GetSymName (S));
302 if (AddrSize != S->AddrSize) {
303 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
306 if (S->Flags & SF_GLOBAL) {
307 S->Flags &= ~SF_GLOBAL;
308 if (AddrSize != S->AddrSize) {
309 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
313 /* Set the symbol data */
314 S->Flags |= (SF_IMPORT | Flags);
315 S->AddrSize = AddrSize;
320 void SymExport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
321 /* Mark the given symbol as an exported symbol */
323 /* Check if it's ok to export the symbol */
324 if (S->Flags & SF_IMPORT) {
325 /* The symbol is already marked as imported external symbol */
326 Error ("Symbol `%s' is already an import", GetSymName (S));
330 /* If the symbol was marked as global before, remove the global flag and
331 * proceed, but check the address size.
333 if (S->Flags & SF_GLOBAL) {
334 if (AddrSize != S->ExportSize) {
335 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
337 S->Flags &= ~SF_GLOBAL;
340 /* If the symbol was already marked as an export, but wasn't defined
341 * before, the address sizes in both definitions must match.
343 if ((S->Flags & (SF_EXPORT|SF_DEFINED)) == SF_EXPORT) {
344 if (S->ExportSize != AddrSize) {
345 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
348 S->ExportSize = AddrSize;
350 /* If the symbol is already defined, check symbol size against the
353 if (S->Flags & SF_DEFINED) {
354 if (S->ExportSize == ADDR_SIZE_DEFAULT) {
355 /* No export size given, use the real size of the symbol */
356 S->ExportSize = S->AddrSize;
357 } else if (S->AddrSize > S->ExportSize) {
358 /* We're exporting a symbol smaller than it actually is */
359 Warning (1, "Symbol `%s' is %s but exported %s",
360 GetSymName (S), AddrSizeToStr (S->AddrSize),
361 AddrSizeToStr (S->ExportSize));
365 /* Set the symbol data */
366 S->Flags |= (SF_EXPORT | SF_REFERENCED | Flags);
371 void SymGlobal (SymEntry* S, unsigned char AddrSize, unsigned Flags)
372 /* Mark the given symbol as a global symbol, that is, as a symbol that is
373 * either imported or exported.
376 /* If the symbol is already marked as import, the address size must match.
377 * Apart from that, ignore the global declaration.
379 if (S->Flags & SF_IMPORT) {
380 if (AddrSize == ADDR_SIZE_DEFAULT) {
381 /* Use the size of the current segment */
382 AddrSize = GetCurrentSegAddrSize ();
384 if (AddrSize != S->AddrSize) {
385 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
390 /* If the symbol is already an export: If it is not defined, the address
393 if (S->Flags & SF_EXPORT) {
394 if ((S->Flags & SF_DEFINED) == 0) {
395 /* Symbol is undefined */
396 if (AddrSize != S->ExportSize) {
397 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
399 } else if (AddrSize != ADDR_SIZE_DEFAULT) {
400 /* Symbol is defined and address size given */
401 if (AddrSize != S->ExportSize) {
402 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
408 /* If the symbol is already marked as global, the address size must match.
409 * Use the ExportSize here, since it contains the actual address size
410 * passed to this function.
412 if (S->Flags & SF_GLOBAL) {
413 if (AddrSize != S->ExportSize) {
414 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
419 /* If we come here, the symbol was neither declared as export, import or
420 * global before. Check if it is already defined, in which case it will
421 * become an export. If it is not defined, mark it as global and remember
422 * the given address sizes.
424 if (S->Flags & SF_DEFINED) {
425 /* The symbol is defined, export it */
426 S->ExportSize = AddrSize;
427 if (S->ExportSize == ADDR_SIZE_DEFAULT) {
428 /* No export size given, use the real size of the symbol */
429 S->ExportSize = S->AddrSize;
430 } else if (S->AddrSize > S->ExportSize) {
431 /* We're exporting a symbol smaller than it actually is */
432 Warning (1, "Symbol `%s' is %s but exported %s",
433 GetSymName (S), AddrSizeToStr (S->AddrSize),
434 AddrSizeToStr (S->ExportSize));
436 S->Flags |= (SF_EXPORT | Flags);
438 /* Since we don't know if the symbol will get exported or imported,
439 * remember two different address sizes: One for an import in AddrSize,
440 * and the other one for an export in ExportSize.
442 S->AddrSize = AddrSize;
443 if (S->AddrSize == ADDR_SIZE_DEFAULT) {
444 /* Use the size of the current segment */
445 S->AddrSize = GetCurrentSegAddrSize ();
447 S->ExportSize = AddrSize;
448 S->Flags |= (SF_GLOBAL | Flags);
454 void SymConDes (SymEntry* S, unsigned char AddrSize, unsigned Type, unsigned Prio)
455 /* Mark the given symbol as a module constructor/destructor. This will also
456 * mark the symbol as an export. Initializers may never be zero page symbols.
459 /* Check the parameters */
460 #if (CD_TYPE_MIN != 0)
461 CHECK (Type >= CD_TYPE_MIN && Type <= CD_TYPE_MAX);
463 CHECK (Type <= CD_TYPE_MAX);
465 CHECK (Prio >= CD_PRIO_MIN && Prio <= CD_PRIO_MAX);
467 /* Check for errors */
468 if (S->Flags & SF_IMPORT) {
469 /* The symbol is already marked as imported external symbol */
470 Error ("Symbol `%s' is already an import", GetSymName (S));
474 /* If the symbol was already marked as an export or global, check if
475 * this was done specifiying the same address size. In case of a global
476 * declaration, silently remove the global flag.
478 if (S->Flags & (SF_EXPORT | SF_GLOBAL)) {
479 if (S->ExportSize != AddrSize) {
480 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
482 S->Flags &= ~SF_GLOBAL;
484 S->ExportSize = AddrSize;
486 /* If the symbol is already defined, check symbol size against the
489 if (S->Flags & SF_DEFINED) {
490 if (S->ExportSize == ADDR_SIZE_DEFAULT) {
491 /* Use the real size of the symbol */
492 S->ExportSize = S->AddrSize;
493 } else if (S->AddrSize != S->ExportSize) {
494 Error ("Address size mismatch for symbol `%s'", GetSymName (S));
498 /* If the symbol was already declared as a condes, check if the new
499 * priority value is the same as the old one.
501 if (S->ConDesPrio[Type] != CD_PRIO_NONE) {
502 if (S->ConDesPrio[Type] != Prio) {
503 Error ("Redeclaration mismatch for symbol `%s'", GetSymName (S));
506 S->ConDesPrio[Type] = Prio;
508 /* Set the symbol data */
509 S->Flags |= (SF_EXPORT | SF_REFERENCED);
514 int SymIsConst (SymEntry* S, long* Val)
515 /* Return true if the given symbol has a constant value. If Val is not NULL
516 * and the symbol has a constant value, store it's value there.
519 /* Check for constness */
520 return (SymHasExpr (S) && IsConstExpr (S->V.Expr, Val));
525 struct ExprNode* GetSymExpr (SymEntry* S)
526 /* Get the expression for a non-const symbol */
528 PRECONDITION (S != 0 && SymHasExpr (S));
534 const struct ExprNode* SymResolve (const SymEntry* S)
535 /* Helper function for DumpExpr. Resolves a symbol into an expression or return
536 * NULL. Do not call in other contexts!
539 return SymHasExpr (S)? S->V.Expr : 0;
544 long GetSymVal (SymEntry* S)
545 /* Return the value of a symbol assuming it's constant. FAIL will be called
546 * in case the symbol is undefined or not constant.
550 CHECK (S != 0 && SymHasExpr (S) && IsConstExpr (GetSymExpr (S), &Val));
556 unsigned GetSymIndex (const SymEntry* S)
557 /* Return the symbol index for the given symbol */
559 PRECONDITION (S != 0 && (S->Flags & SF_INDEXED) != 0);