X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fca65%2Fsymentry.c;h=1b81f6a2b22d70292f11490290a74fb1c7841475;hb=c52916f461f5f723bc8f2146e346dcb2de3b2f18;hp=2c1600760c16fbec4b9bf5d94d53639680fbae16;hpb=4555fdcad17b14439dc4876ec1ac275accdb5c14;p=cc65 diff --git a/src/ca65/symentry.c b/src/ca65/symentry.c index 2c1600760..1b81f6a2b 100644 --- a/src/ca65/symentry.c +++ b/src/ca65/symentry.c @@ -2,14 +2,14 @@ /* */ /* symentry.c */ /* */ -/* Symbol table entry forward for the ca65 macroassembler */ +/* Symbol table entry for the ca65 macroassembler */ /* */ /* */ /* */ -/* (C) 1998-2003 Ullrich von Bassewitz */ -/* Römerstraße 52 */ -/* D-70794 Filderstadt */ -/* EMail: uz@cc65.org */ +/* (C) 1998-2011, Ullrich von Bassewitz */ +/* Roemerstrasse 52 */ +/* D-70794 Filderstadt */ +/* EMail: uz@cc65.org */ /* */ /* */ /* This software is provided 'as-is', without any expressed or implied */ @@ -37,6 +37,7 @@ /* common */ #include "addrsize.h" +#include "symdefs.h" #include "xmalloc.h" /* ca65 */ @@ -44,7 +45,9 @@ #include "expr.h" #include "global.h" #include "scanner.h" +#include "segment.h" #include "spool.h" +#include "studyexpr.h" /* ### */ #include "symentry.h" #include "symtab.h" @@ -70,202 +73,332 @@ SymEntry* SymLast = 0; -int IsLocalName (const char* Name) -/* Return true if Name is the name of a local symbol */ +SymEntry* NewSymEntry (const StrBuf* Name, unsigned Flags) +/* Allocate a symbol table entry, initialize and return it */ { - return (*Name == LocalStart); + unsigned I; + + /* Allocate memory */ + SymEntry* S = xmalloc (sizeof (SymEntry)); + + /* Initialize the entry */ + S->Left = 0; + S->Right = 0; + S->Locals = 0; + S->Sym.Tab = 0; + S->DefLines = EmptyCollection; + S->RefLines = EmptyCollection; + for (I = 0; I < sizeof (S->GuessedUse) / sizeof (S->GuessedUse[0]); ++I) { + S->GuessedUse[I] = 0; + } + S->Flags = Flags; + S->DebugSymId = ~0U; + S->ImportId = ~0U; + S->ExportId = ~0U; + S->Expr = 0; + S->ExprRefs = AUTO_COLLECTION_INITIALIZER; + S->ExportSize = ADDR_SIZE_DEFAULT; + S->AddrSize = ADDR_SIZE_DEFAULT; + memset (S->ConDesPrio, 0, sizeof (S->ConDesPrio)); + S->Name = GetStrBufId (Name); + + /* Insert it into the list of all entries */ + S->List = SymList; + SymList = S; + + /* Return the initialized entry */ + return S; } -int IsLocalNameId (unsigned Name) -/* Return true if Name is the name of a local symbol */ +int SymSearchTree (SymEntry* T, const StrBuf* Name, SymEntry** E) +/* Search in the given tree for a name. If we find the symbol, the function + * will return 0 and put the entry pointer into E. If we did not find the + * symbol, and the tree is empty, E is set to NULL. If the tree is not empty, + * E will be set to the last entry, and the result of the function is <0 if + * the entry should be inserted on the left side, and >0 if it should get + * inserted on the right side. + */ { - return (*GetString (Name) == LocalStart); + /* Is there a tree? */ + if (T == 0) { + *E = 0; + return 1; + } + + /* We have a table, search it */ + while (1) { + + /* Get the symbol name */ + const StrBuf* SymName = GetStrBuf (T->Name); + + /* Choose next entry */ + int Cmp = SB_Compare (Name, SymName); + if (Cmp < 0 && T->Left) { + T = T->Left; + } else if (Cmp > 0&& T->Right) { + T = T->Right; + } else { + /* Found or end of search, return the result */ + *E = T; + return Cmp; + } + } } -static unsigned SymAddrSize (const SymEntry* S) -/* Get the default address size for a symbol. */ +void SymTransferExprRefs (SymEntry* From, SymEntry* To) +/* Transfer all expression references from one symbol to another. */ { - /* Local symbols are always near (is this ok?) */ - if (IsLocalNameId (S->Name)) { - return ADDR_SIZE_ABS; + unsigned I; + + for (I = 0; I < CollCount (&From->ExprRefs); ++I) { + + /* Get the expression node */ + ExprNode* E = CollAtUnchecked (&From->ExprRefs, I); + + /* Safety */ + CHECK (E->Op == EXPR_SYMBOL && E->V.Sym == From); + + /* Replace the symbol reference */ + E->V.Sym = To; + + /* Add the expression reference */ + SymAddExprRef (To, E); } - /* Return the address size of the enclosing scope */ - return S->SymTab->AddrSize; + /* Remove all symbol references from the old symbol */ + CollDeleteAll (&From->ExprRefs); } -SymEntry* NewSymEntry (const char* Name) -/* Allocate a symbol table entry, initialize and return it */ +static void SymReplaceExprRefs (SymEntry* S) +/* Replace the references to this symbol by a copy of the symbol expression */ { - /* Allocate memory */ - SymEntry* S = xmalloc (sizeof (SymEntry)); + unsigned I; + long Val; - /* Initialize the entry */ - S->Left = 0; - S->Right = 0; - S->Locals = 0; - S->SymTab = 0; - S->Pos = CurPos; - S->Flags = 0; - S->V.Expr = 0; - S->ExprRefs = AUTO_COLLECTION_INITIALIZER; - S->ExportSize = ADDR_SIZE_DEFAULT; - S->AddrSize = ADDR_SIZE_DEFAULT; - memset (S->ConDesPrio, 0, sizeof (S->ConDesPrio)); - S->Name = GetStringId (Name); + /* Check if the expression is const and get its value */ + int IsConst = IsConstExpr (S->Expr, &Val); + CHECK (IsConst); - /* Insert it into the list of all entries */ - S->List = SymList; - SymList = S; + /* Loop over all references */ + for (I = 0; I < CollCount (&S->ExprRefs); ++I) { - /* Return the initialized entry */ - return S; -} + /* Get the expression node */ + ExprNode* E = CollAtUnchecked (&S->ExprRefs, I); + /* Safety */ + CHECK (E->Op == EXPR_SYMBOL && E->V.Sym == S); + /* We cannot touch the root node, since there are pointers to it. + * Replace it by a literal node. + */ + E->Op = EXPR_LITERAL; + E->V.IVal = Val; + } -void SymRef (SymEntry* S) -/* Mark the given symbol as referenced */ -{ - /* Mark the symbol as referenced */ - S->Flags |= SF_REFERENCED; + /* Remove all symbol references from the symbol */ + CollDeleteAll (&S->ExprRefs); } -void SymDef (SymEntry* S, ExprNode* Expr, unsigned AddrSize, unsigned Flags) +void SymDef (SymEntry* S, ExprNode* Expr, unsigned char AddrSize, unsigned Flags) /* Define a new symbol */ { if (S->Flags & SF_IMPORT) { /* Defined symbol is marked as imported external symbol */ - Error ("Symbol `%s' is already an import", GetSymName (S)); + Error ("Symbol `%m%p' is already an import", GetSymName (S)); return; } + if ((Flags & SF_VAR) != 0 && (S->Flags & (SF_EXPORT | SF_GLOBAL))) { + /* Variable symbols cannot be exports or globals */ + Error ("Var symbol `%m%p' cannot be an export or global symbol", GetSymName (S)); + return; + } if (S->Flags & SF_DEFINED) { - /* Multiple definition */ - Error ("Symbol `%s' is already defined", GetSymName (S)); - S->Flags |= SF_MULTDEF; - return; + /* Multiple definition. In case of a variable, this is legal. */ + if ((S->Flags & SF_VAR) == 0) { + Error ("Symbol `%m%p' is already defined", GetSymName (S)); + S->Flags |= SF_MULTDEF; + return; + } else { + /* Redefinition must also be a variable symbol */ + if ((Flags & SF_VAR) == 0) { + Error ("Symbol `%m%p' is already different kind", GetSymName (S)); + return; + } + /* Delete the current symbol expression, since it will get + * replaced + */ + FreeExpr (S->Expr); + S->Expr = 0; + } } /* Map a default address size to a real value */ if (AddrSize == ADDR_SIZE_DEFAULT) { - AddrSize = SymAddrSize (S); + /* ### Must go! Delay address size calculation until end of assembly! */ + ExprDesc ED; + ED_Init (&ED); + StudyExpr (Expr, &ED); + AddrSize = ED.AddrSize; + ED_Done (&ED); } /* Set the symbol value */ - S->V.Expr = Expr; + S->Expr = Expr; - /* If the symbol is marked as global, export it */ + /* In case of a variable symbol, walk over all expressions containing + * this symbol and replace the (sub-)expression by the literal value of + * the tree. Be sure to replace the expression node in place, since there + * may be pointers to it. + */ + if (Flags & SF_VAR) { + SymReplaceExprRefs (S); + } + + /* If the symbol is marked as global, export it. Address size is checked + * below. + */ if (S->Flags & SF_GLOBAL) { - S->ExportSize = S->AddrSize; S->Flags = (S->Flags & ~SF_GLOBAL) | SF_EXPORT; + ReleaseFullLineInfo (&S->DefLines); } /* Mark the symbol as defined and use the given address size */ S->Flags |= (SF_DEFINED | Flags); S->AddrSize = AddrSize; + /* Remember the line info of the symbol definition */ + GetFullLineInfo (&S->DefLines); + /* If the symbol is exported, check the address sizes */ if (S->Flags & SF_EXPORT) { if (S->ExportSize == ADDR_SIZE_DEFAULT) { /* Use the real size of the symbol */ S->ExportSize = S->AddrSize; } else if (S->AddrSize > S->ExportSize) { - Warning (1, "Address size mismatch for symbol `%s'", GetSymName (S)); + /* We're exporting a symbol smaller than it actually is */ + Warning (1, "Symbol `%m%p' is %s but exported %s", + GetSymName (S), AddrSizeToStr (S->AddrSize), + AddrSizeToStr (S->ExportSize)); } } - /* If the symbol is a ZP symbol, check if the value is in correct range */ - if (S->AddrSize == ADDR_SIZE_ZP) { - /* Already marked as ZP symbol by some means */ - if (!IsByteExpr (Expr)) { - Error ("Range error"); - } - } - /* If this is not a local symbol, remember it as the last global one */ - if (!IsLocalNameId (S->Name)) { + if ((S->Flags & SF_LOCAL) == 0) { SymLast = S; } } -void SymImport (SymEntry* S, unsigned AddrSize, unsigned Flags) -/* Mark the given symbol as an imported symbol */ +void SymRef (SymEntry* S) +/* Mark the given symbol as referenced */ { - /* Don't accept local symbols */ - if (IsLocalNameId (S->Name)) { - Error ("Illegal use of a local symbol"); - return; - } + /* Mark the symbol as referenced */ + S->Flags |= SF_REFERENCED; + /* Remember the current location */ + CollAppend (&S->RefLines, GetAsmLineInfo ()); +} + + + +void SymImport (SymEntry* S, unsigned char AddrSize, unsigned Flags) +/* Mark the given symbol as an imported symbol */ +{ if (S->Flags & SF_DEFINED) { - Error ("Symbol `%s' is already defined", GetSymName (S)); + Error ("Symbol `%m%p' is already defined", GetSymName (S)); S->Flags |= SF_MULTDEF; return; } if (S->Flags & SF_EXPORT) { /* The symbol is already marked as exported symbol */ - Error ("Cannot import exported symbol `%s'", GetSymName (S)); + Error ("Cannot import exported symbol `%m%p'", GetSymName (S)); return; } - /* Map a default address size to a real value */ + /* If no address size is given, use the address size of the enclosing + * segment. + */ if (AddrSize == ADDR_SIZE_DEFAULT) { - AddrSize = SymAddrSize (S); + AddrSize = GetCurrentSegAddrSize (); } - /* If the symbol is marked as import or global, check the symbol flags, - * then do silently remove the global flag + /* If the symbol is marked as import or global, check the address size, + * then do silently remove the global flag. */ - if (S->Flags & (SF_IMPORT | SF_GLOBAL)) { - if ((Flags & SF_FORCED) != (S->Flags & SF_FORCED) || - AddrSize != S->AddrSize) { - Error ("Redeclaration mismatch for symbol `%s'", GetSymName (S)); + if (S->Flags & SF_IMPORT) { + if ((Flags & SF_FORCED) != (S->Flags & SF_FORCED)) { + Error ("Redeclaration mismatch for symbol `%m%p'", GetSymName (S)); } + if (AddrSize != S->AddrSize) { + Error ("Address size mismatch for symbol `%m%p'", GetSymName (S)); + } + } + if (S->Flags & SF_GLOBAL) { S->Flags &= ~SF_GLOBAL; + if (AddrSize != S->AddrSize) { + Error ("Address size mismatch for symbol `%m%p'", GetSymName (S)); + } } /* Set the symbol data */ S->Flags |= (SF_IMPORT | Flags); S->AddrSize = AddrSize; + + /* Mark the position of the import as the position of the definition. + * Please note: In case of multiple .global or .import statements, the line + * infos add up. + */ + GetFullLineInfo (&S->DefLines); } -void SymExport (SymEntry* S, unsigned AddrSize, unsigned Flags) +void SymExport (SymEntry* S, unsigned char AddrSize, unsigned Flags) /* Mark the given symbol as an exported symbol */ { - /* Don't accept local symbols */ - if (IsLocalNameId (S->Name)) { - Error ("Illegal use of a local symbol"); - return; - } - /* Check if it's ok to export the symbol */ if (S->Flags & SF_IMPORT) { /* The symbol is already marked as imported external symbol */ - Error ("Symbol `%s' is already an import", GetSymName (S)); + Error ("Symbol `%m%p' is already an import", GetSymName (S)); return; } + if (S->Flags & SF_VAR) { + /* Variable symbols cannot be exported */ + Error ("Var symbol `%m%p' cannot be exported", GetSymName (S)); + return; + } - /* If the symbol was already marked as an export or global, check if - * this was done specifiying the same address size. In case of a global - * declaration, silently remove the global flag. + /* If the symbol was marked as global before, remove the global flag and + * proceed, but check the address size. */ - if (S->Flags & (SF_EXPORT | SF_GLOBAL)) { - if (S->ExportSize != AddrSize) { - Error ("Address size mismatch for symbol `%s'", GetSymName (S)); + if (S->Flags & SF_GLOBAL) { + if (AddrSize != S->ExportSize) { + Error ("Address size mismatch for symbol `%m%p'", GetSymName (S)); } S->Flags &= ~SF_GLOBAL; + + /* .GLOBAL remembers line infos in case an .IMPORT follows. We have + * to remove these here. + */ + ReleaseFullLineInfo (&S->DefLines); + } + + /* If the symbol was already marked as an export, but wasn't defined + * before, the address sizes in both definitions must match. + */ + if ((S->Flags & (SF_EXPORT|SF_DEFINED)) == SF_EXPORT) { + if (S->ExportSize != AddrSize) { + Error ("Address size mismatch for symbol `%m%p'", GetSymName (S)); + } } S->ExportSize = AddrSize; @@ -274,10 +407,13 @@ void SymExport (SymEntry* S, unsigned AddrSize, unsigned Flags) */ if (S->Flags & SF_DEFINED) { if (S->ExportSize == ADDR_SIZE_DEFAULT) { - /* Use the real size of the symbol */ + /* No export size given, use the real size of the symbol */ S->ExportSize = S->AddrSize; } else if (S->AddrSize > S->ExportSize) { - Warning (1, "Address size mismatch for symbol `%s'", GetSymName (S)); + /* We're exporting a symbol smaller than it actually is */ + Warning (1, "Symbol `%m%p' is %s but exported %s", + GetSymName (S), AddrSizeToStr (S->AddrSize), + AddrSizeToStr (S->ExportSize)); } } @@ -287,154 +423,248 @@ void SymExport (SymEntry* S, unsigned AddrSize, unsigned Flags) -void SymGlobal (SymEntry* S, unsigned AddrSize, unsigned Flags) +void SymGlobal (SymEntry* S, unsigned char AddrSize, unsigned Flags) /* Mark the given symbol as a global symbol, that is, as a symbol that is * either imported or exported. */ { - /* Don't accept local symbols */ - if (IsLocalNameId (S->Name)) { - Error ("Illegal use of a local symbol"); - return; - } - - /* Map a default address size to a real value */ - if (AddrSize == ADDR_SIZE_DEFAULT) { - AddrSize = SymAddrSize (S); + if (S->Flags & SF_VAR) { + /* Variable symbols cannot be exported or imported */ + Error ("Var symbol `%m%p' cannot be made global", GetSymName (S)); + return; } - /* If the symbol is already marked as import or export, check the - * size of the definition, then bail out. + /* If the symbol is already marked as import, the address size must match. + * Apart from that, ignore the global declaration. */ if (S->Flags & SF_IMPORT) { + if (AddrSize == ADDR_SIZE_DEFAULT) { + /* Use the size of the current segment */ + AddrSize = GetCurrentSegAddrSize (); + } if (AddrSize != S->AddrSize) { - Error ("Address size mismatch for symbol `%s'", GetSymName (S)); + Error ("Address size mismatch for symbol `%m%p'", GetSymName (S)); } return; } + + /* If the symbol is already an export: If it is not defined, the address + * sizes must match. + */ if (S->Flags & SF_EXPORT) { + if ((S->Flags & SF_DEFINED) == 0) { + /* Symbol is undefined */ + if (AddrSize != S->ExportSize) { + Error ("Address size mismatch for symbol `%m%p'", GetSymName (S)); + } + } else if (AddrSize != ADDR_SIZE_DEFAULT) { + /* Symbol is defined and address size given */ + if (AddrSize != S->ExportSize) { + Error ("Address size mismatch for symbol `%m%p'", GetSymName (S)); + } + } + return; + } + + /* If the symbol is already marked as global, the address size must match. + * Use the ExportSize here, since it contains the actual address size + * passed to this function. + */ + if (S->Flags & SF_GLOBAL) { if (AddrSize != S->ExportSize) { - Error ("Address size mismatch for symbol `%s'", GetSymName (S)); + Error ("Address size mismatch for symbol `%m%p'", GetSymName (S)); } return; } - /* If the symbol is already defined, export it. Otherwise mark it as - * global. + /* If we come here, the symbol was neither declared as export, import or + * global before. Check if it is already defined, in which case it will + * become an export. If it is not defined, mark it as global and remember + * the given address sizes. */ if (S->Flags & SF_DEFINED) { /* The symbol is defined, export it */ - if (S->ExportSize != AddrSize) { - Error ("Address size mismatch for symbol `%s'", GetSymName (S)); + S->ExportSize = AddrSize; + if (S->ExportSize == ADDR_SIZE_DEFAULT) { + /* No export size given, use the real size of the symbol */ + S->ExportSize = S->AddrSize; + } else if (S->AddrSize > S->ExportSize) { + /* We're exporting a symbol smaller than it actually is */ + Warning (1, "Symbol `%m%p' is %s but exported %s", + GetSymName (S), AddrSizeToStr (S->AddrSize), + AddrSizeToStr (S->ExportSize)); } S->Flags |= (SF_EXPORT | Flags); - S->ExportSize = AddrSize; } else { - S->Flags |= (SF_GLOBAL | Flags); + /* Since we don't know if the symbol will get exported or imported, + * remember two different address sizes: One for an import in AddrSize, + * and the other one for an export in ExportSize. + */ S->AddrSize = AddrSize; + if (S->AddrSize == ADDR_SIZE_DEFAULT) { + /* Use the size of the current segment */ + S->AddrSize = GetCurrentSegAddrSize (); + } + S->ExportSize = AddrSize; + S->Flags |= (SF_GLOBAL | Flags); + + /* Remember the current location as location of definition in case + * an .IMPORT follows later. + */ + GetFullLineInfo (&S->DefLines); } } -int SymIsDef (const SymEntry* S) -/* Return true if the given symbol is already defined */ +void SymConDes (SymEntry* S, unsigned char AddrSize, unsigned Type, unsigned Prio) +/* Mark the given symbol as a module constructor/destructor. This will also + * mark the symbol as an export. Initializers may never be zero page symbols. + */ { - return (S->Flags & SF_DEFINED) != 0; -} - + /* Check the parameters */ +#if (CD_TYPE_MIN != 0) + CHECK (Type >= CD_TYPE_MIN && Type <= CD_TYPE_MAX); +#else + CHECK (Type <= CD_TYPE_MAX); +#endif + CHECK (Prio >= CD_PRIO_MIN && Prio <= CD_PRIO_MAX); + + /* Check for errors */ + if (S->Flags & SF_IMPORT) { + /* The symbol is already marked as imported external symbol */ + Error ("Symbol `%m%p' is already an import", GetSymName (S)); + return; + } + if (S->Flags & SF_VAR) { + /* Variable symbols cannot be exported or imported */ + Error ("Var symbol `%m%p' cannot be exported", GetSymName (S)); + return; + } + /* If the symbol was already marked as an export or global, check if + * this was done specifiying the same address size. In case of a global + * declaration, silently remove the global flag. + */ + if (S->Flags & (SF_EXPORT | SF_GLOBAL)) { + if (S->ExportSize != AddrSize) { + Error ("Address size mismatch for symbol `%m%p'", GetSymName (S)); + } + S->Flags &= ~SF_GLOBAL; + } + S->ExportSize = AddrSize; -int SymIsRef (const SymEntry* S) -/* Return true if the given symbol has been referenced */ -{ - return (S->Flags & SF_REFERENCED) != 0; -} + /* If the symbol is already defined, check symbol size against the + * exported size. + */ + if (S->Flags & SF_DEFINED) { + if (S->ExportSize == ADDR_SIZE_DEFAULT) { + /* Use the real size of the symbol */ + S->ExportSize = S->AddrSize; + } else if (S->AddrSize != S->ExportSize) { + Error ("Address size mismatch for symbol `%m%p'", GetSymName (S)); + } + } + /* If the symbol was already declared as a condes, check if the new + * priority value is the same as the old one. + */ + if (S->ConDesPrio[Type] != CD_PRIO_NONE) { + if (S->ConDesPrio[Type] != Prio) { + Error ("Redeclaration mismatch for symbol `%m%p'", GetSymName (S)); + } + } + S->ConDesPrio[Type] = Prio; + /* Set the symbol data */ + S->Flags |= (SF_EXPORT | SF_REFERENCED); -int SymIsImport (const SymEntry* S) -/* Return true if the given symbol is marked as import */ -{ - /* Resolve trampoline entries */ - if (S->Flags & SF_TRAMPOLINE) { - S = S->V.Sym; + /* In case we have no line info for the definition, record it now */ + if (CollCount (&S->DefLines) == 0) { + GetFullLineInfo (&S->DefLines); } - - /* Check the import flag */ - return (S->Flags & SF_IMPORT) != 0; } -int SymIsConst (SymEntry* S, long* Val) -/* Return true if the given symbol has a constant value. If Val is not NULL - * and the symbol has a constant value, store it's value there. +void SymGuessedAddrSize (SymEntry* Sym, unsigned char AddrSize) +/* Mark the address size of the given symbol as guessed. The address size + * passed as argument is the one NOT used, because the actual address size + * wasn't known. Example: Zero page addressing was not used because symbol + * is undefined, and absolute addressing was available. */ { - /* Resolve trampoline entries */ - if (S->Flags & SF_TRAMPOLINE) { - S = S->V.Sym; + /* We must have a valid address size passed */ + PRECONDITION (AddrSize != ADDR_SIZE_DEFAULT); + + /* We do not support all address sizes currently */ + if (AddrSize > sizeof (Sym->GuessedUse) / sizeof (Sym->GuessedUse[0])) { + return; } - /* Check for constness */ - return (SymHasExpr (S) && IsConstExpr (S->V.Expr, Val)); + /* We can only remember one such occurance */ + if (Sym->GuessedUse[AddrSize-1]) { + return; + } + + /* Ok, remember the file position */ + Sym->GuessedUse[AddrSize-1] = xdup (&CurTok.Pos, sizeof (CurTok.Pos)); } -int SymHasExpr (const SymEntry* S) -/* Return true if the given symbol has an associated expression */ +void SymExportFromGlobal (SymEntry* S) +/* Called at the end of assembly. Converts a global symbol that is defined + * into an export. + */ { - /* Resolve trampoline entries */ - if (S->Flags & SF_TRAMPOLINE) { - S = S->V.Sym; - } - - /* Check the expression */ - return ((S->Flags & (SF_DEFINED|SF_IMPORT)) == SF_DEFINED); + /* Remove the global flag and make the symbol an export */ + S->Flags &= ~SF_GLOBAL; + S->Flags |= SF_EXPORT; } -void SymMarkUser (SymEntry* S) -/* Set a user mark on the specified symbol */ +void SymImportFromGlobal (SymEntry* S) +/* Called at the end of assembly. Converts a global symbol that is undefined + * into an import. + */ { - /* Resolve trampoline entries */ - if (S->Flags & SF_TRAMPOLINE) { - S = S->V.Sym; - } - - /* Set the bit */ - S->Flags |= SF_USER; + /* Remove the global flag and make it an import */ + S->Flags &= ~SF_GLOBAL; + S->Flags |= SF_IMPORT; } -void SymUnmarkUser (SymEntry* S) -/* Remove a user mark from the specified symbol */ +int SymIsConst (const SymEntry* S, long* Val) +/* Return true if the given symbol has a constant value. If Val is not NULL + * and the symbol has a constant value, store it's value there. + */ { - /* Resolve trampoline entries */ - if (S->Flags & SF_TRAMPOLINE) { - S = S->V.Sym; - } - - /* Reset the bit */ - S->Flags &= ~SF_USER; + /* Check for constness */ + return (SymHasExpr (S) && IsConstExpr (S->Expr, Val)); } -int SymHasUserMark (SymEntry* S) -/* Return the state of the user mark for the specified symbol */ +SymTable* GetSymParentScope (SymEntry* S) +/* Get the parent scope of the symbol (not the one it is defined in). Return + * NULL if the symbol is a cheap local, or defined on global level. + */ { - /* Resolve trampoline entries */ - if (S->Flags & SF_TRAMPOLINE) { - S = S->V.Sym; + if ((S->Flags & SF_LOCAL) != 0) { + /* This is a cheap local symbol */ + return 0; + } else if (S->Sym.Tab == 0) { + /* Symbol not in a table. This may happen if there have been errors + * before. Return NULL in this case to avoid further errors. + */ + return 0; + } else { + /* This is a global symbol */ + return S->Sym.Tab->Parent; } - - /* Check the bit */ - return (S->Flags & SF_USER) != 0; } @@ -442,13 +672,8 @@ int SymHasUserMark (SymEntry* S) struct ExprNode* GetSymExpr (SymEntry* S) /* Get the expression for a non-const symbol */ { - /* Resolve trampoline entries */ - if (S->Flags & SF_TRAMPOLINE) { - S = S->V.Sym; - } - PRECONDITION (S != 0 && SymHasExpr (S)); - return S->V.Expr; + return S->Expr; } @@ -458,52 +683,63 @@ const struct ExprNode* SymResolve (const SymEntry* S) * NULL. Do not call in other contexts! */ { - /* Resolve trampoline entries */ - if (S->Flags & SF_TRAMPOLINE) { - S = S->V.Sym; - } + return SymHasExpr (S)? S->Expr : 0; +} - return SymHasExpr (S)? S->V.Expr : 0; + + +long GetSymVal (SymEntry* S) +/* Return the value of a symbol assuming it's constant. FAIL will be called + * in case the symbol is undefined or not constant. + */ +{ + long Val; + CHECK (S != 0 && SymHasExpr (S) && IsConstExpr (GetSymExpr (S), &Val)); + return Val; } -const char* GetSymName (SymEntry* S) -/* Return the name of the symbol */ +unsigned GetSymImportId (const SymEntry* S) +/* Return the import id for the given symbol */ { - /* Resolve trampoline entries */ - if (S->Flags & SF_TRAMPOLINE) { - S = S->V.Sym; - } - return GetString (S->Name); + PRECONDITION (S != 0 && (S->Flags & SF_IMPORT) && S->ImportId != ~0U); + return S->ImportId; } -unsigned GetSymIndex (SymEntry* S) -/* Return the symbol index for the given symbol */ +unsigned GetSymExportId (const SymEntry* S) +/* Return the export id for the given symbol */ { - /* Resolve trampoline entries */ - if (S->Flags & SF_TRAMPOLINE) { - S = S->V.Sym; - } - PRECONDITION (S != 0 && (S->Flags & SF_INDEXED) != 0); - return S->Index; + PRECONDITION (S != 0 && (S->Flags & SF_EXPORT) && S->ExportId != ~0U); + return S->ExportId; } -const FilePos* GetSymPos (SymEntry* S) -/* Return the position of first occurence in the source for the given symbol */ +unsigned GetSymInfoFlags (const SymEntry* S, long* ConstVal) +/* Return a set of flags used when writing symbol information into a file. + * If the SYM_CONST bit is set, ConstVal will contain the constant value + * of the symbol. The result does not include the condes count. + * See common/symdefs.h for more information. + */ { - /* Resolve trampoline entries */ - if (S->Flags & SF_TRAMPOLINE) { - S = S->V.Sym; + /* Setup info flags */ + unsigned Flags = 0; + Flags |= SymIsConst (S, ConstVal)? SYM_CONST : SYM_EXPR; + Flags |= (S->Flags & SF_LABEL)? SYM_LABEL : SYM_EQUATE; + Flags |= (S->Flags & SF_LOCAL)? SYM_CHEAP_LOCAL : SYM_STD; + if (S->Flags & SF_EXPORT) { + Flags |= SYM_EXPORT; + } + if (S->Flags & SF_IMPORT) { + Flags |= SYM_IMPORT; } - PRECONDITION (S != 0); - return &S->Pos; -} + /* Return the result */ + return Flags; +}