]> git.sur5r.net Git - cc65/blobdiff - src/ca65/studyexpr.c
Finished implemenation of commands to delete macros. Added the new commands to
[cc65] / src / ca65 / studyexpr.c
index 2421b35659265e89c18b4ff127570d4eef6e1068..42a8dbbd6a748b513b53791aad8cc49a6ebc357c 100644 (file)
@@ -6,8 +6,8 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 2003      Ullrich von Bassewitz                                       */
-/*               Römerstraße 52                                              */
+/* (C) 2003-2007 Ullrich von Bassewitz                                       */
+/*               Roemerstrasse 52                                            */
 /*               D-70794 Filderstadt                                         */
 /* EMail:        uz@cc65.org                                                 */
 /*                                                                           */
@@ -126,8 +126,47 @@ static void ED_Invalidate (ExprDesc* D)
 static void ED_UpdateAddrSize (ExprDesc* ED, unsigned char AddrSize)
 /* Update the address size of the expression */
 {
-    if (ED->AddrSize == ADDR_SIZE_DEFAULT || AddrSize > ED->AddrSize) {
-        ED->AddrSize = AddrSize;
+    if (ED_IsValid (ED)) {
+        /* ADDR_SIZE_DEFAULT may get overridden */
+        if (ED->AddrSize == ADDR_SIZE_DEFAULT || AddrSize > ED->AddrSize) {
+            ED->AddrSize = AddrSize;
+        }
+    } else {
+        /* ADDR_SIZE_DEFAULT takes precedence */
+        if (ED->AddrSize != ADDR_SIZE_DEFAULT) {
+            if (AddrSize == ADDR_SIZE_DEFAULT || AddrSize > ED->AddrSize) {
+                ED->AddrSize = AddrSize;
+            }
+        }
+    }
+}
+
+
+
+static void ED_MergeAddrSize (ExprDesc* ED, const ExprDesc* Right)
+/* Merge the address sizes of two expressions into ED */
+{
+    if (ED->AddrSize == ADDR_SIZE_DEFAULT) {
+        /* If ED is valid, ADDR_SIZE_DEFAULT gets always overridden, otherwise
+         * it takes precedence over anything else.
+         */
+        if (ED_IsValid (ED)) {
+            ED->AddrSize = Right->AddrSize;
+        }
+    } else if (Right->AddrSize == ADDR_SIZE_DEFAULT) {
+        /* If Right is valid, ADDR_SIZE_DEFAULT gets always overridden,
+         * otherwise it takes precedence over anything else.
+         */
+        if (!ED_IsValid (Right)) {
+            ED->AddrSize = Right->AddrSize;
+        }
+    } else {
+        /* Neither ED nor Right has a default address size, use the larger of
+         * the two.
+         */
+        if (Right->AddrSize > ED->AddrSize) {
+            ED->AddrSize = Right->AddrSize;
+        }
     }
 }
 
@@ -187,7 +226,7 @@ static ED_SymRef* ED_AllocSymRef (ExprDesc* ED, SymEntry* Sym)
     SymRef = ED->SymRef + ED->SymCount++;
 
     /* Initialize the new struct and return it */
-    SymRef->Count = 1;
+    SymRef->Count = 0;
     SymRef->Ref   = Sym;
     return SymRef;
 }
@@ -296,12 +335,39 @@ static void ED_MergeRefs (ExprDesc* ED, const ExprDesc* New)
 
 
 
+static void ED_NegRefs (ExprDesc* D)
+/* Negate the references in ED */
+{
+    unsigned I;
+    for (I = 0; I < D->SymCount; ++I) {
+        D->SymRef[I].Count = -D->SymRef[I].Count;
+    }
+    for (I = 0; I < D->SecCount; ++I) {
+        D->SecRef[I].Count = -D->SecRef[I].Count;
+    }
+}
+
+
+
 static void ED_Add (ExprDesc* ED, const ExprDesc* Right)
 /* Calculate ED = ED + Right, update address size in ED */
 {
     ED->Val += Right->Val;
     ED_MergeRefs (ED, Right);
-    ED_UpdateAddrSize (ED, Right->AddrSize);
+    ED_MergeAddrSize (ED, Right);
+}
+
+
+
+static void ED_Sub (ExprDesc* ED, const ExprDesc* Right)
+/* Calculate ED = ED - Right, update address size in ED */
+{
+    ExprDesc D = *Right;        /* Temporary */
+    ED_NegRefs (&D);
+
+    ED->Val -= Right->Val;
+    ED_MergeRefs (ED, &D);      /* Merge negatives */
+    ED_MergeAddrSize (ED, Right);
 }
 
 
@@ -318,7 +384,7 @@ static void ED_Mul (ExprDesc* ED, const ExprDesc* Right)
     for (I = 0; I < ED->SecCount; ++I) {
         ED->SecRef[I].Count *= Right->Val;
     }
-    ED_UpdateAddrSize (ED, Right->AddrSize);
+    ED_MergeAddrSize (ED, Right);
 }
 
 
@@ -326,15 +392,8 @@ static void ED_Mul (ExprDesc* ED, const ExprDesc* Right)
 static void ED_Neg (ExprDesc* D)
 /* Negate an expression */
 {
-    unsigned I;
-
     D->Val = -D->Val;
-    for (I = 0; I < D->SymCount; ++I) {
-        D->SymRef[I].Count = -D->SymRef[I].Count;
-    }
-    for (I = 0; I < D->SecCount; ++I) {
-        D->SecRef[I].Count = -D->SecRef[I].Count;
-    }
+    ED_NegRefs (D);
 }
 
 
@@ -367,6 +426,22 @@ static void StudyExprInternal (ExprNode* Expr, ExprDesc* D);
 
 
 
+static unsigned char GetConstAddrSize (long Val)
+/* Get the address size of a constant */
+{
+    if ((Val & ~0xFFL) == 0) {
+        return ADDR_SIZE_ZP;
+    } else if ((Val & ~0xFFFFL) == 0) {
+        return ADDR_SIZE_ABS;
+    } else if ((Val & ~0xFFFFFFL) == 0) {
+        return ADDR_SIZE_FAR;
+    } else {
+        return ADDR_SIZE_LONG;
+    }
+}
+
+
+
 static void StudyBinaryExpr (ExprNode* Expr, ExprDesc* D)
 /* Study a binary expression subtree. This is a helper function for StudyExpr
  * used for operations that succeed when both operands are known and constant.
@@ -398,7 +473,7 @@ static void StudyBinaryExpr (ExprNode* Expr, ExprDesc* D)
 
         /* Merge references and update address size */
         ED_MergeRefs (D, &Right);
-        ED_UpdateAddrSize (D, Right.AddrSize);
+        ED_MergeAddrSize (D, &Right);
 
     }
 
@@ -412,7 +487,8 @@ static void StudyLiteral (ExprNode* Expr, ExprDesc* D)
 /* Study a literal expression node */
 {
     /* This one is easy */
-    D->Val = Expr->V.Val;
+    D->Val      = Expr->V.IVal;
+    D->AddrSize = GetConstAddrSize (D->Val);
 }
 
 
@@ -429,31 +505,72 @@ static void StudySymbol (ExprNode* Expr, ExprDesc* D)
      * a circular reference.
      */
     if (SymHasExpr (Sym)) {
+
         if (SymHasUserMark (Sym)) {
             if (Verbosity > 0) {
                 DumpExpr (Expr, SymResolve);
             }
-            PError (GetSymPos (Sym),
-                    "Circular reference in definition of symbol `%s'",
-                    GetSymName (Sym));
+            LIError (&Sym->LineInfos,
+                     "Circular reference in definition of symbol `%m%p'",
+                     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);
+
+            /* 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 him.
+             */
+            AddrSize = GetSymAddrSize (Sym);
+            if (AddrSize != ADDR_SIZE_DEFAULT) {
+                D->AddrSize = AddrSize;
+            }
         }
-    } else {
-        /* The symbol is either undefined or an import. In both cases, track
-         * the symbols used and update the address size, but in case of an
-         * undefined symbol also set the "too complex" flag, since we cannot
-         * evaluate the final result.
+
+    } else if (SymIsImport (Sym)) {
+
+        /* The symbol is an import. Track the symbols used and update the
+         * address size.
          */
         ED_SymRef* SymRef = ED_GetSymRef (D, Sym);
         ++SymRef->Count;
         ED_UpdateAddrSize (D, GetSymAddrSize (Sym));
-        if (!SymIsImport (Sym)) {
-            /* Cannot handle */
-            ED_Invalidate (D);
+
+    } else {
+
+        unsigned char AddrSize;
+        SymTable* Parent;
+
+        /* The symbol is undefined. Track symbol usage but set the "too
+         * complex" flag, since we cannot evaluate the final result.
+         */
+        ED_SymRef* SymRef = ED_GetSymRef (D, Sym);
+        ++SymRef->Count;
+        ED_Invalidate (D);
+
+        /* Since the symbol may be a forward, and we may need a statement
+         * about the address size, check higher lexical levels for a symbol
+         * with the same name and use its address size if we find such a
+         * symbol which is defined.
+         */
+        AddrSize = GetSymAddrSize (Sym);
+        Parent = GetSymParentScope (Sym);
+        if (AddrSize == ADDR_SIZE_DEFAULT && Parent != 0) {
+            SymEntry* H = SymFindAny (Parent, GetSymName (Sym));
+            if (H) {
+                AddrSize = GetSymAddrSize (H);
+                if (AddrSize != ADDR_SIZE_DEFAULT) {
+                    D->AddrSize = AddrSize;
+                }
+            }
+        } else {
+            D->AddrSize = AddrSize;
         }
     }
 }
@@ -464,7 +581,7 @@ static void StudySection (ExprNode* Expr, ExprDesc* D)
 /* Study a section expression node */
 {
     /* Get the section reference */
-    ED_SecRef* SecRef = ED_GetSecRef (D, Expr->V.SegNum);
+    ED_SecRef* SecRef = ED_GetSecRef (D, Expr->V.SecNum);
 
     /* Update the data and the address size */
     ++SecRef->Count;
@@ -481,7 +598,7 @@ static void StudyULabel (ExprNode* Expr, ExprDesc* D)
      */
     if (ULabCanResolve ()) {
         /* We can resolve the label */
-        StudyExprInternal (ULabResolve (Expr->V.Val), D);
+        StudyExprInternal (ULabResolve (Expr->V.IVal), D);
     } else {
         ED_Invalidate (D);
     }
@@ -502,7 +619,7 @@ static void StudyPlus (ExprNode* Expr, ExprDesc* D)
     StudyExprInternal (Expr->Right, &Right);
 
     /* Check if we can handle the operation */
-    if (ED_IsValid (D) || ED_IsValid (&Right)) {
+    if (ED_IsValid (D) && ED_IsValid (&Right)) {
 
         /* Add both */
         ED_Add (D, &Right);
@@ -514,7 +631,7 @@ static void StudyPlus (ExprNode* Expr, ExprDesc* D)
 
         /* Merge references and update address size */
         ED_MergeRefs (D, &Right);
-        ED_UpdateAddrSize (D, Right.AddrSize);
+        ED_MergeAddrSize (D, &Right);
 
     }
 
@@ -537,11 +654,10 @@ static void StudyMinus (ExprNode* Expr, ExprDesc* D)
     StudyExprInternal (Expr->Right, &Right);
 
     /* Check if we can handle the operation */
-    if (ED_IsValid (D) || ED_IsValid (&Right)) {
+    if (ED_IsValid (D) && ED_IsValid (&Right)) {
 
         /* Subtract both */
-        ED_Neg (&Right);
-        ED_Add (D, &Right);
+        ED_Sub (D, &Right);
 
     } else {
 
@@ -550,7 +666,7 @@ static void StudyMinus (ExprNode* Expr, ExprDesc* D)
 
         /* Merge references and update address size */
         ED_MergeRefs (D, &Right);
-        ED_UpdateAddrSize (D, Right.AddrSize);
+        ED_MergeAddrSize (D, &Right);
 
     }
 
@@ -598,7 +714,7 @@ static void StudyMul (ExprNode* Expr, ExprDesc* D)
     /* If we could not handle the op, merge references and update address size */
     if (!ED_IsValid (D)) {
         ED_MergeRefs (D, &Right);
-        ED_UpdateAddrSize (D, Right.AddrSize);
+        ED_MergeAddrSize (D, &Right);
     }
 
     /* Done */
@@ -886,6 +1002,34 @@ static void StudyBoolXor (ExprNode* Expr, ExprDesc* D)
 
 
 
+static void StudyMax (ExprNode* Expr, ExprDesc* D)
+/* Study an MAX binary expression node */
+{
+    /* Use helper function */
+    StudyBinaryExpr (Expr, D);
+
+    /* If the result is valid, apply the operation */
+    if (ED_IsValid (D)) {
+        D->Val = (D->Val > D->Right)? D->Val : D->Right;
+    }
+}
+
+
+
+static void StudyMin (ExprNode* Expr, ExprDesc* D)
+/* Study an MIN binary expression node */
+{
+    /* Use helper function */
+    StudyBinaryExpr (Expr, D);
+
+    /* If the result is valid, apply the operation */
+    if (ED_IsValid (D)) {
+        D->Val = (D->Val < D->Right)? D->Val : D->Right;
+    }
+}
+
+
+
 static void StudyUnaryMinus (ExprNode* Expr, ExprDesc* D)
 /* Study an EXPR_UNARY_MINUS expression node */
 {
@@ -1163,6 +1307,14 @@ static void StudyExprInternal (ExprNode* Expr, ExprDesc* D)
             StudyBoolXor (Expr, D);
             break;
 
+        case EXPR_MAX:
+            StudyMax (Expr, D);
+            break;
+
+        case EXPR_MIN:
+            StudyMin (Expr, D);
+            break;
+
         case EXPR_UNARY_MINUS:
             StudyUnaryMinus (Expr, D);
             break;
@@ -1214,13 +1366,13 @@ static void StudyExprInternal (ExprNode* Expr, ExprDesc* D)
 void StudyExpr (ExprNode* Expr, ExprDesc* D)
 /* Study an expression tree and place the contents into D */
 {
-    unsigned I;
+    unsigned I, J;
 
     /* Call the internal function */
     StudyExprInternal (Expr, D);
 
     /* Remove symbol references with count zero */
-    I = 0;
+    I = J = 0;
     while (I < D->SymCount) {
         if (D->SymRef[I].Count == 0) {
             /* Delete the entry */
@@ -1247,32 +1399,64 @@ void StudyExpr (ExprNode* Expr, ExprDesc* D)
         }
     }
 
-    /* If we don't have an address size, assign one of the expression is a
+    /* If we don't have an address size, assign one if the expression is a
      * constant.
      */
-    if (D->AddrSize == ADDR_SIZE_DEFAULT) {
-        if (ED_IsConst (D)) {
-            if ((D->Val & ~0xFFL) == 0) {
-                D->AddrSize = ADDR_SIZE_ZP;
-            } else if ((D->Val & ~0xFFFFL) == 0) {
-                D->AddrSize = ADDR_SIZE_ABS;
-            } else if ((D->Val & 0xFFFFFFL) == 0) {
-                D->AddrSize = ADDR_SIZE_FAR;
-            } else {
-                D->AddrSize = ADDR_SIZE_LONG;
+    if (D->AddrSize == ADDR_SIZE_DEFAULT && ED_IsConst (D)) {
+        D->AddrSize = GetConstAddrSize (D->Val);
+    }
+
+    /* If the expression is valid, throw away the address size and recalculate
+     * it using the data we have. This is more exact than the on-the-fly
+     * calculation done when evaluating the tree, because symbols may have
+     * been removed from the expression, and the final numeric value is now
+     * known.
+     */
+    if (ED_IsValid (D)) {
+        unsigned char AddrSize;
+
+        /* If there are symbols or sections, use the largest one. If the
+         * expression resolves to a const, use the address size of the value.
+         */
+        if (D->SymCount > 0 || D->SecCount > 0) {
+
+            D->AddrSize = ADDR_SIZE_DEFAULT;
+
+            for (I = 0; I < D->SymCount; ++I) {
+                const SymEntry* Sym = D->SymRef[I].Ref;
+                AddrSize = GetSymAddrSize (Sym);
+                if (AddrSize > D->AddrSize) {
+                    D->AddrSize = AddrSize;
+                }
+            }
+
+            for (I = 0; I < D->SecCount; ++I) {
+                unsigned SegNum = D->SecRef[0].Ref;
+                AddrSize = GetSegAddrSize (SegNum);
+                if (AddrSize > D->AddrSize) {
+                    D->AddrSize = AddrSize;
+                }
+            }
+
+        } else {
+            AddrSize = GetConstAddrSize (D->Val);
+            if (AddrSize > D->AddrSize) {
+                D->AddrSize = AddrSize;
             }
         }
     }
 
 #if 0
+    /* Debug code */
     printf ("StudyExpr: "); DumpExpr (Expr, SymResolve);
+    printf ("Value: %08lX\n", D->Val);
     if (!ED_IsValid (D)) {
         printf ("Invalid: %s\n", AddrSizeToStr (D->AddrSize));
     } else {
         printf ("Valid:   %s\n", AddrSizeToStr (D->AddrSize));
-        printf ("%u symbols:\n", D->SymCount);
-        printf ("%u sections:\n", D->SecCount);
     }
+    printf ("%u symbols:\n", D->SymCount);
+    printf ("%u sections:\n", D->SecCount);
 #endif
 }