diff --git a/src/ca65/ea.c b/src/ca65/ea.c
index e243a83f5..ea19bb271 100644
--- a/src/ca65/ea.c
+++ b/src/ca65/ea.c
@@ -55,7 +55,6 @@ void GetEA (EffAddr* A)
 
     /* Clear the output struct */
     A->AddrModeSet = 0;
-    A->Bank = 0;
     A->Expr = 0;
 
     /* Handle an addressing size override */
diff --git a/src/ca65/ea.h b/src/ca65/ea.h
index 9bc6c1ba3..ae2d37d0f 100644
--- a/src/ca65/ea.h
+++ b/src/ca65/ea.h
@@ -50,7 +50,6 @@ struct EffAddr {
     /* First three fields get filled when calling GetEA */
     unsigned long       AddrModeSet;    /* Possible addressing modes */
     struct ExprNode*    Expr;           /* Expression if any (NULL otherwise) */
-    struct ExprNode*    Bank;           /* Bank expression if any */
 
     /* The following fields are used inside instr.c */
     unsigned            AddrMode;       /* Actual addressing mode used */
diff --git a/src/ca65/expr.c b/src/ca65/expr.c
index 1d066784f..d8f46f6bd 100644
--- a/src/ca65/expr.c
+++ b/src/ca65/expr.c
@@ -1469,103 +1469,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.
diff --git a/src/ca65/instr.c b/src/ca65/instr.c
index 4c5d66786..d0bb0ab14 100644
--- a/src/ca65/instr.c
+++ b/src/ca65/instr.c
@@ -54,6 +54,7 @@
 #include "nexttok.h"
 #include "objcode.h"
 #include "spool.h"
+#include "studyexpr.h"
 #include "symtab.h"
 
 
@@ -571,12 +572,36 @@ static int EvalEA (const InsDesc* Ins, EffAddr* A)
      */
     A->AddrModeSet &= Ins->AddrMode;
 
-    /* If we have possible zero page addressing modes, and the expression
-     * involved (if any) is not in byte range, remove the zero page addressing
-     * modes.
+    /* If we have an expression, check it and remove any addressing modes that
+     * are too small for the expression size. Since we have to study the
+     * expression anyway, do also replace it by a simpler one if possible.
      */
-    if (A->Expr && (A->AddrModeSet & AM_ZP) && !IsByteExpr (A->Expr)) {
-       	A->AddrModeSet &= ~AM_ZP;
+    if (A->Expr) {
+        ExprDesc ED;
+        ED_Init (&ED);
+
+        /* Study the expression */
+        StudyExpr (A->Expr, &ED);
+
+        /* Simplify it if possible */
+        A->Expr = SimplifyExpr (A->Expr, &ED);
+
+        /* Check the size */
+        switch (ED.AddrSize) {
+
+            case ADDR_SIZE_ABS:
+                printf ("abs\n");
+                A->AddrModeSet &= ~AM_SET_ZP;
+                break;
+
+            case ADDR_SIZE_FAR:
+                printf ("far\n");
+                A->AddrModeSet &= ~(AM_SET_ZP | AM_SET_ABS);
+                break;
+        }
+
+        /* Free any resource associated with the expression desc */
+        ED_Done (&ED);
     }
 
     /* Check if we have any adressing modes left */
@@ -600,8 +625,8 @@ static int EvalEA (const InsDesc* Ins, EffAddr* A)
         /* Found, check the expression */
         ExprNode* Left = A->Expr->Left;
         if ((A->Expr->Op == EXPR_BYTE0 || A->Expr->Op == EXPR_BYTE1) &&
-            Left->Op == EXPR_SYMBOL                                &&
-            !SymIsZP (Left->V.Sym)) {
+            Left->Op == EXPR_SYMBOL                                  &&
+            GetSymAddrSize (Left->V.Sym) != ADDR_SIZE_ZP) {
 
             /* Output a warning */
             Warning (1, "Suspicious address expression");
@@ -644,13 +669,8 @@ static void EmitCode (EffAddr* A)
 	    break;
 
 	case 3:
-	    if (A->Bank) {
-	      	/* Separate bank given */
-	       	Emit3b (A->Opcode, A->Expr, A->Bank);
-	    } else {
-	      	/* One far argument */
-	      	Emit3 (A->Opcode, A->Expr);
-	    }
+            /* Far argument */
+	    Emit3 (A->Opcode, A->Expr);
 	    break;
 
 	default:
diff --git a/src/ca65/instr.h b/src/ca65/instr.h
index 7429e447c..de752fd63 100644
--- a/src/ca65/instr.h
+++ b/src/ca65/instr.h
@@ -66,31 +66,34 @@
 #define AM_ABS_X            	0x00000040UL
 #define AM_ABS_LONG_X		0x00000080UL
 #define AM_DIR_Y               	0x00000100UL
-#define AM_ABS_Y           	0x00000200UL
-#define AM_DIR_IND      	0x00000400UL
-#define AM_ABS_IND     		0x00000800UL
-#define AM_DIR_IND_LONG     	0x00001000UL
-#define AM_DIR_IND_Y     	0x00002000UL
-#define AM_DIR_IND_LONG_Y    	0x00004000UL
-#define AM_DIR_X_IND         	0x00008000UL
-#define AM_ABS_X_IND    	0x00010000UL
-#define AM_REL             	0x00020000UL
+#define AM_ABS_Y               	0x00000200UL
+#define AM_DIR_IND             	0x00000400UL
+#define AM_ABS_IND     	       	0x00000800UL
+#define AM_DIR_IND_LONG        	0x00001000UL
+#define AM_DIR_IND_Y           	0x00002000UL
+#define AM_DIR_IND_LONG_Y      	0x00004000UL
+#define AM_DIR_X_IND           	0x00008000UL
+#define AM_ABS_X_IND           	0x00010000UL
+#define AM_REL                 	0x00020000UL
 #define AM_REL_LONG            	0x00040000UL
-#define AM_STACK_REL        	0x00080000UL
-#define AM_STACK_REL_IND_Y	0x00100000UL
-#define AM_IMM_ACCU		0x00200000UL
-#define AM_IMM_INDEX		0x00400000UL
-#define AM_IMM_IMPLICIT		0x00800000UL
-#define AM_IMM           	(AM_IMM_ACCU | AM_IMM_INDEX | AM_IMM_IMPLICIT)
+#define AM_STACK_REL           	0x00080000UL
+#define AM_STACK_REL_IND_Y     	0x00100000UL
+#define AM_IMM_ACCU	       	0x00200000UL
+#define AM_IMM_INDEX	       	0x00400000UL
+#define AM_IMM_IMPLICIT	       	0x00800000UL
+#define AM_IMM                 	(AM_IMM_ACCU | AM_IMM_INDEX | AM_IMM_IMPLICIT)
 #define AM_BLOCKMOVE           	0x01000000UL
 
 /* Bitmask for all ZP operations that have correspondent ABS ops */
-#define AM_ZP	(AM_DIR | AM_DIR_X | AM_DIR_Y | AM_DIR_IND | AM_DIR_X_IND)
+#define AM_SET_ZP 	(AM_DIR | AM_DIR_X | AM_DIR_Y | AM_DIR_IND | AM_DIR_X_IND)
+
+/* Bitmask for all ABS operations that have correspondent FAR ops */
+#define AM_SET_ABS      (AM_ABS | AM_ABS_X)
 
 /* Bit numbers and count */
-#define AMI_IMM_ACCU		21
-#define AMI_IMM_INDEX		22
-#define AMI_COUNT		25
+#define AMI_IMM_ACCU	       	21
+#define AMI_IMM_INDEX	       	22
+#define AMI_COUNT	       	25
 
 
 
diff --git a/src/ca65/objcode.c b/src/ca65/objcode.c
index 35d4dd841..9ca419c11 100644
--- a/src/ca65/objcode.c
+++ b/src/ca65/objcode.c
@@ -86,16 +86,6 @@ void Emit3 (unsigned char OPC, ExprNode* Expr)
 
 
 
-void Emit3b (unsigned char OPC, ExprNode* Expr, ExprNode* Bank)
-/* Emit an instruction with a three byte argument and separate bank */
-{
-    Emit0 (OPC);
-    EmitWord (Expr);
-    EmitByte (Bank);
-}
-
-
-
 void EmitSigned (ExprNode* Expr, unsigned Size)
 /* Emit a signed expression with the given size */
 {
diff --git a/src/ca65/objcode.h b/src/ca65/objcode.h
index d3f88ea5c..980e373b1 100644
--- a/src/ca65/objcode.h
+++ b/src/ca65/objcode.h
@@ -7,7 +7,7 @@
 /*                                                                           */
 /*                                                                           */
 /* (C) 1998-2003 Ullrich von Bassewitz                                       */
-/*               R�merstrasse 52                                             */
+/*               R�merstra�e 52                                              */
 /*               D-70794 Filderstadt                                         */
 /* EMail:        uz@cc65.org                                                 */
 /*                                                                           */
@@ -61,9 +61,6 @@ void Emit2 (unsigned char OPC, ExprNode* Value);
 void Emit3 (unsigned char OPC, ExprNode* Expr);
 /* Emit an instruction with a three byte argument */
 
-void Emit3b (unsigned char OPC, ExprNode* Expr, ExprNode* Bank);
-/* Emit an instruction with a three byte argument and separate bank */
-
 void EmitSigned (ExprNode* Expr, unsigned Size);
 /* Emit a signed expression with the given size */
 
diff --git a/src/ca65/studyexpr.c b/src/ca65/studyexpr.c
index c71a27109..6cc44fb3d 100644
--- a/src/ca65/studyexpr.c
+++ b/src/ca65/studyexpr.c
@@ -438,10 +438,23 @@ static void StudySymbol (ExprNode* Expr, ExprDesc* D)
                     GetSymName (Sym));
             ED_Invalidate (D);
         } else {
+
+            unsigned char AddrSize;
+
+            /* Mark the symbol and study its associated expression */
             SymMarkUser (Sym);
             StudyExprInternal (GetSymExpr (Sym), D);
             SymUnmarkUser (Sym);
-            ED_UpdateAddrSize (D, GetSymAddrSize (Sym));
+
+            /* If the symbol has an explicit address size, use it. This may
+             * lead to range errors later (maybe even in the linker stage), if
+             * the user lied about the address size, but for now we trust the
+             * user.
+             */
+            AddrSize = GetSymAddrSize (Sym);
+            if (AddrSize != ADDR_SIZE_DEFAULT) {
+                D->AddrSize = AddrSize;
+            }
         }
     } else {
         /* The symbol is either undefined or an import. In both cases, track
diff --git a/src/ca65/symtab.c b/src/ca65/symtab.c
index 52a6f9f20..32c549e7a 100644
--- a/src/ca65/symtab.c
+++ b/src/ca65/symtab.c
@@ -223,7 +223,7 @@ void SymLeaveLevel (void)
      * active, when the scope was opened. Set the size of the scope to the
      * number of data bytes emitted into this segment.
      */
-    if (CollCount (&CurrentScope->SegRanges) > 0) {                                       
+    if (CollCount (&CurrentScope->SegRanges) > 0) {
         const SegRange* R = CollAtUnchecked (&CurrentScope->SegRanges, 0);
         DefSizeOfScope (CurrentScope, GetSegRangeSize (R));
     }
@@ -397,31 +397,6 @@ SymEntry* SymFindAny (SymTable* Scope, const char* Name)
 
 
 
-int SymIsZP (SymEntry* S)
-/* Return true if the symbol is explicitly marked as zeropage symbol */
-{
-    /* If the symbol is not a global symbol, was not defined before, check the
-     * enclosing scope for a symbol with the same name, and return the ZP
-     * attribute of this symbol if we find one.
-     */
-    if ((S->Flags & (SF_DEFINED | SF_IMPORT | SF_LOCAL)) == 0 &&
-	S->SymTab->Parent != 0) {
-
-	/* Try to find a symbol with the same name in the enclosing scope */
-	SymEntry* E = SymFindAny (S->SymTab->Parent, GetString (S->Name));
-
-	/* If we found one, use the ZP flag */
-       	if (E && E->AddrSize == ADDR_SIZE_ZP) {
-            S->AddrSize = ADDR_SIZE_ZP;
-	}
-    }
-
-    /* Check the ZP flag */
-    return (S->AddrSize == ADDR_SIZE_ZP);
-}
-
-
-
 unsigned char GetCurrentSymTabType ()
 /* Return the type of the current symbol table */
 {
diff --git a/src/ca65/symtab.h b/src/ca65/symtab.h
index aaac2eeb8..d3787c3df 100644
--- a/src/ca65/symtab.h
+++ b/src/ca65/symtab.h
@@ -134,9 +134,6 @@ SymEntry* SymFindAny (SymTable* Scope, const char* Name);
  * scope.
  */
 
-int SymIsZP (SymEntry* Sym);
-/* Return true if the symbol is explicitly marked as zeropage symbol */
-
 #if defined(HAVE_INLINE)
 INLINE unsigned char GetSymTabType (const SymTable* S)
 /* Return the type of the given symbol table */