X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fca65%2Fsymtab.c;h=e592d06d4a2d05ab3a6bcc593c363ce2877c7c55;hb=4191eb771878e678121e22748475e81778d0e820;hp=f6055591e40ba683f41789f489f61a99f67e8c5a;hpb=6f088806d7f1424f3bceac0041e34e7fe3acd590;p=cc65 diff --git a/src/ca65/symtab.c b/src/ca65/symtab.c index f6055591e..e592d06d4 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 */ @@ -39,6 +39,8 @@ #include "addrsize.h" #include "check.h" #include "hashstr.h" +#include "mmodel.h" +#include "scopedefs.h" #include "symdefs.h" #include "xmalloc.h" @@ -49,7 +51,9 @@ #include "objfile.h" #include "scanner.h" #include "segment.h" +#include "sizeof.h" #include "spool.h" +#include "studyexpr.h" #include "symtab.h" @@ -63,18 +67,18 @@ /* 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_DBGINFOMASK (SF_UNUSED | SF_DEFINED | SF_IMPORT) #define SF_DBGINFOVAL (SF_DEFINED) /* 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 */ @@ -96,7 +100,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 */ @@ -110,18 +114,33 @@ static SymTable* NewSymTable (SymTable* Parent, const char* Name) S->Left = 0; S->Right = 0; S->Childs = 0; + S->OwnerSym = 0; + S->SegRanges = AUTO_COLLECTION_INITIALIZER; S->Flags = ST_NONE; S->AddrSize = ADDR_SIZE_DEFAULT; - S->Type = 0; + S->Type = SCOPETYPE_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 and maintain + * a unqiue id for each scope. Count the number of scopes. + */ + S->Next = LastScope; + if (RootScope == 0) { + S->Id = 0; + RootScope = S; + } else { + S->Id = LastScope->Id + 1; + } + LastScope = S; + ++ScopeCount; + /* Insert the symbol table into the child tree of the parent */ if (Parent) { SymTable* T = Parent->Childs; @@ -131,7 +150,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 +167,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 +179,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* OwnerSym) /* Enter a new lexical level */ { /* Map a default address size to something real */ @@ -216,18 +199,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->OwnerSym = OwnerSym; + + /* If this is a scope that allows to emit data into segments, add segment + * ranges 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 <= SCOPETYPE_HAS_DATA) { + AddSegRanges (&CurrentScope->SegRanges); + } } @@ -235,17 +234,37 @@ void SymEnterLevel (const char* ScopeName, unsigned AddrSize) void SymLeaveLevel (void) /* Leave the current lexical level */ { + /* Close the segment ranges. We don't care about the scope type here, + * since types without segment ranges will just have an empty list. + */ + CloseSegRanges (&CurrentScope->SegRanges); + + /* If we have segment ranges, 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->SegRanges) > 0) { + const SegRange* R = CollAtUnchecked (&CurrentScope->SegRanges, 0); + unsigned long Size = GetSegRangeSize (R); + DefSizeOfScope (CurrentScope, Size); + if (CurrentScope->OwnerSym) { + DefSizeOfSymbol (CurrentScope->OwnerSym, 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,85 +286,110 @@ 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. +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. + */ +{ + SymTable* Scope; + do { + /* Search in the current table */ + Scope = SymFindScope (Parent, Name, SYM_FIND_EXISTING); + if (Scope == 0) { + /* Not found, search in the parent scope, if we have one */ + Parent = Parent->Parent; + } + } while (Scope == 0 && Parent != 0); + + return Scope; +} + + + +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; - if (IsLocalName (Name)) { + /* 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; + } + } - /* 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 = SymSearchTree (Parent->Locals, Name, &S); - /* 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 we found an entry, return it */ - if (Cmp == 0) { - return S; - } + if (AllocNew) { - if (AllocNew) { + /* 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; + } - /* 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; - } + /* We did not find the entry and AllocNew is false. */ + return 0; +} - } 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); +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. + */ +{ + SymEntry* 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; - } + /* Global symbol: Get the hash value for the name */ + unsigned Hash = HashBuf (Name) % Scope->TableSlots; - if (AllocNew) { + /* Search for the entry */ + int Cmp = SymSearchTree (Scope->Table[Hash], Name, &S); - /* 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; + /* 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, 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. */ @@ -354,7 +398,7 @@ SymEntry* SymFind (SymTable* Scope, const char* Name, int AllocNew) -static SymEntry* SymFindAny (SymTable* Scope, const char* Name) +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. @@ -364,126 +408,27 @@ static SymEntry* SymFindAny (SymTable* Scope, const char* Name) do { /* Search in the current table */ Sym = SymFind (Scope, Name, SYM_FIND_EXISTING); - if (Sym) { + if (Sym) { /* Found, return it */ - return Sym; - } else { - /* Not found, search in the parent scope, if we have one */ - Scope = Scope->Parent; + break; } - } while (Sym == 0 && Scope != 0); - /* Not found */ - return 0; -} + /* Not found, search in the parent scope, if we have one */ + Scope = Scope->Parent; + } while (Sym == 0 && Scope != 0); - -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* S; - - /* 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; - } - - /* 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; - } - - /* If the symbol is marked as global, silently remove the global flag */ - if (S->Flags & SF_GLOBAL) { - S->Flags &= ~SF_GLOBAL; - } - - /* 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 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); - } - } - S->ConDesPrio[Type] = Prio; - - /* Set the symbol data */ - S->Flags |= SF_EXPORT | SF_REFERENCED; -} - - - -int SymIsConst (SymEntry* S) -/* Return true if the given symbol has a constant value */ -{ - /* Resolve trampoline entries */ - if (S->Flags & SF_TRAMPOLINE) { - S = S->V.Sym; - } - - /* 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; - } - return 0; + /* Return the result */ + return Sym; } -int SymIsZP (SymEntry* S) -/* Return true if the symbol is explicitly marked as zeropage symbol */ +unsigned char GetCurrentSymTabType () +/* Return the type of the current symbol table */ { - /* 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) { - - /* Try to find a symbol with the same name in the enclosing scope */ - SymEntry* E = SymFindAny (S->SymTab->Parent, GetString (S->Name)); - - /* If we found one, use the ZP flag */ - if (E && E->AddrSize == ADDR_SIZE_ZP) { - S->AddrSize = ADDR_SIZE_ZP; - } - } - - /* Check the ZP flag */ - return (S->AddrSize == ADDR_SIZE_ZP); + CHECK (CurrentScope != 0); + return CurrentScope->Type; } @@ -502,63 +447,86 @@ 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->LineInfos, + "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->LineInfos, 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->LineInfos, 1, + "Symbol `%m%p' is %s but exported %s", + GetSymName (Sym), + AddrSizeToStr (Sym->AddrSize), + AddrSizeToStr (Sym->ExportSize)); + } + } + } + Sym->Flags |= (S->Flags & SF_REFERENCED); - /* 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->LineInfos, + "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; } else { - /* Error */ - PError (&S->Pos, "Symbol `%s' is undefined", GetString (S->Name)); + /* Error */ + LIError (&S->LineInfos, + "Symbol `%m%p' is undefined", + GetSymName (S)); } } } @@ -585,11 +553,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; + SymExportFromGlobal (S); } else { - S->Flags |= SF_IMPORT; + SymImportFromGlobal (S); } } @@ -603,37 +570,86 @@ 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) { + + /* Check for defined symbols that were never referenced */ 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)); + const StrBuf* Name = GetStrBuf (S->Name); + if (SB_At (Name, 0) != '.') { /* Ignore internals */ + LIWarning (&S->LineInfos, 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->LineInfos, 2, + "Symbol `%m%p' is imported but never used", + GetSymName (S)); + } else { + /* Give the import an id, count imports */ + S->ImportId = ImportCount++; + } } + + /* Count exports */ if (S->Flags & SF_EXPORT) { - /* Give the export an index, count exports */ - S->Index = ExportCount++; - S->Flags |= SF_INDEXED; + ++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->LineInfos, 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 +665,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 +701,12 @@ 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->LineInfos); } S = S->List; } @@ -705,26 +717,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 +732,61 @@ 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 ExprMask = 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)) { + ExprMask |= 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 (ExprMask); + } } - /* Write the type */ - ObjWrite8 (ExprMask); + /* Write the type and the export size */ + ObjWriteVar (ExprMask); + 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 (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)); + } + } } /* Write the name */ ObjWriteVar (S->Name); /* Write the value */ - if ((ExprMask & EXP_MASK_VAL) == EXP_CONST) { + if (SYM_IS_CONST (ExprMask)) { /* Constant value */ - ObjWrite32 (S->V.Val); + ObjWrite32 (ConstVal); } else { /* Expression involved */ - WriteExpr (S->V.Expr); + WriteExpr (S->Expr); + } + + /* If the symbol has a size, write it to the file */ + if (SYM_HAS_SIZE (ExprMask)) { + ObjWriteVar (Size); } - /* Write the source file position */ - ObjWritePos (&S->Pos); + /* Write the line infos */ + WriteLineInfo (&S->LineInfos); } S = S->List; } @@ -793,26 +797,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 +809,75 @@ 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 ((S->Flags & SF_DBGINFOMASK) == SF_DBGINFOVAL && + !IsSizeOfSymbol (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 ((S->Flags & SF_DBGINFOMASK) == SF_DBGINFOVAL && + !IsSizeOfSymbol (S)) { + + /* Get the expression bits and the value */ + long ConstVal; + unsigned ExprMask = 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)) { + ExprMask |= SYM_SIZE; + } - /* Finalize an associated expression if we have one */ - SymFinalize (S); + /* Write the type */ + ObjWriteVar (ExprMask); - /* 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 (ExprMask)) { + 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 (ExprMask)) { /* 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 (ExprMask)) { + ObjWriteVar (Size); + } + + /* Write the line infos */ + WriteLineInfo (&S->LineInfos); } S = S->List; } @@ -884,4 +895,66 @@ void WriteDbgSyms (void) +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 */ + const SymTable* S = LastScope; + + /* Write the scope count to the file */ + ObjWriteVar (ScopeCount); + + /* Walk through all scopes and write them to the file */ + while (S) { + + /* Type must be defined */ + CHECK (S->Type != SCOPETYPE_UNDEF); + + /* Id of scope */ + ObjWriteVar (S->Id); + + /* Id of parent scope */ + if (S->Parent) { + ObjWriteVar (S->Parent->Id); + } else { + ObjWriteVar (0); + } + + /* Lexical level */ + ObjWriteVar (S->Level); + + /* Scope flags (currently always zero) */ + ObjWriteVar (0); + + /* Type of scope */ + ObjWriteVar (S->Type); + + /* Name of the scope */ + ObjWriteVar (S->Name); + + /* Segment ranges for this scope */ + WriteSegRanges (&S->SegRanges); + + /* Next scope */ + S = S->Next; + } + + } else { + + /* No debug info requested */ + ObjWriteVar (0); + + } + + /* Done writing the scopes */ + ObjEndScopes (); +} + +