]> git.sur5r.net Git - cc65/blobdiff - src/ca65/expr.c
Mark segments that are referenced in a .BANK statement.
[cc65] / src / ca65 / expr.c
index dcb2f681e862a3c7b20d8966e4f529ad988c955f..b5af9dc4daececa903d7d7c96b26906f7686da26 100644 (file)
@@ -6,10 +6,10 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 1998-2003 Ullrich von Bassewitz                                       */
-/*               Römerstraße 52                                              */
-/*               D-70794 Filderstadt                                         */
-/* EMail:        uz@cc65.org                                                 */
+/* (C) 1998-2012, Ullrich von Bassewitz                                      */
+/*                Roemerstrasse 52                                           */
+/*                D-70794 Filderstadt                                        */
+/* EMail:         uz@cc65.org                                                */
 /*                                                                           */
 /*                                                                           */
 /* This software is provided 'as-is', without any expressed or implied       */
@@ -42,6 +42,8 @@
 #include "exprdefs.h"
 #include "print.h"
 #include "shift.h"
+#include "segdefs.h"
+#include "strbuf.h"
 #include "tgttrans.h"
 #include "version.h"
 #include "xmalloc.h"
@@ -54,7 +56,7 @@
 #include "nexttok.h"
 #include "objfile.h"
 #include "segment.h"
-#include "struct.h"
+#include "sizeof.h"
 #include "studyexpr.h"
 #include "symbol.h"
 #include "symtab.h"
@@ -64,7 +66,7 @@
 
 
 /*****************************************************************************/
-/*                                          Data                                    */
+/*                                          Data                                    */
 /*****************************************************************************/
 
 
@@ -93,10 +95,11 @@ static ExprNode* NewExprNode (unsigned Op)
     ExprNode* N;
 
     /* Do we have some nodes in the list already? */
-    if (FreeExprNodes) {
+    if (FreeNodeCount) {
        /* Use first node from list */
        N = FreeExprNodes;
        FreeExprNodes = N->Left;
+        --FreeNodeCount;
     } else {
        /* Allocate fresh memory */
         N = xmalloc (sizeof (ExprNode));
@@ -123,6 +126,7 @@ static void FreeExprNode (ExprNode* E)
            /* Remember this node for later */
            E->Left = FreeExprNodes;
            FreeExprNodes = E;
+            ++FreeNodeCount;
        } else {
            /* Free the memory */
            xfree (E);
@@ -166,7 +170,7 @@ int IsFarRange (long Val)
 
 
 
-static int IsEasyConst (const ExprNode* E, long* Val)
+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.
@@ -184,7 +188,7 @@ static int IsEasyConst (const ExprNode* E, long* Val)
     /* Symbols resolved, check for a literal */
     if (E->Op == EXPR_LITERAL) {
         if (Val) {
-            *Val = E->V.Val;
+            *Val = E->V.IVal;
         }
         return 1;
     }
@@ -195,34 +199,190 @@ static int IsEasyConst (const ExprNode* E, long* Val)
 
 
 
+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_BANKRAW);
+    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 */
 {
-    int Result = 1;
-
-    /* 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) {
-       /* 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 ();
+    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;
        }
-       return 0;
+
+       /* One more token */
+       ++Count;
+
+       /* Skip the token */
+       NextTok ();
     }
-    return GenLiteralExpr (Result);
+
+    /* 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);
 }
 
 
@@ -249,7 +409,7 @@ static ExprNode* FuncDefined (void)
 /* Handle the .DEFINED builtin function */
 {
     /* Parse the symbol name and search for the symbol */
-    SymEntry* Sym = ParseScopedSymName (SYM_FIND_EXISTING);
+    SymEntry* Sym = ParseAnySymName (SYM_FIND_EXISTING);
 
     /* Check if the symbol is defined */
     return GenLiteralExpr (Sym != 0 && SymIsDef (Sym));
@@ -257,25 +417,58 @@ static ExprNode* FuncDefined (void)
 
 
 
+ExprNode* FuncHiByte (void)
+/* Handle the .HIBYTE builtin function */
+{
+    return HiByte (Expression ());
+}
+
+
+
+static ExprNode* FuncHiWord (void)
+/* Handle the .HIWORD builtin function */
+{
+    return HiWord (Expression ());
+}
+
+
+
+ExprNode* FuncLoByte (void)
+/* Handle the .LOBYTE builtin function */
+{
+    return LoByte (Expression ());
+}
+
+
+
+static ExprNode* FuncLoWord (void)
+/* Handle the .LOWORD builtin function */
+{
+    return LoWord (Expression ());
+}
+
+
+
 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) {
+    token_t Term = GetTokListTerm (TOK_COMMA);
+    while (CurTok.Tok != Term) {
 
        /* We may not end-of-line of end-of-file here */
-       if (TokIsSep (Tok)) {
+       if (TokIsSep (CurTok.Tok)) {
            Error ("Unexpected end of line");
-           return 0;
-       }
+           return GenLiteral0 ();
+       }
 
        /* Get a node with this token */
        Node = NewTokNode ();
@@ -292,20 +485,27 @@ static ExprNode* DoMatch (enum TC EqualityLevel)
        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) {
+    while (CurTok.Tok != Term) {
 
        /* We may not end-of-line of end-of-file here */
-       if (TokIsSep (Tok)) {
+       if (TokIsSep (CurTok.Tok)) {
            Error ("Unexpected end of line");
-           return 0;
+           return GenLiteral0 ();
        }
 
                /* Compare the tokens if the result is not already known */
@@ -328,6 +528,11 @@ static ExprNode* DoMatch (enum TC EqualityLevel)
        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;
@@ -354,11 +559,69 @@ static ExprNode* FuncMatch (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 */
 {
     /* Parse the symbol name and search for the symbol */
-    SymEntry* Sym = ParseScopedSymName (SYM_FIND_EXISTING);
+    SymEntry* Sym = ParseAnySymName (SYM_FIND_EXISTING);
 
     /* Check if the symbol is referenced */
     return GenLiteralExpr (Sym != 0 && SymIsRef (Sym));
@@ -369,19 +632,92 @@ static ExprNode* FuncReferenced (void)
 static ExprNode* FuncSizeOf (void)
 /* Handle the .SIZEOF function */
 {
-    long Size;
+    StrBuf    ScopeName = STATIC_STRBUF_INITIALIZER;
+    StrBuf    Name = STATIC_STRBUF_INITIALIZER;
+    SymTable* Scope;
+    SymEntry* Sym;
+    SymEntry* SizeSym;
+    long      Size;
+    int       NoScope;
+
 
-    /* Get the struct for the scoped struct name */
-    SymTable* Struct = ParseScopedSymTable (SYM_FIND_EXISTING);
+    /* 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);
 
-    /* Check if the given symbol is really a struct */
-    if (GetSymTabType (Struct) != ST_STRUCT) {
-        Error ("Argument to .SIZEOF is not a struct");
-        Size = 1;
     } else {
-        Size = GetStructSize (Struct);
+
+        /* 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);
+            }
+        }
+    }
+
+    /* 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);
 }
@@ -391,20 +727,19 @@ static ExprNode* FuncSizeOf (void)
 static ExprNode* FuncStrAt (void)
 /* Handle the .STRAT function */
 {
-    char Str [sizeof(SVal)];
+    StrBuf Str = STATIC_STRBUF_INITIALIZER;
     long Index;
-    unsigned char C;
+    unsigned char C = 0;
 
     /* String constant expected */
-    if (Tok != TOK_STRCON) {
+    if (CurTok.Tok != TOK_STRCON) {
        Error ("String constant expected");
        NextTok ();
-               return 0;
-
+               goto ExitPoint;
     }
 
     /* Remember the string and skip it */
-    strcpy (Str, SVal);
+    SB_Copy (&Str, &CurTok.SVal);
     NextTok ();
 
     /* Comma must follow */
@@ -414,15 +749,19 @@ static ExprNode* FuncStrAt (void)
     Index = ConstExpression ();
 
     /* Must be a valid index */
-    if (Index >= (long) strlen (Str)) {
+    if (Index >= (long) SB_GetLen (&Str)) {
        Error ("Range error");
-       return 0;
+        goto ExitPoint;
     }
 
     /* Get the char, handle as unsigned. Be sure to translate it into
      * the target character set.
      */
-    C = 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);
@@ -436,11 +775,11 @@ static ExprNode* FuncStrLen (void)
     int Len;
 
     /* String constant expected */
-    if (Tok != TOK_STRCON) {
+    if (CurTok.Tok != TOK_STRCON) {
 
        Error ("String constant expected");
        /* Smart error recovery */
-       if (Tok != TOK_RPAREN) {
+       if (CurTok.Tok != TOK_RPAREN) {
            NextTok ();
        }
                Len = 0;
@@ -448,7 +787,7 @@ static ExprNode* FuncStrLen (void)
     } else {
 
         /* Get the length of the string */
-       Len = strlen (SVal);
+               Len = SB_GetLen (&CurTok.SVal);
 
        /* Skip the string */
        NextTok ();
@@ -464,34 +803,32 @@ 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) {
+    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 (Tok)) {
+       if (TokIsSep (CurTok.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 ();
     }
 
+    /* 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 GenLiteralExpr (Count);
 }
@@ -515,10 +852,10 @@ static ExprNode* Function (ExprNode* (*F) (void))
     NextTok ();
 
     /* Expression must be enclosed in braces */
-    if (Tok != TOK_LPAREN) {
+    if (CurTok.Tok != TOK_LPAREN) {
        Error ("'(' expected");
        SkipUntilSep ();
-       return GenLiteralExpr (0);
+       return GenLiteral0 ();
     }
     NextTok ();
 
@@ -538,46 +875,36 @@ static ExprNode* Factor (void)
 {
     ExprNode* L;
     ExprNode* N;
-    SymEntry* S;
     long      Val;
 
-    switch (Tok) {
+    switch (CurTok.Tok) {
 
        case TOK_INTCON:
-           N = GenLiteralExpr (IVal);
+           N = GenLiteralExpr (CurTok.IVal);
                    NextTok ();
            break;
 
        case TOK_CHARCON:
-           N = GenLiteralExpr (TgtTranslateChar (IVal));
+           N = GenLiteralExpr (TgtTranslateChar (CurTok.IVal));
                    NextTok ();
            break;
 
        case TOK_NAMESPACE:
        case TOK_IDENT:
-           /* Search for the symbol */
-           S = ParseScopedSymName (SYM_ALLOC_NEW);
-           if (S == 0) {
-               /* Some weird error happened before */
-               N = GenLiteralExpr (0);
-           } else {
-               /* Mark the symbol as referenced */
-               SymRef (S);
-                /* Remove the symbol if possible */
-                if (SymHasExpr (S)) {
-                    N = CloneExpr (GetSymExpr (S));
-                } else {
-                    /* Create symbol node */
-                    N = GenSymExpr (S);
-                }
-           }
+        case TOK_LOCAL_IDENT:
+            N = Symbol (ParseAnySymName (SYM_ALLOC_NEW));
            break;
 
        case TOK_ULABEL:
-           N = ULabRef (IVal);
+           N = ULabRef (CurTok.IVal);
            NextTok ();
            break;
 
+        case TOK_PLUS:
+            NextTok ();
+            N = Factor ();
+            break;
+
        case TOK_MINUS:
            NextTok ();
             L = Factor ();
@@ -610,38 +937,18 @@ static ExprNode* Factor (void)
 
        case TOK_LT:
            NextTok ();
-            L = Factor ();
-            if (IsEasyConst (L, &Val)) {
-                FreeExpr (L);
-                N = GenLiteralExpr (Val & 0xFF);
-            } else {
-                N = NewExprNode (EXPR_BYTE0);
-                N->Left = L;
-            }
+            N = LoByte (Factor ());
            break;
 
        case TOK_GT:
            NextTok ();
-            L = Factor ();
-            if (IsEasyConst (L, &Val)) {
-                FreeExpr (L);
-                N = GenLiteralExpr ((Val >> 8) & 0xFF);
-            } else {
-                N = NewExprNode (EXPR_BYTE1);
-                N->Left = L;
-            }
+            N = HiByte (Factor ());
            break;
 
-        case TOK_BANK:
+        case TOK_XOR:
+            /* ^ means the bank byte of an expression */
             NextTok ();
-            L = Factor ();
-            if (IsEasyConst (L, &Val)) {
-                FreeExpr (L);
-                N = GenLiteralExpr ((Val >> 16) & 0xFF);
-            } else {
-                N = NewExprNode (EXPR_BYTE2);
-                N->Left = L;
-            }
+            N = BankByte (Factor ());
             break;
 
        case TOK_LPAREN:
@@ -650,6 +957,14 @@ static ExprNode* Factor (void)
                    ConsumeRParen ();
            break;
 
+        case TOK_BANK:
+            N = Function (FuncBank);
+            break;
+
+        case TOK_BANKBYTE:
+            N = Function (FuncBankByte);
+            break;
+
         case TOK_BLANK:
            N = Function (FuncBlank);
            break;
@@ -667,10 +982,34 @@ static ExprNode* Factor (void)
            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_MAX:
+            N = Function (FuncMax);
+            break;
+
+        case TOK_MIN:
+            N = Function (FuncMin);
+            break;
+
         case TOK_REFERENCED:
            N = Function (FuncReferenced);
            break;
@@ -697,7 +1036,7 @@ static ExprNode* Factor (void)
            break;
 
         case TOK_VERSION:
-            N = GenLiteralExpr (VERSION);
+            N = GenLiteralExpr (GetVersionAsNumber ());
             NextTok ();
             break;
 
@@ -706,11 +1045,12 @@ static ExprNode* Factor (void)
            break;
 
        default:
-           if (LooseCharTerm && Tok == TOK_STRCON && strlen(SVal) == 1) {
+           if (LooseCharTerm && CurTok.Tok == TOK_STRCON &&
+                SB_GetLen (&CurTok.SVal) == 1) {
                /* A character constant */
-               N = GenLiteralExpr (TgtTranslateChar (SVal[0]));
+               N = GenLiteralExpr (TgtTranslateChar (SB_At (&CurTok.SVal, 0)));
            } else {
-               N = GenLiteralExpr (0); /* Dummy */
+               N = GenLiteral0 ();     /* Dummy */
                Error ("Syntax error");
            }
            NextTok ();
@@ -727,16 +1067,17 @@ static ExprNode* Term (void)
     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) {
+    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 */
-        enum Token T = Tok;
+        token_t T = CurTok.Tok;
         NextTok ();
 
         /* Move root to left side and read the right side */
@@ -830,14 +1171,16 @@ static ExprNode* SimpleExpr (void)
     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) {
 
         long LVal, RVal, Val;
         ExprNode* Left;
         ExprNode* Right;
 
         /* Remember the token and skip it */
-        enum Token T = Tok;
+        token_t T = CurTok.Tok;
         NextTok ();
 
         /* Move root to left side and read the right side */
@@ -891,15 +1234,16 @@ 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) {
+    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 */
-        enum Token T = Tok;
+        token_t T = CurTok.Tok;
         NextTok ();
 
         /* Move root to left side and read the right side */
@@ -959,14 +1303,14 @@ static ExprNode* Expr2 (void)
     ExprNode* Root = BoolExpr ();
 
     /* Handle booleans */
-    while (Tok == TOK_BOOLAND || Tok == TOK_BOOLXOR) {
+    while (CurTok.Tok == TOK_BOOLAND || CurTok.Tok == TOK_BOOLXOR) {
 
         long LVal, RVal, Val;
         ExprNode* Left;
         ExprNode* Right;
 
         /* Remember the token and skip it */
-        enum Token T = Tok;
+        token_t T = CurTok.Tok;
         NextTok ();
 
         /* Move root to left side and read the right side */
@@ -1018,14 +1362,14 @@ static ExprNode* Expr1 (void)
     ExprNode* Root = Expr2 ();
 
     /* Handle booleans */
-    while (Tok == TOK_BOOLOR) {
+    while (CurTok.Tok == TOK_BOOLOR) {
 
         long LVal, RVal, Val;
         ExprNode* Left;
         ExprNode* Right;
 
         /* Remember the token and skip it */
-        enum Token T = Tok;
+        token_t T = CurTok.Tok;
         NextTok ();
 
         /* Move root to left side and read the right side */
@@ -1074,7 +1418,7 @@ static ExprNode* Expr0 (void)
     ExprNode* Root;
 
     /* Handle booleans */
-    if (Tok == TOK_BOOLNOT) {
+    if (CurTok.Tok == TOK_BOOLNOT) {
 
         long Val;
         ExprNode* Left;
@@ -1112,16 +1456,7 @@ ExprNode* Expression (void)
  * a pointer to the root of the tree.
  */
 {
-#if 1
-    return SimplifyExpr (Expr0 ());
-#else
-    /* Test code */
-    ExprNode* Expr = Expr0 ();
-    printf ("Before: "); DumpExpr (Expr, SymResolve);
-    Expr = SimplifyExpr (Expr);
-    printf ("After:  "); DumpExpr (Expr, SymResolve);
-    return Expr;
-#endif
+    return Expr0 ();
 }
 
 
@@ -1134,13 +1469,8 @@ long ConstExpression (void)
 {
     long Val;
 
-#if 1
     /* Read the expression */
-    ExprNode* Expr = Expr0 ();
-#else
-    /* Test code */
     ExprNode* Expr = Expression ();
-#endif
 
     /* Study the expression */
     ExprDesc D;
@@ -1170,34 +1500,20 @@ void FreeExpr (ExprNode* Root)
 {
     if (Root) {
        FreeExpr (Root->Left);
-       FreeExpr (Root->Right);
-       FreeExprNode (Root);
+       FreeExpr (Root->Right);
+       FreeExprNode (Root);
     }
 }
 
 
 
-ExprNode* SimplifyExpr (ExprNode* Expr)
+ExprNode* SimplifyExpr (ExprNode* Expr, const ExprDesc* D)
 /* Try to simplify the given expression tree */
 {
-    if (Expr && Expr->Op != EXPR_LITERAL) {
-
-        /* Create an expression description and initialize it */
-        ExprDesc D;
-        ED_Init (&D);
-
-        /* Study the expression */
-        StudyExpr (Expr, &D);
-
-        /* Now check if we can generate a literal value */
-        if (ED_IsConst (&D)) {
-            /* No external references */
-            FreeExpr (Expr);
-            Expr = GenLiteralExpr (D.Val);
-        }
-
-        /* Free allocated memory */
-        ED_Done (&D);
+    if (Expr->Op != EXPR_LITERAL && ED_IsConst (D)) {
+        /* No external references */
+        FreeExpr (Expr);
+        Expr = GenLiteralExpr (D->Val);
     }
     return Expr;
 }
@@ -1208,12 +1524,20 @@ ExprNode* GenLiteralExpr (long Val)
 /* Return an expression tree that encodes the given literal value */
 {
     ExprNode* Expr = NewExprNode (EXPR_LITERAL);
-    Expr->V.Val = Val;
+    Expr->V.IVal = Val;
     return Expr;
 }
 
 
 
+ExprNode* GenLiteral0 (void)
+/* Return an expression tree that encodes the the number zero */
+{
+    return GenLiteralExpr (0);
+}
+
+
+
 ExprNode* GenSymExpr (SymEntry* Sym)
 /* Return an expression node that encodes the given symbol */
 {
@@ -1225,11 +1549,21 @@ ExprNode* GenSymExpr (SymEntry* Sym)
 
 
 
-static ExprNode* GenSectionExpr (unsigned SegNum)
+static ExprNode* GenSectionExpr (unsigned SecNum)
 /* Return an expression node for the given section */
 {
     ExprNode* Expr = NewExprNode (EXPR_SECTION);
-    Expr->V.SegNum = SegNum;
+    Expr->V.SecNum = SecNum;
+    return Expr;
+}
+
+
+
+static ExprNode* GenBankExpr (unsigned SecNum)
+/* Return an expression node for the given bank */
+{
+    ExprNode* Expr = NewExprNode (EXPR_BANK);
+    Expr->V.SecNum = SecNum;
     return Expr;
 }
 
@@ -1238,10 +1572,19 @@ static ExprNode* GenSectionExpr (unsigned SegNum)
 ExprNode* GenAddExpr (ExprNode* Left, ExprNode* Right)
 /* Generate an addition from the two operands */
 {
-    ExprNode* Root = NewExprNode (EXPR_PLUS);
-    Root->Left = Left;
-    Root->Right = Right;
-    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;
+    }
 }
 
 
@@ -1251,7 +1594,7 @@ ExprNode* GenCurrentPC (void)
 {
     ExprNode* Root;
 
-    if (RelocMode) {
+    if (GetRelocMode ()) {
        /* Create SegmentBase + Offset */
                Root = GenAddExpr (GenSectionExpr (GetCurrentSegNum ()),
                            GenLiteralExpr (GetPC ()));
@@ -1300,7 +1643,7 @@ ExprNode* GenBranchExpr (unsigned Offs)
          * (Val - PC - Offs) - Seg
          */
         Root = GenLiteralExpr (Val - GetPC () - Offs);
-        if (RelocMode) {
+        if (GetRelocMode ()) {
             N = Root;
             Root = NewExprNode (EXPR_MINUS);
             Root->Left  = N;
@@ -1318,7 +1661,7 @@ ExprNode* GenBranchExpr (unsigned Offs)
         Root = NewExprNode (EXPR_MINUS);
         Root->Left  = N;
         Root->Right = GenLiteralExpr (GetPC () + Offs);
-        if (RelocMode) {
+        if (GetRelocMode ()) {
             N = Root;
             Root = NewExprNode (EXPR_MINUS);
             Root->Left  = N;
@@ -1336,7 +1679,7 @@ ExprNode* GenULabelExpr (unsigned Num)
 /* Return an expression for an unnamed label with the given index */
 {
     ExprNode* Node = NewExprNode (EXPR_ULABEL);
-    Node->V.Val        = Num;
+    Node->V.IVal       = Num;
 
     /* Return the new node */
     return Node;
@@ -1348,11 +1691,7 @@ ExprNode* GenByteExpr (ExprNode* Expr)
 /* Force the given expression into a byte and return the result */
 {
     /* Use the low byte operator to force the expression into byte size */
-    ExprNode* Root = NewExprNode (EXPR_BYTE0);
-    Root->Left  = Expr;
-
-    /* Return the result */
-    return Root;
+    return LoByte (Expr);
 }
 
 
@@ -1360,13 +1699,8 @@ ExprNode* GenByteExpr (ExprNode* Expr)
 ExprNode* GenWordExpr (ExprNode* Expr)
 /* Force the given expression into a word and return the result. */
 {
-    /* AND the expression by $FFFF to force it into word size */
-    ExprNode* Root = NewExprNode (EXPR_AND);
-    Root->Left  = Expr;
-    Root->Right        = GenLiteralExpr (0xFFFF);
-
-    /* Return the result */
-    return Root;
+    /* Use the low byte operator to force the expression into word size */
+    return LoWord (Expr);
 }
 
 
@@ -1411,103 +1745,6 @@ int IsConstExpr (ExprNode* Expr, long* Val)
 
 
 
-static void CheckAddrSize (const ExprNode* N, unsigned char* AddrSize)
-/* Internal routine that is recursively called to check for the address size
- * of the expression tree.
- */
-{
-    unsigned char A;
-    unsigned char Left, Right;
-
-    if (N) {
-       switch (N->Op & EXPR_TYPEMASK) {
-
-           case EXPR_LEAFNODE:
-               switch (N->Op) {
-
-                   case EXPR_SYMBOL:
-                       if (SymIsZP (N->V.Sym)) {
-                           if (*AddrSize < ADDR_SIZE_ZP) {
-                                *AddrSize = ADDR_SIZE_ZP;
-                            }
-                       } else if (SymHasExpr (N->V.Sym)) {
-                           /* Check if this expression is a byte expression */
-                           CheckAddrSize (GetSymExpr (N->V.Sym), AddrSize);
-                       } else {
-                            /* Undefined symbol, use absolute */
-                            if (*AddrSize < ADDR_SIZE_ABS) {
-                                *AddrSize = ADDR_SIZE_ABS;
-                            }
-                        }
-                       break;
-
-                   case EXPR_SECTION:
-                        A = GetSegAddrSize (N->V.SegNum);
-                        if (A > *AddrSize) {
-                            *AddrSize = A;
-                        }
-                       break;
-
-               }
-               break;
-
-           case EXPR_UNARYNODE:
-                switch (N->Op) {
-
-                    case EXPR_BYTE0:
-                    case EXPR_BYTE1:
-                    case EXPR_BYTE2:
-                    case EXPR_BYTE3:
-                        /* No need to look at the expression */
-                        *AddrSize = ADDR_SIZE_ZP;
-                        break;
-
-                    case EXPR_WORD0:
-                    case EXPR_WORD1:
-                        /* No need to look at the expression */
-                        *AddrSize = ADDR_SIZE_ABS;
-                        break;
-
-                    default:
-                        CheckAddrSize (N->Left, AddrSize);
-                        break;
-                }
-                break;
-
-           case EXPR_BINARYNODE:
-                Left = Right = ADDR_SIZE_DEFAULT;
-               CheckAddrSize (N->Left, &Left);
-               CheckAddrSize (N->Right, &Right);
-                A = (Left > Right)? Left : Right;
-                if (A > *AddrSize) {
-                    *AddrSize = A;
-                }
-               break;
-
-           default:
-               Internal ("Unknown expression op: %02X", N->Op);
-       }
-    }
-}
-
-
-
-int IsByteExpr (ExprNode* Root)
-/* Return true if this is a byte expression */
-{
-    long Val;
-
-    if (IsConstExpr (Root, &Val)) {
-               return IsByteRange (Val);
-    } else {
-        unsigned char AddrSize = ADDR_SIZE_DEFAULT;
-        CheckAddrSize (Root, &AddrSize);
-        return (AddrSize == ADDR_SIZE_ZP);
-    }
-}
-
-
-
 ExprNode* CloneExpr (ExprNode* Expr)
 /* Clone the given expression tree. The function will simply clone symbol
  * nodes, it will not resolve them.
@@ -1524,11 +1761,11 @@ ExprNode* CloneExpr (ExprNode* Expr)
     switch (Expr->Op) {
 
        case EXPR_LITERAL:
-            Clone = GenLiteralExpr (Expr->V.Val);
+            Clone = GenLiteralExpr (Expr->V.IVal);
             break;
 
        case EXPR_ULABEL:
-           Clone = GenULabelExpr (Expr->V.Val);
+           Clone = GenULabelExpr (Expr->V.IVal);
            break;
 
        case EXPR_SYMBOL:
@@ -1536,9 +1773,13 @@ ExprNode* CloneExpr (ExprNode* Expr)
            break;
 
        case EXPR_SECTION:
-           Clone = GenSectionExpr (Expr->V.SegNum);
+           Clone = GenSectionExpr (Expr->V.SecNum);
            break;
 
+        case EXPR_BANK:
+            Clone = GenBankExpr (Expr->V.SecNum);
+            break;
+
         default:
             /* Generate a new node */
             Clone = NewExprNode (Expr->Op);
@@ -1554,6 +1795,76 @@ ExprNode* CloneExpr (ExprNode* Expr)
 
 
 
+ExprNode* FinalizeExpr (ExprNode* Expr, const Collection* LineInfos)
+/* Finalize an expression tree before it is written to the file. This will
+ * replace EXPR_BANKRAW nodes by EXPR_BANK nodes, and replace constant
+ * expressions by their result. The LineInfos are used when diagnosing errors.
+ * Beware: The expression tree may get replaced in future versions, so don't
+ * use Expr after calling this function.
+ */
+{
+    ExprDesc ED;
+
+    /* Check the type code */
+    switch (EXPR_NODETYPE (Expr->Op)) {
+
+        case EXPR_LEAFNODE:
+            /* Nothing to do for leaf nodes */
+            break;
+
+        case EXPR_BINARYNODE:
+            Expr->Left  = FinalizeExpr (Expr->Left, LineInfos);
+            Expr->Right = FinalizeExpr (Expr->Right, LineInfos);
+            /* FALLTHROUGH */
+
+        case EXPR_UNARYNODE:
+            Expr->Left = FinalizeExpr (Expr->Left, LineInfos);
+
+            /* Special handling for BANKRAW */
+            if (Expr->Op == EXPR_BANKRAW) {
+
+                /* Study the expression */
+                ED_Init (&ED);
+                StudyExpr (Expr->Left, &ED);
+
+                /* The expression must be ok and must have exactly one segment
+                 * reference.
+                 */
+                if (ED.Flags & ED_TOO_COMPLEX) {
+                    LIError (LineInfos,
+                             "Cannot evaluate expression");
+                } else if (ED.SecCount == 0) {
+                    LIError (LineInfos,
+                             ".BANK expects a segment reference");
+                } else if (ED.SecCount > 1 || ED.SecRef[0].Count > 1) {
+                    LIError (LineInfos,
+                             "Too many segment references in argument to .BANK");
+                } else {
+                    Segment* S;
+
+                    FreeExpr (Expr->Left);
+                    Expr->Op = EXPR_BANK;
+                    Expr->Left = 0;
+                    Expr->V.SecNum = ED.SecRef[0].Ref;
+
+                    /* Mark the segment */
+                    S = CollAt (&SegmentList, Expr->V.SecNum);
+                    S->Flags |= SEG_FLAG_BANKREF;
+                }
+
+                /* Cleanup */
+                ED_Done (&ED);
+
+            }
+            break;
+    }
+
+    /* Return the (partial) tree */
+    return Expr;
+}
+
+
+
 void WriteExpr (ExprNode* Expr)
 /* Write the given expression to the object file */
 {
@@ -1570,13 +1881,13 @@ void WriteExpr (ExprNode* Expr)
 
         case EXPR_LITERAL:
             ObjWrite8 (EXPR_LITERAL);
-           ObjWrite32 (Expr->V.Val);
-           break;
+           ObjWrite32 (Expr->V.IVal);
+           break;
 
         case EXPR_SYMBOL:
-           if (SymIsImport (Expr->V.Sym)) {
+           if (SymIsImport (Expr->V.Sym)) {
                 ObjWrite8 (EXPR_SYMBOL);
-                ObjWriteVar (GetSymIndex (Expr->V.Sym));
+                ObjWriteVar (GetSymImportId (Expr->V.Sym));
             } else {
                 WriteExpr (GetSymExpr (Expr->V.Sym));
             }
@@ -1584,13 +1895,18 @@ void WriteExpr (ExprNode* Expr)
 
         case EXPR_SECTION:
             ObjWrite8 (EXPR_SECTION);
-           ObjWrite8 (Expr->V.SegNum);
+           ObjWriteVar (Expr->V.SecNum);
            break;
 
        case EXPR_ULABEL:
-            WriteExpr (ULabResolve (Expr->V.Val));
+            WriteExpr (ULabResolve (Expr->V.IVal));
            break;
 
+        case EXPR_BANK:
+            ObjWrite8 (EXPR_BANK);
+            ObjWriteVar (Expr->V.SecNum);
+            break;
+
         default:
            /* Not a leaf node */
             ObjWrite8 (Expr->Op);
@@ -1603,4 +1919,41 @@ void WriteExpr (ExprNode* Expr)
 
 
 
+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;
+    }
+}
+
+