]> git.sur5r.net Git - cc65/blobdiff - src/ca65/symtab.c
Made 'wrapped call' code build with VS 2015.
[cc65] / src / ca65 / symtab.c
index 76055f92715df2b02148bc568311290eca3735a1..35d5a8066a220d514c29e4a7baca7eae525efb68 100644 (file)
@@ -1,15 +1,15 @@
 /*****************************************************************************/
 /*                                                                           */
-/*                                symtab.c                                  */
+/*                                 symtab.c                                  */
 /*                                                                           */
-/*                Symbol table for the ca65 macroassembler                  */
+/*                 Symbol table for the ca65 macroassembler                  */
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 1998-2000 Ullrich von Bassewitz                                       */
-/*               Wacholderweg 14                                             */
-/*               D-70597 Stuttgart                                           */
-/* EMail:        uz@musoftware.de                                            */
+/* (C) 1998-2014, Ullrich von Bassewitz                                      */
+/*                Roemerstrasse 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 "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                                    */
 /*****************************************************************************/
 
 
 
-/* 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 */
-#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_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
-
+/* Combined symbol entry flags used within this module */
+#define SF_UNDEFMASK    (SF_REFERENCED | SF_DEFINED | SF_IMPORT)
+#define SF_UNDEFVAL     (SF_REFERENCED)
 
+/* Symbol tables */
+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 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 */
 
 
 
 /*****************************************************************************/
-/*                                Internally used functions                         */
+/*                         Internally used functions                         */
 /*****************************************************************************/
 
 
 
-static int IsLocal (const char* Name)
-/* Return true if Name is the name of a local symbol */
+static int IsDbgSym (const SymEntry* S)
+/* Return true if this is a debug symbol */
 {
-    return (*Name == LocalStart);
+    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 SymEntry* NewSymEntry (const char* Name)
-/* Allocate a symbol table entry, initialize and return it */
+static unsigned ScopeTableSize (unsigned Level)
+/* Get the size of a table for the given lexical level */
 {
-    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 StrBuf* 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->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         = SCOPE_UNDEF;
+    S->Level        = Level;
+    S->TableSlots   = Slots;
     S->TableEntries = 0;
-    S->BackLink     = 0;
-    while (Size--) {
-       S->Table [Size] = 0;
+    S->Parent       = Parent;
+    S->Name         = GetStrBufId (Name);
+    while (Slots--) {
+        S->Table[Slots] = 0;
     }
 
-    /* Return the prepared struct */
-    return S;
-}
-
-
-
-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;
-               }
+    /* 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;
+        if (T == 0) {
+            /* First entry */
+            Parent->Childs = S;
+        } else {
+            while (1) {
+                /* Choose next entry */
+                int Cmp = SB_Compare (Name, GetStrBuf (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: `%m%p'", Name);
+                }
+            }
+        }
     }
 
-    /* Return the search result */
-    *E = T;
-    return Cmp;
+    /* Return the prepared struct */
+    return S;
 }
 
 
 
 /*****************************************************************************/
-/*                                          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 StrBuf* ScopeName, unsigned char Type,
+                    unsigned char AddrSize, SymEntry* ScopeLabel)
 /* 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 ();
     }
-}
-
 
+    /* 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) {
 
-void SymLeaveLevel (void)
-/* Leave the current lexical level */
-{
-    SymTab = SymTab->BackLink;
-}
-
+        /* 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 `%m%p'", ScopeName);
+        }
 
-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;
-    }
-
-    /* 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, address size and owner symbol */
+    CurrentScope->Flags    |= ST_DEFINED;
+    CurrentScope->AddrSize = AddrSize;
+    CurrentScope->Type     = Type;
+    CurrentScope->Label    = ScopeLabel;
 
-    /* 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 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);
     }
 }
 
 
 
-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;
+    /* 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);
     }
 
-    /* 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;
+    /* 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);
+        }
     }
 
-    /* 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;
-    }
+    /* Mark the scope as closed */
+    CurrentScope->Flags |= ST_CLOSED;
 
-    /* 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 StrBuf* Name, SymFindAction Action)
+/* 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 = SB_Compare (Name, GetStrBuf ((*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 && (Action & SYM_ALLOC_NEW) != 0) {
+        *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 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* 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 StrBuf* Name, SymFindAction Action)
+/* Find a cheap local symbol. If Action contains SYM_ALLOC_NEW and the entry is
+** not found, create a new one. Return the entry found, or the new entry
+** created, or - in case Action is SYM_FIND_EXISTING - 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;
-    }
-
-    /* If the symbol is marked as global, silently remove the global flag */
-    if (S->Flags & SF_GLOBAL) {
-        S->Flags &= ~SF_GLOBAL;
+    /* Local symbol, get the table */
+    if (!Parent) {
+        /* No last global, so there's no local table */
+        Error ("No preceeding global symbol");
+        if (Action & SYM_ALLOC_NEW) {
+            return NewSymEntry (Name, SF_LOCAL);
+        } else {
+            return 0;
+        }
     }
 
-    /* Check if the symbol was not already defined as ZP symbol */
-    if ((S->Flags & SF_ZP) != 0) {
-       Error (ERR_SYM_REDECL_MISMATCH);
-    }
+    /* Search for the symbol if we have a table */
+    Cmp = SymSearchTree (Parent->Locals, Name, &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);
-       }
+    /* If we found an entry, return it */
+    if (Cmp == 0) {
+        return S;
     }
-    S->ConDesPrio[Type] = Prio;
-
-    /* Set the symbol data */
-    S->Flags |= SF_EXPORT | SF_REFERENCED;
-}
-
-
-
-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 | SF_IMPORT)) != 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;
-}
-
 
+    if (Action & SYM_ALLOC_NEW) {
 
-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);
+        N->Sym.Entry = Parent;
+        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 */
+SymEntry* SymFind (SymTable* Scope, const StrBuf* Name, SymFindAction Action)
+/* Find a new symbol table entry in the given table. If Action contains
+** SYM_ALLOC_NEW and the entry is not found, create a new one. Return the
+** entry found, or the new entry created, or - in case Action is
+** SYM_FIND_EXISTING - return 0.
+*/
 {
-    /* 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 */
-{
-    /* Resolve trampoline entries */
-    if (S->Flags & SF_TRAMPOLINE) {
-       S = S->V.Sym;
-    }
-
-    /* Reset the bit */
-    S->Flags &= ~SF_USER;
-}
-
-
-
-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;
-    }
-
-    /* Check the bit */
-    return (S->Flags & SF_USER) != 0;
-}
+    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);
 
-long GetSymVal (SymEntry* S)
-/* Return the symbol value */
-{
-    /* Resolve trampoline entries */
-    if (S->Flags & SF_TRAMPOLINE) {
-       S = S->V.Sym;
+    /* If we found an entry, return it */
+    if (Cmp == 0) {
+        if ((Action & SYM_CHECK_ONLY) == 0 && SymTabIsClosed (Scope)) {
+            S->Flags |= SF_FIXED;
+        }
+        return S;
     }
 
-    PRECONDITION ((S->Flags & SF_DEFINED) != 0 && (S->Flags & SF_CONST) != 0);
-    return S->V.Val;
-}
-
+    if (Action & SYM_ALLOC_NEW) {
 
+        /* Otherwise create a new entry, insert and return it. If the scope is
+        ** already closed, mark the symbol as fixed so it won't be resolved
+        ** by a symbol in the enclosing scopes later.
+        */
+        SymEntry* N = NewSymEntry (Name, SF_NONE);
+        if (SymTabIsClosed (Scope)) {
+            N->Flags |= SF_FIXED;
+        }
+        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;
 
-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 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;
-    }
-    return S->Name;
-}
+    /* Generate the name hash */
+    unsigned Hash = HashBuf (Name);
 
+    /* Search for the symbol */
+    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.
+        */
+        if (SymSearchTree (Scope->Table[Hash % Scope->TableSlots], Name, &Sym) == 0) {
+            if (Sym->Flags & SF_UNUSED) {
+                Sym = 0;
+            } else {
+                /* Found, return it */
+                break;
+            }
+        } else {
+            Sym = 0;
+        }
 
+        /* Not found, search in the parent scope, if we have one */
+        Scope = Scope->Parent;
 
-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;
-}
-
-
+    } while (Sym == 0 && Scope != 0);
 
-const FilePos* GetSymPos (SymEntry* S)
-/* Return the position of first occurence in the source for the given symbol */
-{
-    /* Resolve trampoline entries */
-    if (S->Flags & SF_TRAMPOLINE) {
-       S = S->V.Sym;
-    }
-    PRECONDITION (S != 0);
-    return &S->Pos;
+    /* Return the result */
+    return Sym;
 }
 
 
@@ -862,73 +467,97 @@ static void SymCheckUndefined (SymEntry* S)
 /* Handle an undefined symbol */
 {
     /* Undefined symbol. It may be...
-     *
-     *   - An undefined symbol in a nested lexical level. In this
-     *     case, search for the symbol in the higher levels and
-     *            make the entry a trampoline entry if we find one.
-     *
-     *   - If the symbol is not found, it is a real undefined symbol.
-     *     If the AutoImport flag is set, make it an import. If the
-     *     AutoImport flag is not set, it's an error.
-     */
+    **
+    **   - An undefined symbol in a nested lexical level. If the symbol is not
+    **     fixed to this level, search for the symbol in the higher levels and
+    **     make the entry a trampoline entry if we find one.
+    **
+    **   - If the symbol is not found, it is a real undefined symbol. If the
+    **     AutoImport flag is set, make it an import. If the 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;
-           }
-       }
+    if ((S->Flags & SF_FIXED) == 0) {
+        SymTable* Tab = GetSymParentScope (S);
+        while (Tab) {
+            Sym = SymFind (Tab, GetStrBuf (S->Name), SYM_FIND_EXISTING | SYM_CHECK_ONLY);
+            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) {
-           if (Sym->Flags & SF_IMPORT) {
-               /* The symbol is already marked as imported external symbol */
-               PError (&S->Pos, ERR_SYM_ALREADY_IMPORT, S->Name);
-           }
-           Sym->Flags |= S->Flags & (SF_EXPORT | SF_ZP);
-       }
-
-       /* Transfer the referenced flag */
-       Sym->Flags |= (S->Flags & SF_REFERENCED);
+
+        /* 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 import */
+                LIError (&S->RefLines,
+                         "Symbol `%s' is already an import",
+                         GetString (Sym->Name));
+            }
+            if ((Sym->Flags & SF_EXPORT) == 0) {
+                /* 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 (&Sym->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 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);
-       } else {
-           if (AutoImport) {
-               /* Mark as import, will be indexed later */
-               S->Flags |= SF_IMPORT;
-           } else {
-               /* Error */
-               PError (&S->Pos, ERR_SYM_UNDEFINED, S->Name);
-           }
-       }
+        /* The symbol is definitely undefined */
+        if (S->Flags & SF_EXPORT) {
+            /* We will not auto-import an export */
+            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;
+                /* Use the address size for code */
+                S->AddrSize = CodeAddrSize;
+                /* Mark point of import */
+                GetFullLineInfo (&S->DefLines);
+            } else {
+                /* Error */
+                LIError (&S->RefLines,
+                         "Symbol `%m%p' is undefined",
+                         GetSymName (S));
+            }
+        }
     }
 }
 
@@ -939,69 +568,122 @@ void SymCheck (void)
 {
     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
-     * changing them to trampoline symbols or make them imports.
-     */
+    ** changing them to trampoline symbols or make them imports.
+    */
     S = SymList;
     while (S) {
-       /* If the symbol is marked as global, mark it as export, if it is
-        * 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;
-           }
-       }
-
-       /* Handle undefined symbols */
-               if ((S->Flags & SF_UNDEFMASK) == SF_UNDEFVAL) {
-           /* This is an undefined symbol. Handle it. */
-           SymCheckUndefined (S);
-       }
-
-       /* Next symbol */
-       S = S->List;
+        /* If the symbol is marked as global, mark it as export, if it is
+        ** already defined, otherwise mark it as import.
+        */
+        if (S->Flags & SF_GLOBAL) {
+            if (S->Flags & SF_DEFINED) {
+                SymExportFromGlobal (S);
+            } else {
+                SymImportFromGlobal (S);
+            }
+        }
+
+        /* Handle undefined symbols */
+        if ((S->Flags & SF_UNDEFMASK) == SF_UNDEFVAL) {
+            /* This is an undefined symbol. Handle it. */
+            SymCheckUndefined (S);
+        }
+
+        /* Next symbol */
+        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 &&
-           (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, WARN_SYM_NOT_REFERENCED, S->Name);
-           }
-           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_EXPORT) {
-               /* Give the export an index, count exports */
-               S->Index = ExportCount++;
-               S->Flags |= SF_INDEXED;
-           }
-       }
-
-       /* Next symbol */
-       S = S->List;
+        if ((S->Flags & SF_UNUSED) == 0 &&
+            (S->Flags & SF_UNDEFMASK) != SF_UNDEFVAL) {
+
+            /* 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 */
+                    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) {
+                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 */
+        S = S->List;
     }
 }
 
@@ -1013,18 +695,19 @@ void SymDump (FILE* F)
     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" : "--");
-       }
-       /* Next symbol */
-       S = S->List;
+        /* Ignore unused symbols */
+        if ((S->Flags & SF_UNUSED) == 0) {
+            fprintf (F,
+                     "%-24s %s %s %s %s %s\n",
+                     SB_GetConstBuf (GetSymName (S)),
+                     (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;
     }
 }
 
@@ -1041,19 +724,22 @@ void WriteImports (void)
     /* 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);
-           ObjWritePos (&S->Pos);
-       }
-       S = S->List;
+        if ((S->Flags & (SF_UNUSED | SF_IMPORT)) == SF_IMPORT &&
+            (S->Flags & (SF_REFERENCED | SF_FORCED)) != 0) {
+
+            ObjWrite8 (S->AddrSize);
+            ObjWriteVar (S->Name);
+            WriteLineInfo (&S->DefLines);
+            WriteLineInfo (&S->RefLines);
+        }
+        S = S->List;
     }
 
     /* Done writing imports */
@@ -1077,54 +763,64 @@ 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);
-
-           /* Check if the symbol is const */
-           ExprMask = (SymIsConst (S))? EXP_CONST : EXP_EXPR;
-
-           /* Add zeropage/abs bits */
-           ExprMask |= (S->Flags & SF_ZP)? EXP_ZP : EXP_ABS;
-
-           /* 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);
-               }
-           }
-
-           /* Write the type */
-           ObjWrite8 (ExprMask);
-
-           /* 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));
-                   }
-               }
-           }
-
-           /* Write the name */
-                   ObjWriteStr (S->Name);
-
-           /* Write the value */
-           if ((ExprMask & EXP_MASK_VAL) == EXP_CONST) {
-               /* Constant value */
-               ObjWrite32 (S->V.Val);
-           } else {
-               /* Expression involved */
-               WriteExpr (S->V.Expr);
+        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) {
+                    SYM_INC_CONDES_COUNT (SymFlags);
+                }
+            }
+
+            /* Write the type and the export size */
+            ObjWriteVar (SymFlags);
+            ObjWrite8 (S->ExportSize);
+
+            /* Write any ConDes declarations */
+            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 (SYM_IS_CONST (SymFlags)) {
+                /* Constant value */
+                ObjWrite32 (ConstVal);
+            } else {
+                /* Expression involved */
+                WriteExpr (S->Expr);
             }
 
-           /* Write the source file position */
-           ObjWritePos (&S->Pos);
-       }
-       S = S->List;
+            /* 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;
     }
 
     /* Done writing exports */
@@ -1145,65 +841,183 @@ 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;
-       }
-
-       /* 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);
-
-               /* Check if the symbol is const */
-               ExprMask = (SymIsConst (S))? EXP_CONST : EXP_EXPR;
-
-               /* Add zeropage/abs bits */
-               ExprMask |= (S->Flags & SF_ZP)? EXP_ZP : EXP_ABS;
-
-               /* Write the type */
-               ObjWrite8 (ExprMask);
-
-               /* Write the name */
-               ObjWriteStr (S->Name);
-
-               /* Write the value */
-               if ((ExprMask & EXP_MASK_VAL) == EXP_CONST) {
-                   /* Constant value */
-                   ObjWrite32 (S->V.Val);
-               } else {
-                   /* Expression involved */
-                   WriteExpr (S->V.Expr);
-               }
-
-               /* Write the source file position */
-               ObjWritePos (&S->Pos);
-           }
-           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 */
+        ObjWriteVar (Count);
+
+        /* 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;
+                }
+
+                /* Write the type */
+                ObjWriteVar (SymFlags);
+
+                /* Write the address size */
+                ObjWrite8 (S->AddrSize);
+
+                /* 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 (SYM_IS_CONST (SymFlags)) {
+                    /* Constant value */
+                    ObjWrite32 (ConstVal);
+                } else {
+                    /* Expression involved */
+                    WriteExpr (S->Expr);
+                }
+
+                /* 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;
+        }
 
     } else {
 
-       /* No debug symbols */
-       ObjWriteVar (0);
+        /* No debug symbols */
+        ObjWriteVar (0);
 
     }
 
+    /* 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 ();
+}