]> 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 cbca98ee3bd7cc6f20b7d7a4dc181c51be4c51bb..b5af9dc4daececa903d7d7c96b26906f7686da26 100644 (file)
@@ -6,7 +6,7 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 1998-2009, 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                                    */
 /*****************************************************************************/
 
 
@@ -94,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));
@@ -124,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);
@@ -167,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.
@@ -236,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 */
 {
@@ -319,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 */
 {
@@ -333,15 +357,15 @@ static ExprNode* FuncBlank (void)
     /* We have a list of tokens that ends with the closing paren. Skip
      * the tokens, and count them. Allow optionally curly braces.
      */
-    Token Term = GetTokListTerm (TOK_RPAREN);
+    token_t Term = GetTokListTerm (TOK_RPAREN);
     unsigned Count = 0;
-    while (Tok != Term) {
+    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;
        }
 
@@ -353,7 +377,7 @@ static ExprNode* FuncBlank (void)
     }
 
     /* If the list was enclosed in curly braces, skip the closing brace */
-    if (Term == TOK_RCURLY && Tok == TOK_RCURLY) {
+    if (Term == TOK_RCURLY && CurTok.Tok == TOK_RCURLY) {
         NextTok ();
     }
 
@@ -385,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));
@@ -437,14 +461,14 @@ static ExprNode* DoMatch (enum TC EqualityLevel)
      * single linked list of tokens including attributes. The list is
      * either enclosed in curly braces, or terminated by a comma.
      */
-    Token Term = GetTokListTerm (TOK_COMMA);
-    while (Tok != Term) {
+    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 GenLiteral0 ();
-       }
+       }
 
        /* Get a node with this token */
        Node = NewTokNode ();
@@ -476,10 +500,10 @@ static ExprNode* DoMatch (enum TC EqualityLevel)
     Term = GetTokListTerm (TOK_RPAREN);
     Result = 1;
     Node = Root;
-    while (Tok != Term) {
+    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 GenLiteral0 ();
        }
@@ -535,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));
@@ -563,18 +645,18 @@ static ExprNode* FuncSizeOf (void)
     SizeSym = 0;
 
     /* Check for a cheap local which needs special handling */
-    if (Tok == TOK_LOCAL_IDENT) {
+    if (CurTok.Tok == TOK_LOCAL_IDENT) {
 
         /* Cheap local symbol */
-        Sym = SymFindLocal (SymLast, &SVal, SYM_FIND_EXISTING);
+        Sym = SymFindLocal (SymLast, &CurTok.SVal, SYM_FIND_EXISTING);
         if (Sym == 0) {
-            Error ("Unknown symbol or scope: `%m%p'", &SVal);
+            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, &SVal);
+        SB_Copy (&Name, &CurTok.SVal);
         NextTok ();
         SB_Terminate (&ScopeName);
 
@@ -650,14 +732,14 @@ static ExprNode* FuncStrAt (void)
     unsigned char C = 0;
 
     /* String constant expected */
-    if (Tok != TOK_STRCON) {
+    if (CurTok.Tok != TOK_STRCON) {
        Error ("String constant expected");
        NextTok ();
                goto ExitPoint;
     }
 
     /* Remember the string and skip it */
-    SB_Copy (&Str, &SVal);
+    SB_Copy (&Str, &CurTok.SVal);
     NextTok ();
 
     /* Comma must follow */
@@ -693,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;
@@ -705,7 +787,7 @@ static ExprNode* FuncStrLen (void)
     } else {
 
         /* Get the length of the string */
-               Len = SB_GetLen (&SVal);
+               Len = SB_GetLen (&CurTok.SVal);
 
        /* Skip the string */
        NextTok ();
@@ -723,15 +805,15 @@ static ExprNode* FuncTCount (void)
     /* We have a list of tokens that ends with the closing paren. Skip
      * the tokens, and count them. Allow optionally curly braces.
      */
-    Token Term = GetTokListTerm (TOK_RPAREN);
+    token_t Term = GetTokListTerm (TOK_RPAREN);
     int Count = 0;
-    while (Tok != Term) {
+    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;
        }
 
@@ -743,7 +825,7 @@ static ExprNode* FuncTCount (void)
     }
 
     /* If the list was enclosed in curly braces, skip the closing brace */
-    if (Term == TOK_RCURLY && Tok == TOK_RCURLY) {
+    if (Term == TOK_RCURLY && CurTok.Tok == TOK_RCURLY) {
         NextTok ();
     }
 
@@ -770,7 +852,7 @@ 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 GenLiteral0 ();
@@ -795,30 +877,26 @@ static ExprNode* Factor (void)
     ExprNode* N;
     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:
-            N = Symbol (ParseScopedSymName (SYM_ALLOC_NEW));
-           break;
-
         case TOK_LOCAL_IDENT:
-            N = Symbol (SymFindLocal (SymLast, &SVal, SYM_ALLOC_NEW));
-            NextTok ();
-            break;
+            N = Symbol (ParseAnySymName (SYM_ALLOC_NEW));
+           break;
 
        case TOK_ULABEL:
-           N = ULabRef (IVal);
+           N = ULabRef (CurTok.IVal);
            NextTok ();
            break;
 
@@ -867,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;
@@ -878,6 +957,10 @@ static ExprNode* Factor (void)
                    ConsumeRParen ();
            break;
 
+        case TOK_BANK:
+            N = Function (FuncBank);
+            break;
+
         case TOK_BANKBYTE:
             N = Function (FuncBankByte);
             break;
@@ -919,6 +1002,14 @@ static ExprNode* Factor (void)
            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;
@@ -954,9 +1045,10 @@ static ExprNode* Factor (void)
            break;
 
        default:
-           if (LooseCharTerm && Tok == TOK_STRCON && SB_GetLen (&SVal) == 1) {
+           if (LooseCharTerm && CurTok.Tok == TOK_STRCON &&
+                SB_GetLen (&CurTok.SVal) == 1) {
                /* A character constant */
-               N = GenLiteralExpr (TgtTranslateChar (SB_At (&SVal, 0)));
+               N = GenLiteralExpr (TgtTranslateChar (SB_At (&CurTok.SVal, 0)));
            } else {
                N = GenLiteral0 ();     /* Dummy */
                Error ("Syntax error");
@@ -975,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 */
-        Token T = Tok;
+        token_t T = CurTok.Tok;
         NextTok ();
 
         /* Move root to left side and read the right side */
@@ -1078,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 */
-        Token T = Tok;
+        token_t T = CurTok.Tok;
         NextTok ();
 
         /* Move root to left side and read the right side */
@@ -1139,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 */
-        Token T = Tok;
+        token_t T = CurTok.Tok;
         NextTok ();
 
         /* Move root to left side and read the right side */
@@ -1207,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 */
-        Token T = Tok;
+        token_t T = CurTok.Tok;
         NextTok ();
 
         /* Move root to left side and read the right side */
@@ -1266,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 */
-        Token T = Tok;
+        token_t T = CurTok.Tok;
         NextTok ();
 
         /* Move root to left side and read the right side */
@@ -1322,7 +1418,7 @@ static ExprNode* Expr0 (void)
     ExprNode* Root;
 
     /* Handle booleans */
-    if (Tok == TOK_BOOLNOT) {
+    if (CurTok.Tok == TOK_BOOLNOT) {
 
         long Val;
         ExprNode* Left;
@@ -1404,8 +1500,8 @@ void FreeExpr (ExprNode* Root)
 {
     if (Root) {
        FreeExpr (Root->Left);
-       FreeExpr (Root->Right);
-       FreeExprNode (Root);
+       FreeExpr (Root->Right);
+       FreeExprNode (Root);
     }
 }
 
@@ -1453,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;
 }
 
@@ -1667,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);
@@ -1685,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 */
 {
@@ -1707,7 +1887,7 @@ void WriteExpr (ExprNode* Expr)
         case EXPR_SYMBOL:
            if (SymIsImport (Expr->V.Sym)) {
                 ObjWrite8 (EXPR_SYMBOL);
-                ObjWriteVar (GetSymIndex (Expr->V.Sym));
+                ObjWriteVar (GetSymImportId (Expr->V.Sym));
             } else {
                 WriteExpr (GetSymExpr (Expr->V.Sym));
             }
@@ -1715,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.IVal));
            break;
 
+        case EXPR_BANK:
+            ObjWrite8 (EXPR_BANK);
+            ObjWriteVar (Expr->V.SecNum);
+            break;
+
         default:
            /* Not a leaf node */
             ObjWrite8 (Expr->Op);
@@ -1749,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) {