]> git.sur5r.net Git - cc65/blobdiff - src/ca65/symtab.c
atari5200: name conio constructor 'initconio'
[cc65] / src / ca65 / symtab.c
index 356f7386d45ad3fff7ecb252230905d548dad223..afe7b3ad6b621b89c291bec0ed562e25cc38cf7f 100644 (file)
@@ -1,12 +1,12 @@
 /*****************************************************************************/
 /*                                                                           */
-/*                                symtab.c                                  */
+/*                                 symtab.c                                  */
 /*                                                                           */
-/*                Symbol table for the ca65 macroassembler                  */
+/*                 Symbol table for the ca65 macroassembler                  */
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 1998-2011, Ullrich von Bassewitz                                      */
+/* (C) 1998-2014, Ullrich von Bassewitz                                      */
 /*                Roemerstrasse 52                                           */
 /*                D-70794 Filderstadt                                        */
 /* EMail:         uz@cc65.org                                                */
 /* common */
 #include "addrsize.h"
 #include "check.h"
-#include "hashstr.h"
+#include "hashfunc.h"
 #include "mmodel.h"
+#include "scopedefs.h"
 #include "symdefs.h"
 #include "xmalloc.h"
 
 /* ca65 */
-#include "global.h"
+#include "dbginfo.h"
 #include "error.h"
 #include "expr.h"
+#include "global.h"
 #include "objfile.h"
 #include "scanner.h"
 #include "segment.h"
 #include "sizeof.h"
+#include "span.h"
 #include "spool.h"
 #include "studyexpr.h"
 #include "symtab.h"
 
 
 /*****************************************************************************/
-/*                                  Data                                    */
+/*                                   Data                                    */
 /*****************************************************************************/
 
 
 
 /* Combined symbol entry flags used within this module */
-#define SF_UNDEFMASK   (SF_REFERENCED | SF_DEFINED | SF_IMPORT)
-#define SF_UNDEFVAL    (SF_REFERENCED)
-#define SF_DBGINFOMASK         (SF_UNUSED | SF_DEFINED | SF_IMPORT)
-#define SF_DBGINFOVAL  (SF_DEFINED)
+#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 */
+SymTable*           CurrentScope = 0;   /* Pointer to current symbol table */
+SymTable*           RootScope    = 0;   /* Root symbol table */
 static SymTable*    LastScope    = 0;   /* Pointer to last scope in list */
+static unsigned     ScopeCount   = 0;   /* Number of scopes */
 
 /* Symbol table variables */
 static unsigned     ImportCount = 0;    /* Counter for import symbols */
@@ -81,11 +83,25 @@ static unsigned     ExportCount = 0;    /* Counter for export symbols */
 
 
 /*****************************************************************************/
-/*                                Internally used functions                         */
+/*                         Internally used functions                         */
 /*****************************************************************************/
 
 
 
+static int IsDbgSym (const SymEntry* S)
+/* Return true if this is a debug symbol */
+{
+    if ((S->Flags & (SF_DEFINED | SF_UNUSED)) == SF_DEFINED) {
+        /* Defined symbols are debug symbols if they aren't sizes */
+        return !IsSizeOfSymbol (S);
+    } else {
+        /* Others are debug symbols if they're referenced imports */
+        return ((S->Flags & SF_REFIMP) == SF_REFIMP);
+    }
+}
+
+
+
 static unsigned ScopeTableSize (unsigned Level)
 /* Get the size of a table for the given lexical level */
 {
@@ -109,32 +125,30 @@ static SymTable* NewSymTable (SymTable* Parent, const StrBuf* Name)
     SymTable* S = xmalloc (sizeof (SymTable) + (Slots-1) * sizeof (SymEntry*));
 
     /* Set variables and clear hash table entries */
+    S->Next         = 0;
     S->Left         = 0;
     S->Right        = 0;
     S->Childs       = 0;
-    S->OwnerSym     = 0;
-    S->SegRanges    = AUTO_COLLECTION_INITIALIZER;
+    S->Label        = 0;
+    S->Spans        = AUTO_COLLECTION_INITIALIZER;
+    S->Id           = ScopeCount++;
     S->Flags        = ST_NONE;
     S->AddrSize     = ADDR_SIZE_DEFAULT;
-    S->Type         = ST_UNDEF;
+    S->Type         = SCOPE_UNDEF;
     S->Level        = Level;
     S->TableSlots   = Slots;
     S->TableEntries = 0;
     S->Parent       = Parent;
     S->Name         = GetStrBufId (Name);
     while (Slots--) {
-               S->Table[Slots] = 0;
+        S->Table[Slots] = 0;
     }
 
-    /* Insert the symbol table into the list of all symbol tables and maintain
-     * a unqiue id for each scope.
-     */
-    S->Next = LastScope;
+    /* Insert the symbol table into the list of all symbol tables */
     if (RootScope == 0) {
-        S->Id = 0;
         RootScope = S;
     } else {
-        S->Id = LastScope->Id + 1;
+        LastScope->Next = S;
     }
     LastScope = S;
 
@@ -161,10 +175,10 @@ static SymTable* NewSymTable (SymTable* Parent, const StrBuf* Name)
                     } else {
                         T->Right = S;
                         break;
-                    }  
+                    }
                 } else {
                     /* Duplicate scope name */
-                    Internal ("Duplicate scope name: `%m%p'", Name);
+                    Internal ("Duplicate scope name: '%m%p'", Name);
                 }
             }
         }
@@ -177,13 +191,13 @@ static SymTable* NewSymTable (SymTable* Parent, const StrBuf* Name)
 
 
 /*****************************************************************************/
-/*                                          Code                                    */
+/*                                   Code                                    */
 /*****************************************************************************/
 
 
 
 void SymEnterLevel (const StrBuf* ScopeName, unsigned char Type,
-                    unsigned char AddrSize, SymEntry* OwnerSym)
+                    unsigned char AddrSize, SymEntry* ScopeLabel)
 /* Enter a new lexical level */
 {
     /* Map a default address size to something real */
@@ -193,8 +207,8 @@ void SymEnterLevel (const StrBuf* ScopeName, unsigned char Type,
     }
 
     /* 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.
-     */
+    ** 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 */
@@ -202,7 +216,7 @@ void SymEnterLevel (const StrBuf* ScopeName, unsigned char Type,
 
         /* Check if the scope has been defined before */
         if (CurrentScope->Flags & ST_DEFINED) {
-            Error ("Duplicate scope `%m%p'", ScopeName);
+            Error ("Duplicate scope '%m%p'", ScopeName);
         }
 
     } else {
@@ -213,16 +227,16 @@ void SymEnterLevel (const StrBuf* ScopeName, unsigned char Type,
     CurrentScope->Flags    |= ST_DEFINED;
     CurrentScope->AddrSize = AddrSize;
     CurrentScope->Type     = Type;
-    CurrentScope->OwnerSym = OwnerSym;
-
-    /* If this is a scope that allows to emit data into segments, add segment
-     * ranges for all currently existing segments. Doing this for just a few
-     * scope types is not really necessary but an optimization, because it
-     * does not allocate memory for useless data (unhandled types here don't
-     * occupy space in any segment).
-     */
-    if (CurrentScope->Type <= ST_SCOPE_HAS_DATA) {
-        AddSegRanges (&CurrentScope->SegRanges);
+    CurrentScope->Label    = ScopeLabel;
+
+    /* If this is a scope that allows to emit data into segments, add spans
+    ** for all currently existing segments. Doing this for just a few scope
+    ** types is not really necessary but an optimization, because it does not
+    ** allocate memory for useless data (unhandled types here don't occupy
+    ** space in any segment).
+    */
+    if (CurrentScope->Type <= SCOPE_HAS_DATA) {
+        OpenSpanList (&CurrentScope->Spans);
     }
 }
 
@@ -231,32 +245,37 @@ void SymEnterLevel (const StrBuf* ScopeName, unsigned char Type,
 void SymLeaveLevel (void)
 /* Leave the current lexical level */
 {
-    /* Close the segment ranges. We don't care about the scope type here,
-     * since types without segment ranges will just have an empty list.
-     */
-    CloseSegRanges (&CurrentScope->SegRanges);
-
-    /* If we have segment ranges, the first one is the segment that was
-     * active, when the scope was opened. Set the size of the scope to the
-     * number of data bytes emitted into this segment. If we have an owner
-     * symbol set the size of this symbol, too.
-     */
-    if (CollCount (&CurrentScope->SegRanges) > 0) {
-        const SegRange* R = CollAtUnchecked (&CurrentScope->SegRanges, 0);
-        unsigned long Size = GetSegRangeSize (R);
+    /* If this is a scope that allows to emit data into segments, close the
+    ** open the spans.
+    */
+    if (CurrentScope->Type <= SCOPE_HAS_DATA) {
+        CloseSpanList (&CurrentScope->Spans);
+    }
+
+    /* If we have spans, the first one is the segment that was active, when the
+    ** scope was opened. Set the size of the scope to the number of data bytes
+    ** emitted into this segment. If we have an owner symbol set the size of
+    ** this symbol, too.
+    */
+    if (CollCount (&CurrentScope->Spans) > 0) {
+        const Span* S = CollAtUnchecked (&CurrentScope->Spans, 0);
+        unsigned long Size = GetSpanSize (S);
         DefSizeOfScope (CurrentScope, Size);
-        if (CurrentScope->OwnerSym) {              
-            DefSizeOfSymbol (CurrentScope->OwnerSym, Size);
+        if (CurrentScope->Label) {
+            DefSizeOfSymbol (CurrentScope->Label, Size);
         }
     }
 
+    /* Mark the scope as closed */
+    CurrentScope->Flags |= ST_CLOSED;
+
     /* Leave the scope */
     CurrentScope = CurrentScope->Parent;
 }
 
 
 
-SymTable* SymFindScope (SymTable* Parent, const StrBuf* Name, int AllocNew)
+SymTable* SymFindScope (SymTable* Parent, const StrBuf* Name, SymFindAction Action)
 /* Find a scope in the given enclosing scope */
 {
     SymTable** T = &Parent->Childs;
@@ -273,7 +292,7 @@ SymTable* SymFindScope (SymTable* Parent, const StrBuf* Name, int AllocNew)
     }
 
     /* Create a new scope if requested and we didn't find one */
-    if (*T == 0 && AllocNew) {
+    if (*T == 0 && (Action & SYM_ALLOC_NEW) != 0) {
         *T = NewSymTable (Parent, Name);
     }
 
@@ -285,18 +304,18 @@ SymTable* SymFindScope (SymTable* Parent, const StrBuf* Name, int AllocNew)
 
 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.
- */
+** never create a new symbol, since this can only be done in one specific
+** scope.
+*/
 {
     SymTable* Scope;
     do {
-       /* Search in the current table */
-       Scope = SymFindScope (Parent, Name, SYM_FIND_EXISTING);
-               if (Scope == 0) {
-           /* Not found, search in the parent scope, if we have one */
-           Parent = Parent->Parent;
-       }
+        /* Search in the current table */
+        Scope = SymFindScope (Parent, Name, SYM_FIND_EXISTING);
+        if (Scope == 0) {
+            /* Not found, search in the parent scope, if we have one */
+            Parent = Parent->Parent;
+        }
     } while (Scope == 0 && Parent != 0);
 
     return Scope;
@@ -304,11 +323,12 @@ SymTable* SymFindAnyScope (SymTable* Parent, const StrBuf* Name)
 
 
 
-SymEntry* SymFindLocal (SymEntry* Parent, const StrBuf* Name, int AllocNew)
-/* Find a cheap local symbol. If AllocNew is given and the entry is not
- * found, create a new one. Return the entry found, or the new entry created,
- * or - in case AllocNew is zero - return 0.
- */
+SymEntry* 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;
@@ -317,7 +337,7 @@ SymEntry* SymFindLocal (SymEntry* Parent, const StrBuf* Name, int AllocNew)
     if (!Parent) {
         /* No last global, so there's no local table */
         Error ("No preceeding global symbol");
-        if (AllocNew) {
+        if (Action & SYM_ALLOC_NEW) {
             return NewSymEntry (Name, SF_LOCAL);
         } else {
             return 0;
@@ -332,7 +352,7 @@ SymEntry* SymFindLocal (SymEntry* Parent, const StrBuf* Name, int AllocNew)
         return S;
     }
 
-    if (AllocNew) {
+    if (Action & SYM_ALLOC_NEW) {
 
         /* Otherwise create a new entry, insert and return it */
         SymEntry* N = NewSymEntry (Name, SF_LOCAL);
@@ -353,11 +373,12 @@ SymEntry* SymFindLocal (SymEntry* Parent, const StrBuf* Name, int AllocNew)
 
 
 
-SymEntry* SymFind (SymTable* Scope, const StrBuf* Name, int AllocNew)
-/* Find a new symbol table entry in the given table. If AllocNew is given and
- * the entry is not found, create a new one. Return the entry found, or the
- * new entry created, or - in case AllocNew is zero - return 0.
- */
+SymEntry* 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.
+*/
 {
     SymEntry* S;
 
@@ -369,13 +390,22 @@ SymEntry* SymFind (SymTable* Scope, const StrBuf* Name, int AllocNew)
 
     /* If we found an entry, return it */
     if (Cmp == 0) {
+        if ((Action & SYM_CHECK_ONLY) == 0 && SymTabIsClosed (Scope)) {
+            S->Flags |= SF_FIXED;
+        }
         return S;
     }
 
-    if (AllocNew) {
+    if (Action & SYM_ALLOC_NEW) {
 
-        /* Otherwise create a new entry, insert and return it */
+        /* 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;
@@ -397,21 +427,33 @@ SymEntry* SymFind (SymTable* Scope, const StrBuf* Name, int AllocNew)
 
 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.
- */
+** never create a new symbol, since this can only be done in one specific
+** scope.
+*/
 {
+    /* Generate the name hash */
+    unsigned Hash = HashBuf (Name);
+
+    /* Search for the symbol */
     SymEntry* Sym;
     do {
-       /* Search in the current table */
-       Sym = SymFind (Scope, Name, SYM_FIND_EXISTING);
-               if (Sym) {
-           /* Found, return it */
-           break;
-       }
+        /* 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;
+        Scope = Scope->Parent;
 
     } while (Sym == 0 && Scope != 0);
 
@@ -421,66 +463,49 @@ SymEntry* SymFindAny (SymTable* Scope, const StrBuf* Name)
 
 
 
-unsigned char GetCurrentSymTabType ()
-/* Return the type of the current symbol table */
-{
-    CHECK (CurrentScope != 0);
-    return CurrentScope->Type;
-}
-
-
-
 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;
-    SymTable* Tab = GetSymParentScope (S);
-    while (Tab) {
-        Sym = SymFind (Tab, GetStrBuf (S->Name), SYM_FIND_EXISTING);
-        if (Sym && (Sym->Flags & (SF_DEFINED | SF_IMPORT)) != 0) {
-            /* We've found a symbol in a higher level that is
-             * either defined in the source, or an import.
-             */
-             break;
+    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;
         }
-        /* No matching symbol found in this level. Look further */
-        Tab = Tab->Parent;
     }
 
     if (Sym) {
 
         /* 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.
-         */
+        ** 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->LineInfos,
-                         "Symbol `%s' is already an import",
+            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) {
-                /* The symbol is already marked as an export. */
-                if (Sym->AddrSize > S->ExportSize) {
-                    /* We're exporting a symbol smaller than it actually is */
-                    LIWarning (&S->LineInfos, 1,
-                               "Symbol `%m%p' is %s but exported %s",
-                              GetSymName (Sym),
-                              AddrSizeToStr (Sym->AddrSize),
-                              AddrSizeToStr (S->ExportSize));
-                }
-            } else {
+            }
+            if ((Sym->Flags & SF_EXPORT) == 0) {
                 /* Mark the symbol as an export */
                 Sym->Flags |= SF_EXPORT;
                 Sym->ExportSize = S->ExportSize;
@@ -490,15 +515,20 @@ static void SymCheckUndefined (SymEntry* S)
                 }
                 if (Sym->AddrSize > Sym->ExportSize) {
                     /* We're exporting a symbol smaller than it actually is */
-                    LIWarning (&S->LineInfos, 1,
-                               "Symbol `%m%p' is %s but exported %s",
+                    LIWarning (&Sym->DefLines, 1,
+                               "Symbol '%m%p' is %s but exported %s",
                                GetSymName (Sym),
                                AddrSizeToStr (Sym->AddrSize),
                                AddrSizeToStr (Sym->ExportSize));
                 }
             }
         }
-        Sym->Flags |= (S->Flags & SF_REFERENCED);
+        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);
@@ -507,25 +537,27 @@ static void SymCheckUndefined (SymEntry* S)
         S->Flags = SF_UNUSED;
 
     } else {
-       /* The symbol is definitely undefined */
-       if (S->Flags & SF_EXPORT) {
-           /* We will not auto-import an export */
-           LIError (&S->LineInfos,
-                     "Exported symbol `%m%p' was never defined",
+        /* 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;
+        } else {
+            if (AutoImport) {
+                /* Mark as import, will be indexed later */
+                S->Flags |= SF_IMPORT;
                 /* Use the address size for code */
                 S->AddrSize = CodeAddrSize;
-           } else {
-               /* Error */
-               LIError (&S->LineInfos,
-                         "Symbol `%m%p' is undefined",
+                /* Mark point of import */
+                GetFullLineInfo (&S->DefLines);
+            } else {
+                /* Error */
+                LIError (&S->RefLines,
+                         "Symbol '%m%p' is undefined",
                          GetSymName (S));
-           }
-       }
+            }
+        }
     }
 }
 
@@ -538,76 +570,77 @@ void SymCheck (void)
 
     /* Check for open scopes */
     if (CurrentScope->Parent != 0) {
-       Error ("Local scope was not closed");
+        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) {
-           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;
+        /* 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. 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.
-     */
+    ** 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_UNUSED) == 0 &&
-           (S->Flags & SF_UNDEFMASK) != SF_UNDEFVAL) {
+        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) {
-                const StrBuf* Name = GetStrBuf (S->Name);
-                if (SB_At (Name, 0) != '.') {           /* Ignore internals */
-                    LIWarning (&S->LineInfos, 2,
-                               "Symbol `%m%p' is defined but never used",
-                               GetSymName (S));
-                }
-           }
+            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->LineInfos, 2,
-                               "Symbol `%m%p' is imported but never used",
+            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++;
-               }
-           }
+                } else {
+                    /* Give the import an id, count imports */
+                    S->ImportId = ImportCount++;
+                }
+            }
 
-            /* Count exports */
-           if (S->Flags & SF_EXPORT) {
-               ++ExportCount;
-           }
+            /* 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.
-             */
+            ** recalculate it.
+            */
             if (SymHasExpr (S) && S->AddrSize == ADDR_SIZE_DEFAULT) {
                 ExprDesc ED;
                 ED_Init (&ED);
@@ -619,8 +652,8 @@ void SymCheck (void)
                         S->ExportSize = S->AddrSize;
                     } else if (S->AddrSize > S->ExportSize) {
                         /* We're exporting a symbol smaller than it actually is */
-                        LIWarning (&S->LineInfos, 1,
-                                   "Symbol `%m%p' is %s but exported %s",
+                        LIWarning (&S->DefLines, 1,
+                                   "Symbol '%m%p' is %s but exported %s",
                                    GetSymName (S),
                                    AddrSizeToStr (S->AddrSize),
                                    AddrSizeToStr (S->ExportSize));
@@ -630,9 +663,9 @@ void SymCheck (void)
             }
 
             /* 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.
-             */
+            ** 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])) {
@@ -640,17 +673,17 @@ void SymCheck (void)
                     const FilePos* P = S->GuessedUse[S->AddrSize - 1];
                     if (P) {
                         PWarning (P, 0,
-                                  "Didn't use %s addressing for `%m%p'",
+                                  "Didn't use %s addressing for '%m%p'",
                                   AddrSizeToStr (S->AddrSize),
                                   GetSymName (S));
                     }
                 }
             }
 
-       }
+        }
 
-       /* Next symbol */
-       S = S->List;
+        /* Next symbol */
+        S = S->List;
     }
 }
 
@@ -662,19 +695,19 @@ void SymDump (FILE* F)
     SymEntry* S = SymList;
 
     while (S) {
-       /* Ignore unused symbols */
-       if ((S->Flags & SF_UNUSED) != 0) {
-           fprintf (F,
-                    "%m%-24p %s %s %s %s %s\n",
-                    GetSymName (S),
-                    (S->Flags & SF_DEFINED)? "DEF" : "---",
-                    (S->Flags & SF_REFERENCED)? "REF" : "---",
-                    (S->Flags & SF_IMPORT)? "IMP" : "---",
-                    (S->Flags & SF_EXPORT)? "EXP" : "---",
+        /* 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;
+        }
+        /* Next symbol */
+        S = S->List;
     }
 }
 
@@ -692,20 +725,21 @@ void WriteImports (void)
     ObjWriteVar (ImportCount);
 
     /* 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).
-     */
+    ** 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_UNUSED | SF_IMPORT)) == SF_IMPORT &&
             (S->Flags & (SF_REFERENCED | SF_FORCED)) != 0) {
 
             ObjWrite8 (S->AddrSize);
-                   ObjWriteVar (S->Name);
-           WriteLineInfo (&S->LineInfos);
-       }
-       S = S->List;
+            ObjWriteVar (S->Name);
+            WriteLineInfo (&S->DefLines);
+            WriteLineInfo (&S->RefLines);
+        }
+        S = S->List;
     }
 
     /* Done writing imports */
@@ -729,63 +763,64 @@ void WriteExports (void)
     /* Walk throught list and write all exports to the file */
     S = SymList;
     while (S) {
-               if ((S->Flags & (SF_UNUSED | SF_EXPORT)) == SF_EXPORT) {
+        if ((S->Flags & (SF_UNUSED | SF_EXPORT)) == SF_EXPORT) {
 
-           /* Get the expression bits and the value */
+            /* Get the expression bits and the value */
             long ConstVal;
-            unsigned ExprMask = GetSymInfoFlags (S, &ConstVal);
+            unsigned SymFlags = GetSymInfoFlags (S, &ConstVal);
 
             /* Check if this symbol has a size. If so, remember it in the
-             * flags.
-             */
+            ** flags.
+            */
             long Size;
             SymEntry* SizeSym = FindSizeOfSymbol (S);
             if (SizeSym != 0 && SymIsConst (SizeSym, &Size)) {
-                ExprMask |= SYM_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 (ExprMask);
-               }
-           }
+            /* 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 (ExprMask);
+            /* Write the type and the export size */
+            ObjWriteVar (SymFlags);
             ObjWrite8 (S->ExportSize);
 
-           /* Write any ConDes declarations */
-           if (SYM_GET_CONDES_COUNT (ExprMask) > 0) {
-               for (Type = 0; Type < CD_TYPE_COUNT; ++Type) {
-                   unsigned char Prio = S->ConDesPrio[Type];
-                   if (Prio != CD_PRIO_NONE) {
-                       ObjWrite8 (CD_BUILD (Type, Prio));
-                   }
-               }
-           }
-
-           /* Write the name */
-                   ObjWriteVar (S->Name);
-
-           /* Write the value */
-           if (SYM_IS_CONST (ExprMask)) {
-               /* Constant value */
-               ObjWrite32 (ConstVal);
-           } else {
-               /* Expression involved */
-               WriteExpr (S->Expr);
+            /* 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);
             }
 
             /* If the symbol has a size, write it to the file */
-            if (SYM_HAS_SIZE (ExprMask)) {
+            if (SYM_HAS_SIZE (SymFlags)) {
                 ObjWriteVar (Size);
             }
 
-           /* Write the line infos */
-           WriteLineInfo (&S->LineInfos);
-       }
-       S = S->List;
+            /* Write the line infos */
+            WriteLineInfo (&S->DefLines);
+            WriteLineInfo (&S->RefLines);
+        }
+        S = S->List;
     }
 
     /* Done writing exports */
@@ -806,77 +841,96 @@ void WriteDbgSyms (void)
     /* Check if debug info is requested */
     if (DbgSyms) {
 
-       /* Walk through the list, give each symbol an id and count them */
-       Count = 0;
-       S = SymList;
-       while (S) {
-           if ((S->Flags & SF_DBGINFOMASK) == SF_DBGINFOVAL &&
-                !IsSizeOfSymbol (S)) {
+        /* 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;
-       }
+            }
+            S = S->List;
+        }
 
-       /* Write the symbol count to the list */
-               ObjWriteVar (Count);
+        /* 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 ((S->Flags & SF_DBGINFOMASK) == SF_DBGINFOVAL &&
-                !IsSizeOfSymbol (S)) {
+        /* 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 ExprMask = GetSymInfoFlags (S, &ConstVal);
+                unsigned SymFlags = GetSymInfoFlags (S, &ConstVal);
 
                 /* Check if this symbol has a size. If so, remember it in the
-                 * flags.
-                 */
+                ** flags.
+                */
                 long Size;
                 SymEntry* SizeSym = FindSizeOfSymbol (S);
                 if (SizeSym != 0 && SymIsConst (SizeSym, &Size)) {
-                    ExprMask |= SYM_SIZE;
+                    SymFlags |= SYM_SIZE;
                 }
 
-               /* Write the type */
-               ObjWriteVar (ExprMask);
+                /* Write the type */
+                ObjWriteVar (SymFlags);
 
                 /* Write the address size */
                 ObjWrite8 (S->AddrSize);
 
-               /* Write the name */
-                       ObjWriteVar (S->Name);
+                /* 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 (ExprMask)) {
-                   /* Constant value */
-                   ObjWrite32 (ConstVal);
-               } else {
-                   /* Expression involved */
-                   WriteExpr (S->Expr);
-               }
+                /* 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 (ExprMask)) {
+                if (SYM_HAS_SIZE (SymFlags)) {
                     ObjWriteVar (Size);
                 }
 
-               /* Write the line infos */
-               WriteLineInfo (&S->LineInfos);
-           }
-           S = S->List;
-       }
+                /* 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 ();
 }
@@ -889,12 +943,81 @@ void WriteScopes (void)
     /* Tell the object file module that we're about to start the scopes */
     ObjStartScopes ();
 
-    /* No debug info requested */
-    ObjWriteVar (0);
+    /* We will write scopes only if debug symbols are requested */
+    if (DbgSyms) {
 
-    /* Done writing the scopes */
-    ObjEndScopes ();
-}
+        /* 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 ();
+}