]> git.sur5r.net Git - cc65/blobdiff - src/ca65/expr.c
New .FEATURE org_per_seg. If enabled, .org/.reloc do only influence the
[cc65] / src / ca65 / expr.c
index 1d066784f921f3f869465d313184a08c61331d11..fc64f29c7e879fd0a14d38057cb0aa919dbb64c0 100644 (file)
@@ -6,8 +6,8 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 1998-2003 Ullrich von Bassewitz                                       */
-/*               Römerstraße 52                                              */
+/* (C) 1998-2007 Ullrich von Bassewitz                                       */
+/*               Roemerstrasse 52                                            */
 /*               D-70794 Filderstadt                                         */
 /* EMail:        uz@cc65.org                                                 */
 /*                                                                           */
@@ -196,6 +196,106 @@ 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* 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 */
 {
@@ -205,41 +305,60 @@ static ExprNode* Symbol (SymEntry* S)
     } else {
         /* Mark the symbol as referenced */
         SymRef (S);
-        /* Create symbol node */
-        return GenSymExpr (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);
+        }
     }
 }
 
 
 
+static 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 ();
+    enum Token Term = GetTokListTerm (TOK_RPAREN);
+    unsigned Count = 0;
+    while (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)) {
+           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 && Tok == TOK_RCURLY) {
+        NextTok ();
+    }
+
+    /* Return true if the list was empty */
+    return GenLiteralExpr (Count == 0);
 }
 
 
@@ -274,24 +393,57 @@ static ExprNode* FuncDefined (void)
 
 
 
+static ExprNode* FuncHiByte (void)
+/* Handle the .HIBYTE builtin function */
+{
+    return HiByte (Expression ());
+}
+
+
+
+static ExprNode* FuncHiWord (void)
+/* Handle the .HIWORD builtin function */
+{
+    return HiWord (Expression ());
+}
+
+
+
+static 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) {
+    enum Token Term = GetTokListTerm (TOK_COMMA);
+    while (Tok != Term) {
 
        /* We may not end-of-line of end-of-file here */
        if (TokIsSep (Tok)) {
            Error ("Unexpected end of line");
-           return 0;
+           return GenLiteral0 ();
        }
 
        /* Get a node with this token */
@@ -309,20 +461,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 (Tok != Term) {
 
        /* We may not end-of-line of end-of-file here */
        if (TokIsSep (Tok)) {
            Error ("Unexpected end of line");
-           return 0;
+           return GenLiteral0 ();
        }
 
                /* Compare the tokens if the result is not already known */
@@ -345,6 +504,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;
@@ -423,7 +587,7 @@ static ExprNode* FuncSizeOf (void)
         if (ParentScope == 0) {
             /* No such scope */
             DoneStrBuf (&ScopeName);
-            return GenLiteralExpr (0);
+            return GenLiteral0 ();
         }
 
         /* If ScopeName is empty, no explicit scope was specified. We have to
@@ -487,8 +651,7 @@ static ExprNode* FuncStrAt (void)
     if (Tok != TOK_STRCON) {
        Error ("String constant expected");
        NextTok ();
-               return 0;
-
+               return GenLiteral0 ();
     }
 
     /* Remember the string and skip it */
@@ -504,7 +667,7 @@ static ExprNode* FuncStrAt (void)
     /* Must be a valid index */
     if (Index >= (long) strlen (Str)) {
        Error ("Range error");
-       return 0;
+       return GenLiteral0 ();
     }
 
     /* Get the char, handle as unsigned. Be sure to translate it into
@@ -552,11 +715,11 @@ 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) {
+    enum Token Term = GetTokListTerm (TOK_RPAREN);
+    int Count = 0;
+    while (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
@@ -569,17 +732,15 @@ static ExprNode* FuncTCount (void)
        /* 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 && Tok == TOK_RCURLY) {
+        NextTok ();
+    }
+
     /* Return the number of tokens */
     return GenLiteralExpr (Count);
 }
@@ -606,7 +767,7 @@ static ExprNode* Function (ExprNode* (*F) (void))
     if (Tok != TOK_LPAREN) {
        Error ("'(' expected");
        SkipUntilSep ();
-       return GenLiteralExpr (0);
+       return GenLiteral0 ();
     }
     NextTok ();
 
@@ -655,6 +816,11 @@ static ExprNode* Factor (void)
            NextTok ();
            break;
 
+        case TOK_PLUS:
+            NextTok ();
+            N = Factor ();
+            break;
+
        case TOK_MINUS:
            NextTok ();
             L = Factor ();
@@ -687,38 +853,17 @@ 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:
             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:
@@ -727,6 +872,10 @@ static ExprNode* Factor (void)
                    ConsumeRParen ();
            break;
 
+        case TOK_BANKBYTE:
+            N = Function (FuncBankByte);
+            break;
+
         case TOK_BLANK:
            N = Function (FuncBlank);
            break;
@@ -744,6 +893,22 @@ 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;
@@ -787,7 +952,7 @@ static ExprNode* Factor (void)
                /* A character constant */
                N = GenLiteralExpr (TgtTranslateChar (SVal[0]));
            } else {
-               N = GenLiteralExpr (0); /* Dummy */
+               N = GenLiteral0 ();     /* Dummy */
                Error ("Syntax error");
            }
            NextTok ();
@@ -1263,6 +1428,14 @@ ExprNode* GenLiteralExpr (long Val)
 
 
 
+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 */
 {
@@ -1309,7 +1482,7 @@ ExprNode* GenCurrentPC (void)
 {
     ExprNode* Root;
 
-    if (RelocMode) {
+    if (GetRelocMode ()) {
        /* Create SegmentBase + Offset */
                Root = GenAddExpr (GenSectionExpr (GetCurrentSegNum ()),
                            GenLiteralExpr (GetPC ()));
@@ -1358,7 +1531,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;
@@ -1376,7 +1549,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;
@@ -1406,11 +1579,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);
 }
 
 
@@ -1418,13 +1587,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);
 }
 
 
@@ -1469,103 +1633,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.
@@ -1628,11 +1695,11 @@ void WriteExpr (ExprNode* Expr)
 
         case EXPR_LITERAL:
             ObjWrite8 (EXPR_LITERAL);
-           ObjWrite32 (Expr->V.Val);
-           break;
+           ObjWrite32 (Expr->V.Val);
+           break;
 
         case EXPR_SYMBOL:
-           if (SymIsImport (Expr->V.Sym)) {
+           if (SymIsImport (Expr->V.Sym)) {
                 ObjWrite8 (EXPR_SYMBOL);
                 ObjWriteVar (GetSymIndex (Expr->V.Sym));
             } else {
@@ -1661,4 +1728,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->Op & EXPR_TYPEMASK) {
+
+        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;
+    }
+}
+
+