X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fca65%2Fsymtab.c;h=2bd2149fc118c7141682b7c8000df4fff9eccdb9;hb=aaa21c64172feee5e0427f94e9ef9632d6e05d05;hp=f6055591e40ba683f41789f489f61a99f67e8c5a;hpb=6f088806d7f1424f3bceac0041e34e7fe3acd590;p=cc65 diff --git a/src/ca65/symtab.c b/src/ca65/symtab.c index f6055591e..2bd2149fc 100644 --- a/src/ca65/symtab.c +++ b/src/ca65/symtab.c @@ -6,10 +6,10 @@ /* */ /* */ /* */ -/* (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 */ @@ -38,43 +38,47 @@ /* common */ #include "addrsize.h" #include "check.h" -#include "hashstr.h" +#include "hashfunc.h" +#include "mmodel.h" +#include "scopedefs.h" #include "symdefs.h" #include "xmalloc.h" /* ca65 */ -#include "global.h" +#include "dbginfo.h" #include "error.h" #include "expr.h" +#include "global.h" #include "objfile.h" #include "scanner.h" #include "segment.h" +#include "sizeof.h" +#include "span.h" #include "spool.h" +#include "studyexpr.h" #include "symtab.h" /*****************************************************************************/ -/* Data */ +/* Data */ /*****************************************************************************/ /* Combined symbol entry flags used within this module */ #define SF_UNDEFMASK (SF_REFERENCED | SF_DEFINED | SF_IMPORT) -#define SF_UNDEFVAL (SF_REFERENCED) -#define SF_EXPMASK (SF_TRAMPOLINE | SF_EXPORT) -#define SF_EXPVAL (SF_EXPORT) -#define SF_DBGINFOMASK (SF_TRAMPOLINE | SF_DEFINED | SF_EXPORT | SF_IMPORT) -#define SF_DBGINFOVAL (SF_DEFINED) +#define SF_UNDEFVAL (SF_REFERENCED) /* Symbol tables */ -SymTable* CurrentScope = 0; /* Pointer to current symbol table */ -SymTable* RootScope = 0; /* Root symbol table */ +SymTable* CurrentScope = 0; /* Pointer to current symbol table */ +SymTable* RootScope = 0; /* Root symbol table */ +static SymTable* LastScope = 0; /* Pointer to last scope in list */ +static unsigned ScopeCount = 0; /* Number of scopes */ /* Symbol table variables */ -static unsigned ImportCount = 0;/* Counter for import symbols */ -static unsigned ExportCount = 0;/* Counter for export symbols */ +static unsigned ImportCount = 0; /* Counter for import symbols */ +static unsigned ExportCount = 0; /* Counter for export symbols */ @@ -84,6 +88,20 @@ static unsigned ExportCount = 0;/* Counter for export symbols */ +static int IsDbgSym (const SymEntry* S) +/* Return true if this is a debug symbol */ +{ + if ((S->Flags & (SF_DEFINED | SF_UNUSED)) == SF_DEFINED) { + /* Defined symbols are debug symbols if they aren't sizes */ + return !IsSizeOfSymbol (S); + } else { + /* Others are debug symbols if they're referenced imports */ + return ((S->Flags & SF_REFIMP) == SF_REFIMP); + } +} + + + static unsigned ScopeTableSize (unsigned Level) /* Get the size of a table for the given lexical level */ { @@ -96,7 +114,7 @@ static unsigned ScopeTableSize (unsigned Level) -static SymTable* NewSymTable (SymTable* Parent, const char* Name) +static SymTable* NewSymTable (SymTable* Parent, const StrBuf* Name) /* Allocate a symbol table on the heap and return it */ { /* Determine the lexical level and the number of table slots */ @@ -107,21 +125,33 @@ static SymTable* NewSymTable (SymTable* Parent, const char* Name) SymTable* S = xmalloc (sizeof (SymTable) + (Slots-1) * sizeof (SymEntry*)); /* Set variables and clear hash table entries */ + S->Next = 0; S->Left = 0; S->Right = 0; S->Childs = 0; + S->Label = 0; + S->Spans = AUTO_COLLECTION_INITIALIZER; + S->Id = ScopeCount++; S->Flags = ST_NONE; S->AddrSize = ADDR_SIZE_DEFAULT; - S->Type = 0; + S->Type = SCOPE_UNDEF; S->Level = Level; S->TableSlots = Slots; S->TableEntries = 0; S->Parent = Parent; - S->Name = GetStringId (Name); + S->Name = GetStrBufId (Name); while (Slots--) { S->Table[Slots] = 0; } + /* Insert the symbol table into the list of all symbol tables */ + if (RootScope == 0) { + RootScope = S; + } else { + LastScope->Next = S; + } + LastScope = S; + /* Insert the symbol table into the child tree of the parent */ if (Parent) { SymTable* T = Parent->Childs; @@ -131,7 +161,7 @@ static SymTable* NewSymTable (SymTable* Parent, const char* Name) } else { while (1) { /* Choose next entry */ - int Cmp = strcmp (Name, GetString (T->Name)); + int Cmp = SB_Compare (Name, GetStrBuf (T->Name)); if (Cmp < 0) { if (T->Left) { T = T->Left; @@ -148,7 +178,7 @@ static SymTable* NewSymTable (SymTable* Parent, const char* Name) } } else { /* Duplicate scope name */ - Internal ("Duplicate scope name: `%s'", Name); + Internal ("Duplicate scope name: `%m%p'", Name); } } } @@ -160,50 +190,14 @@ static SymTable* NewSymTable (SymTable* Parent, const char* Name) -static int SearchSymTree (SymEntry* T, const char* 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. - */ -{ - /* Is there a tree? */ - if (T == 0) { - *E = 0; - return 1; - } - - /* We have a table, search it */ - while (1) { - - /* Get the symbol name */ - const char* SymName = GetString (T->Name); - - /* Choose next entry */ - int Cmp = strcmp (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; - } - } -} - - - /*****************************************************************************/ -/* Code */ +/* Code */ /*****************************************************************************/ -void SymEnterLevel (const char* ScopeName, unsigned AddrSize) +void SymEnterLevel (const StrBuf* ScopeName, unsigned char Type, + unsigned char AddrSize, SymEntry* ScopeLabel) /* Enter a new lexical level */ { /* Map a default address size to something real */ @@ -216,18 +210,34 @@ void SymEnterLevel (const char* ScopeName, unsigned AddrSize) * new one if it doesn't exist. If this is the root scope, just create it. */ if (CurrentScope) { + + /* Search for the scope, create a new one */ CurrentScope = SymFindScope (CurrentScope, ScopeName, SYM_ALLOC_NEW); /* Check if the scope has been defined before */ if (CurrentScope->Flags & ST_DEFINED) { - Error ("Duplicate scope `%s'", ScopeName); + Error ("Duplicate scope `%m%p'", ScopeName); } + } else { CurrentScope = RootScope = NewSymTable (0, ScopeName); } - /* Mark the scope as defined */ - CurrentScope->Flags |= ST_DEFINED; + /* Mark the scope as defined and set type, address size and owner symbol */ + CurrentScope->Flags |= ST_DEFINED; + CurrentScope->AddrSize = AddrSize; + CurrentScope->Type = Type; + CurrentScope->Label = ScopeLabel; + + /* If this is a scope that allows to emit data into segments, add spans + * for all currently existing segments. Doing this for just a few scope + * types is not really necessary but an optimization, because it does not + * allocate memory for useless data (unhandled types here don't occupy + * space in any segment). + */ + if (CurrentScope->Type <= SCOPE_HAS_DATA) { + OpenSpanList (&CurrentScope->Spans); + } } @@ -235,17 +245,39 @@ void SymEnterLevel (const char* ScopeName, unsigned AddrSize) void SymLeaveLevel (void) /* Leave the current lexical level */ { + /* If this is a scope that allows to emit data into segments, close the + * open the spans. + */ + if (CurrentScope->Type <= SCOPE_HAS_DATA) { + CloseSpanList (&CurrentScope->Spans); + } + + /* If we have spans, the first one is the segment that was active, when the + * scope was opened. Set the size of the scope to the number of data bytes + * emitted into this segment. If we have an owner symbol set the size of + * this symbol, too. + */ + if (CollCount (&CurrentScope->Spans) > 0) { + const Span* S = CollAtUnchecked (&CurrentScope->Spans, 0); + unsigned long Size = GetSpanSize (S); + DefSizeOfScope (CurrentScope, Size); + if (CurrentScope->Label) { + DefSizeOfSymbol (CurrentScope->Label, Size); + } + } + + /* Leave the scope */ CurrentScope = CurrentScope->Parent; } -SymTable* SymFindScope (SymTable* Parent, const char* Name, int AllocNew) +SymTable* SymFindScope (SymTable* Parent, const StrBuf* Name, int AllocNew) /* Find a scope in the given enclosing scope */ { SymTable** T = &Parent->Childs; while (*T) { - int Cmp = strcmp (Name, GetString ((*T)->Name)); + int Cmp = SB_Compare (Name, GetStrBuf ((*T)->Name)); if (Cmp < 0) { T = &(*T)->Left; } else if (Cmp > 0) { @@ -267,223 +299,147 @@ SymTable* SymFindScope (SymTable* Parent, const char* Name, int AllocNew) -SymEntry* SymFind (SymTable* Scope, const char* Name, int AllocNew) -/* Find a new symbol table entry in the given table. If AllocNew is given and - * the entry is not found, create a new one. Return the entry found, or the - * new entry created, or - in case AllocNew is zero - return 0. - */ -{ - SymEntry* S; - int Cmp; - - if (IsLocalName (Name)) { - - /* Local symbol, get the table */ - if (!SymLast) { - /* No last global, so there's no local table */ - Error ("No preceeding global symbol"); - if (AllocNew) { - return NewSymEntry (Name); - } else { - return 0; - } - } - - /* Search for the symbol if we have a table */ - Cmp = SearchSymTree (SymLast->Locals, Name, &S); - - /* If we found an entry, return it */ - if (Cmp == 0) { - return S; - } - - if (AllocNew) { - - /* Otherwise create a new entry, insert and return it */ - SymEntry* N = NewSymEntry (Name); - if (S == 0) { - SymLast->Locals = N; - } else if (Cmp < 0) { - S->Left = N; - } else { - S->Right = N; - } - return N; - } - - } else { - - /* Global symbol: Get the hash value for the name */ - unsigned Hash = HashStr (Name) % Scope->TableSlots; - - /* Search for the entry */ - Cmp = SearchSymTree (Scope->Table[Hash], Name, &S); - - /* If we found an entry, return it */ - if (Cmp == 0) { - /* Check for a trampoline entry, in this case return the real - * symbol. - */ - while (S->Flags & SF_TRAMPOLINE) { - S = S->V.Sym; - } - return S; - } - - if (AllocNew) { - - /* Otherwise create a new entry, insert and return it */ - SymEntry* N = NewSymEntry (Name); - if (S == 0) { - Scope->Table[Hash] = N; - } else if (Cmp < 0) { - S->Left = N; - } else { - S->Right = N; - } - N->SymTab = Scope; - ++Scope->TableEntries; - return N; - - } - } - - /* We did not find the entry and AllocNew is false. */ - return 0; -} - - - -static SymEntry* SymFindAny (SymTable* Scope, const char* Name) -/* Find a symbol in the given or any of its parent scopes. The function will +SymTable* SymFindAnyScope (SymTable* Parent, const StrBuf* Name) +/* Find a scope in the given or any of its parent scopes. The function will * never create a new symbol, since this can only be done in one specific * scope. */ { - SymEntry* Sym; + SymTable* Scope; do { /* Search in the current table */ - Sym = SymFind (Scope, Name, SYM_FIND_EXISTING); - if (Sym) { - /* Found, return it */ - return Sym; - } else { + Scope = SymFindScope (Parent, Name, SYM_FIND_EXISTING); + if (Scope == 0) { /* Not found, search in the parent scope, if we have one */ - Scope = Scope->Parent; + Parent = Parent->Parent; } - } while (Sym == 0 && Scope != 0); + } while (Scope == 0 && Parent != 0); - /* Not found */ - return 0; + return Scope; } -void SymConDes (const char* Name, 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. +SymEntry* SymFindLocal (SymEntry* Parent, const StrBuf* Name, int AllocNew) +/* Find a cheap local symbol. If AllocNew is given and the entry is not + * found, create a new one. Return the entry found, or the new entry created, + * or - in case AllocNew is zero - return 0. */ { SymEntry* S; + int Cmp; - /* 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); - - /* Don't accept local symbols */ - if (IsLocalName (Name)) { - Error ("Illegal use of a local symbol"); - return; + /* Local symbol, get the table */ + if (!Parent) { + /* No last global, so there's no local table */ + Error ("No preceeding global symbol"); + if (AllocNew) { + return NewSymEntry (Name, SF_LOCAL); + } else { + return 0; + } } - /* Do we have such a symbol? */ - S = SymFind (CurrentScope, Name, SYM_ALLOC_NEW); - if (S->Flags & SF_IMPORT) { - /* The symbol is already marked as imported external symbol */ - Error ("Symbol `%s' is already an import", Name); - return; - } + /* Search for the symbol if we have a table */ + Cmp = SymSearchTree (Parent->Locals, Name, &S); - /* If the symbol is marked as global, silently remove the global flag */ - if (S->Flags & SF_GLOBAL) { - S->Flags &= ~SF_GLOBAL; + /* If we found an entry, return it */ + if (Cmp == 0) { + return S; } - /* Check if the symbol was not already defined as ZP symbol */ - if (S->AddrSize == ADDR_SIZE_ZP) { - Error ("Redeclaration mismatch for symbol `%s'", Name); - } + if (AllocNew) { - /* 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 `%s'", Name); - } + /* Otherwise create a new entry, insert and return it */ + SymEntry* N = NewSymEntry (Name, SF_LOCAL); + N->Sym.Entry = Parent; + if (S == 0) { + Parent->Locals = N; + } else if (Cmp < 0) { + S->Left = N; + } else { + S->Right = N; + } + return N; } - S->ConDesPrio[Type] = Prio; - /* Set the symbol data */ - S->Flags |= SF_EXPORT | SF_REFERENCED; + /* We did not find the entry and AllocNew is false. */ + return 0; } -int SymIsConst (SymEntry* S) -/* Return true if the given symbol has a constant value */ +SymEntry* SymFind (SymTable* Scope, const StrBuf* Name, int AllocNew) +/* Find a new symbol table entry in the given table. If AllocNew is given and + * the entry is not found, create a new one. Return the entry found, or the + * new entry created, or - in case AllocNew is zero - return 0. + */ { - /* Resolve trampoline entries */ - if (S->Flags & SF_TRAMPOLINE) { - S = S->V.Sym; + SymEntry* S; + + /* Global symbol: Get the hash value for the name */ + unsigned Hash = HashBuf (Name) % Scope->TableSlots; + + /* Search for the entry */ + int Cmp = SymSearchTree (Scope->Table[Hash], Name, &S); + + /* If we found an entry, return it */ + if (Cmp == 0) { + return S; } - /* Check for constness */ - if (S->Flags & SF_CONST) { - return 1; - } else if ((S->Flags & SF_DEFINED) && IsConstExpr (S->V.Expr)) { - /* Constant expression, remember the value */ - ExprNode* Expr = S->V.Expr; - S->Flags |= SF_CONST; - S->V.Val = GetExprVal (Expr); - FreeExpr (Expr); - return 1; + if (AllocNew) { + + /* Otherwise create a new entry, insert and return it */ + SymEntry* N = NewSymEntry (Name, SF_NONE); + N->Sym.Tab = Scope; + if (S == 0) { + Scope->Table[Hash] = N; + } else if (Cmp < 0) { + S->Left = N; + } else { + S->Right = N; + } + ++Scope->TableEntries; + return N; + } + + /* We did not find the entry and AllocNew is false. */ return 0; } -int SymIsZP (SymEntry* S) -/* Return true if the symbol is explicitly marked as zeropage symbol */ +SymEntry* SymFindAny (SymTable* Scope, const StrBuf* Name) +/* Find a symbol in the given or any of its parent scopes. The function will + * never create a new symbol, since this can only be done in one specific + * scope. + */ { - /* Resolve trampoline entries */ - if (S->Flags & SF_TRAMPOLINE) { - S = S->V.Sym; - } - - /* If the symbol is not a global symbol, was not defined before, check the - * enclosing scope for a symbol with the same name, and return the ZP - * attribute of this symbol if we find one. - */ - if (!IsLocalNameId (S->Name) && (S->Flags & (SF_DEFINED | SF_IMPORT)) == 0 && - S->SymTab->Parent != 0) { + SymEntry* Sym; + do { + /* Search in the current table. Ignore entries flagged with SF_UNUSED, + * because for such symbols there is a real entry in one of the parent + * scopes. + */ + Sym = SymFind (Scope, Name, SYM_FIND_EXISTING); + if (Sym) { + if (Sym->Flags & SF_UNUSED) { + Sym = 0; + } else { + /* Found, return it */ + break; + } + } - /* Try to find a symbol with the same name in the enclosing scope */ - SymEntry* E = SymFindAny (S->SymTab->Parent, GetString (S->Name)); + /* Not found, search in the parent scope, if we have one */ + Scope = Scope->Parent; - /* If we found one, use the ZP flag */ - if (E && E->AddrSize == ADDR_SIZE_ZP) { - S->AddrSize = ADDR_SIZE_ZP; - } - } + } while (Sym == 0 && Scope != 0); - /* Check the ZP flag */ - return (S->AddrSize == ADDR_SIZE_ZP); + /* Return the result */ + return Sym; } @@ -502,63 +458,93 @@ static void SymCheckUndefined (SymEntry* S) * AutoImport flag is not set, it's an error. */ SymEntry* Sym = 0; - if (S->SymTab) { - /* It's a global symbol, get the higher level table */ - SymTable* Tab = S->SymTab->Parent; - while (Tab) { - Sym = SymFindAny (Tab, GetString (S->Name)); - if (Sym) { - if (Sym->Flags & (SF_DEFINED | SF_IMPORT)) { - /* We've found a symbol in a higher level that is - * either defined in the source, or an import. - */ - break; - } else { - /* The symbol found is undefined itself. Look further */ - Tab = Sym->SymTab->Parent; - } - } else { - /* No symbol found */ - break; - } - } + SymTable* Tab = GetSymParentScope (S); + while (Tab) { + Sym = SymFind (Tab, GetStrBuf (S->Name), SYM_FIND_EXISTING); + if (Sym && (Sym->Flags & (SF_DEFINED | SF_IMPORT)) != 0) { + /* We've found a symbol in a higher level that is + * either defined in the source, or an import. + */ + break; + } + /* No matching symbol found in this level. Look further */ + Tab = Tab->Parent; } + if (Sym) { - /* We found the symbol in a higher level. Make S a trampoline - * symbol. Beware: We have to transfer the symbol attributes to - * the real symbol and check for any conflicts. - */ - S->Flags |= SF_TRAMPOLINE; - S->V.Sym = Sym; - /* Transfer the flags. Note: S may not be imported, since in that - * case it wouldn't be undefined. - */ - if (S->Flags & SF_EXPORT) { + /* We found the symbol in a higher level. Transfer the flags and + * address size from the local symbol to that in the higher level + * and check for problems. + */ + if (S->Flags & SF_EXPORT) { if (Sym->Flags & SF_IMPORT) { - /* The symbol is already marked as imported external symbol */ - PError (&S->Pos, "Symbol `%s' is already an import", GetString (S->Name)); + /* The symbol is already marked as import */ + LIError (&S->RefLines, + "Symbol `%s' is already an import", + GetString (Sym->Name)); } - Sym->Flags |= (S->Flags & SF_EXPORT); - Sym->ExportSize = S->ExportSize; - } + if (Sym->Flags & SF_EXPORT) { + /* The symbol is already marked as an export. */ + if (Sym->AddrSize > S->ExportSize) { + /* We're exporting a symbol smaller than it actually is */ + LIWarning (&S->DefLines, 1, + "Symbol `%m%p' is %s but exported %s", + GetSymName (Sym), + AddrSizeToStr (Sym->AddrSize), + AddrSizeToStr (S->ExportSize)); + } + } else { + /* Mark the symbol as an export */ + Sym->Flags |= SF_EXPORT; + Sym->ExportSize = S->ExportSize; + if (Sym->ExportSize == ADDR_SIZE_DEFAULT) { + /* Use the actual size of the symbol */ + Sym->ExportSize = Sym->AddrSize; + } + if (Sym->AddrSize > Sym->ExportSize) { + /* We're exporting a symbol smaller than it actually is */ + LIWarning (&S->DefLines, 1, + "Symbol `%m%p' is %s but exported %s", + GetSymName (Sym), + AddrSizeToStr (Sym->AddrSize), + AddrSizeToStr (Sym->ExportSize)); + } + } + } + if (S->Flags & SF_REFERENCED) { + /* Mark as referenced and move the line info */ + Sym->Flags |= SF_REFERENCED; + CollTransfer (&Sym->RefLines, &S->RefLines); + CollDeleteAll (&S->RefLines); + } - /* Transfer the referenced flag */ - Sym->Flags |= (S->Flags & SF_REFERENCED); + /* Transfer all expression references */ + SymTransferExprRefs (S, Sym); + + /* Mark the symbol as unused removing all other flags */ + S->Flags = SF_UNUSED; } else { /* The symbol is definitely undefined */ if (S->Flags & SF_EXPORT) { /* We will not auto-import an export */ - PError (&S->Pos, "Exported symbol `%s' was never defined", - GetString (S->Name)); + LIError (&S->RefLines, + "Exported symbol `%m%p' was never defined", + GetSymName (S)); } else { if (AutoImport) { - /* Mark as import, will be indexed later */ - S->Flags |= SF_IMPORT; + /* Mark as import, will be indexed later */ + S->Flags |= SF_IMPORT; + /* Use the address size for code */ + S->AddrSize = CodeAddrSize; + /* Mark point of import */ + GetFullLineInfo (&S->DefLines); } else { - /* Error */ - PError (&S->Pos, "Symbol `%s' is undefined", GetString (S->Name)); + /* Error */ + LIError (&S->RefLines, + "Symbol `%m%p' is undefined", + GetSymName (S)); } } } @@ -585,11 +571,10 @@ void SymCheck (void) * already defined, otherwise mark it as import. */ if (S->Flags & SF_GLOBAL) { - S->Flags &= ~SF_GLOBAL; if (S->Flags & SF_DEFINED) { - S->Flags |= SF_EXPORT; - } else { - S->Flags |= SF_IMPORT; + SymExportFromGlobal (S); + } else { + SymImportFromGlobal (S); } } @@ -603,37 +588,87 @@ void SymCheck (void) S = S->List; } - /* Second pass: Walk again through the symbols. Ignore undefined's, since - * we handled them in the last pass, and ignore trampoline symbols, since - * we handled them in the last pass, too. + /* Second pass: Walk again through the symbols. Count exports and imports + * and set address sizes where this has not happened before. Ignore + * undefined's, since we handled them in the last pass, and ignore unused + * symbols, since we handled them in the last pass, too. */ S = SymList; while (S) { - if ((S->Flags & SF_TRAMPOLINE) == 0 && + if ((S->Flags & SF_UNUSED) == 0 && (S->Flags & SF_UNDEFMASK) != SF_UNDEFVAL) { - if ((S->Flags & SF_DEFINED) != 0 && (S->Flags & SF_REFERENCED) == 0) { - /* Symbol was defined but never referenced */ - PWarning (&S->Pos, 2, - "Symbol `%s' is defined but never used", - GetString (S->Name)); - } + + /* Check for defined symbols that were never referenced */ + if (IsSizeOfSymbol (S)) { + /* Remove line infos, we don't need them any longer */ + ReleaseFullLineInfo (&S->DefLines); + ReleaseFullLineInfo (&S->RefLines); + } else if ((S->Flags & SF_DEFINED) != 0 && (S->Flags & SF_REFERENCED) == 0) { + LIWarning (&S->DefLines, 2, + "Symbol `%m%p' is defined but never used", + GetSymName (S)); + } + + /* Assign an index to all imports */ if (S->Flags & SF_IMPORT) { - if ((S->Flags & (SF_REFERENCED | SF_FORCED)) == SF_NONE) { - /* Imported symbol is not referenced */ - PWarning (&S->Pos, 2, - "Symbol `%s' is imported but never used", - GetString (S->Name)); - } else { - /* Give the import an index, count imports */ - S->Index = ImportCount++; - S->Flags |= SF_INDEXED; - } + if ((S->Flags & (SF_REFERENCED | SF_FORCED)) == SF_NONE) { + /* Imported symbol is not referenced */ + LIWarning (&S->DefLines, 2, + "Symbol `%m%p' is imported but never used", + GetSymName (S)); + } else { + /* Give the import an id, count imports */ + S->ImportId = ImportCount++; + } } + + /* Count exports, assign the export ID */ if (S->Flags & SF_EXPORT) { - /* Give the export an index, count exports */ - S->Index = ExportCount++; - S->Flags |= SF_INDEXED; + S->ExportId = ExportCount++; } + + /* If the symbol is defined but has an unknown address size, + * recalculate it. + */ + if (SymHasExpr (S) && S->AddrSize == ADDR_SIZE_DEFAULT) { + ExprDesc ED; + ED_Init (&ED); + StudyExpr (S->Expr, &ED); + S->AddrSize = ED.AddrSize; + if (SymIsExport (S)) { + if (S->ExportSize == ADDR_SIZE_DEFAULT) { + /* Use the real export size */ + S->ExportSize = S->AddrSize; + } else if (S->AddrSize > S->ExportSize) { + /* We're exporting a symbol smaller than it actually is */ + LIWarning (&S->DefLines, 1, + "Symbol `%m%p' is %s but exported %s", + GetSymName (S), + AddrSizeToStr (S->AddrSize), + AddrSizeToStr (S->ExportSize)); + } + } + ED_Done (&ED); + } + + /* If the address size of the symbol was guessed, check the guess + * against the actual address size and print a warning if the two + * differ. + */ + if (S->AddrSize != ADDR_SIZE_DEFAULT) { + /* Do we have data for this address size? */ + if (S->AddrSize <= sizeof (S->GuessedUse) / sizeof (S->GuessedUse[0])) { + /* Get the file position where the symbol was used */ + const FilePos* P = S->GuessedUse[S->AddrSize - 1]; + if (P) { + PWarning (P, 0, + "Didn't use %s addressing for `%m%p'", + AddrSizeToStr (S->AddrSize), + GetSymName (S)); + } + } + } + } /* Next symbol */ @@ -649,11 +684,11 @@ void SymDump (FILE* F) SymEntry* S = SymList; while (S) { - /* Ignore trampoline symbols */ - if ((S->Flags & SF_TRAMPOLINE) != 0) { + /* Ignore unused symbols */ + if ((S->Flags & SF_UNUSED) != 0) { fprintf (F, - "%-24s %s %s %s %s %s\n", - GetString (S->Name), + "%m%-24p %s %s %s %s %s\n", + GetSymName (S), (S->Flags & SF_DEFINED)? "DEF" : "---", (S->Flags & SF_REFERENCED)? "REF" : "---", (S->Flags & SF_IMPORT)? "IMP" : "---", @@ -685,16 +720,13 @@ void WriteImports (void) */ S = SymList; while (S) { - if ((S->Flags & (SF_TRAMPOLINE | SF_IMPORT)) == SF_IMPORT && + if ((S->Flags & (SF_UNUSED | SF_IMPORT)) == SF_IMPORT && (S->Flags & (SF_REFERENCED | SF_FORCED)) != 0) { - if (S->AddrSize == ADDR_SIZE_ZP) { - ObjWrite8 (IMP_ZP); - } else { - ObjWrite8 (IMP_ABS); - } + ObjWrite8 (S->AddrSize); ObjWriteVar (S->Name); - ObjWritePos (&S->Pos); + WriteLineInfo (&S->DefLines); + WriteLineInfo (&S->RefLines); } S = S->List; } @@ -705,26 +737,6 @@ void WriteImports (void) -static unsigned char GetExportExprMask (SymEntry* S) -/* Return the expression bits for the given symbol table entry */ -{ - unsigned char ExprMask; - - /* Check if the symbol is const */ - ExprMask = (SymIsConst (S))? EXP_CONST : EXP_EXPR; - - /* Add zeropage/abs bits */ - ExprMask |= (S->ExportSize == ADDR_SIZE_ZP)? EXP_ZP : EXP_ABS; - - /* Add the label/equate bits */ - ExprMask |= (S->Flags & SF_LABEL)? EXP_LABEL : EXP_EQUATE; - - /* Return the mask */ - return ExprMask; -} - - - void WriteExports (void) /* Write the exports list to the object file */ { @@ -740,49 +752,62 @@ void WriteExports (void) /* Walk throught list and write all exports to the file */ S = SymList; while (S) { - if ((S->Flags & SF_EXPMASK) == SF_EXPVAL) { - unsigned char ExprMask; - - /* Finalize an associated expression if we have one */ - SymFinalize (S); - - /* Get the expression bits */ - ExprMask = GetExportExprMask (S); + if ((S->Flags & (SF_UNUSED | SF_EXPORT)) == SF_EXPORT) { + + /* Get the expression bits and the value */ + long ConstVal; + unsigned SymFlags = GetSymInfoFlags (S, &ConstVal); + + /* Check if this symbol has a size. If so, remember it in the + * flags. + */ + long Size; + SymEntry* SizeSym = FindSizeOfSymbol (S); + if (SizeSym != 0 && SymIsConst (SizeSym, &Size)) { + SymFlags |= SYM_SIZE; + } /* Count the number of ConDes types */ for (Type = 0; Type < CD_TYPE_COUNT; ++Type) { - if (S->ConDesPrio[Type] != CD_PRIO_NONE) { - INC_EXP_CONDES_COUNT (ExprMask); - } + if (S->ConDesPrio[Type] != CD_PRIO_NONE) { + SYM_INC_CONDES_COUNT (SymFlags); + } } - /* Write the type */ - ObjWrite8 (ExprMask); + /* Write the type and the export size */ + ObjWriteVar (SymFlags); + ObjWrite8 (S->ExportSize); /* Write any ConDes declarations */ - if (GET_EXP_CONDES_COUNT (ExprMask) > 0) { - for (Type = 0; Type < CD_TYPE_COUNT; ++Type) { - unsigned char Prio = S->ConDesPrio[Type]; - if (Prio != CD_PRIO_NONE) { - ObjWrite8 (CD_BUILD (Type, Prio)); - } - } + if (SYM_GET_CONDES_COUNT (SymFlags) > 0) { + for (Type = 0; Type < CD_TYPE_COUNT; ++Type) { + unsigned char Prio = S->ConDesPrio[Type]; + if (Prio != CD_PRIO_NONE) { + ObjWrite8 (CD_BUILD (Type, Prio)); + } + } } /* Write the name */ ObjWriteVar (S->Name); /* Write the value */ - if ((ExprMask & EXP_MASK_VAL) == EXP_CONST) { + if (SYM_IS_CONST (SymFlags)) { /* Constant value */ - ObjWrite32 (S->V.Val); + ObjWrite32 (ConstVal); } else { /* Expression involved */ - WriteExpr (S->V.Expr); + WriteExpr (S->Expr); } - /* Write the source file position */ - ObjWritePos (&S->Pos); + /* If the symbol has a size, write it to the file */ + if (SYM_HAS_SIZE (SymFlags)) { + ObjWriteVar (Size); + } + + /* Write the line infos */ + WriteLineInfo (&S->DefLines); + WriteLineInfo (&S->RefLines); } S = S->List; } @@ -793,26 +818,6 @@ void WriteExports (void) -static unsigned char GetDbgExprMask (SymEntry* S) -/* Return the expression bits for the given symbol table entry */ -{ - unsigned char ExprMask; - - /* Check if the symbol is const */ - ExprMask = (SymIsConst (S))? EXP_CONST : EXP_EXPR; - - /* Add zeropage/abs bits */ - ExprMask |= (S->AddrSize == ADDR_SIZE_ZP)? EXP_ZP : EXP_ABS; - - /* Add the label/equate bits */ - ExprMask |= (S->Flags & SF_LABEL)? EXP_LABEL : EXP_EQUATE; - - /* Return the mask */ - return ExprMask; -} - - - void WriteDbgSyms (void) /* Write a list of all symbols to the object file */ { @@ -825,48 +830,82 @@ void WriteDbgSyms (void) /* Check if debug info is requested */ if (DbgSyms) { - /* Walk through the list and count the symbols */ - Count = 0; - S = SymList; - while (S) { - if ((S->Flags & SF_DBGINFOMASK) == SF_DBGINFOVAL) { - ++Count; - } - S = S->List; - } + /* Walk through the list, give each symbol an id and count them */ + Count = 0; + S = SymList; + while (S) { + if (IsDbgSym (S)) { + S->DebugSymId = Count++; + } + S = S->List; + } - /* Write the symbol count to the list */ + /* Write the symbol count to the list */ ObjWriteVar (Count); - /* Walk through list and write all symbols to the file */ - S = SymList; - while (S) { - if ((S->Flags & SF_DBGINFOMASK) == SF_DBGINFOVAL) { - unsigned char ExprMask; + /* Walk through list and write all symbols to the file. Ignore size + * symbols. + */ + S = SymList; + while (S) { + if (IsDbgSym (S)) { + + /* Get the expression bits and the value */ + long ConstVal; + unsigned SymFlags = GetSymInfoFlags (S, &ConstVal); + + /* Check if this symbol has a size. If so, remember it in the + * flags. + */ + long Size; + SymEntry* SizeSym = FindSizeOfSymbol (S); + if (SizeSym != 0 && SymIsConst (SizeSym, &Size)) { + SymFlags |= SYM_SIZE; + } - /* Finalize an associated expression if we have one */ - SymFinalize (S); + /* Write the type */ + ObjWriteVar (SymFlags); - /* Get the expression bits */ - ExprMask = GetDbgExprMask (S); + /* Write the address size */ + ObjWrite8 (S->AddrSize); - /* Write the type */ - ObjWrite8 (ExprMask); + /* Write the id of the parent. For normal symbols, this is a + * scope (symbol table), for cheap locals, it's a symbol. + */ + if (SYM_IS_STD (SymFlags)) { + ObjWriteVar (S->Sym.Tab->Id); + } else { + ObjWriteVar (S->Sym.Entry->DebugSymId); + } /* Write the name */ ObjWriteVar (S->Name); /* Write the value */ - if ((ExprMask & EXP_MASK_VAL) == EXP_CONST) { + if (SYM_IS_CONST (SymFlags)) { /* Constant value */ - ObjWrite32 (S->V.Val); + ObjWrite32 (ConstVal); } else { /* Expression involved */ - WriteExpr (S->V.Expr); + WriteExpr (S->Expr); } - /* Write the source file position */ - ObjWritePos (&S->Pos); + /* If the symbol has a size, write it to the file */ + if (SYM_HAS_SIZE (SymFlags)) { + ObjWriteVar (Size); + } + + /* If the symbol is an im- or export, write out the ids */ + if (SYM_IS_IMPORT (SymFlags)) { + ObjWriteVar (GetSymImportId (S)); + } + if (SYM_IS_EXPORT (SymFlags)) { + ObjWriteVar (GetSymExportId (S)); + } + + /* Write the line infos */ + WriteLineInfo (&S->DefLines); + WriteLineInfo (&S->RefLines); } S = S->List; } @@ -878,10 +917,99 @@ void WriteDbgSyms (void) } + /* Write the high level symbols */ + WriteHLLDbgSyms (); + /* Done writing debug symbols */ ObjEndDbgSyms (); } +void WriteScopes (void) +/* Write the scope table to the object file */ +{ + /* Tell the object file module that we're about to start the scopes */ + ObjStartScopes (); + + /* We will write scopes only if debug symbols are requested */ + if (DbgSyms) { + + /* Get head of list */ + SymTable* S = RootScope; + + /* Write the scope count to the file */ + ObjWriteVar (ScopeCount); + + /* Walk through all scopes and write them to the file */ + while (S) { + + /* Flags for this scope */ + unsigned Flags = 0; + + /* Check if this scope has a size. If so, remember it in the + * flags. + */ + long Size; + SymEntry* SizeSym = FindSizeOfScope (S); + if (SizeSym != 0 && SymIsConst (SizeSym, &Size)) { + Flags |= SCOPE_SIZE; + } + + /* Check if the scope has a label */ + if (S->Label) { + Flags |= SCOPE_LABELED; + } + + /* Scope must be defined */ + CHECK (S->Type != SCOPE_UNDEF); + + /* Id of parent scope */ + if (S->Parent) { + ObjWriteVar (S->Parent->Id); + } else { + ObjWriteVar (0); + } + + /* Lexical level */ + ObjWriteVar (S->Level); + + /* Scope flags */ + ObjWriteVar (Flags); + + /* Type of scope */ + ObjWriteVar (S->Type); + + /* Name of the scope */ + ObjWriteVar (S->Name); + + /* If the scope has a size, write it to the file */ + if (SCOPE_HAS_SIZE (Flags)) { + ObjWriteVar (Size); + } + + /* If the scope has a label, write its id to the file */ + if (SCOPE_HAS_LABEL (Flags)) { + ObjWriteVar (S->Label->DebugSymId); + } + + /* Spans for this scope */ + WriteSpanList (&S->Spans); + + /* Next scope */ + S = S->Next; + } + + } else { + + /* No debug info requested */ + ObjWriteVar (0); + + } + + /* Done writing the scopes */ + ObjEndScopes (); +} + +