]> git.sur5r.net Git - cc65/blobdiff - src/cc65/expr.c
Changed solution for r4329 so that it uses less memory.
[cc65] / src / cc65 / expr.c
index 211b1b6d4303d44089de6d600792abf556e9a90b..cf417577f5963837a3e87073ecd4055a499100c1 100644 (file)
@@ -740,6 +740,7 @@ static void Primary (ExprDesc* E)
             break;
 
         case TOK_SCONST:
+        case TOK_WCSCONST:
             /* String literal */
             E->Type  = GetCharArrayType (GetLiteralPoolOffs () - CurTok.IVal);
             E->Flags = E_LOC_LITERAL | E_RTYPE_RVAL;
@@ -828,7 +829,7 @@ static void ArrayRef (ExprDesc* Expr)
     }
 
     /* TOS now contains ptr to array elements. Get the subscript. */
-    ExprWithCheck (hie0, &Subscript);
+    MarkedExprWithCheck (hie0, &Subscript);
 
     /* Check the types of array and subscript. We can either have a
      * pointer/array to the left, in which case the subscript must be of an
@@ -870,7 +871,7 @@ static void ArrayRef (ExprDesc* Expr)
     }
 
     /* Check if the subscript is constant absolute value */
-    if (ED_IsConstAbs (&Subscript)) {
+    if (ED_IsConstAbs (&Subscript) && ED_CodeRangeIsEmpty (&Subscript)) {
 
                /* The array subscript is a numeric constant. If we had pushed the
          * array base address onto the stack before, we can remove this value,
@@ -1069,6 +1070,7 @@ static void StructRef (ExprDesc* Expr)
 {
     ident Ident;
     SymEntry* Field;
+    TypeCode Q;
 
     /* Skip the token and check for an identifier */
     NextToken ();
@@ -1103,8 +1105,14 @@ static void StructRef (ExprDesc* Expr)
     /* Set the struct field offset */
     Expr->IVal += Field->V.Offs;
 
-    /* The type is now the type of the field */
-    Expr->Type = Field->Type;
+    /* The type is the type of the field plus any qualifiers from the struct */
+    Q = GetQualifier (Expr->Type);
+    if (GetQualifier (Field->Type) == (GetQualifier (Field->Type) | Q)) {
+        Expr->Type = Field->Type;
+    } else {
+        Expr->Type = TypeDup (Field->Type);
+        Expr->Type->C |= Q;
+    }
 
     /* An struct member is actually a variable. So the rules for variables
      * with respect to the reference type apply: If it's an array, it is
@@ -1591,9 +1599,12 @@ void hie10 (ExprDesc* Expr)
                 ED_MakeRValExpr (Expr);
             }
             /* If the expression is already a pointer to function, the
-             * additional dereferencing operator must be ignored.
+             * additional dereferencing operator must be ignored. A function
+             * itself is represented as "pointer to function", so any number
+             * of dereference operators is legal, since the result will
+             * always be converted to "pointer to function".
              */
-            if (IsTypeFuncPtr (Expr->Type)) {
+            if (IsTypeFuncPtr (Expr->Type) || IsTypeFunc (Expr->Type)) {
                 /* Expression not storable */
                 ED_MakeRVal (Expr);
             } else {
@@ -1896,7 +1907,14 @@ static void hie_compare (const GenDesc* Ops,    /* List of generators */
        }
 
        /* Get the right hand side */
-       rconst = (evalexpr (CF_NONE, hienext, &Expr2) == 0);
+        MarkedExprWithCheck (hienext, &Expr2);
+
+        /* Check for a constant expression */
+        rconst = (ED_IsConstAbs (&Expr2) && ED_CodeRangeIsEmpty (&Expr2));
+        if (!rconst) {
+            /* Not constant, load into the primary */
+            LoadExpr (CF_NONE, &Expr2);
+        }
 
        /* Make sure, the types are compatible */
        if (IsClassInt (Expr->Type)) {
@@ -2064,21 +2082,21 @@ static void parseadd (ExprDesc* Expr)
 
            /* Both expressions are constants. Check for pointer arithmetic */
                    if (IsClassPtr (lhst) && IsClassInt (rhst)) {
-                       /* Left is pointer, right is int, must scale rhs */
+                       /* Left is pointer, right is int, must scale rhs */
                        Expr->IVal += Expr2.IVal * CheckedPSizeOf (lhst);
-               /* Result type is a pointer */
+               /* Result type is a pointer */
            } else if (IsClassInt (lhst) && IsClassPtr (rhst)) {
-               /* Left is int, right is pointer, must scale lhs */
+               /* Left is int, right is pointer, must scale lhs */
                        Expr->IVal = Expr->IVal * CheckedPSizeOf (rhst) + Expr2.IVal;
-               /* Result type is a pointer */
-               Expr->Type = Expr2.Type;
+               /* Result type is a pointer */
+               Expr->Type = Expr2.Type;
                    } else if (IsClassInt (lhst) && IsClassInt (rhst)) {
-               /* Integer addition */
-               Expr->IVal += Expr2.IVal;
-               typeadjust (Expr, &Expr2, 1);
+               /* Integer addition */
+               Expr->IVal += Expr2.IVal;
+               typeadjust (Expr, &Expr2, 1);
            } else {
                        /* OOPS */
-               Error ("Invalid operands for binary operator `+'");
+               Error ("Invalid operands for binary operator `+'");
            }
 
                } else {
@@ -2176,7 +2194,10 @@ static void parseadd (ExprDesc* Expr)
        g_push (TypeOf (Expr->Type), 0);        /* --> stack */
 
        /* Evaluate the rhs */
-               if (evalexpr (CF_NONE, hie9, &Expr2) == 0) {
+        MarkedExprWithCheck (hie9, &Expr2);
+
+        /* Check for a constant rhs expression */
+        if (ED_IsConstAbs (&Expr2) && ED_CodeRangeIsEmpty (&Expr2)) {
 
                    /* Right hand side is a constant. Get the rhs type */
            rhst = Expr2.Type;
@@ -2210,6 +2231,9 @@ static void parseadd (ExprDesc* Expr)
 
        } else {
 
+            /* Not constant, load into the primary */
+            LoadExpr (CF_NONE, &Expr2);
+
            /* lhs and rhs are not constant. Get the rhs type. */
            rhst = Expr2.Type;
 
@@ -2289,7 +2313,10 @@ static void parsesub (ExprDesc* Expr)
     g_push (TypeOf (lhst), 0); /* --> stack */
 
     /* Parse the right hand side */
-    if (evalexpr (CF_NONE, hie9, &Expr2) == 0) {
+    MarkedExprWithCheck (hie9, &Expr2);
+
+    /* Check for a constant rhs expression */
+    if (ED_IsConstAbs (&Expr2) && ED_CodeRangeIsEmpty (&Expr2)) {
 
        /* The right hand side is constant. Get the rhs type. */
                rhst = Expr2.Type;
@@ -2361,38 +2388,41 @@ static void parsesub (ExprDesc* Expr)
            /* Do the subtraction */
            g_dec (flags | CF_CONST, Expr2.IVal);
 
-           /* If this was a pointer subtraction, we must scale the result */
-           if (rscale != 1) {
-               g_scale (flags, -rscale);
-           }
+           /* If this was a pointer subtraction, we must scale the result */
+           if (rscale != 1) {
+               g_scale (flags, -rscale);
+           }
 
-           /* Result is a rvalue in the primary register */
-           ED_MakeRValExpr (Expr);
-           ED_MarkAsUntested (Expr);
+           /* Result is a rvalue in the primary register */
+           ED_MakeRValExpr (Expr);
+           ED_MarkAsUntested (Expr);
 
-       }
+       }
 
     } else {
 
-       /* Right hand side is not constant. Get the rhs type. */
-       rhst = Expr2.Type;
+        /* Not constant, load into the primary */
+        LoadExpr (CF_NONE, &Expr2);
+
+       /* Right hand side is not constant. Get the rhs type. */
+       rhst = Expr2.Type;
 
                /* Check for pointer arithmetic */
-       if (IsClassPtr (lhst) && IsClassInt (rhst)) {
+       if (IsClassPtr (lhst) && IsClassInt (rhst)) {
            /* Left is pointer, right is int, must scale rhs */
-           g_scale (CF_INT, CheckedPSizeOf (lhst));
-           /* Operate on pointers, result type is a pointer */
-           flags = CF_PTR;
-       } else if (IsClassPtr (lhst) && IsClassPtr (rhst)) {
-           /* Left is pointer, right is pointer, must scale result */
-           if (TypeCmp (Indirect (lhst), Indirect (rhst)) < TC_QUAL_DIFF) {
-               Error ("Incompatible pointer types");
-           } else {
-               rscale = CheckedPSizeOf (lhst);
-           }
-           /* Operate on pointers, result type is an integer */
-           flags = CF_PTR;
-           Expr->Type = type_int;
+           g_scale (CF_INT, CheckedPSizeOf (lhst));
+           /* Operate on pointers, result type is a pointer */
+           flags = CF_PTR;
+       } else if (IsClassPtr (lhst) && IsClassPtr (rhst)) {
+           /* Left is pointer, right is pointer, must scale result */
+           if (TypeCmp (Indirect (lhst), Indirect (rhst)) < TC_QUAL_DIFF) {
+               Error ("Incompatible pointer types");
+           } else {
+               rscale = CheckedPSizeOf (lhst);
+           }
+           /* Operate on pointers, result type is an integer */
+           flags = CF_PTR;
+           Expr->Type = type_int;
        } else if (IsClassInt (lhst) && IsClassInt (rhst)) {
            /* Integer subtraction. If the left hand side descriptor says that
             * the lhs is const, we have to remove this mark, since this is no
@@ -2823,7 +2853,7 @@ static void hieQuest (ExprDesc* Expr)
 
 
 
-static void opeq (const GenDesc* Gen, ExprDesc* Expr)
+static void opeq (const GenDesc* Gen, ExprDesc* Expr, const char* Op)
 /* Process "op=" operators. */
 {
     ExprDesc Expr2;
@@ -2868,7 +2898,18 @@ static void opeq (const GenDesc* Gen, ExprDesc* Expr)
     g_push (flags, 0);
 
     /* Evaluate the rhs */
-    if (evalexpr (CF_NONE, hie1, &Expr2) == 0) {
+    MarkedExprWithCheck (hie1, &Expr2);
+
+    /* The rhs must be an integer (or a float, but we don't support that yet */
+    if (!IsClassInt (Expr2.Type)) {
+        Error ("Invalid right operand for binary operator `%s'", Op);
+        /* Continue. Wrong code will be generated, but the compiler won't
+         * break, so this is the best error recovery.
+         */
+    }
+
+    /* Check for a constant expression */
+    if (ED_IsConstAbs (&Expr2) && ED_CodeRangeIsEmpty (&Expr2)) {
        /* The resulting value is a constant. If the generator has the NOPUSH
         * flag set, don't push the lhs.
         */
@@ -2904,7 +2945,9 @@ static void opeq (const GenDesc* Gen, ExprDesc* Expr)
                    Gen->Func (flags | CF_CONST, Expr2.IVal);
        }
     } else {
-       /* rhs is not constant and already in the primary register */
+
+       /* rhs is not constant. Load into the primary */
+        LoadExpr (CF_NONE, &Expr2);
                if (MustScale) {
            /* lhs is a pointer, scale rhs */
                    g_scale (TypeOf (Expr2.Type), CheckedSizeOf (Expr->Type+1));
@@ -2926,7 +2969,7 @@ static void opeq (const GenDesc* Gen, ExprDesc* Expr)
 
 
 
-static void addsubeq (const GenDesc* Gen, ExprDesc *Expr)
+static void addsubeq (const GenDesc* Gen, ExprDesc *Expr, const char* Op)
 /* Process the += and -= operators */
 {
     ExprDesc Expr2;
@@ -2938,7 +2981,7 @@ static void addsubeq (const GenDesc* Gen, ExprDesc *Expr)
     /* We're currently only able to handle some adressing modes */
     if (ED_GetLoc (Expr) == E_LOC_EXPR || ED_GetLoc (Expr) == E_LOC_PRIMARY) {
        /* Use generic routine */
-               opeq (Gen, Expr);
+               opeq (Gen, Expr, Op);
        return;
     }
 
@@ -2971,8 +3014,16 @@ static void addsubeq (const GenDesc* Gen, ExprDesc *Expr)
     lflags = 0;
     rflags = 0;
 
-    /* Evaluate the rhs */
+    /* Evaluate the rhs. We expect an integer here, since float is not
+     * supported
+     */
     hie1 (&Expr2);
+    if (!IsClassInt (Expr2.Type)) {
+        Error ("Invalid right operand for binary operator `%s'", Op);
+        /* Continue. Wrong code will be generated, but the compiler won't
+         * break, so this is the best error recovery.
+         */
+    }
     if (ED_IsConstAbs (&Expr2)) {
        /* The resulting value is a constant. Scale it. */
         if (MustScale) {
@@ -3066,43 +3117,43 @@ void hie1 (ExprDesc* Expr)
            break;
 
        case TOK_PLUS_ASSIGN:
-                   addsubeq (&GenPASGN, Expr);
+                   addsubeq (&GenPASGN, Expr, "+=");
            break;
 
        case TOK_MINUS_ASSIGN:
-                   addsubeq (&GenSASGN, Expr);
+                   addsubeq (&GenSASGN, Expr, "-=");
            break;
 
        case TOK_MUL_ASSIGN:
-                   opeq (&GenMASGN, Expr);
+                   opeq (&GenMASGN, Expr, "*=");
            break;
 
        case TOK_DIV_ASSIGN:
-                   opeq (&GenDASGN, Expr);
+                   opeq (&GenDASGN, Expr, "/=");
            break;
 
        case TOK_MOD_ASSIGN:
-                   opeq (&GenMOASGN, Expr);
+                   opeq (&GenMOASGN, Expr, "%=");
            break;
 
        case TOK_SHL_ASSIGN:
-                   opeq (&GenSLASGN, Expr);
+                   opeq (&GenSLASGN, Expr, "<<=");
            break;
 
        case TOK_SHR_ASSIGN:
-                   opeq (&GenSRASGN, Expr);
+                   opeq (&GenSRASGN, Expr, ">>=");
            break;
 
        case TOK_AND_ASSIGN:
-                   opeq (&GenAASGN, Expr);
+                   opeq (&GenAASGN, Expr, "&=");
            break;
 
        case TOK_XOR_ASSIGN:
-                   opeq (&GenXOASGN, Expr);
+                   opeq (&GenXOASGN, Expr, "^=");
            break;
 
        case TOK_OR_ASSIGN:
-                   opeq (&GenOASGN, Expr);
+                   opeq (&GenOASGN, Expr, "|=");
            break;
 
        default: