]> git.sur5r.net Git - cc65/blobdiff - src/ca65/symentry.c
Added variable symbols using .set
[cc65] / src / ca65 / symentry.c
index 9fe7f154fcd59c82930f389c74191cebba4b278e..8fcd5c0a505dbd7e4238ea106bfc73d543527166 100644 (file)
@@ -6,8 +6,8 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 1998-2003 Ullrich von Bassewitz                                       */
-/*               Römerstrasse 52                                             */
+/* (C) 1998-2004 Ullrich von Bassewitz                                       */
+/*               Römerstraße 52                                              */
 /*               D-70794 Filderstadt                                         */
 /* EMail:        uz@cc65.org                                                 */
 /*                                                                           */
@@ -44,7 +44,9 @@
 #include "expr.h"
 #include "global.h"
 #include "scanner.h"
+#include "segment.h"
 #include "spool.h"
+#include "studyexpr.h"          /* ### */
 #include "symentry.h"
 #include "symtab.h"
 
@@ -70,37 +72,7 @@ SymEntry* SymLast = 0;
 
 
 
-int IsLocalName (const char* Name)
-/* Return true if Name is the name of a local symbol */
-{
-    return (*Name == LocalStart);
-}
-
-
-
-int IsLocalNameId (unsigned Name)
-/* Return true if Name is the name of a local symbol */
-{
-    return (*GetString (Name) == LocalStart);
-}
-
-
-
-static unsigned SymAddrSize (const SymEntry* S)
-/* Get the default address size for a symbol. */
-{
-    /* Local symbols are always near (is this ok?) */
-    if (IsLocalNameId (S->Name)) {
-        return ADDR_SIZE_ABS;
-    }
-
-    /* Return the address size of the enclosing scope */
-    return S->SymTab->AddrSize;
-}
-
-
-
-SymEntry* NewSymEntry (const char* Name)
+SymEntry* NewSymEntry (const char* Name, unsigned Flags)
 /* Allocate a symbol table entry, initialize and return it */
 {
     /* Allocate memory */
@@ -112,8 +84,8 @@ SymEntry* NewSymEntry (const char* Name)
     S->Locals    = 0;
     S->SymTab    = 0;
     S->Pos       = CurPos;
-    S->Flags     = 0;
-    S->V.Expr    = 0;
+    S->Flags     = Flags;
+    S->Expr       = 0;
     S->ExprRefs   = AUTO_COLLECTION_INITIALIZER;
     S->ExportSize = ADDR_SIZE_DEFAULT;
     S->AddrSize   = ADDR_SIZE_DEFAULT;
@@ -130,6 +102,43 @@ SymEntry* NewSymEntry (const char* Name)
 
 
 
+int SymSearchTree (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;
+               }
+    }
+}
+
+
+
 void SymRef (SymEntry* S)
 /* Mark the given symbol as referenced */
 {
@@ -139,7 +148,65 @@ void SymRef (SymEntry* S)
 
 
 
-void SymDef (SymEntry* S, ExprNode* Expr, unsigned AddrSize, unsigned Flags)
+void SymTransferExprRefs (SymEntry* From, SymEntry* To)
+/* Transfer all expression references from one symbol to another. */
+{
+    unsigned I;
+
+    for (I = 0; I < CollCount (&From->ExprRefs); ++I) {
+
+        /* Get the expression node */
+        ExprNode* E = CollAtUnchecked (&From->ExprRefs, I);
+
+        /* Safety */
+        CHECK (E->Op == EXPR_SYMBOL && E->V.Sym == From);
+
+        /* Replace the symbol reference */
+        E->V.Sym = To;
+
+        /* Add the expression reference */
+        SymAddExprRef (To, E);
+    }
+
+    /* Remove all symbol references from the old symbol */
+    CollDeleteAll (&From->ExprRefs);
+}
+
+
+
+static void SymReplaceExprRefs (SymEntry* S)
+/* Replace the references to this symbol by a copy of the symbol expression */
+{
+    unsigned I;
+    long     Val;
+
+    /* Check if the expression is const and get its value */
+    int IsConst = IsConstExpr (S->Expr, &Val);
+    CHECK (IsConst);
+
+    /* Loop over all references */
+    for (I = 0; I < CollCount (&S->ExprRefs); ++I) {
+
+        /* Get the expression node */
+        ExprNode* E = CollAtUnchecked (&S->ExprRefs, I);
+
+        /* Safety */
+        CHECK (E->Op == EXPR_SYMBOL && E->V.Sym == S);
+
+        /* We cannot touch the root node, since there are pointers to it. 
+         * Replace it by a literal node.
+         */
+        E->Op = EXPR_LITERAL;
+        E->V.Val = Val;
+    }
+
+    /* Remove all symbol references from the symbol */
+    CollDeleteAll (&S->ExprRefs);
+}
+
+
+
+void SymDef (SymEntry* S, ExprNode* Expr, unsigned char AddrSize, unsigned Flags)
 /* Define a new symbol */
 {
     if (S->Flags & SF_IMPORT) {
@@ -147,32 +214,57 @@ void SymDef (SymEntry* S, ExprNode* Expr, unsigned AddrSize, unsigned Flags)
                Error ("Symbol `%s' is already an import", GetSymName (S));
                return;
     }
+    if ((Flags & SF_VAR) != 0 && (S->Flags & (SF_EXPORT | SF_GLOBAL))) {
+        /* Variable symbols cannot be exports or globals */
+        Error ("Var symbol `%s' cannot be an export or global symbol", GetSymName (S));
+        return;
+    }
     if (S->Flags & SF_DEFINED) {
-               /* Multiple definition */
-               Error ("Symbol `%s' is already defined", GetSymName (S));
-               S->Flags |= SF_MULTDEF;
-               return;
+               /* Multiple definition. In case of a variable, this is legal. */
+        if ((S->Flags & SF_VAR) == 0) {
+            Error ("Symbol `%s' is already defined", GetSymName (S));
+            S->Flags |= SF_MULTDEF;
+            return;
+        } else {
+            /* Redefinition must also be a variable symbol */
+            if ((Flags & SF_VAR) == 0) {
+                Error ("Symbol `%s' is already different kind", GetSymName (S));
+                return;
+            }
+            /* Delete the current symbol expression, since it will get
+             * replaced
+             */
+            FreeExpr (S->Expr);
+            S->Expr = 0;
+        }
     }
 
     /* Map a default address size to a real value */
     if (AddrSize == ADDR_SIZE_DEFAULT) {
-        AddrSize = SymAddrSize (S);
+        /* ### Must go! Delay address size calculation until end of assembly! */
+        ExprDesc ED;
+        ED_Init (&ED);
+        StudyExpr (Expr, &ED);
+        AddrSize = ED.AddrSize;
+        ED_Done (&ED);
     }
 
     /* Set the symbol value */
-    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->Expr = Expr;
+
+    /* In case of a variable symbol, walk over all expressions containing 
+     * this symbol and replace the (sub-)expression by the literal value of
+     * the tree. Be sure to replace the expression node in place, since there
+     * may be pointers to it.
+     */
+    if (Flags & SF_VAR) {
+        SymReplaceExprRefs (S);
     }
 
-    /* If the symbol is marked as global, export it */
+    /* If the symbol is marked as global, export it. Address size is checked
+     * below.
+     */
     if (S->Flags & SF_GLOBAL) {
-        S->ExportSize = S->AddrSize;
         S->Flags = (S->Flags & ~SF_GLOBAL) | SF_EXPORT;
     }
 
@@ -182,36 +274,28 @@ void SymDef (SymEntry* S, ExprNode* Expr, unsigned AddrSize, unsigned Flags)
 
     /* If the symbol is exported, check the address sizes */
     if (S->Flags & SF_EXPORT) {
-        if (S->AddrSize > S->ExportSize) {
-            Warning (1, "Address size mismatch for symbol `%s'", GetSymName (S));
+        if (S->ExportSize == ADDR_SIZE_DEFAULT) {
+            /* Use the real size of the symbol */
+            S->ExportSize = S->AddrSize;
+        } else if (S->AddrSize > S->ExportSize) {
+            /* We're exporting a symbol smaller than it actually is */
+            PWarning (GetSymPos (S), 1, "Symbol `%s' is %s but exported %s",
+                      GetSymName (S), AddrSizeToStr (S->AddrSize),
+                      AddrSizeToStr (S->ExportSize));
         }
     }
 
-    /* If the symbol is a ZP symbol, check if the value is in correct range */
-    if (S->AddrSize == ADDR_SIZE_ZP) {
-       /* Already marked as ZP symbol by some means */
-       if (!IsByteExpr (Expr)) {
-           Error ("Range error");
-       }
-    }
-
     /* If this is not a local symbol, remember it as the last global one */
-    if (!IsLocalNameId (S->Name)) {
+    if ((S->Flags & SF_LOCAL) == 0) {
                SymLast = S;
     }
 }
 
 
 
-void SymImport (SymEntry* S, unsigned AddrSize, unsigned Flags)
+void SymImport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
 /* Mark the given symbol as an imported symbol */
 {
-    /* Don't accept local symbols */
-    if (IsLocalNameId (S->Name)) {
-       Error ("Illegal use of a local symbol");
-       return;
-    }
-
     if (S->Flags & SF_DEFINED) {
        Error ("Symbol `%s' is already defined", GetSymName (S));
        S->Flags |= SF_MULTDEF;
@@ -223,20 +307,29 @@ void SymImport (SymEntry* S, unsigned AddrSize, unsigned Flags)
        return;
     }
 
-    /* Map a default address size to a real value */
+    /* If no address size is given, use the address size of the enclosing
+     * segment.
+     */
     if (AddrSize == ADDR_SIZE_DEFAULT) {
-        AddrSize = SymAddrSize (S);
+        AddrSize = GetCurrentSegAddrSize ();
     }
 
-    /* If the symbol is marked as import or global, check the symbol flags,
-     * then do silently remove the global flag
+    /* If the symbol is marked as import or global, check the address size,
+     * then do silently remove the global flag.
      */
-    if (S->Flags & (SF_IMPORT | SF_GLOBAL)) {
-       if ((Flags & SF_FORCED) != (S->Flags & SF_FORCED) ||
-            AddrSize != S->AddrSize) {
+    if (S->Flags & SF_IMPORT) {
+       if ((Flags & SF_FORCED) != (S->Flags & SF_FORCED)) {
                    Error ("Redeclaration mismatch for symbol `%s'", GetSymName (S));
        }
+        if (AddrSize != S->AddrSize) {
+            Error ("Address size mismatch for symbol `%s'", GetSymName (S));
+        }
+    }
+    if (S->Flags & SF_GLOBAL) {
         S->Flags &= ~SF_GLOBAL;
+        if (AddrSize != S->AddrSize) {
+            Error ("Address size mismatch for symbol `%s'", GetSymName (S));
+       }
     }
 
     /* Set the symbol data */
@@ -246,36 +339,38 @@ void SymImport (SymEntry* S, unsigned AddrSize, unsigned Flags)
 
 
 
-void SymExport (SymEntry* S, unsigned AddrSize, unsigned Flags)
+void SymExport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
 /* Mark the given symbol as an exported symbol */
 {
-    /* Don't accept local symbols */
-    if (IsLocalNameId (S->Name)) {
-       Error ("Illegal use of a local symbol");
-       return;
-    }
-
     /* Check if it's ok to export the symbol */
     if (S->Flags & SF_IMPORT) {
        /* The symbol is already marked as imported external symbol */
        Error ("Symbol `%s' is already an import", GetSymName (S));
        return;
     }
+    if (S->Flags & SF_VAR) {
+        /* Variable symbols cannot be exported */
+        Error ("Var symbol `%s' cannot be exported", GetSymName (S));
+        return;
+    }
 
-    /* Map a default address size to a real value */
-    if (AddrSize == ADDR_SIZE_DEFAULT) {
-        AddrSize = SymAddrSize (S);
+    /* If the symbol was marked as global before, remove the global flag and
+     * proceed, but check the address size.
+     */
+    if (S->Flags & SF_GLOBAL) {
+        if (AddrSize != S->ExportSize) {
+            Error ("Address size mismatch for symbol `%s'", GetSymName (S));
+        }
+        S->Flags &= ~SF_GLOBAL;
     }
 
-    /* If the symbol was already marked as an export or global, check if
-     * this was done specifiying the same address size. In case of a global
-     * declaration, silently remove the global flag.
+    /* If the symbol was already marked as an export, but wasn't defined
+     * before, the address sizes in both definitions must match.
      */
-    if (S->Flags & (SF_EXPORT | SF_GLOBAL)) {
+    if ((S->Flags & (SF_EXPORT|SF_DEFINED)) == SF_EXPORT) {
         if (S->ExportSize != AddrSize) {
             Error ("Address size mismatch for symbol `%s'", GetSymName (S));
         }
-        S->Flags &= ~SF_GLOBAL;
     }
     S->ExportSize = AddrSize;
 
@@ -283,8 +378,14 @@ void SymExport (SymEntry* S, unsigned AddrSize, unsigned Flags)
      * exported size.
      */
     if (S->Flags & SF_DEFINED) {
-        if (S->AddrSize > S->ExportSize) {
-            Warning (1, "Address size mismatch for symbol `%s'", GetSymName (S));
+        if (S->ExportSize == ADDR_SIZE_DEFAULT) {
+            /* No export size given, use the real size of the symbol */
+            S->ExportSize = S->AddrSize;
+        } else if (S->AddrSize > S->ExportSize) {
+            /* We're exporting a symbol smaller than it actually is */
+            Warning (1, "Symbol `%s' is %s but exported %s",
+                     GetSymName (S), AddrSizeToStr (S->AddrSize),
+                     AddrSizeToStr (S->ExportSize));
         }
     }
 
@@ -294,171 +395,201 @@ void SymExport (SymEntry* S, unsigned AddrSize, unsigned Flags)
 
 
 
-void SymGlobal (SymEntry* S, unsigned AddrSize, unsigned Flags)
+void SymGlobal (SymEntry* S, unsigned char AddrSize, unsigned Flags)
 /* Mark the given symbol as a global symbol, that is, as a symbol that is
  * either imported or exported.
  */
 {
-    /* Don't accept local symbols */
-    if (IsLocalNameId (S->Name)) {
-       Error ("Illegal use of a local symbol");
-       return;
-    }
-
-    /* Map a default address size to a real value */
-    if (AddrSize == ADDR_SIZE_DEFAULT) {
-        AddrSize = SymAddrSize (S);
+    if (S->Flags & SF_VAR) {
+        /* Variable symbols cannot be exported or imported */
+        Error ("Var symbol `%s' cannot be made global", GetSymName (S));
+        return;
     }
 
-    /* If the symbol is already marked as import or export, check the
-     * size of the definition, then bail out.
+    /* If the symbol is already marked as import, the address size must match.
+     * Apart from that, ignore the global declaration.
      */
     if (S->Flags & SF_IMPORT) {
+        if (AddrSize == ADDR_SIZE_DEFAULT) {
+            /* Use the size of the current segment */
+            AddrSize = GetCurrentSegAddrSize ();
+        }
         if (AddrSize != S->AddrSize) {
             Error ("Address size mismatch for symbol `%s'", GetSymName (S));
         }
         return;
     }
+
+    /* If the symbol is already an export: If it is not defined, the address
+     * sizes must match.
+     */
     if (S->Flags & SF_EXPORT) {
+        if ((S->Flags & SF_DEFINED) == 0) {
+            /* Symbol is undefined */
+            if (AddrSize != S->ExportSize) {
+                Error ("Address size mismatch for symbol `%s'", GetSymName (S));
+            }
+        } else if (AddrSize != ADDR_SIZE_DEFAULT) {
+            /* Symbol is defined and address size given */
+            if (AddrSize != S->ExportSize) {
+                Error ("Address size mismatch for symbol `%s'", GetSymName (S));
+            }
+        }
+        return;
+    }
+
+    /* If the symbol is already marked as global, the address size must match.
+     * Use the ExportSize here, since it contains the actual address size
+     * passed to this function.
+     */
+    if (S->Flags & SF_GLOBAL) {
         if (AddrSize != S->ExportSize) {
             Error ("Address size mismatch for symbol `%s'", GetSymName (S));
         }
         return;
     }
 
-    /* If the symbol is already defined, export it. Otherwise mark it as
-     * global.
+    /* If we come here, the symbol was neither declared as export, import or
+     * global before. Check if it is already defined, in which case it will
+     * become an export. If it is not defined, mark it as global and remember
+     * the given address sizes.
      */
     if (S->Flags & SF_DEFINED) {
         /* The symbol is defined, export it */
-        if (S->ExportSize != AddrSize) {
-            Error ("Address size mismatch for symbol `%s'", GetSymName (S));
+        S->ExportSize = AddrSize;
+        if (S->ExportSize == ADDR_SIZE_DEFAULT) {
+            /* No export size given, use the real size of the symbol */
+            S->ExportSize = S->AddrSize;
+        } else if (S->AddrSize > S->ExportSize) {
+            /* We're exporting a symbol smaller than it actually is */
+            Warning (1, "Symbol `%s' is %s but exported %s",
+                     GetSymName (S), AddrSizeToStr (S->AddrSize),
+                     AddrSizeToStr (S->ExportSize));
         }
         S->Flags |= (SF_EXPORT | Flags);
-        S->ExportSize = AddrSize;
     } else {
-        S->Flags |= (SF_GLOBAL | Flags);
+        /* Since we don't know if the symbol will get exported or imported,
+         * remember two different address sizes: One for an import in AddrSize,
+         * and the other one for an export in ExportSize.
+         */
         S->AddrSize = AddrSize;
+        if (S->AddrSize == ADDR_SIZE_DEFAULT) {
+            /* Use the size of the current segment */
+            S->AddrSize = GetCurrentSegAddrSize ();
+        }
+        S->ExportSize = AddrSize;
+        S->Flags |= (SF_GLOBAL | Flags);
     }
 }
 
 
 
-int SymIsDef (const SymEntry* S)
-/* Return true if the given symbol is already defined */
-{
-    return (S->Flags & SF_DEFINED) != 0;
-}
-
-
-
-int SymIsRef (const SymEntry* S)
-/* Return true if the given symbol has been referenced */
-{
-    return (S->Flags & SF_REFERENCED) != 0;
-}
-
-
-
-int SymIsImport (const SymEntry* S)
-/* Return true if the given symbol is marked as import */
+void SymConDes (SymEntry* S, unsigned char AddrSize, 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.
+ */
 {
-    /* Resolve trampoline entries */
-    if (S->Flags & SF_TRAMPOLINE) {
-       S = S->V.Sym;
+    /* 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);
+
+    /* Check for errors */
+    if (S->Flags & SF_IMPORT) {
+               /* The symbol is already marked as imported external symbol */
+               Error ("Symbol `%s' is already an import", GetSymName (S));
+               return;
     }
-
-    /* Check the import flag */
-    return (S->Flags & SF_IMPORT) != 0;
-}
-
-
-
-int SymHasExpr (const SymEntry* S)
-/* Return true if the given symbol has an associated expression */
-{
-    /* Resolve trampoline entries */
-    if (S->Flags & SF_TRAMPOLINE) {
-       S = S->V.Sym;
+    if (S->Flags & SF_VAR) {
+        /* Variable symbols cannot be exported or imported */
+        Error ("Var symbol `%s' cannot be exported", GetSymName (S));
+        return;
     }
 
-    /* Check the expression */
-    return ((S->Flags & SF_DEFINED) != 0 &&
-                   (S->Flags & SF_IMPORT)  == 0 &&
-                   (S->Flags & SF_CONST)   == 0);
-}
-
-
+    /* If the symbol was already marked as an export or global, check if
+     * this was done specifiying the same address size. In case of a global
+     * declaration, silently remove the global flag.
+     */
+    if (S->Flags & (SF_EXPORT | SF_GLOBAL)) {
+        if (S->ExportSize != AddrSize) {
+            Error ("Address size mismatch for symbol `%s'", GetSymName (S));
+        }
+        S->Flags &= ~SF_GLOBAL;
+    }
+    S->ExportSize = AddrSize;
 
-void SymFinalize (SymEntry* S)
-/* Finalize a symbol expression if there is one */
-{
-    /* Resolve trampoline entries */
-    if (S->Flags & SF_TRAMPOLINE) {
-               S = S->V.Sym;
+    /* If the symbol is already defined, check symbol size against the
+     * exported size.
+     */
+    if (S->Flags & SF_DEFINED) {
+        if (S->ExportSize == ADDR_SIZE_DEFAULT) {
+            /* Use the real size of the symbol */
+            S->ExportSize = S->AddrSize;
+        } else if (S->AddrSize != S->ExportSize) {
+            Error ("Address size mismatch for symbol `%s'", GetSymName (S));
+        }
     }
 
-    /* Check if we have an expression */
-    if ((S->Flags & SF_FINALIZED) == 0 && SymHasExpr (S)) {
-               S->V.Expr = FinalizeExpr (S->V.Expr);
-        S->Flags |= SF_FINALIZED;
+    /* 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'", GetSymName (S));
+       }
     }
+    S->ConDesPrio[Type] = Prio;
+
+    /* Set the symbol data */
+    S->Flags |= (SF_EXPORT | SF_REFERENCED);
 }
 
 
 
-void SymMarkUser (SymEntry* S)
-/* Set a user mark on the specified symbol */
+void SymExportFromGlobal (SymEntry* S)
+/* Called at the end of assembly. Converts a global symbol that is defined
+ * into an export.
+ */
 {
-    /* Resolve trampoline entries */
-    if (S->Flags & SF_TRAMPOLINE) {
-               S = S->V.Sym;
-    }
-
-    /* Set the bit */
-    S->Flags |= SF_USER;
+    /* Remove the global flag and make the symbol an export */
+    S->Flags &= ~SF_GLOBAL;
+    S->Flags |= SF_EXPORT;
 }
 
 
 
-void SymUnmarkUser (SymEntry* S)
-/* Remove a user mark from the specified symbol */
+void SymImportFromGlobal (SymEntry* S)
+/* Called at the end of assembly. Converts a global symbol that is undefined
+ * into an import.
+ */
 {
-    /* Resolve trampoline entries */
-    if (S->Flags & SF_TRAMPOLINE) {
-       S = S->V.Sym;
-    }
-
-    /* Reset the bit */
-    S->Flags &= ~SF_USER;
+    /* Remove the global flag and make it an import */
+    S->Flags &= ~SF_GLOBAL;
+    S->Flags |= SF_IMPORT;
 }
 
 
 
-int SymHasUserMark (SymEntry* S)
-/* Return the state of the user mark for the specified symbol */
+int SymIsConst (SymEntry* S, long* Val)
+/* Return true if the given symbol has a constant value. If Val is not NULL
+ * and the symbol has a constant value, store it's value there.
+ */
 {
-    /* Resolve trampoline entries */
-    if (S->Flags & SF_TRAMPOLINE) {
-       S = S->V.Sym;
-    }
-
-    /* Check the bit */
-    return (S->Flags & SF_USER) != 0;
+    /* Check for constness */
+    return (SymHasExpr (S) && IsConstExpr (S->Expr, Val));
 }
 
 
 
-long GetSymVal (SymEntry* S)
-/* Return the symbol value */
+SymTable* GetSymParentScope (SymEntry* S)
+/* Get the parent scope of the symbol (not the one it is defined in). Return
+ * NULL if the symbol is a cheap local, or defined on global level.
+ */
 {
-    /* Resolve trampoline entries */
-    if (S->Flags & SF_TRAMPOLINE) {
-       S = S->V.Sym;
-    }
-
-    PRECONDITION ((S->Flags & SF_DEFINED) != 0 && (S->Flags & SF_CONST) != 0);
-    return S->V.Val;
+    return (S->SymTab && S->SymTab->Parent)? S->SymTab->Parent : 0;
 }
 
 
@@ -466,53 +597,40 @@ long GetSymVal (SymEntry* S)
 struct 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;
+    PRECONDITION (S != 0 && SymHasExpr (S));
+    return S->Expr;
 }
 
 
 
-const char* GetSymName (SymEntry* S)
-/* Return the name of the symbol */
+const struct ExprNode* SymResolve (const SymEntry* S)
+/* Helper function for DumpExpr. Resolves a symbol into an expression or return
+ * NULL. Do not call in other contexts!
+ */
 {
-    /* Resolve trampoline entries */
-    if (S->Flags & SF_TRAMPOLINE) {
-       S = S->V.Sym;
-    }
-    return GetString (S->Name);
+    return SymHasExpr (S)? S->Expr : 0;
 }
 
 
 
-unsigned GetSymIndex (SymEntry* S)
-/* Return the symbol index for the given symbol */
+long GetSymVal (SymEntry* S)
+/* Return the value of a symbol assuming it's constant. FAIL will be called
+ * in case the symbol is undefined or not constant.
+ */
 {
-    /* Resolve trampoline entries */
-    if (S->Flags & SF_TRAMPOLINE) {
-       S = S->V.Sym;
-    }
-    PRECONDITION (S != 0 && (S->Flags & SF_INDEXED));
-    return S->Index;
+    long Val;
+    CHECK (S != 0 && SymHasExpr (S) && IsConstExpr (GetSymExpr (S), &Val));
+    return Val;
 }
 
 
 
-const FilePos* GetSymPos (SymEntry* S)
-/* Return the position of first occurence in the source for the given symbol */
+unsigned GetSymIndex (const 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);
-    return &S->Pos;
+    PRECONDITION (S != 0 && (S->Flags & SF_INDEXED) != 0);
+    return S->Index;
 }
 
 
 
-