]> git.sur5r.net Git - cc65/blobdiff - src/ca65/symtab.c
Move scope type definitions to common/
[cc65] / src / ca65 / symtab.c
index f6055591e40ba683f41789f489f61a99f67e8c5a..e592d06d4a2d05ab3a6bcc593c363ce2877c7c55 100644 (file)
@@ -6,10 +6,10 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 1998-2003 Ullrich von Bassewitz                                       */
-/*               Römerstraße 52                                              */
-/*               D-70794 Filderstadt                                         */
-/* EMail:        uz@cc65.org                                                 */
+/* (C) 1998-2011, Ullrich von Bassewitz                                      */
+/*                Roemerstrasse 52                                           */
+/*                D-70794 Filderstadt                                        */
+/* EMail:         uz@cc65.org                                                */
 /*                                                                           */
 /*                                                                           */
 /* This software is provided 'as-is', without any expressed or implied       */
@@ -39,6 +39,8 @@
 #include "addrsize.h"
 #include "check.h"
 #include "hashstr.h"
+#include "mmodel.h"
+#include "scopedefs.h"
 #include "symdefs.h"
 #include "xmalloc.h"
 
@@ -49,7 +51,9 @@
 #include "objfile.h"
 #include "scanner.h"
 #include "segment.h"
+#include "sizeof.h"
 #include "spool.h"
+#include "studyexpr.h"
 #include "symtab.h"
 
 
 /* Combined symbol entry flags used within this module */
 #define SF_UNDEFMASK   (SF_REFERENCED | SF_DEFINED | SF_IMPORT)
 #define SF_UNDEFVAL    (SF_REFERENCED)
-#define SF_EXPMASK     (SF_TRAMPOLINE | SF_EXPORT)
-#define SF_EXPVAL      (SF_EXPORT)
-#define SF_DBGINFOMASK (SF_TRAMPOLINE | SF_DEFINED | SF_EXPORT | SF_IMPORT)
+#define SF_DBGINFOMASK         (SF_UNUSED | SF_DEFINED | SF_IMPORT)
 #define SF_DBGINFOVAL  (SF_DEFINED)
 
 /* Symbol tables */
-SymTable*              CurrentScope = 0;       /* Pointer to current symbol table */
-SymTable*      RootScope    = 0;       /* Root symbol table */
+SymTable*                  CurrentScope = 0;   /* Pointer to current symbol table */
+SymTable*          RootScope    = 0;   /* Root symbol table */
+static SymTable*    LastScope    = 0;   /* Pointer to last scope in list */
+static unsigned     ScopeCount   = 0;   /* Number of scopes */
 
 /* Symbol table variables */
-static unsigned                ImportCount = 0;/* Counter for import symbols */
-static unsigned        ExportCount = 0;/* Counter for export symbols */
+static unsigned     ImportCount = 0;    /* Counter for import symbols */
+static unsigned     ExportCount = 0;    /* Counter for export symbols */
 
 
 
@@ -96,7 +100,7 @@ static unsigned ScopeTableSize (unsigned Level)
 
 
 
-static SymTable* NewSymTable (SymTable* Parent, const char* Name)
+static SymTable* NewSymTable (SymTable* Parent, const StrBuf* Name)
 /* Allocate a symbol table on the heap and return it */
 {
     /* Determine the lexical level and the number of table slots */
@@ -110,18 +114,33 @@ static SymTable* NewSymTable (SymTable* Parent, const char* Name)
     S->Left         = 0;
     S->Right        = 0;
     S->Childs       = 0;
+    S->OwnerSym     = 0;
+    S->SegRanges    = AUTO_COLLECTION_INITIALIZER;
     S->Flags        = ST_NONE;
     S->AddrSize     = ADDR_SIZE_DEFAULT;
-    S->Type         = 0;
+    S->Type         = SCOPETYPE_UNDEF;
     S->Level        = Level;
     S->TableSlots   = Slots;
     S->TableEntries = 0;
     S->Parent       = Parent;
-    S->Name         = GetStringId (Name);
+    S->Name         = GetStrBufId (Name);
     while (Slots--) {
                S->Table[Slots] = 0;
     }
 
+    /* Insert the symbol table into the list of all symbol tables and maintain
+     * a unqiue id for each scope. Count the number of scopes.
+     */
+    S->Next = LastScope;
+    if (RootScope == 0) {
+        S->Id = 0;
+        RootScope = S;
+    } else {
+        S->Id = LastScope->Id + 1;
+    }
+    LastScope = S;
+    ++ScopeCount;
+
     /* Insert the symbol table into the child tree of the parent */
     if (Parent) {
         SymTable* T = Parent->Childs;
@@ -131,7 +150,7 @@ static SymTable* NewSymTable (SymTable* Parent, const char* Name)
         } else {
             while (1) {
                 /* Choose next entry */
-                int Cmp = strcmp (Name, GetString (T->Name));
+                int Cmp = SB_Compare (Name, GetStrBuf (T->Name));
                 if (Cmp < 0) {
                     if (T->Left) {
                         T = T->Left;
@@ -148,7 +167,7 @@ static SymTable* NewSymTable (SymTable* Parent, const char* Name)
                     }
                 } else {
                     /* Duplicate scope name */
-                    Internal ("Duplicate scope name: `%s'", Name);
+                    Internal ("Duplicate scope name: `%m%p'", Name);
                 }
             }
         }
@@ -160,50 +179,14 @@ static SymTable* NewSymTable (SymTable* Parent, const char* Name)
 
 
 
-static int SearchSymTree (SymEntry* T, const char* Name, SymEntry** E)
-/* Search in the given tree for a name. If we find the symbol, the function
- * will return 0 and put the entry pointer into E. If we did not find the
- * symbol, and the tree is empty, E is set to NULL. If the tree is not empty,
- * E will be set to the last entry, and the result of the function is <0 if
- * the entry should be inserted on the left side, and >0 if it should get
- * inserted on the right side.
- */
-{
-    /* Is there a tree? */
-    if (T == 0) {
-       *E = 0;
-       return 1;
-    }
-
-    /* We have a table, search it */
-    while (1) {
-
-        /* Get the symbol name */
-        const char* SymName = GetString (T->Name);
-
-       /* Choose next entry */
-        int Cmp = strcmp (Name, SymName);
-               if (Cmp < 0 && T->Left) {
-           T = T->Left;
-       } else if (Cmp > 0&& T->Right) {
-           T = T->Right;
-       } else {
-           /* Found or end of search, return the result */
-            *E = T;
-            return Cmp;
-               }
-    }
-}
-
-
-
 /*****************************************************************************/
-/*                                          Code                                    */
+/*                                          Code                                    */
 /*****************************************************************************/
 
 
 
-void SymEnterLevel (const char* ScopeName, unsigned AddrSize)
+void SymEnterLevel (const StrBuf* ScopeName, unsigned char Type,
+                    unsigned char AddrSize, SymEntry* OwnerSym)
 /* Enter a new lexical level */
 {
     /* Map a default address size to something real */
@@ -216,18 +199,34 @@ void SymEnterLevel (const char* ScopeName, unsigned AddrSize)
      * new one if it doesn't exist. If this is the root scope, just create it.
      */
     if (CurrentScope) {
+
+        /* Search for the scope, create a new one */
         CurrentScope = SymFindScope (CurrentScope, ScopeName, SYM_ALLOC_NEW);
 
         /* Check if the scope has been defined before */
         if (CurrentScope->Flags & ST_DEFINED) {
-            Error ("Duplicate scope `%s'", ScopeName);
+            Error ("Duplicate scope `%m%p'", ScopeName);
         }
+
     } else {
         CurrentScope = RootScope = NewSymTable (0, ScopeName);
     }
 
-    /* Mark the scope as defined */
-    CurrentScope->Flags |= ST_DEFINED;
+    /* Mark the scope as defined and set type, address size and owner symbol */
+    CurrentScope->Flags    |= ST_DEFINED;
+    CurrentScope->AddrSize = AddrSize;
+    CurrentScope->Type     = Type;
+    CurrentScope->OwnerSym = OwnerSym;
+
+    /* If this is a scope that allows to emit data into segments, add segment
+     * ranges for all currently existing segments. Doing this for just a few
+     * scope types is not really necessary but an optimization, because it
+     * does not allocate memory for useless data (unhandled types here don't
+     * occupy space in any segment).
+     */
+    if (CurrentScope->Type <= SCOPETYPE_HAS_DATA) {
+        AddSegRanges (&CurrentScope->SegRanges);
+    }
 }
 
 
@@ -235,17 +234,37 @@ void SymEnterLevel (const char* ScopeName, unsigned AddrSize)
 void SymLeaveLevel (void)
 /* Leave the current lexical level */
 {
+    /* Close the segment ranges. We don't care about the scope type here,
+     * since types without segment ranges will just have an empty list.
+     */
+    CloseSegRanges (&CurrentScope->SegRanges);
+
+    /* If we have segment ranges, the first one is the segment that was
+     * active, when the scope was opened. Set the size of the scope to the
+     * number of data bytes emitted into this segment. If we have an owner
+     * symbol set the size of this symbol, too.
+     */
+    if (CollCount (&CurrentScope->SegRanges) > 0) {
+        const SegRange* R = CollAtUnchecked (&CurrentScope->SegRanges, 0);
+        unsigned long Size = GetSegRangeSize (R);
+        DefSizeOfScope (CurrentScope, Size);
+        if (CurrentScope->OwnerSym) {
+            DefSizeOfSymbol (CurrentScope->OwnerSym, Size);
+        }
+    }
+
+    /* Leave the scope */
     CurrentScope = CurrentScope->Parent;
 }
 
 
 
-SymTable* SymFindScope (SymTable* Parent, const char* Name, int AllocNew)
+SymTable* SymFindScope (SymTable* Parent, const StrBuf* Name, int AllocNew)
 /* Find a scope in the given enclosing scope */
 {
     SymTable** T = &Parent->Childs;
     while (*T) {
-        int Cmp = strcmp (Name, GetString ((*T)->Name));
+        int Cmp = SB_Compare (Name, GetStrBuf ((*T)->Name));
         if (Cmp < 0) {
             T = &(*T)->Left;
         } else if (Cmp > 0) {
@@ -267,85 +286,110 @@ SymTable* SymFindScope (SymTable* Parent, const char* Name, int AllocNew)
 
 
 
-SymEntry* SymFind (SymTable* Scope, const char* Name, int AllocNew)
-/* Find a new symbol table entry in the given table. If AllocNew is given and
- * the entry is not found, create a new one. Return the entry found, or the
- * new entry created, or - in case AllocNew is zero - return 0.
+SymTable* SymFindAnyScope (SymTable* Parent, const StrBuf* Name)
+/* Find a scope in the given or any of its parent scopes. The function will
+ * never create a new symbol, since this can only be done in one specific
+ * scope.
+ */
+{
+    SymTable* Scope;
+    do {
+       /* Search in the current table */
+       Scope = SymFindScope (Parent, Name, SYM_FIND_EXISTING);
+               if (Scope == 0) {
+           /* Not found, search in the parent scope, if we have one */
+           Parent = Parent->Parent;
+       }
+    } while (Scope == 0 && Parent != 0);
+
+    return Scope;
+}
+
+
+
+SymEntry* SymFindLocal (SymEntry* Parent, const StrBuf* Name, int AllocNew)
+/* Find a cheap local symbol. If AllocNew is given and the entry is not
+ * found, create a new one. Return the entry found, or the new entry created,
+ * or - in case AllocNew is zero - return 0.
  */
 {
     SymEntry* S;
     int Cmp;
 
-    if (IsLocalName (Name)) {
+    /* Local symbol, get the table */
+    if (!Parent) {
+        /* No last global, so there's no local table */
+        Error ("No preceeding global symbol");
+        if (AllocNew) {
+            return NewSymEntry (Name, SF_LOCAL);
+        } else {
+            return 0;
+        }
+    }
 
-       /* Local symbol, get the table */
-       if (!SymLast) {
-           /* No last global, so there's no local table */
-           Error ("No preceeding global symbol");
-           if (AllocNew) {
-               return NewSymEntry (Name);
-           } else {
-               return 0;
-           }
-               }
+    /* Search for the symbol if we have a table */
+    Cmp = SymSearchTree (Parent->Locals, Name, &S);
 
-       /* Search for the symbol if we have a table */
-        Cmp = SearchSymTree (SymLast->Locals, Name, &S);
+    /* If we found an entry, return it */
+    if (Cmp == 0) {
+        return S;
+    }
 
-       /* If we found an entry, return it */
-       if (Cmp == 0) {
-           return S;
-       }
+    if (AllocNew) {
 
-       if (AllocNew) {
+        /* Otherwise create a new entry, insert and return it */
+        SymEntry* N = NewSymEntry (Name, SF_LOCAL);
+        N->Sym.Entry = Parent;
+        if (S == 0) {
+            Parent->Locals = N;
+        } else if (Cmp < 0) {
+            S->Left = N;
+        } else {
+            S->Right = N;
+        }
+        return N;
+    }
 
-           /* Otherwise create a new entry, insert and return it */
-           SymEntry* N = NewSymEntry (Name);
-           if (S == 0) {
-               SymLast->Locals = N;
-           } else if (Cmp < 0) {
-               S->Left = N;
-           } else {
-               S->Right = N;
-           }
-           return N;
-       }
+    /* We did not find the entry and AllocNew is false. */
+    return 0;
+}
 
-    } else {
 
-       /* Global symbol: Get the hash value for the name */
-               unsigned Hash = HashStr (Name) % Scope->TableSlots;
 
-       /* Search for the entry */
-       Cmp = SearchSymTree (Scope->Table[Hash], Name, &S);
+SymEntry* SymFind (SymTable* Scope, const StrBuf* Name, int AllocNew)
+/* Find a new symbol table entry in the given table. If AllocNew is given and
+ * the entry is not found, create a new one. Return the entry found, or the
+ * new entry created, or - in case AllocNew is zero - return 0.
+ */
+{
+    SymEntry* S;
 
-       /* If we found an entry, return it */
-       if (Cmp == 0) {
-           /* Check for a trampoline entry, in this case return the real
-            * symbol.
-            */
-           while (S->Flags & SF_TRAMPOLINE) {
-               S = S->V.Sym;
-           }
-            return S;
-       }
+    /* Global symbol: Get the hash value for the name */
+    unsigned Hash = HashBuf (Name) % Scope->TableSlots;
 
-       if (AllocNew) {
+    /* Search for the entry */
+    int Cmp = SymSearchTree (Scope->Table[Hash], Name, &S);
 
-           /* Otherwise create a new entry, insert and return it */
-           SymEntry* N = NewSymEntry (Name);
-           if (S == 0) {
-               Scope->Table[Hash] = N;
-           } else if (Cmp < 0) {
-               S->Left = N;
-           } else {
-               S->Right = N;
-           }
-                   N->SymTab = Scope;
-           ++Scope->TableEntries;
-           return N;
+    /* If we found an entry, return it */
+    if (Cmp == 0) {
+        return S;
+    }
+
+    if (AllocNew) {
+
+        /* Otherwise create a new entry, insert and return it */
+        SymEntry* N = NewSymEntry (Name, SF_NONE);
+        N->Sym.Tab = Scope;
+        if (S == 0) {
+            Scope->Table[Hash] = N;
+        } else if (Cmp < 0) {
+            S->Left = N;
+        } else {
+            S->Right = N;
+        }
+        ++Scope->TableEntries;
+        return N;
 
-       }
     }
 
     /* We did not find the entry and AllocNew is false. */
@@ -354,7 +398,7 @@ SymEntry* SymFind (SymTable* Scope, const char* Name, int AllocNew)
 
 
 
-static SymEntry* SymFindAny (SymTable* Scope, const char* Name)
+SymEntry* SymFindAny (SymTable* Scope, const StrBuf* Name)
 /* Find a symbol in the given or any of its parent scopes. The function will
  * never create a new symbol, since this can only be done in one specific
  * scope.
@@ -364,126 +408,27 @@ static SymEntry* SymFindAny (SymTable* Scope, const char* Name)
     do {
        /* Search in the current table */
        Sym = SymFind (Scope, Name, SYM_FIND_EXISTING);
-       if (Sym) {
+               if (Sym) {
            /* Found, return it */
-           return Sym;
-       } else {
-           /* Not found, search in the parent scope, if we have one */
-           Scope = Scope->Parent;
+           break;
        }
-    } while (Sym == 0 && Scope != 0);
 
-    /* Not found */
-    return 0;
-}
+        /* Not found, search in the parent scope, if we have one */
+       Scope = Scope->Parent;
 
+    } while (Sym == 0 && Scope != 0);
 
-
-void SymConDes (const char* Name, unsigned Type, unsigned Prio)
-/* Mark the given symbol as a module constructor/destructor. This will also
- * mark the symbol as an export. Initializers may never be zero page symbols.
- */
-{
-    SymEntry* S;
-
-    /* Check the parameters */
-#if (CD_TYPE_MIN != 0)
-    CHECK (Type >= CD_TYPE_MIN && Type <= CD_TYPE_MAX);
-#else
-    CHECK (Type <= CD_TYPE_MAX);
-#endif
-    CHECK (Prio >= CD_PRIO_MIN && Prio <= CD_PRIO_MAX);
-
-    /* Don't accept local symbols */
-    if (IsLocalName (Name)) {
-       Error ("Illegal use of a local symbol");
-       return;
-    }
-
-    /* Do we have such a symbol? */
-    S = SymFind (CurrentScope, Name, SYM_ALLOC_NEW);
-    if (S->Flags & SF_IMPORT) {
-       /* The symbol is already marked as imported external symbol */
-       Error ("Symbol `%s' is already an import", Name);
-       return;
-    }
-
-    /* If the symbol is marked as global, silently remove the global flag */
-    if (S->Flags & SF_GLOBAL) {
-        S->Flags &= ~SF_GLOBAL;
-    }
-
-    /* Check if the symbol was not already defined as ZP symbol */
-    if (S->AddrSize == ADDR_SIZE_ZP) {
-       Error ("Redeclaration mismatch for symbol `%s'", Name);
-    }
-
-    /* If the symbol was already declared as a condes, check if the new
-     * priority value is the same as the old one.
-     */
-    if (S->ConDesPrio[Type] != CD_PRIO_NONE) {
-       if (S->ConDesPrio[Type] != Prio) {
-           Error ("Redeclaration mismatch for symbol `%s'", Name);
-       }
-    }
-    S->ConDesPrio[Type] = Prio;
-
-    /* Set the symbol data */
-    S->Flags |= SF_EXPORT | SF_REFERENCED;
-}
-
-
-
-int SymIsConst (SymEntry* S)
-/* Return true if the given symbol has a constant value */
-{
-    /* Resolve trampoline entries */
-    if (S->Flags & SF_TRAMPOLINE) {
-       S = S->V.Sym;
-    }
-
-    /* Check for constness */
-    if (S->Flags & SF_CONST) {
-       return 1;
-    } else if ((S->Flags & SF_DEFINED) && IsConstExpr (S->V.Expr)) {
-       /* Constant expression, remember the value */
-       ExprNode* Expr = S->V.Expr;
-               S->Flags |= SF_CONST;
-       S->V.Val = GetExprVal (Expr);
-       FreeExpr (Expr);
-       return 1;
-    }
-    return 0;
+    /* Return the result */
+    return Sym;
 }
 
 
 
-int SymIsZP (SymEntry* S)
-/* Return true if the symbol is explicitly marked as zeropage symbol */
+unsigned char GetCurrentSymTabType ()
+/* Return the type of the current symbol table */
 {
-    /* Resolve trampoline entries */
-    if (S->Flags & SF_TRAMPOLINE) {
-       S = S->V.Sym;
-    }
-
-    /* If the symbol is not a global symbol, was not defined before, check the
-     * enclosing scope for a symbol with the same name, and return the ZP
-     * attribute of this symbol if we find one.
-     */
-    if (!IsLocalNameId (S->Name) && (S->Flags & (SF_DEFINED | SF_IMPORT)) == 0 &&
-       S->SymTab->Parent != 0) {
-
-       /* Try to find a symbol with the same name in the enclosing scope */
-       SymEntry* E = SymFindAny (S->SymTab->Parent, GetString (S->Name));
-
-       /* If we found one, use the ZP flag */
-               if (E && E->AddrSize == ADDR_SIZE_ZP) {
-            S->AddrSize = ADDR_SIZE_ZP;
-       }
-    }
-
-    /* Check the ZP flag */
-    return (S->AddrSize == ADDR_SIZE_ZP);
+    CHECK (CurrentScope != 0);
+    return CurrentScope->Type;
 }
 
 
@@ -502,63 +447,86 @@ static void SymCheckUndefined (SymEntry* S)
      *     AutoImport flag is not set, it's an error.
      */
     SymEntry* Sym = 0;
-    if (S->SymTab) {
-       /* It's a global symbol, get the higher level table */
-       SymTable* Tab = S->SymTab->Parent;
-       while (Tab) {
-           Sym = SymFindAny (Tab, GetString (S->Name));
-           if (Sym) {
-               if (Sym->Flags & (SF_DEFINED | SF_IMPORT)) {
-                   /* We've found a symbol in a higher level that is
-                    * either defined in the source, or an import.
-                    */
-                    break;
-               } else {
-                   /* The symbol found is undefined itself. Look further */
-                   Tab = Sym->SymTab->Parent;
-               }
-           } else {
-               /* No symbol found */
-               break;
-           }
-       }
+    SymTable* Tab = GetSymParentScope (S);
+    while (Tab) {
+        Sym = SymFind (Tab, GetStrBuf (S->Name), SYM_FIND_EXISTING);
+        if (Sym && (Sym->Flags & (SF_DEFINED | SF_IMPORT)) != 0) {
+            /* We've found a symbol in a higher level that is
+             * either defined in the source, or an import.
+             */
+             break;
+        }
+        /* No matching symbol found in this level. Look further */
+        Tab = Tab->Parent;
     }
+
     if (Sym) {
-       /* We found the symbol in a higher level. Make S a trampoline
-        * symbol. Beware: We have to transfer the symbol attributes to
-        * the real symbol and check for any conflicts.
-        */
-       S->Flags |= SF_TRAMPOLINE;
-       S->V.Sym = Sym;
 
-       /* Transfer the flags. Note: S may not be imported, since in that
-        * case it wouldn't be undefined.
-        */
-               if (S->Flags & SF_EXPORT) {
+        /* We found the symbol in a higher level. Transfer the flags and
+         * address size from the local symbol to that in the higher level
+         * and check for problems.
+         */
+        if (S->Flags & SF_EXPORT) {
            if (Sym->Flags & SF_IMPORT) {
-               /* The symbol is already marked as imported external symbol */
-               PError (&S->Pos, "Symbol `%s' is already an import", GetString (S->Name));
+               /* The symbol is already marked as import */
+                       LIError (&S->LineInfos,
+                         "Symbol `%s' is already an import",
+                         GetString (Sym->Name));
            }
-           Sym->Flags |= (S->Flags & SF_EXPORT);
-            Sym->ExportSize = S->ExportSize;
-       }
+            if (Sym->Flags & SF_EXPORT) {
+                /* The symbol is already marked as an export. */
+                if (Sym->AddrSize > S->ExportSize) {
+                    /* We're exporting a symbol smaller than it actually is */
+                    LIWarning (&S->LineInfos, 1,
+                               "Symbol `%m%p' is %s but exported %s",
+                              GetSymName (Sym),
+                              AddrSizeToStr (Sym->AddrSize),
+                              AddrSizeToStr (S->ExportSize));
+                }
+            } else {
+                /* Mark the symbol as an export */
+                Sym->Flags |= SF_EXPORT;
+                Sym->ExportSize = S->ExportSize;
+                if (Sym->ExportSize == ADDR_SIZE_DEFAULT) {
+                    /* Use the actual size of the symbol */
+                    Sym->ExportSize = Sym->AddrSize;
+                }
+                if (Sym->AddrSize > Sym->ExportSize) {
+                    /* We're exporting a symbol smaller than it actually is */
+                    LIWarning (&S->LineInfos, 1,
+                               "Symbol `%m%p' is %s but exported %s",
+                               GetSymName (Sym),
+                               AddrSizeToStr (Sym->AddrSize),
+                               AddrSizeToStr (Sym->ExportSize));
+                }
+            }
+        }
+        Sym->Flags |= (S->Flags & SF_REFERENCED);
 
-       /* Transfer the referenced flag */
-       Sym->Flags |= (S->Flags & SF_REFERENCED);
+        /* Transfer all expression references */
+        SymTransferExprRefs (S, Sym);
+
+        /* Mark the symbol as unused removing all other flags */
+        S->Flags = SF_UNUSED;
 
     } else {
        /* The symbol is definitely undefined */
        if (S->Flags & SF_EXPORT) {
            /* We will not auto-import an export */
-           PError (&S->Pos, "Exported symbol `%s' was never defined",
-                    GetString (S->Name));
+           LIError (&S->LineInfos,
+                     "Exported symbol `%m%p' was never defined",
+                     GetSymName (S));
        } else {
            if (AutoImport) {
-               /* Mark as import, will be indexed later */
-               S->Flags |= SF_IMPORT;
+               /* Mark as import, will be indexed later */
+               S->Flags |= SF_IMPORT;
+                /* Use the address size for code */
+                S->AddrSize = CodeAddrSize;
            } else {
-               /* Error */
-               PError (&S->Pos, "Symbol `%s' is undefined", GetString (S->Name));
+               /* Error */
+               LIError (&S->LineInfos,
+                         "Symbol `%m%p' is undefined",
+                         GetSymName (S));
            }
        }
     }
@@ -585,11 +553,10 @@ void SymCheck (void)
         * already defined, otherwise mark it as import.
         */
        if (S->Flags & SF_GLOBAL) {
-           S->Flags &= ~SF_GLOBAL;
            if (S->Flags & SF_DEFINED) {
-               S->Flags |= SF_EXPORT;
+               SymExportFromGlobal (S);
            } else {
-               S->Flags |= SF_IMPORT;
+               SymImportFromGlobal (S);
            }
        }
 
@@ -603,37 +570,86 @@ void SymCheck (void)
        S = S->List;
     }
 
-    /* Second pass: Walk again through the symbols. Ignore undefined's, since
-     * we handled them in the last pass, and ignore trampoline symbols, since
-     * we handled them in the last pass, too.
+    /* Second pass: Walk again through the symbols. Count exports and imports
+     * and set address sizes where this has not happened before. Ignore
+     * undefined's, since we handled them in the last pass, and ignore unused
+     * symbols, since we handled them in the last pass, too.
      */
     S = SymList;
     while (S) {
-       if ((S->Flags & SF_TRAMPOLINE) == 0 &&
+       if ((S->Flags & SF_UNUSED) == 0 &&
            (S->Flags & SF_UNDEFMASK) != SF_UNDEFVAL) {
+
+            /* Check for defined symbols that were never referenced */
            if ((S->Flags & SF_DEFINED) != 0 && (S->Flags & SF_REFERENCED) == 0) {
-               /* Symbol was defined but never referenced */
-               PWarning (&S->Pos, 2,
-                          "Symbol `%s' is defined but never used",
-                          GetString (S->Name));
+                const StrBuf* Name = GetStrBuf (S->Name);
+                if (SB_At (Name, 0) != '.') {           /* Ignore internals */
+                    LIWarning (&S->LineInfos, 2,
+                               "Symbol `%m%p' is defined but never used",
+                               GetSymName (S));
+                }
            }
+
+            /* Assign an index to all imports */
            if (S->Flags & SF_IMPORT) {
-               if ((S->Flags & (SF_REFERENCED | SF_FORCED)) == SF_NONE) {
-                   /* Imported symbol is not referenced */
-                   PWarning (&S->Pos, 2,
-                              "Symbol `%s' is imported but never used",
-                              GetString (S->Name));
-               } else {
-                   /* Give the import an index, count imports */
-                   S->Index = ImportCount++;
-                   S->Flags |= SF_INDEXED;
-               }
+               if ((S->Flags & (SF_REFERENCED | SF_FORCED)) == SF_NONE) {
+                   /* Imported symbol is not referenced */
+                   LIWarning (&S->LineInfos, 2,
+                               "Symbol `%m%p' is imported but never used",
+                               GetSymName (S));
+               } else {
+                   /* Give the import an id, count imports */
+                   S->ImportId = ImportCount++;
+               }
            }
+
+            /* Count exports */
            if (S->Flags & SF_EXPORT) {
-               /* Give the export an index, count exports */
-               S->Index = ExportCount++;
-               S->Flags |= SF_INDEXED;
+               ++ExportCount;
            }
+
+            /* If the symbol is defined but has an unknown address size,
+             * recalculate it.
+             */
+            if (SymHasExpr (S) && S->AddrSize == ADDR_SIZE_DEFAULT) {
+                ExprDesc ED;
+                ED_Init (&ED);
+                StudyExpr (S->Expr, &ED);
+                S->AddrSize = ED.AddrSize;
+                if (SymIsExport (S)) {
+                    if (S->ExportSize == ADDR_SIZE_DEFAULT) {
+                        /* Use the real export size */
+                        S->ExportSize = S->AddrSize;
+                    } else if (S->AddrSize > S->ExportSize) {
+                        /* We're exporting a symbol smaller than it actually is */
+                        LIWarning (&S->LineInfos, 1,
+                                   "Symbol `%m%p' is %s but exported %s",
+                                   GetSymName (S),
+                                   AddrSizeToStr (S->AddrSize),
+                                   AddrSizeToStr (S->ExportSize));
+                    }
+                }
+                ED_Done (&ED);
+            }
+
+            /* If the address size of the symbol was guessed, check the guess
+             * against the actual address size and print a warning if the two
+             * differ.
+             */
+            if (S->AddrSize != ADDR_SIZE_DEFAULT) {
+                /* Do we have data for this address size? */
+                if (S->AddrSize <= sizeof (S->GuessedUse) / sizeof (S->GuessedUse[0])) {
+                    /* Get the file position where the symbol was used */
+                    const FilePos* P = S->GuessedUse[S->AddrSize - 1];
+                    if (P) {
+                        PWarning (P, 0,
+                                  "Didn't use %s addressing for `%m%p'",
+                                  AddrSizeToStr (S->AddrSize),
+                                  GetSymName (S));
+                    }
+                }
+            }
+
        }
 
        /* Next symbol */
@@ -649,11 +665,11 @@ void SymDump (FILE* F)
     SymEntry* S = SymList;
 
     while (S) {
-       /* Ignore trampoline symbols */
-       if ((S->Flags & SF_TRAMPOLINE) != 0) {
+       /* Ignore unused symbols */
+       if ((S->Flags & SF_UNUSED) != 0) {
            fprintf (F,
-                    "%-24s %s %s %s %s %s\n",
-                    GetString (S->Name),
+                    "%m%-24p %s %s %s %s %s\n",
+                    GetSymName (S),
                     (S->Flags & SF_DEFINED)? "DEF" : "---",
                     (S->Flags & SF_REFERENCED)? "REF" : "---",
                     (S->Flags & SF_IMPORT)? "IMP" : "---",
@@ -685,16 +701,12 @@ void WriteImports (void)
      */
     S = SymList;
     while (S) {
-        if ((S->Flags & (SF_TRAMPOLINE | SF_IMPORT)) == SF_IMPORT &&
+        if ((S->Flags & (SF_UNUSED | SF_IMPORT)) == SF_IMPORT &&
             (S->Flags & (SF_REFERENCED | SF_FORCED)) != 0) {
 
-           if (S->AddrSize == ADDR_SIZE_ZP) {
-               ObjWrite8 (IMP_ZP);
-           } else {
-               ObjWrite8 (IMP_ABS);
-           }
+            ObjWrite8 (S->AddrSize);
                    ObjWriteVar (S->Name);
-           ObjWritePos (&S->Pos);
+           WriteLineInfo (&S->LineInfos);
        }
        S = S->List;
     }
@@ -705,26 +717,6 @@ void WriteImports (void)
 
 
 
-static unsigned char GetExportExprMask (SymEntry* S)
-/* Return the expression bits for the given symbol table entry */
-{
-    unsigned char ExprMask;
-
-    /* Check if the symbol is const */
-    ExprMask = (SymIsConst (S))? EXP_CONST : EXP_EXPR;
-
-    /* Add zeropage/abs bits */
-    ExprMask |= (S->ExportSize == ADDR_SIZE_ZP)? EXP_ZP : EXP_ABS;
-
-    /* Add the label/equate bits */
-    ExprMask |= (S->Flags & SF_LABEL)? EXP_LABEL : EXP_EQUATE;
-
-    /* Return the mask */
-    return ExprMask;
-}
-
-
-
 void WriteExports (void)
 /* Write the exports list to the object file */
 {
@@ -740,49 +732,61 @@ void WriteExports (void)
     /* Walk throught list and write all exports to the file */
     S = SymList;
     while (S) {
-               if ((S->Flags & SF_EXPMASK) == SF_EXPVAL) {
-                   unsigned char ExprMask;
-
-           /* Finalize an associated expression if we have one */
-           SymFinalize (S);
-
-           /* Get the expression bits */
-           ExprMask = GetExportExprMask (S);
+               if ((S->Flags & (SF_UNUSED | SF_EXPORT)) == SF_EXPORT) {
+
+           /* Get the expression bits and the value */
+            long ConstVal;
+            unsigned ExprMask = GetSymInfoFlags (S, &ConstVal);
+
+            /* Check if this symbol has a size. If so, remember it in the
+             * flags.
+             */
+            long Size;
+            SymEntry* SizeSym = FindSizeOfSymbol (S);
+            if (SizeSym != 0 && SymIsConst (SizeSym, &Size)) {
+                ExprMask |= SYM_SIZE;
+            }
 
            /* Count the number of ConDes types */
            for (Type = 0; Type < CD_TYPE_COUNT; ++Type) {
-               if (S->ConDesPrio[Type] != CD_PRIO_NONE) {
-                   INC_EXP_CONDES_COUNT (ExprMask);
-               }
+               if (S->ConDesPrio[Type] != CD_PRIO_NONE) {
+                   SYM_INC_CONDES_COUNT (ExprMask);
+               }
            }
 
-           /* Write the type */
-           ObjWrite8 (ExprMask);
+           /* Write the type and the export size */
+           ObjWriteVar (ExprMask);
+            ObjWrite8 (S->ExportSize);
 
            /* Write any ConDes declarations */
-           if (GET_EXP_CONDES_COUNT (ExprMask) > 0) {
-               for (Type = 0; Type < CD_TYPE_COUNT; ++Type) {
-                   unsigned char Prio = S->ConDesPrio[Type];
-                   if (Prio != CD_PRIO_NONE) {
-                       ObjWrite8 (CD_BUILD (Type, Prio));
-                   }
-               }
+           if (SYM_GET_CONDES_COUNT (ExprMask) > 0) {
+               for (Type = 0; Type < CD_TYPE_COUNT; ++Type) {
+                   unsigned char Prio = S->ConDesPrio[Type];
+                   if (Prio != CD_PRIO_NONE) {
+                       ObjWrite8 (CD_BUILD (Type, Prio));
+                   }
+               }
            }
 
            /* Write the name */
                    ObjWriteVar (S->Name);
 
            /* Write the value */
-           if ((ExprMask & EXP_MASK_VAL) == EXP_CONST) {
+           if (SYM_IS_CONST (ExprMask)) {
                /* Constant value */
-               ObjWrite32 (S->V.Val);
+               ObjWrite32 (ConstVal);
            } else {
                /* Expression involved */
-               WriteExpr (S->V.Expr);
+               WriteExpr (S->Expr);
+            }
+
+            /* If the symbol has a size, write it to the file */
+            if (SYM_HAS_SIZE (ExprMask)) {
+                ObjWriteVar (Size);
             }
 
-           /* Write the source file position */
-           ObjWritePos (&S->Pos);
+           /* Write the line infos */
+           WriteLineInfo (&S->LineInfos);
        }
        S = S->List;
     }
@@ -793,26 +797,6 @@ void WriteExports (void)
 
 
 
-static unsigned char GetDbgExprMask (SymEntry* S)
-/* Return the expression bits for the given symbol table entry */
-{
-    unsigned char ExprMask;
-
-    /* Check if the symbol is const */
-    ExprMask = (SymIsConst (S))? EXP_CONST : EXP_EXPR;
-
-    /* Add zeropage/abs bits */
-    ExprMask |= (S->AddrSize == ADDR_SIZE_ZP)? EXP_ZP : EXP_ABS;
-
-    /* Add the label/equate bits */
-    ExprMask |= (S->Flags & SF_LABEL)? EXP_LABEL : EXP_EQUATE;
-
-    /* Return the mask */
-    return ExprMask;
-}
-
-
-
 void WriteDbgSyms (void)
 /* Write a list of all symbols to the object file */
 {
@@ -825,48 +809,75 @@ void WriteDbgSyms (void)
     /* Check if debug info is requested */
     if (DbgSyms) {
 
-       /* Walk through the list and count the symbols */
-       Count = 0;
-       S = SymList;
-       while (S) {
-           if ((S->Flags & SF_DBGINFOMASK) == SF_DBGINFOVAL) {
-               ++Count;
-           }
-           S = S->List;
-       }
+       /* Walk through the list, give each symbol an id and count them */
+       Count = 0;
+       S = SymList;
+       while (S) {
+           if ((S->Flags & SF_DBGINFOMASK) == SF_DBGINFOVAL &&
+                !IsSizeOfSymbol (S)) {
+                S->DebugSymId = Count++;
+           }
+           S = S->List;
+       }
 
-       /* Write the symbol count to the list */
+       /* Write the symbol count to the list */
                ObjWriteVar (Count);
 
-               /* Walk through list and write all symbols to the file */
-       S = SymList;
-       while (S) {
-           if ((S->Flags & SF_DBGINFOMASK) == SF_DBGINFOVAL) {
-               unsigned char ExprMask;
+               /* Walk through list and write all symbols to the file. Ignore size
+         * symbols.
+         */
+       S = SymList;
+       while (S) {
+           if ((S->Flags & SF_DBGINFOMASK) == SF_DBGINFOVAL &&
+                !IsSizeOfSymbol (S)) {
+
+                /* Get the expression bits and the value */
+                long ConstVal;
+                unsigned ExprMask = GetSymInfoFlags (S, &ConstVal);
+
+                /* Check if this symbol has a size. If so, remember it in the
+                 * flags.
+                 */
+                long Size;
+                SymEntry* SizeSym = FindSizeOfSymbol (S);
+                if (SizeSym != 0 && SymIsConst (SizeSym, &Size)) {
+                    ExprMask |= SYM_SIZE;
+                }
 
-               /* Finalize an associated expression if we have one */
-               SymFinalize (S);
+               /* Write the type */
+               ObjWriteVar (ExprMask);
 
-               /* Get the expression bits */
-                       ExprMask = GetDbgExprMask (S);
+                /* Write the address size */
+                ObjWrite8 (S->AddrSize);
 
-               /* Write the type */
-               ObjWrite8 (ExprMask);
+                /* Write the id of the parent. For normal symbols, this is a
+                 * scope (symbol table), for cheap locals, it's a symbol.
+                 */
+                if (SYM_IS_STD (ExprMask)) {
+                    ObjWriteVar (S->Sym.Tab->Id);
+                } else {
+                    ObjWriteVar (S->Sym.Entry->DebugSymId);
+                }
 
                /* Write the name */
                        ObjWriteVar (S->Name);
 
                /* Write the value */
-               if ((ExprMask & EXP_MASK_VAL) == EXP_CONST) {
+               if (SYM_IS_CONST (ExprMask)) {
                    /* Constant value */
-                   ObjWrite32 (S->V.Val);
+                   ObjWrite32 (ConstVal);
                } else {
                    /* Expression involved */
-                   WriteExpr (S->V.Expr);
+                   WriteExpr (S->Expr);
                }
 
-               /* Write the source file position */
-               ObjWritePos (&S->Pos);
+                /* If the symbol has a size, write it to the file */
+                if (SYM_HAS_SIZE (ExprMask)) {
+                    ObjWriteVar (Size);
+                }
+
+               /* Write the line infos */
+               WriteLineInfo (&S->LineInfos);
            }
            S = S->List;
        }
@@ -884,4 +895,66 @@ void WriteDbgSyms (void)
 
 
 
+void WriteScopes (void)
+/* Write the scope table to the object file */
+{
+    /* Tell the object file module that we're about to start the scopes */
+    ObjStartScopes ();
+
+    /* We will write scopes only if debug symbols are requested */
+    if (DbgSyms) {
+
+        /* Get head of list */
+        const SymTable* S = LastScope;
+
+        /* Write the scope count to the file */
+        ObjWriteVar (ScopeCount);
+
+        /* Walk through all scopes and write them to the file */
+        while (S) {
+
+            /* Type must be defined */
+            CHECK (S->Type != SCOPETYPE_UNDEF);
+
+            /* Id of scope */
+            ObjWriteVar (S->Id);
+
+            /* Id of parent scope */
+            if (S->Parent) {
+                ObjWriteVar (S->Parent->Id);
+            } else {
+                ObjWriteVar (0);
+            }
+
+            /* Lexical level */
+            ObjWriteVar (S->Level);
+
+            /* Scope flags (currently always zero) */
+            ObjWriteVar (0);
+
+            /* Type of scope */
+            ObjWriteVar (S->Type);
+
+            /* Name of the scope */
+            ObjWriteVar (S->Name);
+
+            /* Segment ranges for this scope */
+            WriteSegRanges (&S->SegRanges);
+
+            /* Next scope */
+            S = S->Next;
+        }
+
+    } else {
+
+        /* No debug info requested */
+        ObjWriteVar (0);
+
+    }
+
+    /* Done writing the scopes */
+    ObjEndScopes ();
+}
+
+