]> 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 25129decc7e1b292b675dbfde8b1b5f431b2ca28..b5af9dc4daececa903d7d7c96b26906f7686da26 100644 (file)
@@ -6,7 +6,7 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 1998-2011, Ullrich von Bassewitz                                      */
+/* (C) 1998-2012, Ullrich von Bassewitz                                      */
 /*                Roemerstrasse 52                                           */
 /*                D-70794 Filderstadt                                        */
 /* EMail:         uz@cc65.org                                                */
@@ -42,6 +42,7 @@
 #include "exprdefs.h"
 #include "print.h"
 #include "shift.h"
+#include "segdefs.h"
 #include "strbuf.h"
 #include "tgttrans.h"
 #include "version.h"
@@ -65,7 +66,7 @@
 
 
 /*****************************************************************************/
-/*                                          Data                                    */
+/*                                          Data                                    */
 /*****************************************************************************/
 
 
@@ -238,6 +239,19 @@ static ExprNode* HiByte (ExprNode* Operand)
 
 
 
+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 */
 {
@@ -321,6 +335,14 @@ static ExprNode* Symbol (SymEntry* S)
 
 
 
+ExprNode* FuncBank (void)
+/* Handle the .BANK builtin function */
+{
+    return Bank (Expression ());
+}
+
+
+
 ExprNode* FuncBankByte (void)
 /* Handle the .BANKBYTE builtin function */
 {
@@ -446,7 +468,7 @@ static ExprNode* DoMatch (enum TC EqualityLevel)
        if (TokIsSep (CurTok.Tok)) {
            Error ("Unexpected end of line");
            return GenLiteral0 ();
-       }
+       }
 
        /* Get a node with this token */
        Node = NewTokNode ();
@@ -923,7 +945,8 @@ static ExprNode* Factor (void)
             N = HiByte (Factor ());
            break;
 
-        case TOK_BANK:
+        case TOK_XOR:
+            /* ^ means the bank byte of an expression */
             NextTok ();
             N = BankByte (Factor ());
             break;
@@ -934,6 +957,10 @@ static ExprNode* Factor (void)
                    ConsumeRParen ();
            break;
 
+        case TOK_BANK:
+            N = Function (FuncBank);
+            break;
+
         case TOK_BANKBYTE:
             N = Function (FuncBankByte);
             break;
@@ -1532,6 +1559,16 @@ static ExprNode* GenSectionExpr (unsigned SecNum)
 
 
 
+static ExprNode* GenBankExpr (unsigned SecNum)
+/* Return an expression node for the given bank */
+{
+    ExprNode* Expr = NewExprNode (EXPR_BANK);
+    Expr->V.SecNum = SecNum;
+    return Expr;
+}
+
+
+
 ExprNode* GenAddExpr (ExprNode* Left, ExprNode* Right)
 /* Generate an addition from the two operands */
 {
@@ -1739,6 +1776,10 @@ ExprNode* CloneExpr (ExprNode* Expr)
            Clone = GenSectionExpr (Expr->V.SecNum);
            break;
 
+        case EXPR_BANK:
+            Clone = GenBankExpr (Expr->V.SecNum);
+            break;
+
         default:
             /* Generate a new node */
             Clone = NewExprNode (Expr->Op);
@@ -1754,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 */
 {
@@ -1784,13 +1895,18 @@ void WriteExpr (ExprNode* Expr)
 
         case EXPR_SECTION:
             ObjWrite8 (EXPR_SECTION);
-           ObjWrite8 (Expr->V.SecNum);
+           ObjWriteVar (Expr->V.SecNum);
            break;
 
        case EXPR_ULABEL:
             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);
@@ -1818,7 +1934,7 @@ void ExprGuessedAddrSize (const ExprNode* Expr, unsigned char AddrSize)
     }
 
     /* Check the type code */
-    switch (Expr->Op & EXPR_TYPEMASK) {
+    switch (EXPR_NODETYPE (Expr->Op)) {
 
         case EXPR_LEAFNODE:
             if (Expr->Op == EXPR_SYMBOL) {