} else {
         /* Mark the symbol as referenced */
         SymRef (S);
-        /* Create symbol node */
-        return GenSymExpr (S);
+        /* If the symbol is a variable, return just its value, otherwise
+         * return a reference to the symbol.
+         */
+        if (SymIsVar (S)) {
+            return CloneExpr (GetSymExpr (S));
+        } else {
+            /* Create symbol node */
+            return GenSymExpr (S);
+        }
     }
 }
 
 
          * is no colon, it's an assignment.
          */
         if (Tok == TOK_EQ || Tok == TOK_ASSIGN) {
-            /* If it's an assign token, we have a label */
+
+            /* Determine the symbol flags from the assignment token */
             unsigned Flags = (Tok == TOK_ASSIGN)? SF_LABEL : SF_NONE;
+
             /* Skip the '=' */
             NextTok ();
+
             /* Define the symbol with the expression following the '=' */
             SymDef (Sym, Expression(), ADDR_SIZE_DEFAULT, Flags);
+
             /* Don't allow anything after a symbol definition */
             ConsumeSep ();
             return;
+
+        } else if (Tok == TOK_SET) {
+
+            ExprNode* Expr;
+
+            /* .SET defines variables (= redefinable symbols) */
+            NextTok ();
+
+            /* Read the assignment expression, which must be constant */
+            Expr = GenLiteralExpr (ConstExpression ());
+
+            /* Define the symbol with the constant expression following
+             * the '='
+             */
+            SymDef (Sym, Expr, ADDR_SIZE_DEFAULT, SF_VAR);
+
+            /* Don't allow anything after a symbol definition */
+            ConsumeSep ();
+            return;
+
         } else {
+
             /* A label. Remember the current segment, so we can later
              * determine the size of the data stored under the label.
              */
 
 
 
 
-static void FuncLeft (void)
-/* Handle the .LEFT function */
-{
-    long               Count;
-    TokList*   List;
-
-    /* Skip it */
-    NextTok ();
-
-    /* Left paren expected */
-    ConsumeLParen ();
-
-    /* Count argument */
-    Count = ConstExpression ();
-    if (Count < 0 || Count > 100) {
-       Error ("Range error");
-       Count = 1;
-    }
-    ConsumeComma ();
-
-    /* Read the token list */
-    List = CollectTokens (0, (unsigned) Count);
-
-    /* Since we want to insert the list before the now current token, we have
-     * to save the current token in some way and then skip it. To do this, we
-     * will add the current token at the end of the token list (so the list
-     * will never be empty), push the token list, and then skip the current
-     * token. This will replace the current token by the first token from the
-     * list (which will be the old current token in case the list was empty).
-     */
-    AddCurTok (List);
-
-    /* Insert it into the scanner feed */
-    PushTokList (List, ".LEFT");
-
-    /* Skip the current token */
-    NextTok ();
-}
-
-
-
 static void NoIdent (void)
 /* Print an error message and skip the remainder of the line */
 {
 
 
 
+static void FuncLeft (void)
+/* Handle the .LEFT function */
+{
+    long               Count;
+    TokList*   List;
+
+    /* Skip it */
+    NextTok ();
+
+    /* Left paren expected */
+    ConsumeLParen ();
+
+    /* Count argument. Correct negative counts to zero. */
+    Count = ConstExpression ();
+    if (Count < 0) {
+       Count = 1;
+    }
+    ConsumeComma ();
+
+    /* Read the token list */
+    List = CollectTokens (0, (unsigned) Count);
+
+    /* Since we want to insert the list before the now current token, we have
+     * to save the current token in some way and then skip it. To do this, we
+     * will add the current token at the end of the token list (so the list
+     * will never be empty), push the token list, and then skip the current
+     * token. This will replace the current token by the first token from the
+     * list (which will be the old current token in case the list was empty).
+     */
+    AddCurTok (List);
+
+    /* Insert it into the scanner feed */
+    PushTokList (List, ".LEFT");
+
+    /* Skip the current token */
+    NextTok ();
+}
+
+
+
 static void FuncMid (void)
 /* Handle the .MID function */
 {
     /* Left paren expected */
     ConsumeLParen ();
 
-    /* Start argument */
+    /* Start argument. Since the start argument can get negative with 
+     * expressions like ".tcount(arg)-2", we correct it to zero silently.
+     */
     Start = ConstExpression ();
     if (Start < 0 || Start > 100) {
-       Error ("Range error");
        Start = 0;
     }
     ConsumeComma ();
 
-    /* Count argument */
+    /* Count argument. Similar as above, we will accept negative counts and
+     * correct them to zero silently.
+     */
     Count = ConstExpression ();
-    if (Count < 0 || Count > 100) {
-       Error ("Range error");
-       Count = 1;
+    if (Count < 0) {
+       Count = 0;
     }
     ConsumeComma ();
 
     /* Left paren expected */
     ConsumeLParen ();
 
-    /* Count argument */
+    /* Count argument. Correct negative counts to zero. */
     Count = ConstExpression ();
-    if (Count < 0 || Count > 100) {
-       Error ("Range error");
-       Count = 1;
+    if (Count < 0) {
+       Count = 0;
     }
     ConsumeComma ();
 
 
     { ccNone,          DoROData        },
     { ccNone,           DoScope         },
     { ccNone,          DoSegment       },
+    { ccNone,           DoUnexpected    },      /* .SET */
     { ccNone,                  DoSetCPU        },
     { ccNone,           DoUnexpected    },      /* .SIZEOF */
-    { ccNone,          DoSmart         },                  
+    { ccNone,          DoSmart         },
     { ccNone,           DoUnexpected    },      /* .SPRINTF */
     { ccNone,          DoUnexpected    },      /* .STRAT */
     { ccNone,                  DoUnexpected    },      /* .STRING */
 
     { ".RODATA",       TOK_RODATA      },
     { ".SCOPE",         TOK_SCOPE       },
     { ".SEGMENT",      TOK_SEGMENT     },
+    { ".SET",           TOK_SET         },
     { ".SETCPU",       TOK_SETCPU      },
     { ".SHL",          TOK_SHL         },
     { ".SHR",          TOK_SHR         },
 
     TOK_RODATA,
     TOK_SCOPE,
     TOK_SEGMENT,
+    TOK_SET,
     TOK_SETCPU,
     TOK_SIZEOF,
     TOK_SMART,
 
 
 
 
+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 */
 {
                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 */
     /* Set the symbol value */
     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. Address size is checked
      * below.
      */
        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;
+    }
 
     /* If the symbol was marked as global before, remove the global flag and
      * proceed, but check the address size.
  * either imported or exported.
  */
 {
+    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, the address size must match.
      * Apart from that, ignore the global declaration.
      */
                Error ("Symbol `%s' is already an import", GetSymName (S));
                return;
     }
+    if (S->Flags & SF_VAR) {
+        /* Variable symbols cannot be exported or imported */
+        Error ("Var symbol `%s' cannot be exported", GetSymName (S));
+        return;
+    }
 
     /* 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
 
 #define SF_GLOBAL      0x0010          /* Global symbol */
 #define SF_LOCAL        0x0020          /* Cheap local symbol */
 #define SF_LABEL        0x0080          /* Used as a label */
-#define SF_FORCED       0x0100          /* Forced import, SF_IMPORT also set */
+#define SF_VAR          0x0100          /* Variable symbol */
+#define SF_FORCED       0x0400          /* Forced import, SF_IMPORT also set */
 #define SF_INDEXED     0x0800          /* Index is valid */
 #define SF_MULTDEF             0x2000          /* Multiply defined symbol */
 #define        SF_DEFINED      0x4000          /* Defined */
 #  define SymIsExport(S)  (((S)->Flags & SF_EXPORT) != 0)
 #endif
 
+#if defined(HAVE_INLINE)
+INLINE int SymIsVar (const SymEntry* S)
+/* Return true if the given symbol is marked as variable */
+{
+    /* Check the variable flag */
+    return (S->Flags & SF_VAR) != 0;
+}
+#else
+#  define SymIsVar(S)   (((S)->Flags & SF_VAR) != 0)
+#endif
+
 int SymIsConst (SymEntry* Sym, 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.