/* */
/* */
/* */
-/* (C) 1998-2000 Ullrich von Bassewitz */
-/* Wacholderweg 14 */
-/* D-70597 Stuttgart */
-/* EMail: uz@musoftware.de */
+/* (C) 1998-2003 Ullrich von Bassewitz */
+/* Römerstraße 52 */
+/* D-70794 Filderstadt */
+/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
#include <string.h>
/* common */
-#include "cddefs.h"
+#include "addrsize.h"
#include "check.h"
#include "hashstr.h"
+#include "mmodel.h"
#include "symdefs.h"
#include "xmalloc.h"
#include "expr.h"
#include "objfile.h"
#include "scanner.h"
+#include "segment.h"
+#include "sizeof.h"
+#include "spool.h"
+#include "studyexpr.h"
#include "symtab.h"
-/* Bits for the Flags value in SymEntry */
-#define SF_USER 0x0001 /* User bit */
-#define SF_TRAMPOLINE 0x0002 /* Trampoline entry */
-#define SF_EXPORT 0x0004 /* Export this symbol */
-#define SF_IMPORT 0x0008 /* Import this symbol */
-#define SF_GLOBAL 0x0010 /* Global symbol */
-#define SF_ZP 0x0020 /* Declared as zeropage symbol */
-#define SF_ABS 0x0040 /* Declared as absolute symbol */
-#define SF_INDEXED 0x0800 /* Index is valid */
-#define SF_CONST 0x1000 /* The symbol has a constant value */
-#define SF_MULTDEF 0x2000 /* Multiply defined symbol */
-#define SF_DEFINED 0x4000 /* Defined */
-#define SF_REFERENCED 0x8000 /* Referenced */
-
-/* Combined stuff */
+/* Combined symbol entry flags used within this module */
#define SF_UNDEFMASK (SF_REFERENCED | SF_DEFINED | SF_IMPORT)
#define SF_UNDEFVAL (SF_REFERENCED)
-#define SF_IMPMASK (SF_TRAMPOLINE | SF_IMPORT | SF_REFERENCED)
-#define SF_IMPVAL (SF_IMPORT | 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)
-/* Structure of a symbol table entry */
-struct SymEntry {
- SymEntry* Left; /* Lexically smaller entry */
- SymEntry* Right; /* Lexically larger entry */
- SymEntry* List; /* List of all entries */
- SymEntry* Locals; /* Root of subtree for local symbols */
- struct SymTable* SymTab; /* Table this symbol is in, 0 for locals */
- FilePos Pos; /* File position for this symbol */
- unsigned Flags; /* Symbol flags */
- unsigned Index; /* Index of import/export entries */
- union {
- struct ExprNode* Expr; /* Expression if CONST not set */
- long Val; /* Value (if CONST set) */
- SymEntry* Sym; /* Symbol (if trampoline entry) */
- } V;
- unsigned char ConDesPrio[CD_TYPE_COUNT]; /* ConDes priorities... */
- /* ...actually value+1 (used as flag) */
- char Name [1]; /* Dynamic allocation */
-};
-
-
-
-/* Definitions for the hash table */
-#define MAIN_HASHTAB_SIZE 213
-#define SUB_HASHTAB_SIZE 53
-typedef struct SymTable SymTable;
-struct SymTable {
- unsigned TableSlots; /* Number of hash table slots */
- unsigned TableEntries; /* Number of entries in the table */
- SymTable* BackLink; /* Link to enclosing scope if any */
- SymEntry* Table [1]; /* Dynamic allocation */
-};
-
-
-
-/* Arguments for SymFind */
-#define SF_FIND_EXISTING 0
-#define SF_ALLOC_NEW 1
-
-
+/* Symbol tables */
+SymTable* CurrentScope = 0; /* Pointer to current symbol table */
+SymTable* RootScope = 0; /* Root symbol table */
/* Symbol table variables */
-static SymEntry* SymList = 0; /* List of all symbol table entries */
-static SymEntry* SymLast = 0; /* Pointer to last defined symbol */
-static SymTable* SymTab = 0; /* Pointer to current symbol table */
-static SymTable* RootTab = 0; /* Root symbol table */
-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 */
-static int IsLocal (const char* Name)
-/* Return true if Name is the name of a local symbol */
+static unsigned ScopeTableSize (unsigned Level)
+/* Get the size of a table for the given lexical level */
{
- return (*Name == LocalStart);
-}
-
-
-
-static SymEntry* NewSymEntry (const char* Name)
-/* Allocate a symbol table entry, initialize and return it */
-{
- SymEntry* S;
- unsigned Len;
-
- /* Get the length of the name */
- Len = strlen (Name);
-
- /* Allocate memory */
- S = xmalloc (sizeof (SymEntry) + Len);
-
- /* 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;
- memset (S->ConDesPrio, 0, sizeof (S->ConDesPrio));
- memcpy (S->Name, Name, Len+1);
-
- /* Insert it into the list of all entries */
- S->List = SymList;
- SymList = S;
-
- /* Return the initialized entry */
- return S;
+ switch (Level) {
+ case 0: return 213;
+ case 1: return 53;
+ default: return 29;
+ }
}
-static SymTable* NewSymTable (unsigned Size)
+static SymTable* NewSymTable (SymTable* Parent, const char* Name)
/* Allocate a symbol table on the heap and return it */
{
- SymTable* S;
+ /* Determine the lexical level and the number of table slots */
+ unsigned Level = Parent? Parent->Level + 1 : 0;
+ unsigned Slots = ScopeTableSize (Level);
/* Allocate memory */
- S = xmalloc (sizeof (SymTable) + (Size-1) * sizeof (SymEntry*));
+ SymTable* S = xmalloc (sizeof (SymTable) + (Slots-1) * sizeof (SymEntry*));
/* Set variables and clear hash table entries */
- S->TableSlots = Size;
+ S->Left = 0;
+ S->Right = 0;
+ S->Childs = 0;
+ S->SegRanges = AUTO_COLLECTION_INITIALIZER;
+ S->Flags = ST_NONE;
+ S->AddrSize = ADDR_SIZE_DEFAULT;
+ S->Type = ST_UNDEF;
+ S->Level = Level;
+ S->TableSlots = Slots;
S->TableEntries = 0;
- S->BackLink = 0;
- while (Size--) {
- S->Table [Size] = 0;
+ S->Parent = Parent;
+ S->Name = GetStringId (Name);
+ while (Slots--) {
+ S->Table[Slots] = 0;
+ }
+
+ /* Insert the symbol table into the child tree of the parent */
+ if (Parent) {
+ SymTable* T = Parent->Childs;
+ if (T == 0) {
+ /* First entry */
+ Parent->Childs = S;
+ } else {
+ while (1) {
+ /* Choose next entry */
+ int Cmp = strcmp (Name, GetString (T->Name));
+ if (Cmp < 0) {
+ if (T->Left) {
+ T = T->Left;
+ } else {
+ T->Left = S;
+ break;
+ }
+ } else if (Cmp > 0) {
+ if (T->Right) {
+ T = T->Right;
+ } else {
+ T->Right = S;
+ break;
+ }
+ } else {
+ /* Duplicate scope name */
+ Internal ("Duplicate scope name: `%s'", Name);
+ }
+ }
+ }
}
/* Return the prepared struct */
-static int SearchSymTab (SymEntry* T, const char* Name, SymEntry** E)
-/* Search in the given table for a name (Hash is the hash value of Name and
- * is given as parameter so that it will not get calculated twice if we search
- * in more than one table). 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.
- */
-{
- int Cmp;
-
- /* Is there a tree? */
- if (T == 0) {
- *E = 0;
- return 1;
- }
-
- /* We have a table, search it */
- while (1) {
- /* Choose next entry */
- Cmp = strcmp (Name, T->Name);
- if (Cmp < 0 && T->Left) {
- T = T->Left;
- } else if (Cmp > 0 && T->Right) {
- T = T->Right;
- } else {
- /* Found or end of search */
- break;
- }
- }
-
- /* Return the search result */
- *E = T;
- return Cmp;
-}
-
-
-
/*****************************************************************************/
-/* Code */
+/* Code */
/*****************************************************************************/
-static SymEntry* SymFind (SymTable* Tab, 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;
- unsigned Hash;
-
- if (IsLocal (Name)) {
-
- /* Local symbol, get the table */
- if (!SymLast) {
- /* No last global, so there's no local table */
- Error (ERR_ILLEGAL_LOCAL_USE);
- if (AllocNew) {
- return NewSymEntry (Name);
- } else {
- return 0;
- }
- }
-
- /* Search for the symbol if we have a table */
- Cmp = SearchSymTab (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 */
- Hash = HashStr (Name) % Tab->TableSlots;
-
- /* Search for the entry */
- Cmp = SearchSymTab (Tab->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.
- */
- if (S->Flags & SF_TRAMPOLINE) {
- return S->V.Sym;
- } else {
- return S;
- }
- }
-
- if (AllocNew) {
-
- /* Otherwise create a new entry, insert and return it */
- SymEntry* N = NewSymEntry (Name);
- if (S == 0) {
- Tab->Table [Hash] = N;
- } else if (Cmp < 0) {
- S->Left = N;
- } else {
- S->Right = N;
- }
- N->SymTab = Tab;
- ++Tab->TableEntries;
- return N;
-
- }
- }
-
- /* We did not find the entry and AllocNew is false. */
- return 0;
-}
-
-
-
-static SymEntry* SymFindAny (SymTable* Tab, const char* Name)
-/* Find a symbol in any table */
-{
- SymEntry* Sym;
- do {
- /* Search in the current table */
- Sym = SymFind (Tab, Name, 0);
- if (Sym) {
- /* Found, return it */
- return Sym;
- } else {
- /* Not found, search in the backlink, if we have one */
- Tab = Tab->BackLink;
- }
- } while (Sym == 0 && Tab != 0);
-
- /* Not found */
- return 0;
-}
-
-
-
-static SymEntry* SymRefInternal (SymTable* Table, const char* Name)
-/* Search for the symbol in the given table and return it */
-{
- /* Try to find the symbol, create a new one if the symbol does not exist */
- SymEntry* S = SymFind (Table, Name, SF_ALLOC_NEW);
-
- /* Mark the symbol as referenced */
- S->Flags |= SF_REFERENCED;
-
- /* Return it */
- return S;
-}
-
-
-
-void SymEnterLevel (void)
+void SymEnterLevel (const char* ScopeName, unsigned char Type, unsigned char AddrSize)
/* Enter a new lexical level */
{
- if (RootTab == 0) {
- /* Create the main symbol table */
- RootTab = SymTab = NewSymTable (MAIN_HASHTAB_SIZE);
- } else {
- /* Create a local symbol table */
- SymTable* LocalSyms;
- LocalSyms = NewSymTable (SUB_HASHTAB_SIZE);
- LocalSyms->BackLink = SymTab;
- SymTab = LocalSyms;
+ /* Map a default address size to something real */
+ if (AddrSize == ADDR_SIZE_DEFAULT) {
+ /* Use the segment address size */
+ AddrSize = GetCurrentSegAddrSize ();
}
-}
-
-
-
-void SymLeaveLevel (void)
-/* Leave the current lexical level */
-{
- SymTab = SymTab->BackLink;
-}
+ /* If we have a current scope, search for the given name and create a
+ * 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);
-void SymDef (const char* Name, ExprNode* Expr, int ZP)
-/* Define a new symbol */
-{
- /* Do we have such a symbol? */
- SymEntry* S = SymFind (SymTab, Name, SF_ALLOC_NEW);
- if (S->Flags & SF_IMPORT) {
- /* Defined symbol is marked as imported external symbol */
- Error (ERR_SYM_ALREADY_IMPORT, Name);
- return;
- }
- if (S->Flags & SF_DEFINED) {
- /* Multiple definition */
- Error (ERR_SYM_ALREADY_DEFINED, Name);
- S->Flags |= SF_MULTDEF;
- return;
- }
+ /* Check if the scope has been defined before */
+ if (CurrentScope->Flags & ST_DEFINED) {
+ Error ("Duplicate scope `%s'", ScopeName);
+ }
- /* Set the symbol data */
- if (IsConstExpr (Expr)) {
- /* Expression is const, store the value */
- S->Flags |= SF_CONST;
- S->V.Val = GetExprVal (Expr);
- FreeExpr (Expr);
} else {
- /* Not const, store the expression */
- S->V.Expr = Expr;
- }
- S->Flags |= SF_DEFINED;
- if (ZP) {
- S->Flags |= SF_ZP;
+ CurrentScope = RootScope = NewSymTable (0, ScopeName);
}
- /* If the symbol is a ZP symbol, check if the value is in correct range */
- if (S->Flags & SF_ZP) {
- /* Already marked as ZP symbol by some means */
- if (!IsByteExpr (Expr)) {
- Error (ERR_RANGE);
- }
- }
+ /* Mark the scope as defined and set type and address size */
+ CurrentScope->Flags |= ST_DEFINED;
+ CurrentScope->AddrSize = AddrSize;
+ CurrentScope->Type = Type;
- /* If this is not a local symbol, remember it as the last global one */
- if (!IsLocal (Name)) {
- SymLast = S;
+ /* 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 <= ST_SCOPE_HAS_DATA) {
+ AddSegRanges (&CurrentScope->SegRanges);
}
}
-SymEntry* SymRef (const char* Name)
-/* Search for the symbol and return it */
-{
- /* Reference the symbol in the current table */
- return SymRefInternal (SymTab, Name);
-}
-
-
-
-SymEntry* SymRefGlobal (const char* Name)
-/* Search for the symbol in the global namespace and return it */
-{
- /* Reference the symbol in the current table */
- return SymRefInternal (RootTab, Name);
-}
-
-
-
-void SymImport (const char* Name, int ZP)
-/* Mark the given symbol as an imported symbol */
+void SymLeaveLevel (void)
+/* Leave the current lexical level */
{
- SymEntry* S;
-
- /* Don't accept local symbols */
- if (IsLocal (Name)) {
- Error (ERR_ILLEGAL_LOCAL_USE);
- return;
- }
-
- /* Do we have such a symbol? */
- S = SymFind (SymTab, Name, SF_ALLOC_NEW);
- if (S->Flags & SF_DEFINED) {
- Error (ERR_SYM_ALREADY_DEFINED, Name);
- S->Flags |= SF_MULTDEF;
- return;
- }
- if (S->Flags & SF_EXPORT) {
- /* The symbol is already marked as exported symbol */
- Error (ERR_SYM_ALREADY_EXPORT, Name);
- return;
- }
+ /* 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 the symbol is marked as global, check the symbol size, then do
- * silently remove the global flag
+ /* 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 (S->Flags & SF_GLOBAL) {
- if ((ZP != 0) != ((S->Flags & SF_ZP) != 0)) {
- Error (ERR_SYM_REDECL_MISMATCH);
- }
- S->Flags &= ~SF_GLOBAL;
+ if (CollCount (&CurrentScope->SegRanges) > 0) {
+ const SegRange* R = CollAtUnchecked (&CurrentScope->SegRanges, 0);
+ DefSizeOfScope (CurrentScope, GetSegRangeSize (R));
}
- /* Set the symbol data */
- S->Flags |= SF_IMPORT;
- if (ZP) {
- S->Flags |= SF_ZP;
- }
+ /* Leave the scope */
+ CurrentScope = CurrentScope->Parent;
}
-void SymExport (const char* Name, int ZP)
-/* Mark the given symbol as an exported symbol */
+SymTable* SymFindScope (SymTable* Parent, const char* Name, int AllocNew)
+/* Find a scope in the given enclosing scope */
{
- SymEntry* S;
-
- /* Don't accept local symbols */
- if (IsLocal (Name)) {
- Error (ERR_ILLEGAL_LOCAL_USE);
- return;
+ SymTable** T = &Parent->Childs;
+ while (*T) {
+ int Cmp = strcmp (Name, GetString ((*T)->Name));
+ if (Cmp < 0) {
+ T = &(*T)->Left;
+ } else if (Cmp > 0) {
+ T = &(*T)->Right;
+ } else {
+ /* Found the scope */
+ return *T;
+ }
}
- /* Do we have such a symbol? */
- S = SymFind (SymTab, Name, SF_ALLOC_NEW);
- if (S->Flags & SF_IMPORT) {
- /* The symbol is already marked as imported external symbol */
- Error (ERR_SYM_ALREADY_IMPORT, Name);
- return;
+ /* Create a new scope if requested and we didn't find one */
+ if (*T == 0 && AllocNew) {
+ *T = NewSymTable (Parent, Name);
}
- /* If the symbol is marked as global, check the symbol size, then do
- * silently remove the global flag
- */
- if (S->Flags & SF_GLOBAL) {
- if ((ZP != 0) != ((S->Flags & SF_ZP) != 0)) {
- Error (ERR_SYM_REDECL_MISMATCH);
- }
- S->Flags &= ~SF_GLOBAL;
- }
-
- /* Set the symbol data */
- S->Flags |= SF_EXPORT | SF_REFERENCED;
- if (ZP) {
- S->Flags |= SF_ZP;
- }
+ /* Return the scope */
+ return *T;
}
-void SymGlobal (const char* Name, int ZP)
-/* Mark the given symbol as a global symbol, that is, as a symbol that is
- * either imported or exported.
+SymTable* SymFindAnyScope (SymTable* Parent, const char* 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* S;
-
- /* Don't accept local symbols */
- if (IsLocal (Name)) {
- Error (ERR_ILLEGAL_LOCAL_USE);
- return;
- }
-
- /* Search for this symbol, create a new entry if needed */
- S = SymFind (SymTab, Name, SF_ALLOC_NEW);
-
- /* If the symbol is already marked as import or export, check the
- * size of the definition, then bail out. */
- if (S->Flags & SF_IMPORT || S->Flags & SF_EXPORT) {
- if ((ZP != 0) != ((S->Flags & SF_ZP) != 0)) {
- Error (ERR_SYM_REDECL_MISMATCH);
- }
- return;
- }
+ 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);
- /* Mark the symbol */
- S->Flags |= SF_GLOBAL;
- if (ZP) {
- S->Flags |= SF_ZP;
- }
+ 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 char* 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 */
- CHECK (Type >= CD_TYPE_MIN && Type <= CD_TYPE_MAX);
- CHECK (Prio >= CD_PRIO_MIN && Prio <= CD_PRIO_MAX);
-
- /* Don't accept local symbols */
- if (IsLocal (Name)) {
- Error (ERR_ILLEGAL_LOCAL_USE);
- return;
- }
-
- /* Do we have such a symbol? */
- S = SymFind (SymTab, Name, SF_ALLOC_NEW);
- if (S->Flags & SF_IMPORT) {
- /* The symbol is already marked as imported external symbol */
- Error (ERR_SYM_ALREADY_IMPORT, Name);
- 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;
+ }
}
- /* If the symbol is marked as global, silently remove the global flag */
- if (S->Flags & SF_GLOBAL) {
- S->Flags &= ~SF_GLOBAL;
- }
+ /* Search for the symbol if we have a table */
+ Cmp = SymSearchTree (Parent->Locals, Name, &S);
- /* Check if the symbol was not already defined as ZP symbol */
- if ((S->Flags & SF_ZP) != 0) {
- Error (ERR_SYM_REDECL_MISMATCH);
+ /* If we found an entry, return it */
+ if (Cmp == 0) {
+ return 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 (ERR_SYM_REDECL_MISMATCH);
- }
- }
- S->ConDesPrio[Type] = Prio;
-
- /* Set the symbol data */
- S->Flags |= SF_EXPORT | SF_REFERENCED;
-}
-
+ if (AllocNew) {
-
-int SymIsDef (const char* Name)
-/* Return true if the given symbol is already defined */
-{
- SymEntry* S = SymFindAny (SymTab, Name);
- return S != 0 && (S->Flags & SF_DEFINED) != 0;
-}
-
-
-
-int SymIsRef (const char* Name)
-/* Return true if the given symbol has been referenced */
-{
- SymEntry* S = SymFindAny (SymTab, Name);
- return S != 0 && (S->Flags & SF_REFERENCED) != 0;
-}
-
-
-
-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;
+ /* Otherwise create a new entry, insert and return it */
+ SymEntry* N = NewSymEntry (Name, SF_LOCAL);
+ if (S == 0) {
+ Parent->Locals = N;
+ } else if (Cmp < 0) {
+ S->Left = N;
+ } else {
+ S->Right = N;
+ }
+ return N;
}
- /* 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;
- }
+ /* 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 */
-{
- /* 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 (!IsLocal (S->Name) &&
- (S->Flags & (SF_ZP | SF_ABS | SF_DEFINED | SF_IMPORT)) == 0 &&
- S->SymTab->BackLink != 0) {
-
- /* Try to find a symbol with the same name in the enclosing scope */
- SymEntry* E = SymFindAny (S->SymTab->BackLink, S->Name);
-
- /* If we found one, use the ZP flag */
- if (E && (E->Flags & SF_ZP) != 0) {
- S->Flags |= SF_ZP;
- }
- }
-
- /* Check the ZP flag */
- return (S->Flags & SF_ZP) != 0;
-}
-
-
-
-int SymIsImport (SymEntry* S)
-/* Return true if the given symbol is marked as import */
-{
- /* Resolve trampoline entries */
- if (S->Flags & SF_TRAMPOLINE) {
- S = S->V.Sym;
- }
-
- /* Check the import flag */
- return (S->Flags & SF_IMPORT) != 0;
-}
-
-
-
-int SymHasExpr (SymEntry* S)
-/* Return true if the given symbol has an associated expression */
-{
- /* Resolve trampoline entries */
- if (S->Flags & SF_TRAMPOLINE) {
- S = S->V.Sym;
- }
-
- /* Check the expression */
- return ((S->Flags & SF_DEFINED) != 0 &&
- (S->Flags & SF_IMPORT) == 0 &&
- (S->Flags & SF_CONST) == 0);
-}
-
-
-
-void SymFinalize (SymEntry* S)
-/* Finalize a symbol expression if there is one */
-{
- /* Resolve trampoline entries */
- if (S->Flags & SF_TRAMPOLINE) {
- S = S->V.Sym;
- }
-
- /* Check if we have an expression */
- if (SymHasExpr (S)) {
- S->V.Expr = FinalizeExpr (S->V.Expr);
- }
-}
-
-
-
-void SymMarkUser (SymEntry* S)
-/* Set a user mark on the specified symbol */
-{
- /* Resolve trampoline entries */
- if (S->Flags & SF_TRAMPOLINE) {
- S = S->V.Sym;
- }
-
- /* Set the bit */
- S->Flags |= SF_USER;
-}
-
-
-
-void SymUnmarkUser (SymEntry* S)
-/* Remove a user mark from the specified symbol */
+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.
+ */
{
- /* Resolve trampoline entries */
- if (S->Flags & SF_TRAMPOLINE) {
- S = S->V.Sym;
- }
-
- /* Reset the bit */
- S->Flags &= ~SF_USER;
-}
+ SymEntry* S;
+ /* Global symbol: Get the hash value for the name */
+ unsigned Hash = HashStr (Name) % Scope->TableSlots;
+ /* Search for the entry */
+ int Cmp = SymSearchTree (Scope->Table[Hash], Name, &S);
-int SymHasUserMark (SymEntry* S)
-/* Return the state of the user mark for the specified symbol */
-{
- /* Resolve trampoline entries */
- if (S->Flags & SF_TRAMPOLINE) {
- S = S->V.Sym;
+ /* If we found an entry, return it */
+ if (Cmp == 0) {
+ return S;
}
- /* Check the bit */
- return (S->Flags & SF_USER) != 0;
-}
-
+ if (AllocNew) {
+ /* Otherwise create a new entry, insert and return it */
+ SymEntry* N = NewSymEntry (Name, SF_NONE);
+ 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;
-long GetSymVal (SymEntry* S)
-/* Return the symbol value */
-{
- /* Resolve trampoline entries */
- if (S->Flags & SF_TRAMPOLINE) {
- S = S->V.Sym;
}
- PRECONDITION ((S->Flags & SF_DEFINED) != 0 && (S->Flags & SF_CONST) != 0);
- return S->V.Val;
-}
-
-
-
-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 && (S->Flags & SF_CONST) == 0);
- return S->V.Expr;
+ /* We did not find the entry and AllocNew is false. */
+ return 0;
}
-const char* GetSymName (SymEntry* S)
-/* Return the name of the symbol */
+SymEntry* SymFindAny (SymTable* Scope, const char* 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;
- }
- return S->Name;
-}
+ SymEntry* Sym;
+ do {
+ /* Search in the current table */
+ Sym = SymFind (Scope, Name, SYM_FIND_EXISTING);
+ if (Sym) {
+ /* Found, return it */
+ break;
+ }
+ /* Not found, search in the parent scope, if we have one */
+ Scope = Scope->Parent;
+ } while (Sym == 0 && Scope != 0);
-unsigned GetSymIndex (SymEntry* S)
-/* Return the symbol index for the given symbol */
-{
- /* Resolve trampoline entries */
- if (S->Flags & SF_TRAMPOLINE) {
- S = S->V.Sym;
- }
- PRECONDITION (S != 0 && (S->Flags & SF_INDEXED));
- return S->Index;
+ /* Return the result */
+ return Sym;
}
-const FilePos* GetSymPos (SymEntry* S)
-/* Return the position of first occurence in the source for the given symbol */
+unsigned char GetCurrentSymTabType ()
+/* Return the type of the current symbol table */
{
- /* Resolve trampoline entries */
- if (S->Flags & SF_TRAMPOLINE) {
- S = S->V.Sym;
- }
- PRECONDITION (S != 0);
- return &S->Pos;
+ CHECK (CurrentScope != 0);
+ return CurrentScope->Type;
}
* 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->BackLink;
- while (Tab) {
- Sym = SymFindAny (Tab, 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->BackLink;
- }
- } else {
- /* No symbol found */
- break;
- }
- }
+ SymTable* Tab = GetSymParentScope (S);
+ while (Tab) {
+ Sym = SymFind (Tab, GetString (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, ERR_SYM_ALREADY_IMPORT, S->Name);
+ /* The symbol is already marked as import */
+ PError (&S->Pos, "Symbol `%s' is already an import",
+ GetString (Sym->Name));
}
- Sym->Flags |= S->Flags & (SF_EXPORT | SF_ZP);
- }
+ 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 */
+ PWarning (&S->Pos, 1, "Symbol `%s' 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 */
+ PWarning (&S->Pos, 1, "Symbol `%s' 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, ERR_EXPORT_UNDEFINED, S->Name);
+ PError (&S->Pos, "Exported symbol `%s' was never defined",
+ GetString (S->Name));
} 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, ERR_SYM_UNDEFINED, S->Name);
+ /* Error */
+ PError (&S->Pos, "Symbol `%s' is undefined", GetString (S->Name));
}
}
}
{
SymEntry* S;
- /* Check for open lexical levels */
- if (SymTab->BackLink != 0) {
- Error (ERR_OPEN_PROC);
+ /* Check for open scopes */
+ if (CurrentScope->Parent != 0) {
+ Error ("Local scope was not closed");
}
/* First pass: Walk through all symbols, checking for undefined's and
if (S->Flags & SF_GLOBAL) {
S->Flags &= ~SF_GLOBAL;
if (S->Flags & SF_DEFINED) {
- S->Flags |= SF_EXPORT;
+ S->Flags |= SF_EXPORT;
} else {
- S->Flags |= SF_IMPORT;
+ S->Flags |= SF_IMPORT;
}
}
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, WARN_SYM_NOT_REFERENCED, S->Name);
+ PWarning (&S->Pos, 2,
+ "Symbol `%s' is defined but never used",
+ GetString (S->Name));
}
+
+ /* Assign an index to all imports */
if (S->Flags & SF_IMPORT) {
- if ((S->Flags & SF_REFERENCED) == 0) {
- /* Imported symbol is not referenced */
- PWarning (&S->Pos, WARN_IMPORT_NOT_REFERENCED, 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 */
+ 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;
+ }
}
+
+ /* Assign an index to all exports */
if (S->Flags & SF_EXPORT) {
- /* Give the export an index, count exports */
- S->Index = ExportCount++;
- S->Flags |= SF_INDEXED;
+ /* Give the export an index, count exports */
+ S->Index = ExportCount++;
+ S->Flags |= SF_INDEXED;
}
+
+ /* 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;
+ ED_Done (&ED);
+ }
}
/* Next symbol */
SymEntry* S = SymList;
while (S) {
- /* Ignore trampoline symbols */
- if ((S->Flags & SF_TRAMPOLINE) != 0) {
- printf ("%-24s %s %s %s %s %s\n",
- S->Name,
- (S->Flags & SF_DEFINED)? "DEF" : "---",
- (S->Flags & SF_REFERENCED)? "REF" : "---",
- (S->Flags & SF_IMPORT)? "IMP" : "---",
- (S->Flags & SF_EXPORT)? "EXP" : "---",
- (S->Flags & SF_ZP)? "ZP" : "--");
+ /* Ignore unused symbols */
+ if ((S->Flags & SF_UNUSED) != 0) {
+ fprintf (F,
+ "%-24s %s %s %s %s %s\n",
+ GetString (S->Name),
+ (S->Flags & SF_DEFINED)? "DEF" : "---",
+ (S->Flags & SF_REFERENCED)? "REF" : "---",
+ (S->Flags & SF_IMPORT)? "IMP" : "---",
+ (S->Flags & SF_EXPORT)? "EXP" : "---",
+ AddrSizeToStr (S->AddrSize));
}
/* Next symbol */
S = S->List;
/* Write the import count to the list */
ObjWriteVar (ImportCount);
- /* Walk throught list and write all imports to the file */
+ /* Walk throught list and write all valid imports to the file. An import
+ * is considered valid, if it is either referenced, or the forced bit is
+ * set. Otherwise, the import is ignored (no need to link in something
+ * that isn't used).
+ */
S = SymList;
while (S) {
- if ((S->Flags & SF_IMPMASK) == SF_IMPVAL) {
- if (S->Flags & SF_ZP) {
- ObjWrite8 (IMP_ZP);
- } else {
- ObjWrite8 (IMP_ABS);
- }
- ObjWriteStr (S->Name);
+ if ((S->Flags & (SF_UNUSED | SF_IMPORT)) == SF_IMPORT &&
+ (S->Flags & (SF_REFERENCED | SF_FORCED)) != 0) {
+
+ ObjWrite8 (S->AddrSize);
+ ObjWriteVar (S->Name);
ObjWritePos (&S->Pos);
}
S = S->List;
/* 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);
+ if ((S->Flags & (SF_UNUSED | SF_EXPORT)) == SF_EXPORT) {
- /* Check if the symbol is const */
- ExprMask = (SymIsConst (S))? EXP_CONST : EXP_EXPR;
+ long ConstVal;
- /* Add zeropage/abs bits */
- ExprMask |= (S->Flags & SF_ZP)? EXP_ZP : EXP_ABS;
+ /* Get the expression bits */
+ unsigned char ExprMask = SymIsConst (S, &ConstVal)? EXP_CONST : EXP_EXPR;
+ ExprMask |= (S->Flags & SF_LABEL)? EXP_LABEL : EXP_EQUATE;
/* Count the number of ConDes types */
for (Type = 0; Type < CD_TYPE_COUNT; ++Type) {
}
}
- /* Write the type */
+ /* Write the type and the export size */
ObjWrite8 (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));
+ ObjWrite8 (CD_BUILD (Type, Prio));
}
}
}
/* Write the name */
- ObjWriteStr (S->Name);
+ ObjWriteVar (S->Name);
/* Write the value */
if ((ExprMask & EXP_MASK_VAL) == EXP_CONST) {
/* Constant value */
- ObjWrite32 (S->V.Val);
+ ObjWrite32 (ConstVal);
} else {
/* Expression involved */
- WriteExpr (S->V.Expr);
+ WriteExpr (S->Expr);
}
/* Write the source file position */
/* 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 and count the symbols */
+ Count = 0;
+ S = SymList;
+ while (S) {
+ if ((S->Flags & SF_DBGINFOMASK) == SF_DBGINFOVAL) {
+ ++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;
-
- /* Finalize an associated expression if we have one */
- SymFinalize (S);
+ S = SymList;
+ while (S) {
+ if ((S->Flags & SF_DBGINFOMASK) == SF_DBGINFOVAL) {
- /* Check if the symbol is const */
- ExprMask = (SymIsConst (S))? EXP_CONST : EXP_EXPR;
+ long ConstVal;
- /* Add zeropage/abs bits */
- ExprMask |= (S->Flags & SF_ZP)? EXP_ZP : EXP_ABS;
+ /* Get the expression bits */
+ unsigned char ExprMask = (SymIsConst (S, &ConstVal))? EXP_CONST : EXP_EXPR;
+ ExprMask |= (S->Flags & SF_LABEL)? EXP_LABEL : EXP_EQUATE;
/* Write the type */
ObjWrite8 (ExprMask);
+ /* Write the address size */
+ ObjWrite8 (S->AddrSize);
+
/* Write the name */
- ObjWriteStr (S->Name);
+ ObjWriteVar (S->Name);
/* Write the value */
if ((ExprMask & EXP_MASK_VAL) == EXP_CONST) {
/* Constant value */
- ObjWrite32 (S->V.Val);
+ ObjWrite32 (ConstVal);
} else {
/* Expression involved */
- WriteExpr (S->V.Expr);
+ WriteExpr (S->Expr);
}
/* Write the source file position */
+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 ();
+
+ /* For now ...*/
+ ObjWriteVar (0);
+
+ /* Done writing the scopes */
+ ObjEndScopes ();
+}
+
+
+