]> git.sur5r.net Git - cc65/blobdiff - src/ca65/expr.c
Removed (pretty inconsistently used) tab chars from source code base.
[cc65] / src / ca65 / expr.c
index af26c0dfe47a0f25f74840507b7ac14bf58f46b3..ecbd22a27ba902abd81be1ed7d4cfee25fd9f69b 100644 (file)
@@ -1,15 +1,15 @@
 /*****************************************************************************/
 /*                                                                           */
-/*                                 expr.c                                   */
+/*                                  expr.c                                   */
 /*                                                                           */
-/*            Expression evaluation for the ca65 macroassembler             */
+/*             Expression evaluation for the ca65 macroassembler             */
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 1998-2003 Ullrich von Bassewitz                                       */
-/*               Römerstrasse 52                                             */
-/*               D-70794 Filderstadt                                         */
-/* EMail:        uz@cc65.org                                                 */
+/* (C) 1998-2012, Ullrich von Bassewitz                                      */
+/*                Roemerstrasse 52                                           */
+/*                D-70794 Filderstadt                                        */
+/* EMail:         uz@cc65.org                                                */
 /*                                                                           */
 /*                                                                           */
 /* This software is provided 'as-is', without any expressed or implied       */
 
 /* common */
 #include "check.h"
+#include "cpu.h"
 #include "exprdefs.h"
 #include "print.h"
+#include "shift.h"
+#include "segdefs.h"
+#include "strbuf.h"
 #include "tgttrans.h"
+#include "version.h"
 #include "xmalloc.h"
 
 /* ca65 */
 #include "error.h"
+#include "expr.h"
 #include "global.h"
 #include "instr.h"
 #include "nexttok.h"
-#include "objcode.h"
 #include "objfile.h"
+#include "segment.h"
+#include "sizeof.h"
+#include "studyexpr.h"
+#include "symbol.h"
 #include "symtab.h"
 #include "toklist.h"
 #include "ulabel.h"
-#include "expr.h"
 
 
 
 /*****************************************************************************/
-/*                                          Data                                    */
+/*                                   Data                                    */
 /*****************************************************************************/
 
 
  * number of freed nodes for later and remember them in a single linked list
  * using the Left link.
  */
-#define        MAX_FREE_NODES  64
-static ExprNode*       FreeExprNodes = 0;
-static unsigned                FreeNodeCount = 0;
+#define MAX_FREE_NODES  64
+static ExprNode*        FreeExprNodes = 0;
+static unsigned         FreeNodeCount = 0;
 
 
 
 /*****************************************************************************/
-/*                                 Helpers                                  */
+/*                                  Helpers                                  */
 /*****************************************************************************/
 
 
 
-static ExprNode* NewExprNode (void)
+static ExprNode* NewExprNode (unsigned Op)
 /* Create a new expression node */
 {
     ExprNode* N;
 
     /* Do we have some nodes in the list already? */
-    if (FreeExprNodes) {
-       /* Use first node from list */
-       N = FreeExprNodes;
-       FreeExprNodes = N->Left;
+    if (FreeNodeCount) {
+        /* Use first node from list */
+        N = FreeExprNodes;
+        FreeExprNodes = N->Left;
+        --FreeNodeCount;
     } else {
-       /* Allocate fresh memory */
+        /* Allocate fresh memory */
         N = xmalloc (sizeof (ExprNode));
     }
-    N->Op = EXPR_NULL;
+    N->Op = Op;
     N->Left = N->Right = 0;
     N->Obj = 0;
 
@@ -108,21 +117,27 @@ static void FreeExprNode (ExprNode* E)
 /* Free a node */
 {
     if (E) {
-       if (FreeNodeCount < MAX_FREE_NODES) {
-           /* Remember this node for later */
-           E->Left = FreeExprNodes;
-           FreeExprNodes = E;
-       } else {
-           /* Free the memory */
-           xfree (E);
-       }
+        if (E->Op == EXPR_SYMBOL) {
+            /* Remove the symbol reference */
+            SymDelExprRef (E->V.Sym, E);
+        }
+        /* Place the symbol into the free nodes list if possible */
+        if (FreeNodeCount < MAX_FREE_NODES) {
+            /* Remember this node for later */
+            E->Left = FreeExprNodes;
+            FreeExprNodes = E;
+            ++FreeNodeCount;
+        } else {
+            /* Free the memory */
+            xfree (E);
+        }
     }
 }
 
 
 
 /*****************************************************************************/
-/*                                          Code                                    */
+/*                                   Code                                    */
 /*****************************************************************************/
 
 
@@ -142,51 +157,244 @@ int IsByteRange (long Val)
 int IsWordRange (long Val)
 /* Return true if this is a word value */
 {
-    return (Val & ~0xFFFF) == 0;
+    return (Val & ~0xFFFFL) == 0;
+}
+
+
+
+int IsFarRange (long Val)
+/* Return true if this is a far (24 bit) value */
+{
+    return (Val & ~0xFFFFFFL) == 0;
+}
+
+
+
+int IsEasyConst (const ExprNode* E, long* Val)
+/* Do some light checking if the given node is a constant. Don't care if E is
+ * a complex expression. If E is a constant, return true and place its value
+ * into Val, provided that Val is not NULL.
+ */
+{
+    /* Resolve symbols, follow symbol chains */
+    while (E->Op == EXPR_SYMBOL) {
+        E = SymResolve (E->V.Sym);
+        if (E == 0) {
+            /* Could not resolve */
+            return 0;
+        }
+    }
+
+    /* Symbols resolved, check for a literal */
+    if (E->Op == EXPR_LITERAL) {
+        if (Val) {
+            *Val = E->V.IVal;
+        }
+        return 1;
+    }
+
+    /* Not found to be a const according to our tests */
+    return 0;
 }
 
 
 
-static int FuncBlank (void)
+static ExprNode* LoByte (ExprNode* Operand)
+/* Return the low byte of the given expression */
+{
+    ExprNode* Expr;
+    long      Val;
+
+    /* Special handling for const expressions */
+    if (IsEasyConst (Operand, &Val)) {
+        FreeExpr (Operand);
+        Expr = GenLiteralExpr (Val & 0xFF);
+    } else {
+        /* Extract byte #0 */
+        Expr = NewExprNode (EXPR_BYTE0);
+        Expr->Left = Operand;
+    }
+    return Expr;
+}
+
+
+
+static ExprNode* HiByte (ExprNode* Operand)
+/* Return the high byte of the given expression */
+{
+    ExprNode* Expr;
+    long      Val;
+
+    /* Special handling for const expressions */
+    if (IsEasyConst (Operand, &Val)) {
+        FreeExpr (Operand);
+        Expr = GenLiteralExpr ((Val >> 8) & 0xFF);
+    } else {
+        /* Extract byte #1 */
+        Expr = NewExprNode (EXPR_BYTE1);
+        Expr->Left = Operand;
+    }
+    return Expr;
+}
+
+
+
+static ExprNode* Bank (ExprNode* Operand)
+/* Return the bank of the given segmented expression */
+{
+    /* Generate the bank expression */
+    ExprNode* Expr = NewExprNode (EXPR_BANK);
+    Expr->Left = Operand;
+
+    /* Return the result */
+    return Expr;
+}
+
+
+
+static ExprNode* BankByte (ExprNode* Operand)
+/* Return the bank byte of the given expression */
+{
+    ExprNode* Expr;
+    long      Val;
+
+    /* Special handling for const expressions */
+    if (IsEasyConst (Operand, &Val)) {
+        FreeExpr (Operand);
+        Expr = GenLiteralExpr ((Val >> 16) & 0xFF);
+    } else {
+        /* Extract byte #2 */
+        Expr = NewExprNode (EXPR_BYTE2);
+        Expr->Left = Operand;
+    }
+    return Expr;
+}
+
+
+
+static ExprNode* LoWord (ExprNode* Operand)
+/* Return the low word of the given expression */
+{
+    ExprNode* Expr;
+    long      Val;
+
+    /* Special handling for const expressions */
+    if (IsEasyConst (Operand, &Val)) {
+        FreeExpr (Operand);
+        Expr = GenLiteralExpr (Val & 0xFFFF);
+    } else {
+        /* Extract word #0 */
+        Expr = NewExprNode (EXPR_WORD0);
+        Expr->Left = Operand;
+    }
+    return Expr;
+}
+
+
+
+static ExprNode* HiWord (ExprNode* Operand)
+/* Return the high word of the given expression */
+{
+    ExprNode* Expr;
+    long      Val;
+
+    /* Special handling for const expressions */
+    if (IsEasyConst (Operand, &Val)) {
+        FreeExpr (Operand);
+        Expr = GenLiteralExpr ((Val >> 16) & 0xFFFF);
+    } else {
+        /* Extract word #1 */
+        Expr = NewExprNode (EXPR_WORD1);
+        Expr->Left = Operand;
+    }
+    return Expr;
+}
+
+
+
+static ExprNode* Symbol (SymEntry* S)
+/* Reference a symbol and return an expression for it */
+{
+    if (S == 0) {
+        /* Some weird error happened before */
+        return GenLiteralExpr (0);
+    } else {
+        /* Mark the symbol as referenced */
+        SymRef (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);
+        }
+    }
+}
+
+
+
+ExprNode* FuncBank (void)
+/* Handle the .BANK builtin function */
+{
+    return Bank (Expression ());
+}
+
+
+
+ExprNode* FuncBankByte (void)
+/* Handle the .BANKBYTE builtin function */
+{
+    return BankByte (Expression ());
+}
+
+
+
+static ExprNode* FuncBlank (void)
 /* Handle the .BLANK builtin function */
 {
-    /* Assume no tokens if the closing brace follows (this is not correct in
-     * all cases, since the token may be the closing brace, but this will
-     * give a syntax error anyway and may not be handled by .BLANK.
+    /* We have a list of tokens that ends with the closing paren. Skip
+     * the tokens, and count them. Allow optionally curly braces.
      */
-    if (Tok == TOK_RPAREN) {
-       /* No tokens */
-       return 1;
-    } else {
-       /* Skip any tokens */
-       int Braces = 0;
-       while (!TokIsSep (Tok)) {
-           if (Tok == TOK_LPAREN) {
-               ++Braces;
-           } else if (Tok == TOK_RPAREN) {
-               if (Braces == 0) {
-                   /* Done */
-                   break;
-               } else {
-                   --Braces;
-               }
-           }
-           NextTok ();
-       }
-       return 0;
+    token_t Term = GetTokListTerm (TOK_RPAREN);
+    unsigned Count = 0;
+    while (CurTok.Tok != Term) {
+
+        /* Check for end of line or end of input. Since the calling function
+         * will check for the closing paren, we don't need to print an error
+         * here, just bail out.
+         */
+        if (TokIsSep (CurTok.Tok)) {
+            break;
+        }
+
+        /* One more token */
+        ++Count;
+
+        /* Skip the token */
+        NextTok ();
     }
+
+    /* If the list was enclosed in curly braces, skip the closing brace */
+    if (Term == TOK_RCURLY && CurTok.Tok == TOK_RCURLY) {
+        NextTok ();
+    }
+
+    /* Return true if the list was empty */
+    return GenLiteralExpr (Count == 0);
 }
 
 
 
-static int FuncConst (void)
+static ExprNode* FuncConst (void)
 /* Handle the .CONST builtin function */
 {
     /* Read an expression */
     ExprNode* Expr = Expression ();
 
     /* Check the constness of the expression */
-    int Result = IsConstExpr (Expr);
+    ExprNode* Result = GenLiteralExpr (IsConstExpr (Expr, 0));
 
     /* Free the expression */
     FreeExpr (Expr);
@@ -197,168 +405,153 @@ static int FuncConst (void)
 
 
 
-static int FuncDefined (void)
+static ExprNode* FuncDefined (void)
 /* Handle the .DEFINED builtin function */
 {
-    static const char* Keys[] = {
-               "ANY",
-       "GLOBAL",
-        "LOCAL",
-    };
-
-    char Name [sizeof (SVal)];
-    int Result = 0;
-    int Scope;
-
-    /* First argument is a symbol name */
-    if (Tok != TOK_IDENT) {
-       Error (ERR_IDENT_EXPECTED);
-       if (Tok != TOK_RPAREN) {
-           NextTok ();
-       }
-        return 0;
-    }
+    /* Parse the symbol name and search for the symbol */
+    SymEntry* Sym = ParseAnySymName (SYM_FIND_EXISTING);
 
-    /* Remember the name, then skip it */
-    strcpy (Name, SVal);
-    NextTok ();
+    /* Check if the symbol is defined */
+    return GenLiteralExpr (Sym != 0 && SymIsDef (Sym));
+}
 
-    /* Comma and scope spec may follow */
-    if (Tok == TOK_COMMA) {
 
-        /* Skip the comma */
-        NextTok ();
 
-        /* An identifier must follow */
-        if (Tok != TOK_IDENT) {
-            Error (ERR_IDENT_EXPECTED);
-            return 0;
-        }
+ExprNode* FuncHiByte (void)
+/* Handle the .HIBYTE builtin function */
+{
+    return HiByte (Expression ());
+}
 
-        /* Get the scope, then skip it */
-        Scope = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
-        NextTok ();
 
-        /* Check if we got a valid keyword */
-        if (Scope < 0) {
-            Error (ERR_ILLEGAL_SCOPE);
-            return 0;
-        }
 
-        /* Map the scope */
-        switch (Scope) {
-            case 0:     Scope = SCOPE_ANY;    break;
-            case 1:     Scope = SCOPE_GLOBAL; break;
-            case 2:     Scope = SCOPE_LOCAL;  break;
-            default:    Internal ("Invalid scope: %d", Scope);
-        }
+static ExprNode* FuncHiWord (void)
+/* Handle the .HIWORD builtin function */
+{
+    return HiWord (Expression ());
+}
 
-    } else {
 
-        /* Any scope */
-        Scope = SCOPE_ANY;
 
-    }
+ExprNode* FuncLoByte (void)
+/* Handle the .LOBYTE builtin function */
+{
+    return LoByte (Expression ());
+}
 
-    /* Search for the symbol */
-    Result = SymIsDef (SVal, Scope);
 
-    /* Done */
-    return Result;
+
+static ExprNode* FuncLoWord (void)
+/* Handle the .LOWORD builtin function */
+{
+    return LoWord (Expression ());
 }
 
 
 
-static int DoMatch (enum TC EqualityLevel)
+static ExprNode* DoMatch (enum TC EqualityLevel)
 /* Handle the .MATCH and .XMATCH builtin functions */
 {
     int Result;
     TokNode* Root = 0;
     TokNode* Last = 0;
-    TokNode* Node = 0;
+    TokNode* Node;
 
     /* A list of tokens follows. Read this list and remember it building a
      * single linked list of tokens including attributes. The list is
-     * terminated by a comma.
+     * either enclosed in curly braces, or terminated by a comma.
      */
-    while (Tok != TOK_COMMA) {
-
-       /* We may not end-of-line of end-of-file here */
-       if (TokIsSep (Tok)) {
-           Error (ERR_UNEXPECTED_EOL);
-           return 0;
-       }
-
-       /* Get a node with this token */
-       Node = NewTokNode ();
-
-       /* Insert the node into the list */
-       if (Last == 0) {
-                   Root = Node;
-       } else {
-           Last->Next = Node;
-       }
-       Last = Node;
-
-       /* Skip the token */
-       NextTok ();
+    token_t Term = GetTokListTerm (TOK_COMMA);
+    while (CurTok.Tok != Term) {
+
+        /* We may not end-of-line of end-of-file here */
+        if (TokIsSep (CurTok.Tok)) {
+            Error ("Unexpected end of line");
+            return GenLiteral0 ();
+        }
+
+        /* Get a node with this token */
+        Node = NewTokNode ();
+
+        /* Insert the node into the list */
+        if (Last == 0) {
+            Root = Node;
+        } else {
+            Last->Next = Node;
+        }
+        Last = Node;
+
+        /* Skip the token */
+        NextTok ();
     }
 
-    /* Skip the comma */
+    /* Skip the terminator token*/
     NextTok ();
 
-    /* Read the second list which is terminated by the right parenthesis and
-     * compare each token against the one in the first list.
+    /* If the token list was enclosed in curly braces, we expect a comma */
+    if (Term == TOK_RCURLY) {
+        ConsumeComma ();
+    }
+
+    /* Read the second list which is optionally enclosed in curly braces and
+     * terminated by the right parenthesis. Compare each token against the
+     * one in the first list.
      */
+    Term = GetTokListTerm (TOK_RPAREN);
     Result = 1;
     Node = Root;
-    while (Tok != TOK_RPAREN) {
-
-       /* We may not end-of-line of end-of-file here */
-       if (TokIsSep (Tok)) {
-           Error (ERR_UNEXPECTED_EOL);
-           return 0;
-       }
-
-       /* Compare the tokens if the result is not already known */
-       if (Result != 0) {
-           if (Node == 0) {
-               /* The second list is larger than the first one */
-               Result = 0;
-           } else if (TokCmp (Node) < EqualityLevel) {
-               /* Tokens do not match */
-               Result = 0;
-           }
-       }
-
-       /* Next token in first list */
-       if (Node) {
-           Node = Node->Next;
-       }
-
-               /* Next token in current list */
-       NextTok ();
+    while (CurTok.Tok != Term) {
+
+        /* We may not end-of-line of end-of-file here */
+        if (TokIsSep (CurTok.Tok)) {
+            Error ("Unexpected end of line");
+            return GenLiteral0 ();
+        }
+
+        /* Compare the tokens if the result is not already known */
+        if (Result != 0) {
+            if (Node == 0) {
+                /* The second list is larger than the first one */
+                Result = 0;
+            } else if (TokCmp (Node) < EqualityLevel) {
+                /* Tokens do not match */
+                Result = 0;
+            }
+        }
+
+        /* Next token in first list */
+        if (Node) {
+            Node = Node->Next;
+        }
+
+        /* Next token in current list */
+        NextTok ();
+    }
+
+    /* If the token list was enclosed in curly braces, eat the closing brace */
+    if (Term == TOK_RCURLY) {
+        NextTok ();
     }
 
     /* Check if there are remaining tokens in the first list */
     if (Node != 0) {
-       Result = 0;
+        Result = 0;
     }
 
     /* Free the token list */
     while (Root) {
-       Node = Root;
-       Root = Root->Next;
-       FreeTokNode (Node);
+        Node = Root;
+        Root = Root->Next;
+        FreeTokNode (Node);
     }
 
     /* Done, return the result */
-    return Result;
+    return GenLiteralExpr (Result);
 }
 
 
 
-static int FuncMatch (void)
+static ExprNode* FuncMatch (void)
 /* Handle the .MATCH function */
 {
     return DoMatch (tcSameToken);
@@ -366,43 +559,187 @@ static int FuncMatch (void)
 
 
 
-static int FuncReferenced (void)
+static ExprNode* FuncMax (void)
+/* Handle the .MAX function */
+{
+    ExprNode* Left;
+    ExprNode* Right;
+    ExprNode* Expr;
+    long LeftVal, RightVal;
+
+    /* Two arguments to the pseudo function */
+    Left = Expression ();
+    ConsumeComma ();
+    Right = Expression ();
+
+    /* Check if we can evaluate the value immediately */
+    if (IsEasyConst (Left, &LeftVal) && IsEasyConst (Right, &RightVal)) {
+        FreeExpr (Left);
+        FreeExpr (Right);
+        Expr = GenLiteralExpr ((LeftVal > RightVal)? LeftVal : RightVal);
+    } else {
+        /* Make an expression node */
+        Expr = NewExprNode (EXPR_MAX);
+        Expr->Left = Left;
+        Expr->Right = Right;
+    }
+    return Expr;
+}
+
+
+
+static ExprNode* FuncMin (void)
+/* Handle the .MIN function */
+{
+    ExprNode* Left;
+    ExprNode* Right;
+    ExprNode* Expr;
+    long LeftVal, RightVal;
+
+    /* Two arguments to the pseudo function */
+    Left = Expression ();
+    ConsumeComma ();
+    Right = Expression ();
+
+    /* Check if we can evaluate the value immediately */
+    if (IsEasyConst (Left, &LeftVal) && IsEasyConst (Right, &RightVal)) {
+        FreeExpr (Left);
+        FreeExpr (Right);
+        Expr = GenLiteralExpr ((LeftVal < RightVal)? LeftVal : RightVal);
+    } else {
+        /* Make an expression node */
+        Expr = NewExprNode (EXPR_MIN);
+        Expr->Left = Left;
+        Expr->Right = Right;
+    }
+    return Expr;
+}
+
+
+
+static ExprNode* FuncReferenced (void)
 /* Handle the .REFERENCED builtin function */
 {
-    int Result = 0;
+    /* Parse the symbol name and search for the symbol */
+    SymEntry* Sym = ParseAnySymName (SYM_FIND_EXISTING);
+
+    /* Check if the symbol is referenced */
+    return GenLiteralExpr (Sym != 0 && SymIsRef (Sym));
+}
+
+
+
+static ExprNode* FuncSizeOf (void)
+/* Handle the .SIZEOF function */
+{
+    StrBuf    ScopeName = STATIC_STRBUF_INITIALIZER;
+    StrBuf    Name = STATIC_STRBUF_INITIALIZER;
+    SymTable* Scope;
+    SymEntry* Sym;
+    SymEntry* SizeSym;
+    long      Size;
+    int       NoScope;
+
+
+    /* Assume an error */
+    SizeSym = 0;
+
+    /* Check for a cheap local which needs special handling */
+    if (CurTok.Tok == TOK_LOCAL_IDENT) {
+
+        /* Cheap local symbol */
+        Sym = SymFindLocal (SymLast, &CurTok.SVal, SYM_FIND_EXISTING);
+        if (Sym == 0) {
+            Error ("Unknown symbol or scope: `%m%p'", &CurTok.SVal);
+        } else {
+            SizeSym = GetSizeOfSymbol (Sym);
+        }
+
+        /* Remember and skip SVal, terminate ScopeName so it is empty */
+        SB_Copy (&Name, &CurTok.SVal);
+        NextTok ();
+        SB_Terminate (&ScopeName);
 
-    if (Tok != TOK_IDENT) {
-       Error (ERR_IDENT_EXPECTED);
-       if (Tok != TOK_RPAREN) {
-           NextTok ();
-       }
     } else {
-       Result = SymIsRef (SVal, SCOPE_ANY);
-       NextTok ();
+
+        /* Parse the scope and the name */
+        SymTable* ParentScope = ParseScopedIdent (&Name, &ScopeName);
+
+        /* Check if the parent scope is valid */
+        if (ParentScope == 0) {
+            /* No such scope */
+            SB_Done (&ScopeName);
+            SB_Done (&Name);
+            return GenLiteral0 ();
+        }
+
+        /* If ScopeName is empty, no explicit scope was specified. We have to
+         * search upper scope levels in this case.
+         */
+        NoScope = SB_IsEmpty (&ScopeName);
+
+        /* First search for a scope with the given name */
+        if (NoScope) {
+            Scope = SymFindAnyScope (ParentScope, &Name);
+        } else {
+            Scope = SymFindScope (ParentScope, &Name, SYM_FIND_EXISTING);
+        }
+
+        /* If we did find a scope with the name, read the symbol defining the
+         * size, otherwise search for a symbol entry with the name and scope.
+         */
+        if (Scope) {
+            /* Yep, it's a scope */
+            SizeSym = GetSizeOfScope (Scope);
+        } else {
+            if (NoScope) {
+                Sym = SymFindAny (ParentScope, &Name);
+            } else {
+                Sym = SymFind (ParentScope, &Name, SYM_FIND_EXISTING);
+            }
+
+            /* If we found the symbol retrieve the size, otherwise complain */
+            if (Sym) {
+                SizeSym = GetSizeOfSymbol (Sym);
+            } else {
+                Error ("Unknown symbol or scope: `%m%p%m%p'",
+                       &ScopeName, &Name);
+            }
+        }
     }
 
-    /* Done */
-    return Result;
+    /* Check if we have a size */
+    if (SizeSym == 0 || !SymIsConst (SizeSym, &Size)) {
+        Error ("Size of `%m%p%m%p' is unknown", &ScopeName, &Name);
+        Size = 0;
+    }
+
+    /* Free the string buffers */
+    SB_Done (&ScopeName);
+    SB_Done (&Name);
+
+    /* Return the size */
+    return GenLiteralExpr (Size);
 }
 
 
 
-static int FuncStrAt (void)
+static ExprNode* FuncStrAt (void)
 /* Handle the .STRAT function */
 {
-    char Str [sizeof(SVal)];
+    StrBuf Str = STATIC_STRBUF_INITIALIZER;
     long Index;
+    unsigned char C = 0;
 
     /* String constant expected */
-    if (Tok != TOK_STRCON) {
-       Error (ERR_STRCON_EXPECTED);
-       NextTok ();
-               return 0;
-
+    if (CurTok.Tok != TOK_STRCON) {
+        Error ("String constant expected");
+        NextTok ();
+        goto ExitPoint;
     }
 
     /* Remember the string and skip it */
-    strcpy (Str, SVal);
+    SB_Copy (&Str, &CurTok.SVal);
     NextTok ();
 
     /* Comma must follow */
@@ -412,87 +749,93 @@ static int FuncStrAt (void)
     Index = ConstExpression ();
 
     /* Must be a valid index */
-    if (Index >= (long) strlen (Str)) {
-       Error (ERR_RANGE);
-       return 0;
+    if (Index >= (long) SB_GetLen (&Str)) {
+        Error ("Range error");
+        goto ExitPoint;
     }
 
-    /* Return the char, handle as unsigned. Be sure to translate it into
+    /* Get the char, handle as unsigned. Be sure to translate it into
      * the target character set.
      */
-    return (unsigned char) TgtTranslateChar (Str [(size_t)Index]);
+    C = TgtTranslateChar (SB_At (&Str, (unsigned)Index));
+
+ExitPoint:
+    /* Free string buffer memory */
+    SB_Done (&Str);
+
+    /* Return the char expression */
+    return GenLiteralExpr (C);
 }
 
 
 
-static int FuncStrLen (void)
+static ExprNode* FuncStrLen (void)
 /* Handle the .STRLEN function */
 {
+    int Len;
+
     /* String constant expected */
-    if (Tok != TOK_STRCON) {
+    if (CurTok.Tok != TOK_STRCON) {
 
-       Error (ERR_STRCON_EXPECTED);
-       /* Smart error recovery */
-       if (Tok != TOK_RPAREN) {
-           NextTok ();
-       }
-               return 0;
+        Error ("String constant expected");
+        /* Smart error recovery */
+        if (CurTok.Tok != TOK_RPAREN) {
+            NextTok ();
+        }
+        Len = 0;
 
     } else {
 
         /* Get the length of the string */
-       int Len = strlen (SVal);
-
-       /* Skip the string */
-       NextTok ();
-
-       /* Return the length */
-       return Len;
+        Len = SB_GetLen (&CurTok.SVal);
 
+        /* Skip the string */
+        NextTok ();
     }
+
+    /* Return the length */
+    return GenLiteralExpr (Len);
 }
 
 
 
-static int FuncTCount (void)
+static ExprNode* FuncTCount (void)
 /* Handle the .TCOUNT function */
 {
     /* We have a list of tokens that ends with the closing paren. Skip
-     * the tokens, handling nested braces and count them.
+     * the tokens, and count them. Allow optionally curly braces.
      */
-    int      Count  = 0;
-    unsigned Parens = 0;
-    while (Parens != 0 || Tok != TOK_RPAREN) {
-
-       /* Check for end of line or end of input. Since the calling function
-        * will check for the closing paren, we don't need to print an error
-        * here, just bail out.
-        */
-       if (TokIsSep (Tok)) {
-           break;
-       }
-
-       /* One more token */
-       ++Count;
-
-       /* Keep track of the nesting level */
-       switch (Tok) {
-           case TOK_LPAREN:    ++Parens;       break;
-           case TOK_RPAREN:    --Parens;       break;
-           default:                            break;
-       }
-
-       /* Skip the token */
-       NextTok ();
+    token_t Term = GetTokListTerm (TOK_RPAREN);
+    int Count = 0;
+    while (CurTok.Tok != Term) {
+
+        /* Check for end of line or end of input. Since the calling function
+         * will check for the closing paren, we don't need to print an error
+         * here, just bail out.
+         */
+        if (TokIsSep (CurTok.Tok)) {
+            break;
+        }
+
+        /* One more token */
+        ++Count;
+
+        /* Skip the token */
+        NextTok ();
+    }
+
+    /* If the list was enclosed in curly braces, skip the closing brace */
+    if (Term == TOK_RCURLY && CurTok.Tok == TOK_RCURLY) {
+        NextTok ();
     }
 
     /* Return the number of tokens */
-    return Count;
+    return GenLiteralExpr (Count);
 }
 
 
 
-static int FuncXMatch (void)
+static ExprNode* FuncXMatch (void)
 /* Handle the .XMATCH function */
 {
     return DoMatch (tcIdentical);
@@ -500,186 +843,218 @@ static int FuncXMatch (void)
 
 
 
-static ExprNode* Function (int (*F) (void))
+static ExprNode* Function (ExprNode* (*F) (void))
 /* Handle builtin functions */
 {
-    long Result;
+    ExprNode* E;
 
     /* Skip the keyword */
     NextTok ();
 
     /* Expression must be enclosed in braces */
-    if (Tok != TOK_LPAREN) {
-       Error (ERR_LPAREN_EXPECTED);
-       SkipUntilSep ();
-       return LiteralExpr (0);
+    if (CurTok.Tok != TOK_LPAREN) {
+        Error ("'(' expected");
+        SkipUntilSep ();
+        return GenLiteral0 ();
     }
     NextTok ();
 
     /* Call the function itself */
-    Result = F ();
+    E = F ();
 
     /* Closing brace must follow */
     ConsumeRParen ();
 
-    /* Return an expression node with the boolean code */
-    return LiteralExpr (Result);
+    /* Return the result of the actual function */
+    return E;
 }
 
 
 
 static ExprNode* Factor (void)
 {
+    ExprNode* L;
     ExprNode* N;
-    SymEntry* S;
+    long      Val;
 
-    switch (Tok) {
+    switch (CurTok.Tok) {
 
-       case TOK_INTCON:
-           N = LiteralExpr (IVal);
-                   NextTok ();
-           break;
+        case TOK_INTCON:
+            N = GenLiteralExpr (CurTok.IVal);
+            NextTok ();
+            break;
 
-       case TOK_CHARCON:
-           N = LiteralExpr (TgtTranslateChar (IVal));
-                   NextTok ();
-           break;
+        case TOK_CHARCON:
+            N = GenLiteralExpr (TgtTranslateChar (CurTok.IVal));
+            NextTok ();
+            break;
 
         case TOK_NAMESPACE:
-           NextTok ();
-           if (Tok != TOK_IDENT) {
-               Error (ERR_IDENT_EXPECTED);
-               N = LiteralExpr (0);    /* Dummy */
-           } else {
-               S = SymRef (SVal, SCOPE_GLOBAL);
-               if (SymIsConst (S)) {
-                   /* Use the literal value instead */
-                   N = LiteralExpr (GetSymVal (S));
-               } else {
-                   /* Create symbol node */
-                   N = NewExprNode ();
-                   N->Op    = EXPR_SYMBOL;
-                   N->V.Sym = S;
-               }
-               NextTok ();
-           }
-           break;
-
         case TOK_IDENT:
-           S = SymRef (SVal, SCOPE_LOCAL);
-           if (SymIsConst (S)) {
-               /* Use the literal value instead */
-               N = LiteralExpr (GetSymVal (S));
-           } else {
-               /* Create symbol node */
-               N = NewExprNode ();
-               N->Op    = EXPR_SYMBOL;
-               N->V.Sym = S;
-           }
-           NextTok ();
-           break;
-
-       case TOK_ULABEL:
-           N = ULabRef (IVal);
-           NextTok ();
-           break;
-
-       case TOK_MINUS:
-           NextTok ();
-           N = NewExprNode ();
-                   N->Left = Factor ();
-                   N->Op   = EXPR_UNARY_MINUS;
-           break;
-
-       case TOK_NOT:
-           NextTok ();
-           N = NewExprNode ();
-           N->Left = Factor ();
-           N->Op   = EXPR_NOT;
-           break;
-
-       case TOK_STAR:
-       case TOK_PC:
-           NextTok ();
-                   N = CurrentPC ();
-           break;
-
-       case TOK_LT:
-           NextTok ();
-           N = NewExprNode ();
-           N->Left = Factor ();
-           N->Op   = EXPR_BYTE0;
-           break;
-
-       case TOK_GT:
-           NextTok ();
-           N = NewExprNode ();
-           N->Left = Factor ();
-           N->Op   = EXPR_BYTE1;
-           break;
-
-       case TOK_LPAREN:
-           NextTok ();
-           N = Expr0 ();
-                   ConsumeRParen ();
-           break;
+        case TOK_LOCAL_IDENT:
+            N = Symbol (ParseAnySymName (SYM_ALLOC_NEW));
+            break;
+
+        case TOK_ULABEL:
+            N = ULabRef (CurTok.IVal);
+            NextTok ();
+            break;
+
+        case TOK_PLUS:
+            NextTok ();
+            N = Factor ();
+            break;
+
+        case TOK_MINUS:
+            NextTok ();
+            L = Factor ();
+            if (IsEasyConst (L, &Val)) {
+                FreeExpr (L);
+                N = GenLiteralExpr (-Val);
+            } else {
+                N = NewExprNode (EXPR_UNARY_MINUS);
+                N->Left = L;
+            }
+            break;
+
+        case TOK_NOT:
+            NextTok ();
+            L = Factor ();
+            if (IsEasyConst (L, &Val)) {
+                FreeExpr (L);
+                N = GenLiteralExpr (~Val);
+            } else {
+                N = NewExprNode (EXPR_NOT);
+                N->Left = L;
+            }
+            break;
+
+        case TOK_STAR:
+        case TOK_PC:
+            NextTok ();
+            N = GenCurrentPC ();
+            break;
+
+        case TOK_LT:
+            NextTok ();
+            N = LoByte (Factor ());
+            break;
+
+        case TOK_GT:
+            NextTok ();
+            N = HiByte (Factor ());
+            break;
+
+        case TOK_XOR:
+            /* ^ means the bank byte of an expression */
+            NextTok ();
+            N = BankByte (Factor ());
+            break;
+
+        case TOK_LPAREN:
+            NextTok ();
+            N = Expr0 ();
+            ConsumeRParen ();
+            break;
+
+        case TOK_BANK:
+            N = Function (FuncBank);
+            break;
+
+        case TOK_BANKBYTE:
+            N = Function (FuncBankByte);
+            break;
 
         case TOK_BLANK:
-           N = Function (FuncBlank);
-           break;
+            N = Function (FuncBlank);
+            break;
 
-       case TOK_CONST:
-           N = Function (FuncConst);
-           break;
+        case TOK_CONST:
+            N = Function (FuncConst);
+            break;
 
-       case TOK_CPU:
-           N = LiteralExpr (GetCPU());
-           NextTok ();
-           break;
+        case TOK_CPU:
+            N = GenLiteralExpr (CPUIsets[CPU]);
+            NextTok ();
+            break;
 
         case TOK_DEFINED:
-           N = Function (FuncDefined);
-           break;
+            N = Function (FuncDefined);
+            break;
+
+        case TOK_HIBYTE:
+            N = Function (FuncHiByte);
+            break;
+
+        case TOK_HIWORD:
+            N = Function (FuncHiWord);
+            break;
+
+        case TOK_LOBYTE:
+            N = Function (FuncLoByte);
+            break;
+
+        case TOK_LOWORD:
+            N = Function (FuncLoWord);
+            break;
 
-       case TOK_MATCH:
-           N = Function (FuncMatch);
-           break;
+        case TOK_MATCH:
+            N = Function (FuncMatch);
+            break;
+
+        case TOK_MAX:
+            N = Function (FuncMax);
+            break;
+
+        case TOK_MIN:
+            N = Function (FuncMin);
+            break;
 
         case TOK_REFERENCED:
-           N = Function (FuncReferenced);
-           break;
-
-       case TOK_STRAT:
-           N = Function (FuncStrAt);
-           break;
-
-       case TOK_STRLEN:
-           N = Function (FuncStrLen);
-           break;
-
-       case TOK_TCOUNT:
-           N = Function (FuncTCount);
-           break;
-
-       case TOK_TIME:
-           N = LiteralExpr (time (0));
-           NextTok ();
-           break;
-
-       case TOK_XMATCH:
-           N = Function (FuncXMatch);
-           break;
-
-       default:
-           if (LooseCharTerm && Tok == TOK_STRCON && strlen(SVal) == 1) {
-               /* A character constant */
-               N = LiteralExpr (TgtTranslateChar (SVal[0]));
-           } else {
-               N = LiteralExpr (0);    /* Dummy */
-               Error (ERR_SYNTAX);
-           }
-           NextTok ();
-           break;
+            N = Function (FuncReferenced);
+            break;
+
+        case TOK_SIZEOF:
+            N = Function (FuncSizeOf);
+            break;
+
+        case TOK_STRAT:
+            N = Function (FuncStrAt);
+            break;
+
+        case TOK_STRLEN:
+            N = Function (FuncStrLen);
+            break;
+
+        case TOK_TCOUNT:
+            N = Function (FuncTCount);
+            break;
+
+        case TOK_TIME:
+            N = GenLiteralExpr ((long) time (0));
+            NextTok ();
+            break;
+
+        case TOK_VERSION:
+            N = GenLiteralExpr (GetVersionAsNumber ());
+            NextTok ();
+            break;
+
+        case TOK_XMATCH:
+            N = Function (FuncXMatch);
+            break;
+
+        default:
+            if (LooseCharTerm && CurTok.Tok == TOK_STRCON &&
+                SB_GetLen (&CurTok.SVal) == 1) {
+                /* A character constant */
+                N = GenLiteralExpr (TgtTranslateChar (SB_At (&CurTok.SVal, 0)));
+            } else {
+                N = GenLiteral0 ();     /* Dummy */
+                Error ("Syntax error");
+            }
+            NextTok ();
+            break;
     }
     return N;
 }
@@ -688,36 +1063,99 @@ static ExprNode* Factor (void)
 
 static ExprNode* Term (void)
 {
-    ExprNode* Root;
-
     /* Read left hand side */
-    Root = Factor ();
+    ExprNode* Root = Factor ();
 
     /* Handle multiplicative operations */
-    while (Tok == TOK_MUL || Tok == TOK_DIV || Tok == TOK_MOD ||
-          Tok == TOK_AND || Tok == TOK_XOR || Tok == TOK_SHL ||
-          Tok == TOK_SHR) {
-
-       /* Create a new node and insert the left expression */
-       ExprNode* Left = Root;
-       Root = NewExprNode ();
-       Root->Left = Left;
-
-       /* Determine the operator token */
-       switch (Tok) {
-                   case TOK_MUL:       Root->Op = EXPR_MUL;    break;
-           case TOK_DIV:       Root->Op = EXPR_DIV;    break;
-           case TOK_MOD:       Root->Op = EXPR_MOD;    break;
-                   case TOK_AND:       Root->Op = EXPR_AND;    break;
-                   case TOK_XOR:       Root->Op = EXPR_XOR;    break;
-                   case TOK_SHL:       Root->Op = EXPR_SHL;    break;
-                   case TOK_SHR:       Root->Op = EXPR_SHR;    break;
-           default:            Internal ("Invalid token");
-       }
-       NextTok ();
-
-       /* Parse the right hand side */
-       Root->Right = Factor ();
+    while (CurTok.Tok == TOK_MUL || CurTok.Tok == TOK_DIV ||
+           CurTok.Tok == TOK_MOD || CurTok.Tok == TOK_AND ||
+           CurTok.Tok == TOK_XOR || CurTok.Tok == TOK_SHL ||
+           CurTok.Tok == TOK_SHR) {
+
+        long LVal, RVal, Val;
+        ExprNode* Left;
+        ExprNode* Right;
+
+        /* Remember the token and skip it */
+        token_t T = CurTok.Tok;
+        NextTok ();
+
+        /* Move root to left side and read the right side */
+        Left  = Root;
+        Right = Factor ();
+
+        /* If both expressions are constant, we can evaluate the term */
+        if (IsEasyConst (Left, &LVal) && IsEasyConst (Right, &RVal)) {
+
+            switch (T) {
+                case TOK_MUL:
+                    Val = LVal * RVal;
+                    break;
+
+                case TOK_DIV:
+                    if (RVal == 0) {
+                        Error ("Division by zero");
+                        Val = 1;
+                    } else {
+                        Val = LVal / RVal;
+                    }
+                    break;
+
+                case TOK_MOD:
+                    if (RVal == 0) {
+                        Error ("Modulo operation with zero");
+                        Val = 1;
+                    } else {
+                        Val = LVal % RVal;
+                    }
+                    break;
+
+                case TOK_AND:
+                    Val = LVal & RVal;
+                    break;
+
+                case TOK_XOR:
+                    Val = LVal ^ RVal;
+                    break;
+
+                case TOK_SHL:
+                    Val = shl_l (LVal, RVal);
+                    break;
+
+                case TOK_SHR:
+                    Val = shr_l (LVal, RVal);
+                    break;
+
+                default:
+                    Internal ("Invalid token");
+            }
+
+            /* Generate a literal expression and delete the old left and
+             * right sides.
+             */
+            FreeExpr (Left);
+            FreeExpr (Right);
+            Root = GenLiteralExpr (Val);
+
+        } else {
+
+            /* Generate an expression tree */
+            unsigned char Op;
+            switch (T) {
+                case TOK_MUL:   Op = EXPR_MUL;  break;
+                case TOK_DIV:   Op = EXPR_DIV;  break;
+                case TOK_MOD:   Op = EXPR_MOD;  break;
+                case TOK_AND:   Op = EXPR_AND;  break;
+                case TOK_XOR:   Op = EXPR_XOR;  break;
+                case TOK_SHL:   Op = EXPR_SHL;  break;
+                case TOK_SHR:   Op = EXPR_SHR;  break;
+                default:        Internal ("Invalid token");
+            }
+            Root        = NewExprNode (Op);
+            Root->Left  = Left;
+            Root->Right = Right;
+
+        }
 
     }
 
@@ -729,31 +1167,58 @@ static ExprNode* Term (void)
 
 static ExprNode* SimpleExpr (void)
 {
-    ExprNode* Root;
-
     /* Read left hand side */
-    Root = Term ();
+    ExprNode* Root = Term ();
 
     /* Handle additive operations */
-    while (Tok == TOK_PLUS || Tok == TOK_MINUS || Tok == TOK_OR) {
+    while (CurTok.Tok == TOK_PLUS  ||
+           CurTok.Tok == TOK_MINUS ||
+           CurTok.Tok == TOK_OR) {
 
-       /* Create a new node and insert the left expression */
-       ExprNode* Left = Root;
-       Root = NewExprNode ();
-       Root->Left = Left;
+        long LVal, RVal, Val;
+        ExprNode* Left;
+        ExprNode* Right;
 
-       /* Determine the operator token */
-       switch (Tok) {
-                   case TOK_PLUS:      Root->Op = EXPR_PLUS;   break;
-           case TOK_MINUS:     Root->Op = EXPR_MINUS;  break;
-           case TOK_OR:        Root->Op = EXPR_OR;     break;
-           default:            Internal ("Invalid token");
-       }
-       NextTok ();
+        /* Remember the token and skip it */
+        token_t T = CurTok.Tok;
+        NextTok ();
 
-       /* Parse the right hand side */
-       Root->Right = Term ();
+        /* Move root to left side and read the right side */
+        Left  = Root;
+        Right = Term ();
+
+        /* If both expressions are constant, we can evaluate the term */
+        if (IsEasyConst (Left, &LVal) && IsEasyConst (Right, &RVal)) {
+
+            switch (T) {
+                case TOK_PLUS:  Val = LVal + RVal;      break;
+                case TOK_MINUS: Val = LVal - RVal;      break;
+                case TOK_OR:    Val = LVal | RVal;      break;
+                default:        Internal ("Invalid token");
+            }
+
+            /* Generate a literal expression and delete the old left and
+             * right sides.
+             */
+            FreeExpr (Left);
+            FreeExpr (Right);
+            Root = GenLiteralExpr (Val);
+
+        } else {
+
+            /* Generate an expression tree */
+            unsigned char Op;
+            switch (T) {
+                case TOK_PLUS:  Op = EXPR_PLUS;  break;
+                case TOK_MINUS: Op = EXPR_MINUS; break;
+                case TOK_OR:    Op = EXPR_OR;    break;
+                default:        Internal ("Invalid token");
+            }
+            Root        = NewExprNode (Op);
+            Root->Left  = Left;
+            Root->Right = Right;
 
+        }
     }
 
     /* Return the expression tree we've created */
@@ -769,29 +1234,60 @@ static ExprNode* BoolExpr (void)
     ExprNode* Root = SimpleExpr ();
 
     /* Handle booleans */
-    while (Tok == TOK_EQ || Tok == TOK_NE || Tok == TOK_LT ||
-          Tok == TOK_GT || Tok == TOK_LE || Tok == TOK_GE) {
-
-       /* Create a new node and insert the left expression */
-       ExprNode* Left = Root;
-       Root = NewExprNode ();
-       Root->Left = Left;
-
-       /* Determine the operator token */
-       switch (Tok) {
-           case TOK_EQ:        Root->Op = EXPR_EQ;     break;
-           case TOK_NE:        Root->Op = EXPR_NE;     break;
-           case TOK_LT:        Root->Op = EXPR_LT;     break;
-           case TOK_GT:        Root->Op = EXPR_GT;     break;
-           case TOK_LE:        Root->Op = EXPR_LE;     break;
-           case TOK_GE:        Root->Op = EXPR_GE;     break;
-           default:            Internal ("Invalid token");
-       }
-       NextTok ();
-
-       /* Parse the right hand side */
-       Root->Right = SimpleExpr ();
+    while (CurTok.Tok == TOK_EQ || CurTok.Tok == TOK_NE ||
+           CurTok.Tok == TOK_LT || CurTok.Tok == TOK_GT ||
+           CurTok.Tok == TOK_LE || CurTok.Tok == TOK_GE) {
+
+        long LVal, RVal, Val;
+        ExprNode* Left;
+        ExprNode* Right;
+
+        /* Remember the token and skip it */
+        token_t T = CurTok.Tok;
+        NextTok ();
 
+        /* Move root to left side and read the right side */
+        Left  = Root;
+        Right = SimpleExpr ();
+
+        /* If both expressions are constant, we can evaluate the term */
+        if (IsEasyConst (Left, &LVal) && IsEasyConst (Right, &RVal)) {
+
+            switch (T) {
+                case TOK_EQ:    Val = (LVal == RVal);   break;
+                case TOK_NE:    Val = (LVal != RVal);   break;
+                case TOK_LT:    Val = (LVal < RVal);    break;
+                case TOK_GT:    Val = (LVal > RVal);    break;
+                case TOK_LE:    Val = (LVal <= RVal);   break;
+                case TOK_GE:    Val = (LVal >= RVal);   break;
+                default:        Internal ("Invalid token");
+            }
+
+            /* Generate a literal expression and delete the old left and
+             * right sides.
+             */
+            FreeExpr (Left);
+            FreeExpr (Right);
+            Root = GenLiteralExpr (Val);
+
+        } else {
+
+            /* Generate an expression tree */
+            unsigned char Op;
+            switch (T) {
+                case TOK_EQ:    Op = EXPR_EQ;   break;
+                case TOK_NE:    Op = EXPR_NE;   break;
+                case TOK_LT:    Op = EXPR_LT;   break;
+                case TOK_GT:    Op = EXPR_GT;   break;
+                case TOK_LE:    Op = EXPR_LE;   break;
+                case TOK_GE:    Op = EXPR_GE;   break;
+                default:        Internal ("Invalid token");
+            }
+            Root        = NewExprNode (Op);
+            Root->Left  = Left;
+            Root->Right = Right;
+
+        }
     }
 
     /* Return the expression tree we've created */
@@ -807,24 +1303,50 @@ static ExprNode* Expr2 (void)
     ExprNode* Root = BoolExpr ();
 
     /* Handle booleans */
-    while (Tok == TOK_BAND || Tok == TOK_BXOR) {
+    while (CurTok.Tok == TOK_BOOLAND || CurTok.Tok == TOK_BOOLXOR) {
 
-       /* Create a new node and insert the left expression */
-       ExprNode* Left = Root;
-       Root = NewExprNode ();
-       Root->Left = Left;
+        long LVal, RVal, Val;
+        ExprNode* Left;
+        ExprNode* Right;
 
-       /* Determine the operator token */
-       switch (Tok) {
-           case TOK_BAND:      Root->Op = EXPR_BAND;   break;
-           case TOK_BXOR:      Root->Op = EXPR_BXOR;   break;
-           default:            Internal ("Invalid token");
-       }
-       NextTok ();
+        /* Remember the token and skip it */
+        token_t T = CurTok.Tok;
+        NextTok ();
 
-       /* Parse the right hand side */
-       Root->Right = BoolExpr ();
+        /* Move root to left side and read the right side */
+        Left  = Root;
+        Right = BoolExpr ();
+
+        /* If both expressions are constant, we can evaluate the term */
+        if (IsEasyConst (Left, &LVal) && IsEasyConst (Right, &RVal)) {
+
+            switch (T) {
+                case TOK_BOOLAND:   Val = ((LVal != 0) && (RVal != 0)); break;
+                case TOK_BOOLXOR:   Val = ((LVal != 0) ^  (RVal != 0)); break;
+                default:        Internal ("Invalid token");
+            }
+
+            /* Generate a literal expression and delete the old left and
+             * right sides.
+             */
+            FreeExpr (Left);
+            FreeExpr (Right);
+            Root = GenLiteralExpr (Val);
+
+        } else {
+
+            /* Generate an expression tree */
+            unsigned char Op;
+            switch (T) {
+                case TOK_BOOLAND:   Op = EXPR_BOOLAND; break;
+                case TOK_BOOLXOR:   Op = EXPR_BOOLXOR; break;
+                default:            Internal ("Invalid token");
+            }
+            Root        = NewExprNode (Op);
+            Root->Left  = Left;
+            Root->Right = Right;
 
+        }
     }
 
     /* Return the expression tree we've created */
@@ -840,23 +1362,48 @@ static ExprNode* Expr1 (void)
     ExprNode* Root = Expr2 ();
 
     /* Handle booleans */
-    while (Tok == TOK_BOR) {
+    while (CurTok.Tok == TOK_BOOLOR) {
 
-       /* Create a new node and insert the left expression */
-       ExprNode* Left = Root;
-       Root = NewExprNode ();
-       Root->Left = Left;
+        long LVal, RVal, Val;
+        ExprNode* Left;
+        ExprNode* Right;
 
-       /* Determine the operator token */
-       switch (Tok) {
-           case TOK_BOR:       Root->Op = EXPR_BOR;    break;
-           default:            Internal ("Invalid token");
-       }
-       NextTok ();
+        /* Remember the token and skip it */
+        token_t T = CurTok.Tok;
+        NextTok ();
 
-       /* Parse the right hand side */
-       Root->Right = Expr2 ();
+        /* Move root to left side and read the right side */
+        Left  = Root;
+        Right = Expr2 ();
+
+        /* If both expressions are constant, we can evaluate the term */
+        if (IsEasyConst (Left, &LVal) && IsEasyConst (Right, &RVal)) {
+
+            switch (T) {
+                case TOK_BOOLOR:    Val = ((LVal != 0) || (RVal != 0)); break;
+                default:        Internal ("Invalid token");
+            }
+
+            /* Generate a literal expression and delete the old left and
+             * right sides.
+             */
+            FreeExpr (Left);
+            FreeExpr (Right);
+            Root = GenLiteralExpr (Val);
+
+        } else {
+
+            /* Generate an expression tree */
+            unsigned char Op;
+            switch (T) {
+                case TOK_BOOLOR:    Op = EXPR_BOOLOR;  break;
+                default:            Internal ("Invalid token");
+            }
+            Root        = NewExprNode (Op);
+            Root->Left  = Left;
+            Root->Right = Right;
 
+        }
     }
 
     /* Return the expression tree we've created */
@@ -871,25 +1418,30 @@ static ExprNode* Expr0 (void)
     ExprNode* Root;
 
     /* Handle booleans */
-    if (Tok == TOK_BNOT) {
+    if (CurTok.Tok == TOK_BOOLNOT) {
+
+        long Val;
+        ExprNode* Left;
 
-               /* Create a new node */
-       Root = NewExprNode ();
+        /* Skip the operator token */
+        NextTok ();
 
-       /* Determine the operator token */
-       switch (Tok) {
-           case TOK_BNOT:      Root->Op = EXPR_BNOT;   break;
-           default:            Internal ("Invalid token");
-       }
-       NextTok ();
+        /* Read the argument */
+        Left = Expr0 ();
 
-       /* Parse the left hand side, allow more BNOTs */
-       Root->Left = Expr0 ();
+        /* If the argument is const, evaluate it directly */
+        if (IsEasyConst (Left, &Val)) {
+            FreeExpr (Left);
+            Root = GenLiteralExpr (!Val);
+        } else {
+            Root = NewExprNode (EXPR_BOOLNOT);
+            Root->Left = Left;
+        }
 
     } else {
 
-       /* Read left hand side */
-       Root = Expr1 ();
+        /* Read left hand side */
+        Root = Expr1 ();
 
     }
 
@@ -899,32 +1451,12 @@ static ExprNode* Expr0 (void)
 
 
 
-static ExprNode* SimplifyExpr (ExprNode* Root)
-/* Try to simplify the given expression tree */
-{
-    if (Root) {
-       SimplifyExpr (Root->Left);
-       SimplifyExpr (Root->Right);
-       if (IsConstExpr (Root)) {
-           /* The complete expression is constant */
-           Root->V.Val = GetExprVal (Root);
-           Root->Op = EXPR_LITERAL;
-           FreeExpr (Root->Left);
-           FreeExpr (Root->Right);
-           Root->Left = Root->Right = 0;
-               }
-    }
-    return Root;
-}
-
-
-
 ExprNode* Expression (void)
 /* Evaluate an expression, build the expression tree on the heap and return
  * a pointer to the root of the tree.
  */
 {
-    return SimplifyExpr (Expr0 ());
+    return Expr0 ();
 }
 
 
@@ -935,18 +1467,30 @@ long ConstExpression (void)
  * not constant.
  */
 {
-    /* Read the expression, and call finalize (exception here, since we
-     * expect a const).
-     */
-    ExprNode* Expr = FinalizeExpr (Expression ());
+    long Val;
 
-    /* Return the value */
-    if (IsConstExpr (Expr)) {
-       return GetExprVal (Expr);
+    /* Read the expression */
+    ExprNode* Expr = Expression ();
+
+    /* Study the expression */
+    ExprDesc D;
+    ED_Init (&D);
+    StudyExpr (Expr, &D);
+
+    /* Check if the expression is constant */
+    if (ED_IsConst (&D)) {
+        Val = D.Val;
     } else {
-       Error (ERR_CONSTEXPR_EXPECTED);
-       return 0;
+        Error ("Constant expression expected");
+        Val = 0;
     }
+
+    /* Free the expression tree and allocated memory for D */
+    FreeExpr (Expr);
+    ED_Done (&D);
+
+    /* Return the value */
+    return Val;
 }
 
 
@@ -955,609 +1499,286 @@ void FreeExpr (ExprNode* Root)
 /* Free the expression, Root is pointing to. */
 {
     if (Root) {
-       FreeExpr (Root->Left);
-       FreeExpr (Root->Right);
-       FreeExprNode (Root);
+        FreeExpr (Root->Left);
+        FreeExpr (Root->Right);
+        FreeExprNode (Root);
     }
 }
 
 
 
-ExprNode* LiteralExpr (long Val)
-/* Return an expression tree that encodes the given literal value */
+ExprNode* SimplifyExpr (ExprNode* Expr, const ExprDesc* D)
+/* Try to simplify the given expression tree */
 {
-    ExprNode* Expr = NewExprNode ();
-    Expr->Op = EXPR_LITERAL;
-    Expr->V.Val = Val;
+    if (Expr->Op != EXPR_LITERAL && ED_IsConst (D)) {
+        /* No external references */
+        FreeExpr (Expr);
+        Expr = GenLiteralExpr (D->Val);
+    }
     return Expr;
 }
 
 
 
-ExprNode* CurrentPC (void)
-/* Return the current program counter as expression */
+ExprNode* GenLiteralExpr (long Val)
+/* Return an expression tree that encodes the given literal value */
 {
-    ExprNode* Left;
-    ExprNode* Root;
-
-    if (RelocMode) {
-       /* Create SegmentBase + Offset */
-       Left = NewExprNode ();
-       Left->Op = EXPR_SECTION;
-       Left->V.SegNum = GetSegNum ();
-
-       Root = NewExprNode ();
-       Root->Left  = Left;
-       Root->Right = LiteralExpr (GetPC ());
-       Root->Op = EXPR_PLUS;
-    } else {
-       /* Absolute mode, just return PC value */
-       Root = LiteralExpr (GetPC ());
-    }
-
-    return Root;
+    ExprNode* Expr = NewExprNode (EXPR_LITERAL);
+    Expr->V.IVal = Val;
+    return Expr;
 }
 
 
 
-ExprNode* SwapExpr (ExprNode* Expr)
-/* Return an extended expression with lo and hi bytes swapped */
+ExprNode* GenLiteral0 (void)
+/* Return an expression tree that encodes the the number zero */
 {
-    ExprNode* N = NewExprNode ();
-    N->Op = EXPR_SWAP;
-    N->Left = Expr;
-    return N;
+    return GenLiteralExpr (0);
 }
 
 
 
-ExprNode* BranchExpr (unsigned Offs)
-/* Return an expression that encodes the difference between current PC plus
- * offset and the target expression (that is, Expression() - (*+Offs) ).
- */
+ExprNode* GenSymExpr (SymEntry* Sym)
+/* Return an expression node that encodes the given symbol */
 {
-    ExprNode* N;
-    ExprNode* Root;
-    ExprNode* Left;
-
-    /* Create *+Offs */
-    if (RelocMode) {
-       Left = NewExprNode ();
-       Left->Op = EXPR_SECTION;
-       Left->V.SegNum = GetSegNum ();
+    ExprNode* Expr = NewExprNode (EXPR_SYMBOL);
+    Expr->V.Sym = Sym;
+    SymAddExprRef (Sym, Expr);
+    return Expr;
+}
 
-       N = NewExprNode ();
-       N->Left  = Left;
-       N->Right = LiteralExpr (GetPC () + Offs);
-       N->Op = EXPR_PLUS;
-    } else {
-       N = LiteralExpr (GetPC () + Offs);
-    }
 
-    /* Create the root node */
-    Root = NewExprNode ();
-    Root->Left = Expression ();
-    Root->Right = N;
-    Root->Op = EXPR_MINUS;
 
-    /* Return the result */
-    return SimplifyExpr (Root);
+static ExprNode* GenSectionExpr (unsigned SecNum)
+/* Return an expression node for the given section */
+{
+    ExprNode* Expr = NewExprNode (EXPR_SECTION);
+    Expr->V.SecNum = SecNum;
+    return Expr;
 }
 
 
 
-ExprNode* ULabelExpr (unsigned Num)
-/* Return an expression for an unnamed label with the given index */
+static ExprNode* GenBankExpr (unsigned SecNum)
+/* Return an expression node for the given bank */
 {
-    /* Get an expression node */
-    ExprNode* Node = NewExprNode ();
-
-    /* Set the values */
-    Node->Op   = EXPR_ULABEL;
-    Node->V.Val        = Num;
-
-    /* Return the new node */
-    return Node;
+    ExprNode* Expr = NewExprNode (EXPR_BANK);
+    Expr->V.SecNum = SecNum;
+    return Expr;
 }
 
 
 
-ExprNode* ForceByteExpr (ExprNode* Expr)
-/* Force the given expression into a byte and return the result */
+ExprNode* GenAddExpr (ExprNode* Left, ExprNode* Right)
+/* Generate an addition from the two operands */
 {
-    /* Use the low byte operator to force the expression into byte size */
-    ExprNode* Root = NewExprNode ();
-    Root->Left  = Expr;
-    Root->Op    = EXPR_BYTE0;
-
-    /* Return the result */
-    return Root;
+    long Val;
+    if (IsEasyConst (Left, &Val) && Val == 0) {
+        FreeExpr (Left);
+        return Right;
+    } else if (IsEasyConst (Right, &Val) && Val == 0) {
+        FreeExpr (Right);
+        return Left;
+    } else {
+        ExprNode* Root = NewExprNode (EXPR_PLUS);
+        Root->Left = Left;
+        Root->Right = Right;
+        return Root;
+    }
 }
 
 
 
-ExprNode* ForceWordExpr (ExprNode* Expr)
-/* Force the given expression into a word and return the result. */
+ExprNode* GenCurrentPC (void)
+/* Return the current program counter as expression */
 {
-    /* AND the expression by $FFFF to force it into word size */
-    ExprNode* Root = NewExprNode ();
-    Root->Left  = Expr;
-    Root->Op    = EXPR_AND;
-    Root->Right        = LiteralExpr (0xFFFF);
+    ExprNode* Root;
+
+    if (GetRelocMode ()) {
+        /* Create SegmentBase + Offset */
+        Root = GenAddExpr (GenSectionExpr (GetCurrentSegNum ()),
+                           GenLiteralExpr (GetPC ()));
+    } else {
+        /* Absolute mode, just return PC value */
+        Root = GenLiteralExpr (GetPC ());
+    }
 
-    /* Return the result */
     return Root;
 }
 
 
 
-ExprNode* CompareExpr (ExprNode* Expr, long Val)
-/* Generate an expression that compares Expr and Val for equality */
+ExprNode* GenSwapExpr (ExprNode* Expr)
+/* Return an extended expression with lo and hi bytes swapped */
 {
-    /* Generate a compare node */
-    ExprNode* Root = NewExprNode ();
-    Root->Left  = Expr;
-    Root->Op    = EXPR_EQ;
-    Root->Right        = LiteralExpr (Val);
-
-    /* Return the result */
-    return Root;
+    ExprNode* N = NewExprNode (EXPR_SWAP);
+    N->Left = Expr;
+    return N;
 }
 
 
 
-int IsConstExpr (ExprNode* Root)
-/* Return true if the given expression is a constant expression, that is, one
- * with no references to external symbols.
+ExprNode* GenBranchExpr (unsigned Offs)
+/* Return an expression that encodes the difference between current PC plus
+ * offset and the target expression (that is, Expression() - (*+Offs) ).
  */
 {
-    int Const;
-    SymEntry* Sym;
-
-    if (EXPR_IS_LEAF (Root->Op)) {
-       switch (Root->Op) {
-
-           case EXPR_LITERAL:
-               return 1;
-
-           case EXPR_SYMBOL:
-               Sym = Root->V.Sym;
-               if (SymHasUserMark (Sym)) {
-                   if (Verbosity > 0) {
-                       DumpExpr (Root);
-                   }
-                   PError (GetSymPos (Sym), ERR_CIRCULAR_REFERENCE);
-                   Const = 0;
-               } else {
-                   SymMarkUser (Sym);
-                   Const = SymIsConst (Sym);
-                   SymUnmarkUser (Sym);
-               }
-               return Const;
-
-           default:
-               return 0;
-
-       }
-    } else if (EXPR_IS_UNARY (Root->Op)) {
-
-       return IsConstExpr (Root->Left);
+    ExprNode* N;
+    ExprNode* Root;
+    long      Val;
+
+    /* Read Expression() */
+    N = Expression ();
+
+    /* If the expression is a cheap constant, generate a simpler tree */
+    if (IsEasyConst (N, &Val)) {
+
+        /* Free the constant expression tree */
+        FreeExpr (N);
+
+        /* Generate the final expression:
+         * Val - (* + Offs)
+         * Val - ((Seg + PC) + Offs)
+         * Val - Seg - PC - Offs
+         * (Val - PC - Offs) - Seg
+         */
+        Root = GenLiteralExpr (Val - GetPC () - Offs);
+        if (GetRelocMode ()) {
+            N = Root;
+            Root = NewExprNode (EXPR_MINUS);
+            Root->Left  = N;
+            Root->Right = GenSectionExpr (GetCurrentSegNum ());
+        }
 
     } else {
 
-       /* We must handle shortcut boolean expressions here */
-       switch (Root->Op) {
-
-           case EXPR_BAND:
-               if (IsConstExpr (Root->Left)) {
-                   /* lhs is const, if it is zero, don't eval right */
-                   if (GetExprVal (Root->Left) == 0) {
-                       return 1;
-                   } else {
-                       return IsConstExpr (Root->Right);
-                   }
-               } else {
-                   /* lhs not const --> tree not const */
-                   return 0;
-               }
-               break;
-
-           case EXPR_BOR:
-               if (IsConstExpr (Root->Left)) {
-                   /* lhs is const, if it is not zero, don't eval right */
-                   if (GetExprVal (Root->Left) != 0) {
-                       return 1;
-                   } else {
-                       return IsConstExpr (Root->Right);
-                   }
-               } else {
-                   /* lhs not const --> tree not const */
-                   return 0;
-               }
-               break;
-
-           default:
-               /* All others are handled normal */
-               return IsConstExpr (Root->Left) && IsConstExpr (Root->Right);
-       }
+        /* Generate the expression:
+         * N - (* + Offs)
+         * N - ((Seg + PC) + Offs)
+         * N - Seg - PC - Offs
+         * N - (PC + Offs) - Seg
+         */
+        Root = NewExprNode (EXPR_MINUS);
+        Root->Left  = N;
+        Root->Right = GenLiteralExpr (GetPC () + Offs);
+        if (GetRelocMode ()) {
+            N = Root;
+            Root = NewExprNode (EXPR_MINUS);
+            Root->Left  = N;
+            Root->Right = GenSectionExpr (GetCurrentSegNum ());
+        }
     }
-}
-
-
 
-static void CheckByteExpr (const ExprNode* N, int* IsByte)
-/* Internal routine that is recursively called to check if there is a zeropage
- * symbol in the expression tree.
- */
-{
-    if (N) {
-       switch (N->Op & EXPR_TYPEMASK) {
-
-           case EXPR_LEAFNODE:
-               switch (N->Op) {
-
-                   case EXPR_SYMBOL:
-                       if (SymIsZP (N->V.Sym)) {
-                           *IsByte = 1;
-                       } else if (SymHasExpr (N->V.Sym)) {
-                           /* Check if this expression is a byte expression */
-                           *IsByte = IsByteExpr (GetSymExpr (N->V.Sym));
-                       }
-                       break;
-
-                   case EXPR_SECTION:
-                       if (GetSegType (N->V.SegNum) == SEGTYPE_ZP) {
-                           *IsByte = 1;
-                       }
-                       break;
-
-               }
-               break;
-
-           case EXPR_UNARYNODE:
-               CheckByteExpr (N->Left, IsByte);
-               break;
-
-           case EXPR_BINARYNODE:
-               CheckByteExpr (N->Left, IsByte);
-               CheckByteExpr (N->Right, IsByte);
-               break;
-
-           default:
-               Internal ("Unknown expression op: %02X", N->Op);
-       }
-    }
+    /* Return the result */
+    return Root;
 }
 
 
 
-int IsByteExpr (ExprNode* Root)
-/* Return true if this is a byte expression */
+ExprNode* GenULabelExpr (unsigned Num)
+/* Return an expression for an unnamed label with the given index */
 {
-    int IsByte;
+    ExprNode* Node = NewExprNode (EXPR_ULABEL);
+    Node->V.IVal        = Num;
 
-    if (IsConstExpr (Root)) {
-       if (Root->Op != EXPR_LITERAL) {
-           SimplifyExpr (Root);
-       }
-               return IsByteRange (GetExprVal (Root));
-    } else if (Root->Op == EXPR_BYTE0 || Root->Op == EXPR_BYTE1 ||
-              Root->Op == EXPR_BYTE2 || Root->Op == EXPR_BYTE3) {
-       /* Symbol forced to have byte range */
-               IsByte = 1;
-    } else {
-       /* We have undefined symbols in the expression. Assume that the
-        * expression is a byte expression if there is at least one symbol
-        * declared as zeropage in it. Being wrong here is not a very big
-        * problem since the linker knows about all symbols and detects
-        * error like mixing absolute and zeropage labels.
-        */
-       IsByte = 0;
-       CheckByteExpr (Root, &IsByte);
-    }
-    return IsByte;
+    /* Return the new node */
+    return Node;
 }
 
 
 
-long GetExprVal (ExprNode* Expr)
-/* Get the value of a constant expression */
+ExprNode* GenByteExpr (ExprNode* Expr)
+/* Force the given expression into a byte and return the result */
 {
-    long Right, Left;
-
-    switch (Expr->Op) {
-
-               case EXPR_LITERAL:
-           return Expr->V.Val;
-
-               case EXPR_SYMBOL:
-           return GetSymVal (Expr->V.Sym);
-
-               case EXPR_PLUS:
-           return GetExprVal (Expr->Left) + GetExprVal (Expr->Right);
-
-               case EXPR_MINUS:
-           return GetExprVal (Expr->Left) - GetExprVal (Expr->Right);
-
-               case EXPR_MUL:
-           return GetExprVal (Expr->Left) * GetExprVal (Expr->Right);
-
-               case EXPR_DIV:
-           Left  = GetExprVal (Expr->Left);
-           Right = GetExprVal (Expr->Right);
-           if (Right == 0) {
-               Error (ERR_DIV_BY_ZERO);
-               return 0;
-           }
-           return Left / Right;
-
-               case EXPR_MOD:
-           Left  = GetExprVal (Expr->Left);
-           Right = GetExprVal (Expr->Right);
-           if (Right == 0) {
-               Error (ERR_MOD_BY_ZERO);
-               return 0;
-           }
-           return Left % Right;
-
-               case EXPR_OR:
-                   return GetExprVal (Expr->Left) | GetExprVal (Expr->Right);
-
-               case EXPR_XOR:
-                   return GetExprVal (Expr->Left) ^ GetExprVal (Expr->Right);
-
-               case EXPR_AND:
-                   return GetExprVal (Expr->Left) & GetExprVal (Expr->Right);
-
-               case EXPR_SHL:
-                   return GetExprVal (Expr->Left) << GetExprVal (Expr->Right);
-
-               case EXPR_SHR:
-                   return GetExprVal (Expr->Left) >> GetExprVal (Expr->Right);
-
-               case EXPR_EQ:
-                   return (GetExprVal (Expr->Left) == GetExprVal (Expr->Right));
-
-               case EXPR_NE:
-                   return (GetExprVal (Expr->Left) != GetExprVal (Expr->Right));
-
-               case EXPR_LT:
-           return (GetExprVal (Expr->Left) < GetExprVal (Expr->Right));
-
-               case EXPR_GT:
-           return (GetExprVal (Expr->Left) > GetExprVal (Expr->Right));
-
-               case EXPR_LE:
-           return (GetExprVal (Expr->Left) <= GetExprVal (Expr->Right));
-
-               case EXPR_GE:
-           return (GetExprVal (Expr->Left) >= GetExprVal (Expr->Right));
-
-               case EXPR_UNARY_MINUS:
-           return -GetExprVal (Expr->Left);
-
-               case EXPR_NOT:
-           return ~GetExprVal (Expr->Left);
-
-               case EXPR_BYTE0:
-           return GetExprVal (Expr->Left) & 0xFF;
-
-               case EXPR_BYTE1:
-           return (GetExprVal (Expr->Left) >> 8) & 0xFF;
-
-               case EXPR_BYTE2:
-           return (GetExprVal (Expr->Left) >> 16) & 0xFF;
-
-               case EXPR_BYTE3:
-           return (GetExprVal (Expr->Left) >> 24) & 0xFF;
-
-        case EXPR_SWAP:
-           Left = GetExprVal (Expr->Left);
-           return ((Left >> 8) & 0x00FF) | ((Left << 8) & 0xFF00);
-
-       case EXPR_BAND:
-           return GetExprVal (Expr->Left) && GetExprVal (Expr->Right);
-
-       case EXPR_BOR:
-           return GetExprVal (Expr->Left) || GetExprVal (Expr->Right);
-
-       case EXPR_BXOR:
-           return (GetExprVal (Expr->Left) != 0) ^ (GetExprVal (Expr->Right) != 0);
+    /* Use the low byte operator to force the expression into byte size */
+    return LoByte (Expr);
+}
 
-       case EXPR_BNOT:
-                   return !GetExprVal (Expr->Left);
 
-       case EXPR_ULABEL:
-           Internal ("GetExprVal called for EXPR_ULABEL");
-           /* NOTREACHED */
-           return 0;
 
-        default:
-           Internal ("Unknown Op type: %u", Expr->Op);
-           /* NOTREACHED */
-           return 0;
-    }
+ExprNode* GenWordExpr (ExprNode* Expr)
+/* Force the given expression into a word and return the result. */
+{
+    /* Use the low byte operator to force the expression into word size */
+    return LoWord (Expr);
 }
 
 
 
-static ExprNode* RemoveSyms (ExprNode* Expr, int MustClone)
-/* Remove resolved symbols from the tree by cloning symbol expressions */
+ExprNode* GenFarAddrExpr (ExprNode* Expr)
+/* Force the given expression into a far address and return the result. */
 {
-    /* Accept NULL pointers */
-    if (Expr == 0) {
-       return 0;
-    }
-
-    /* Special node handling */
-    switch (Expr->Op) {
-
-       case EXPR_SYMBOL:
-           if (SymHasExpr (Expr->V.Sym)) {
-               /* The symbol has an expression tree */
-               SymEntry* Sym = Expr->V.Sym;
-               if (SymHasUserMark (Sym)) {
-                   /* Circular definition */
-                   if (Verbosity) {
-                       DumpExpr (Expr);
-                   }
-                   PError (GetSymPos (Sym), ERR_CIRCULAR_REFERENCE);
-                   return LiteralExpr (0);             /* Return a dummy value */
-               }
-               SymMarkUser (Sym);
-               Expr = RemoveSyms (GetSymExpr (Sym), 1);
-               SymUnmarkUser (Sym);
-               return Expr;
-           } else if (SymIsConst (Expr->V.Sym)) {
-               /* The symbol is a constant */
-               return LiteralExpr (GetSymVal (Expr->V.Sym));
-           }
-           break;
-
-       case EXPR_ULABEL:
-           if (ULabCanResolve ()) {
-               ExprNode* NewExpr = ULabResolve (Expr->V.Val);
-               FreeExpr (Expr);
-               Expr = NewExpr;
-           }
-           break;
+    long      Val;
 
+    /* Special handling for const expressions */
+    if (IsEasyConst (Expr, &Val)) {
+        FreeExpr (Expr);
+        Expr = GenLiteralExpr (Val & 0xFFFFFF);
+    } else {
+        ExprNode* Operand = Expr;
+        Expr = NewExprNode (EXPR_FARADDR);
+        Expr->Left = Operand;
     }
+    return Expr;
+}
 
-    /* Clone the current node if needed */
-    if (MustClone) {
-
-       /* Create a new node */
-               ExprNode* Clone = NewExprNode ();
-
-       /* Clone the operation */
-       Clone->Op = Expr->Op;
-
-       /* Clone the attribute if needed */
-       switch (Expr->Op) {
-
-           case EXPR_LITERAL:
-           case EXPR_ULABEL:
-               Clone->V.Val = Expr->V.Val;
-               break;
-
-           case EXPR_SYMBOL:
-               Clone->V.Sym = Expr->V.Sym;
-               break;
-
-           case EXPR_SECTION:
-               Clone->V.SegNum = Expr->V.SegNum;
-               break;
-
-       }
 
-       /* Clone the tree nodes */
-               Clone->Left = RemoveSyms (Expr->Left, MustClone);
-       Clone->Right = RemoveSyms (Expr->Right, MustClone);
 
-       /* Done */
-       return Clone;
+ExprNode* GenDWordExpr (ExprNode* Expr)
+/* Force the given expression into a dword and return the result. */
+{
+    long      Val;
 
+    /* Special handling for const expressions */
+    if (IsEasyConst (Expr, &Val)) {
+        FreeExpr (Expr);
+        Expr = GenLiteralExpr (Val & 0xFFFFFFFF);
     } else {
-
-       /* Nothing to clone */
-       Expr->Left = RemoveSyms (Expr->Left, MustClone);
-       Expr->Right = RemoveSyms (Expr->Right, MustClone);
-
-       /* Done */
-       return Expr;
-
+        ExprNode* Operand = Expr;
+        Expr = NewExprNode (EXPR_DWORD);
+        Expr->Left = Operand;
     }
+    return Expr;
 }
 
 
 
-static ExprNode* ConstExtract (ExprNode* Expr, long* Val, int Sign)
-/* Extract and evaluate all constant factors in an subtree that has only
- * additions and subtractions.
- */
+ExprNode* GenNE (ExprNode* Expr, long Val)
+/* Generate an expression that compares Expr and Val for inequality */
 {
-    if (Expr->Op == EXPR_LITERAL) {
-       if (Sign < 0) {
-           *Val -= Expr->V.Val;
-       } else {
-           *Val += Expr->V.Val;
-       }
-               FreeExprNode (Expr);
-       return 0;
-    }
-
-    if (Expr->Op == EXPR_PLUS || Expr->Op == EXPR_MINUS) {
-       ExprNode* Left;
-       ExprNode* Right;
-       Left = ConstExtract (Expr->Left, Val, Sign);
-       if (Expr->Op == EXPR_MINUS) {
-           Sign = -Sign;
-       }
-       Right = ConstExtract (Expr->Right, Val, Sign);
-       if (Left == 0 && Right == 0) {
-           FreeExprNode (Expr);
-           return 0;
-       } else if (Left == 0) {
-           FreeExprNode (Expr);
-           return Right;
-       } else if (Right == 0) {
-           FreeExprNode (Expr);
-           return Left;
-       } else {
-           /* Check for SEG - SEG which is now possible */
-           if (Left->Op == EXPR_SECTION && Right->Op == EXPR_SECTION &&
-               Left->V.SegNum == Right->V.SegNum) {
-               /* SEG - SEG, remove it completely */
-               FreeExprNode (Left);
-               FreeExprNode (Right);
-               FreeExprNode (Expr);
-               return 0;
-           } else {
-               Expr->Left  = Left;
-               Expr->Right = Right;
-               return Expr;
-           }
-       }
-    }
-
-    /* Some other sort of node, finalize the terms */
-    if (Expr->Left) {
-       Expr->Left = FinalizeExpr (Expr->Left);
-    }
-    if (Expr->Right) {
-       Expr->Right = FinalizeExpr (Expr->Right);
-    }
+    /* Generate a compare node */
+    ExprNode* Root = NewExprNode (EXPR_NE);
+    Root->Left  = Expr;
+    Root->Right = GenLiteralExpr (Val);
 
-    return Expr;
+    /* Return the result */
+    return Root;
 }
 
 
 
-ExprNode* FinalizeExpr (ExprNode* Expr)
-/* Resolve any symbols by cloning the symbol expression tree instead of the
- * symbol reference, then try to simplify the expression as much as possible.
- * This function must only be called if all symbols are resolved (no undefined
- * symbol errors).
+int IsConstExpr (ExprNode* Expr, long* Val)
+/* Return true if the given expression is a constant expression, that is, one
+ * with no references to external symbols. If Val is not NULL and the
+ * expression is constant, the constant value is stored here.
  */
 {
-    long Val = 0;
-    ExprNode* N;
+    int IsConst;
 
-    Expr = RemoveSyms (Expr, 0);
-    Expr = ConstExtract (Expr, &Val, 1);
-    if (Expr == 0) {
-       /* Reduced to a literal value */
-       Expr = LiteralExpr (Val);
-    } else if (Val) {
-       /* Extracted a value */
-       N = NewExprNode ();
-       N->Op = EXPR_PLUS;
-       N->Left = Expr;
-       N->Right = LiteralExpr (Val);
-       Expr = N;
+    /* Study the expression */
+    ExprDesc D;
+    ED_Init (&D);
+    StudyExpr (Expr, &D);
+
+    /* Check if the expression is constant */
+    IsConst = ED_IsConst (&D);
+    if (IsConst && Val != 0) {
+        *Val = D.Val;
     }
-    return Expr;
+
+    /* Delete allocated memory and return the result */
+    ED_Done (&D);
+    return IsConst;
 }
 
 
@@ -1574,34 +1795,38 @@ ExprNode* CloneExpr (ExprNode* Expr)
         return 0;
     }
 
-    /* Get a new node */
-    Clone = NewExprNode ();
+    /* Clone the node */
+    switch (Expr->Op) {
 
-    /* Clone the operation */
-    Clone->Op = Expr->Op;
+        case EXPR_LITERAL:
+            Clone = GenLiteralExpr (Expr->V.IVal);
+            break;
 
-    /* Clone the attribute if needed */
-    switch (Expr->Op) {
+        case EXPR_ULABEL:
+            Clone = GenULabelExpr (Expr->V.IVal);
+            break;
 
-       case EXPR_LITERAL:
-       case EXPR_ULABEL:
-           Clone->V.Val = Expr->V.Val;
-           break;
+        case EXPR_SYMBOL:
+            Clone = GenSymExpr (Expr->V.Sym);
+            break;
 
-       case EXPR_SYMBOL:
-           Clone->V.Sym = Expr->V.Sym;
-           break;
+        case EXPR_SECTION:
+            Clone = GenSectionExpr (Expr->V.SecNum);
+            break;
 
-       case EXPR_SECTION:
-           Clone->V.SegNum = Expr->V.SegNum;
-           break;
+        case EXPR_BANK:
+            Clone = GenBankExpr (Expr->V.SecNum);
+            break;
 
+        default:
+            /* Generate a new node */
+            Clone = NewExprNode (Expr->Op);
+            /* Clone the tree nodes */
+            Clone->Left = CloneExpr (Expr->Left);
+            Clone->Right = CloneExpr (Expr->Right);
+            break;
     }
 
-    /* Clone the tree nodes */
-    Clone->Left = CloneExpr (Expr->Left);
-    Clone->Right = CloneExpr (Expr->Right);
-
     /* Done */
     return Clone;
 }
@@ -1613,44 +1838,110 @@ void WriteExpr (ExprNode* Expr)
 {
     /* Null expressions are encoded by a type byte of zero */
     if (Expr == 0) {
-       ObjWrite8 (0);
-       return;
+        ObjWrite8 (EXPR_NULL);
+        return;
     }
 
-    /* Write the expression code */
-    ObjWrite8 (Expr->Op);
-
     /* If the is a leafnode, write the expression attribute, otherwise
      * write the expression operands.
      */
     switch (Expr->Op) {
 
         case EXPR_LITERAL:
-           ObjWrite32 (Expr->V.Val);
-           break;
+            ObjWrite8 (EXPR_LITERAL);
+            ObjWrite32 (Expr->V.IVal);
+            break;
 
         case EXPR_SYMBOL:
-           /* Maybe we should use a code here? */
-           CHECK (SymIsImport (Expr->V.Sym));  /* Safety */
-           ObjWriteVar (GetSymIndex (Expr->V.Sym));
-           break;
+            if (SymIsImport (Expr->V.Sym)) {
+                ObjWrite8 (EXPR_SYMBOL);
+                ObjWriteVar (GetSymImportId (Expr->V.Sym));
+            } else {
+                WriteExpr (GetSymExpr (Expr->V.Sym));
+            }
+            break;
 
         case EXPR_SECTION:
-           ObjWrite8 (Expr->V.SegNum);
-           break;
+            ObjWrite8 (EXPR_SECTION);
+            ObjWriteVar (Expr->V.SecNum);
+            break;
 
-       case EXPR_ULABEL:
-           Internal ("WriteExpr: Cannot write EXPR_ULABEL nodes");
-           break;
+        case EXPR_ULABEL:
+            WriteExpr (ULabResolve (Expr->V.IVal));
+            break;
 
         default:
-           /* Not a leaf node */
-           WriteExpr (Expr->Left);
-           WriteExpr (Expr->Right);
-           break;
+            /* Not a leaf node */
+            ObjWrite8 (Expr->Op);
+            WriteExpr (Expr->Left);
+            WriteExpr (Expr->Right);
+            break;
 
     }
 }
 
 
 
+void ExprGuessedAddrSize (const ExprNode* Expr, unsigned char AddrSize)
+/* Mark the address size of the given expression tree as guessed. The address
+ * size passed as argument is the one NOT used, because the actual address
+ * size wasn't known. Example: Zero page addressing was not used because symbol
+ * is undefined, and absolute addressing was available.
+ * This function will actually parse the expression tree for undefined symbols,
+ * and mark these symbols accordingly.
+ */
+{
+    /* Accept NULL expressions */
+    if (Expr == 0) {
+        return;
+    }
+
+    /* Check the type code */
+    switch (EXPR_NODETYPE (Expr->Op)) {
+
+        case EXPR_LEAFNODE:
+            if (Expr->Op == EXPR_SYMBOL) {
+                if (!SymIsDef (Expr->V.Sym)) {
+                    /* Symbol is undefined, mark it */
+                    SymGuessedAddrSize (Expr->V.Sym, AddrSize);
+                }
+            }
+            return;
+
+        case EXPR_BINARYNODE:
+            ExprGuessedAddrSize (Expr->Right, AddrSize);
+            /* FALLTHROUGH */
+
+        case EXPR_UNARYNODE:
+            ExprGuessedAddrSize (Expr->Left, AddrSize);
+            break;
+    }
+}
+
+
+
+ExprNode* MakeBoundedExpr (ExprNode* Expr, unsigned Size)
+/* Force the given expression into a specific size of ForceRange is true */
+{
+    if (ForceRange) {
+        switch (Size) {
+            case 1:     Expr = GenByteExpr (Expr);      break;
+            case 2:     Expr = GenWordExpr (Expr);      break;
+            case 3:     Expr = GenFarAddrExpr (Expr);   break;
+            case 4:     Expr = GenDWordExpr (Expr);     break;
+            default:    Internal ("Invalid size in BoundedExpr: %u", Size);
+        }
+    }
+    return Expr;
+}
+
+
+
+ExprNode* BoundedExpr (ExprNode* (*ExprFunc) (void), unsigned Size)
+/* Parse an expression and force it within a given size if ForceRange is true */
+{
+    return MakeBoundedExpr (ExprFunc (), Size);
+}
+
+
+