]> git.sur5r.net Git - cc65/blobdiff - src/cc65/expr.c
Fixed _textcolor definition.
[cc65] / src / cc65 / expr.c
index 03374a52147f86d48edbe648b4935cff8e1e371d..e6522f94900a89d3212d496e70d2e06c12b11fd7 100644 (file)
@@ -1,6 +1,7 @@
 /* expr.c
 **
-** Ullrich von Bassewitz, 21.06.1998
+** 1998-06-21, Ullrich von Bassewitz
+** 2017-12-05, Greg King
 */
 
 
@@ -49,6 +50,7 @@
 /* Generator attributes */
 #define GEN_NOPUSH      0x01            /* Don't push lhs */
 #define GEN_COMM        0x02            /* Operator is commutative */
+#define GEN_NOFUNC      0x04            /* Not allowed for function pointers */
 
 /* Map a generator function and its attributes to a token */
 typedef struct {
@@ -470,9 +472,11 @@ static void FunctionCall (ExprDesc* Expr)
     /* Handle function pointers transparently */
     IsFuncPtr = IsTypeFuncPtr (Expr->Type);
     if (IsFuncPtr) {
-
-        /* Check wether it's a fastcall function that has parameters */
-        IsFastcall = IsQualFastcall (Expr->Type + 1) && (Func->ParamCount > 0);
+        /* Check whether it's a fastcall function that has parameters */
+        IsFastcall = (Func->Flags & FD_VARIADIC) == 0 && Func->ParamCount > 0 &&
+            (AutoCDecl ?
+             IsQualFastcall (Expr->Type + 1) :
+             !IsQualCDecl (Expr->Type + 1));
 
         /* Things may be difficult, depending on where the function pointer
         ** resides. If the function pointer is an expression of some sort
@@ -517,7 +521,10 @@ static void FunctionCall (ExprDesc* Expr)
         }
 
         /* If we didn't inline the function, get fastcall info */
-        IsFastcall = IsQualFastcall (Expr->Type);
+        IsFastcall = (Func->Flags & FD_VARIADIC) == 0 &&
+            (AutoCDecl ?
+             IsQualFastcall (Expr->Type) :
+             !IsQualCDecl (Expr->Type));
     }
 
     /* Parse the parameter list */
@@ -529,6 +536,10 @@ static void FunctionCall (ExprDesc* Expr)
     /* Special handling for function pointers */
     if (IsFuncPtr) {
 
+        if (Func->WrappedCall) {
+            Warning ("Calling a wrapped function via a pointer, wrapped-call will not be used");
+        }
+
         /* If the function is not a fastcall function, load the pointer to
         ** the function into the primary.
         */
@@ -577,7 +588,47 @@ static void FunctionCall (ExprDesc* Expr)
     } else {
 
         /* Normal function */
-        g_call (TypeOf (Expr->Type), (const char*) Expr->Name, ParamSize);
+        if (Func->WrappedCall) {
+            char tmp[64];
+            StrBuf S = AUTO_STRBUF_INITIALIZER;
+
+            /* Store the WrappedCall data in tmp4 */
+            sprintf(tmp, "ldy #%u", Func->WrappedCallData);
+            SB_AppendStr (&S, tmp);
+            g_asmcode (&S);
+            SB_Clear(&S);
+
+            SB_AppendStr (&S, "sty tmp4");
+            g_asmcode (&S);
+            SB_Clear(&S);
+
+            /* Store the original function address in ptr4 */
+            SB_AppendStr (&S, "ldy #<(_");
+            SB_AppendStr (&S, (const char*) Expr->Name);
+            SB_AppendChar (&S, ')');
+            g_asmcode (&S);
+            SB_Clear(&S);
+
+            SB_AppendStr (&S, "sty ptr4");
+            g_asmcode (&S);
+            SB_Clear(&S);
+
+            SB_AppendStr (&S, "ldy #>(_");
+            SB_AppendStr (&S, (const char*) Expr->Name);
+            SB_AppendChar (&S, ')');
+            g_asmcode (&S);
+            SB_Clear(&S);
+
+            SB_AppendStr (&S, "sty ptr4+1");
+            g_asmcode (&S);
+            SB_Clear(&S);
+
+            SB_Done (&S);
+
+            g_call (TypeOf (Expr->Type), Func->WrappedCall->Name, ParamSize);
+        } else {
+            g_call (TypeOf (Expr->Type), (const char*) Expr->Name, ParamSize);
+        }
 
     }
 
@@ -645,6 +696,23 @@ static void Primary (ExprDesc* E)
 
     switch (CurTok.Tok) {
 
+        case TOK_BOOL_AND:
+            /* A computed goto label address */
+            if (IS_Get (&Standard) >= STD_CC65) {
+                SymEntry* Entry;
+                NextToken ();
+                Entry = AddLabelSym (CurTok.Ident, SC_REF | SC_GOTO_IND);
+                /* output its label */
+                E->Flags = E_RTYPE_RVAL | E_LOC_STATIC;
+                E->Name = Entry->V.L.Label;
+                E->Type = PointerTo (type_void);
+                NextToken ();
+            } else {
+                Error ("Computed gotos are a C extension, not supported with this --standard");
+                ED_MakeConstAbsInt (E, 1);
+            }
+            break;
+
         case TOK_IDENT:
             /* Identifier. Get a pointer to the symbol table entry */
             Sym = E->Sym = FindSym (CurTok.Ident);
@@ -680,7 +748,7 @@ static void Primary (ExprDesc* E)
                 } else if ((Sym->Flags & SC_FUNC) == SC_FUNC) {
                     /* Function */
                     E->Flags = E_LOC_GLOBAL | E_RTYPE_LVAL;
-                    E->Name = (unsigned long) Sym->Name;
+                    E->Name = (uintptr_t) Sym->Name;
                 } else if ((Sym->Flags & SC_AUTO) == SC_AUTO) {
                     /* Local variable. If this is a parameter for a variadic
                     ** function, we have to add some address calculations, and the
@@ -703,10 +771,10 @@ static void Primary (ExprDesc* E)
                     /* Static variable */
                     if (Sym->Flags & (SC_EXTERN | SC_STORAGE)) {
                         E->Flags = E_LOC_GLOBAL | E_RTYPE_LVAL;
-                        E->Name = (unsigned long) Sym->Name;
+                        E->Name = (uintptr_t) Sym->Name;
                     } else {
                         E->Flags = E_LOC_STATIC | E_RTYPE_LVAL;
-                        E->Name = Sym->V.Label;
+                        E->Name = Sym->V.L.Label;
                     }
                 } else {
                     /* Local static variable */
@@ -740,20 +808,20 @@ static void Primary (ExprDesc* E)
                     ** list and returning int.
                     */
                     if (IS_Get (&Standard) >= STD_C99) {
-                        Error ("Call to undefined function `%s'", Ident);
+                        Error ("Call to undefined function '%s'", Ident);
                     } else {
-                        Warning ("Call to undefined function `%s'", Ident);
+                        Warning ("Call to undefined function '%s'", Ident);
                     }
                     Sym = AddGlobalSym (Ident, GetImplicitFuncType(), SC_EXTERN | SC_REF | SC_FUNC);
                     E->Type  = Sym->Type;
                     E->Flags = E_LOC_GLOBAL | E_RTYPE_RVAL;
-                    E->Name  = (unsigned long) Sym->Name;
+                    E->Name  = (uintptr_t) Sym->Name;
                 } else {
                     /* Undeclared Variable */
                     Sym = AddLocalSym (Ident, type_int, SC_AUTO | SC_REF, 0);
                     E->Flags = E_LOC_STACK | E_RTYPE_LVAL;
                     E->Type = type_int;
-                    Error ("Undefined symbol: `%s'", Ident);
+                    Error ("Undefined symbol: '%s'", Ident);
                 }
 
             }
@@ -1123,7 +1191,7 @@ static void StructRef (ExprDesc* Expr)
     NextToken ();
     Field = FindStructField (Expr->Type, Ident);
     if (Field == 0) {
-        Error ("Struct/union has no field named `%s'", Ident);
+        Error ("Struct/union has no field named '%s'", Ident);
         /* Make the expression an integer at address zero */
         ED_MakeConstAbs (Expr, 0, type_int);
         return;
@@ -1257,7 +1325,7 @@ static void hie11 (ExprDesc *Expr)
                     ** Since we don't have a name, invent one.
                     */
                     ED_MakeConstAbs (Expr, 0, GetImplicitFuncType ());
-                    Expr->Name = (long) IllegalFunc;
+                    Expr->Name = (uintptr_t) IllegalFunc;
                 }
                 /* Call the function */
                 FunctionCall (Expr);
@@ -1527,25 +1595,34 @@ static void PostInc (ExprDesc* Expr)
     /* Get the data type */
     Flags = TypeOf (Expr->Type);
 
-    /* Push the address if needed */
-    PushAddr (Expr);
+    /* Emit smaller code if a char variable is at a constant location */
+    if ((Flags & CF_CHAR) == CF_CHAR && ED_IsLocConst(Expr)) {
 
-    /* Fetch the value and save it (since it's the result of the expression) */
-    LoadExpr (CF_NONE, Expr);
-    g_save (Flags | CF_FORCECHAR);
+        LoadExpr (CF_NONE, Expr);
+        AddCodeLine ("inc %s", ED_GetLabelName(Expr, 0));
 
-    /* If we have a pointer expression, increment by the size of the type */
-    if (IsTypePtr (Expr->Type)) {
-        g_inc (Flags | CF_CONST | CF_FORCECHAR, CheckedSizeOf (Expr->Type + 1));
     } else {
-        g_inc (Flags | CF_CONST | CF_FORCECHAR, 1);
-    }
 
-    /* Store the result back */
-    Store (Expr, 0);
+        /* Push the address if needed */
+        PushAddr (Expr);
 
-    /* Restore the original value in the primary register */
-    g_restore (Flags | CF_FORCECHAR);
+        /* Fetch the value and save it (since it's the result of the expression) */
+        LoadExpr (CF_NONE, Expr);
+        g_save (Flags | CF_FORCECHAR);
+
+        /* If we have a pointer expression, increment by the size of the type */
+        if (IsTypePtr (Expr->Type)) {
+            g_inc (Flags | CF_CONST | CF_FORCECHAR, CheckedSizeOf (Expr->Type + 1));
+        } else {
+            g_inc (Flags | CF_CONST | CF_FORCECHAR, 1);
+        }
+
+        /* Store the result back */
+        Store (Expr, 0);
+
+        /* Restore the original value in the primary register */
+        g_restore (Flags | CF_FORCECHAR);
+    }
 
     /* The result is always an expression, no reference */
     ED_MakeRValExpr (Expr);
@@ -1574,25 +1651,34 @@ static void PostDec (ExprDesc* Expr)
     /* Get the data type */
     Flags = TypeOf (Expr->Type);
 
-    /* Push the address if needed */
-    PushAddr (Expr);
+    /* Emit smaller code if a char variable is at a constant location */
+    if ((Flags & CF_CHAR) == CF_CHAR && ED_IsLocConst(Expr)) {
 
-    /* Fetch the value and save it (since it's the result of the expression) */
-    LoadExpr (CF_NONE, Expr);
-    g_save (Flags | CF_FORCECHAR);
+        LoadExpr (CF_NONE, Expr);
+        AddCodeLine ("dec %s", ED_GetLabelName(Expr, 0));
 
-    /* If we have a pointer expression, increment by the size of the type */
-    if (IsTypePtr (Expr->Type)) {
-        g_dec (Flags | CF_CONST | CF_FORCECHAR, CheckedSizeOf (Expr->Type + 1));
     } else {
-        g_dec (Flags | CF_CONST | CF_FORCECHAR, 1);
-    }
 
-    /* Store the result back */
-    Store (Expr, 0);
+        /* Push the address if needed */
+        PushAddr (Expr);
+
+        /* Fetch the value and save it (since it's the result of the expression) */
+        LoadExpr (CF_NONE, Expr);
+        g_save (Flags | CF_FORCECHAR);
+
+        /* If we have a pointer expression, increment by the size of the type */
+        if (IsTypePtr (Expr->Type)) {
+            g_dec (Flags | CF_CONST | CF_FORCECHAR, CheckedSizeOf (Expr->Type + 1));
+        } else {
+            g_dec (Flags | CF_CONST | CF_FORCECHAR, 1);
+        }
 
-    /* Restore the original value in the primary register */
-    g_restore (Flags | CF_FORCECHAR);
+        /* Store the result back */
+        Store (Expr, 0);
+
+        /* Restore the original value in the primary register */
+        g_restore (Flags | CF_FORCECHAR);
+    }
 
     /* The result is always an expression, no reference */
     ED_MakeRValExpr (Expr);
@@ -1707,8 +1793,13 @@ void hie10 (ExprDesc* Expr)
                 } else {
                     Error ("Illegal indirection");
                 }
-                /* The * operator yields an lvalue */
-                ED_MakeLVal (Expr);
+                /* If the expression points to an array, then don't convert the
+                ** address -- it already is the location of the first element.
+                */
+                if (!IsTypeArray (Expr->Type)) {
+                    /* The * operator yields an lvalue */
+                    ED_MakeLVal (Expr);
+                }
             }
             break;
 
@@ -2031,6 +2122,11 @@ static void hie_compare (const GenDesc* Ops,    /* List of generators */
         Tok = CurTok.Tok;
         NextToken ();
 
+        /* If lhs is a function, convert it to pointer to function */
+        if (IsTypeFunc (Expr->Type)) {
+            Expr->Type = PointerTo (Expr->Type);
+        }
+
         /* Get the lhs on stack */
         GetCodePos (&Mark1);
         ltype = TypeOf (Expr->Type);
@@ -2048,6 +2144,11 @@ static void hie_compare (const GenDesc* Ops,    /* List of generators */
         /* Get the right hand side */
         MarkedExprWithCheck (hienext, &Expr2);
 
+        /* If rhs is a function, convert it to pointer to function */
+        if (IsTypeFunc (Expr2.Type)) {
+            Expr2.Type = PointerTo (Expr2.Type);
+        }
+
         /* Check for a constant expression */
         rconst = (ED_IsConstAbs (&Expr2) && ED_CodeRangeIsEmpty (&Expr2));
         if (!rconst) {
@@ -2055,6 +2156,22 @@ static void hie_compare (const GenDesc* Ops,    /* List of generators */
             LoadExpr (CF_NONE, &Expr2);
         }
 
+        /* Some operations aren't allowed on function pointers */
+        if ((Gen->Flags & GEN_NOFUNC) != 0) {
+            /* Output only one message even if both sides are wrong */
+            if (IsTypeFuncPtr (Expr->Type)) {
+                Error ("Invalid left operand for relational operator");
+                /* Avoid further errors */
+                ED_MakeConstAbsInt (Expr, 0);
+                ED_MakeConstAbsInt (&Expr2, 0);
+            } else if (IsTypeFuncPtr (Expr2.Type)) {
+                Error ("Invalid right operand for relational operator");
+                /* Avoid further errors */
+                ED_MakeConstAbsInt (Expr, 0);
+                ED_MakeConstAbsInt (&Expr2, 0);
+            }
+        }
+
         /* Make sure, the types are compatible */
         if (IsClassInt (Expr->Type)) {
             if (!IsClassInt (Expr2.Type) && !(IsClassPtr(Expr2.Type) && ED_IsNullPtr(Expr))) {
@@ -2067,8 +2184,8 @@ static void hie_compare (const GenDesc* Ops,    /* List of generators */
                 */
                 Type* left  = Indirect (Expr->Type);
                 Type* right = Indirect (Expr2.Type);
-                if (TypeCmp (left, right) < TC_EQUAL && left->C != T_VOID && right->C != T_VOID) {
-                    /* Incomatible pointers */
+                if (TypeCmp (left, right) < TC_QUAL_DIFF && left->C != T_VOID && right->C != T_VOID) {
+                    /* Incompatible pointers */
                     Error ("Incompatible types");
                 }
             } else if (!ED_IsNullPtr (&Expr2)) {
@@ -2352,7 +2469,6 @@ static void parseadd (ExprDesc* Expr)
     Type* lhst;                 /* Type of left hand side */
     Type* rhst;                 /* Type of right hand side */
 
-
     /* Skip the PLUS token */
     NextToken ();
 
@@ -2386,7 +2502,7 @@ static void parseadd (ExprDesc* Expr)
                 typeadjust (Expr, &Expr2, 1);
             } else {
                 /* OOPS */
-                Error ("Invalid operands for binary operator `+'");
+                Error ("Invalid operands for binary operator '+'");
             }
 
         } else {
@@ -2468,7 +2584,7 @@ static void parseadd (ExprDesc* Expr)
                 }
             } else {
                 /* OOPS */
-                Error ("Invalid operands for binary operator `+'");
+                Error ("Invalid operands for binary operator '+'");
                 flags = CF_INT;
             }
 
@@ -2512,7 +2628,7 @@ static void parseadd (ExprDesc* Expr)
                 flags = typeadjust (Expr, &Expr2, 1);
             } else {
                 /* OOPS */
-                Error ("Invalid operands for binary operator `+'");
+                Error ("Invalid operands for binary operator '+'");
                 flags = CF_INT;
             }
 
@@ -2535,7 +2651,7 @@ static void parseadd (ExprDesc* Expr)
                 flags = CF_PTR;
             } else if (IsClassInt (lhst) && IsClassPtr (rhst)) {
                 /* Left is int, right is pointer, must scale lhs */
-                g_tosint (TypeOf (rhst));       /* Make sure, TOS is int */
+                g_tosint (TypeOf (lhst));       /* Make sure TOS is int */
                 g_swap (CF_INT);                /* Swap TOS and primary */
                 g_scale (CF_INT, CheckedPSizeOf (rhst));
                 /* Operate on pointers, result type is a pointer */
@@ -2554,7 +2670,7 @@ static void parseadd (ExprDesc* Expr)
                 flags = typeadjust (Expr, &Expr2, 0) & ~CF_CONST;
             } else {
                 /* OOPS */
-                Error ("Invalid operands for binary operator `+'");
+                Error ("Invalid operands for binary operator '+'");
                 flags = CF_INT;
             }
 
@@ -2569,7 +2685,6 @@ static void parseadd (ExprDesc* Expr)
 
     /* Condition codes not set */
     ED_MarkAsUntested (Expr);
-
 }
 
 
@@ -2589,6 +2704,13 @@ static void parsesub (ExprDesc* Expr)
     int rscale;                 /* Scale factor for the result */
 
 
+    /* lhs cannot be function or pointer to function */
+    if (IsTypeFunc (Expr->Type) || IsTypeFuncPtr (Expr->Type)) {
+        Error ("Invalid left operand for binary operator '-'");
+        /* Make it pointer to char to avoid further errors */
+        Expr->Type = type_uchar;
+    }
+
     /* Skip the MINUS token */
     NextToken ();
 
@@ -2605,6 +2727,13 @@ static void parsesub (ExprDesc* Expr)
     /* Parse the right hand side */
     MarkedExprWithCheck (hie9, &Expr2);
 
+    /* rhs cannot be function or pointer to function */
+    if (IsTypeFunc (Expr2.Type) || IsTypeFuncPtr (Expr2.Type)) {
+        Error ("Invalid right operand for binary operator '-'");
+        /* Make it pointer to char to avoid further errors */
+        Expr2.Type = type_uchar;
+    }
+
     /* Check for a constant rhs expression */
     if (ED_IsConstAbs (&Expr2) && ED_CodeRangeIsEmpty (&Expr2)) {
 
@@ -2638,7 +2767,7 @@ static void parsesub (ExprDesc* Expr)
                 Expr->IVal -= Expr2.IVal;
             } else {
                 /* OOPS */
-                Error ("Invalid operands for binary operator `-'");
+                Error ("Invalid operands for binary operator '-'");
             }
 
             /* Result is constant, condition codes not set */
@@ -2671,7 +2800,7 @@ static void parsesub (ExprDesc* Expr)
                 flags = typeadjust (Expr, &Expr2, 1);
             } else {
                 /* OOPS */
-                Error ("Invalid operands for binary operator `-'");
+                Error ("Invalid operands for binary operator '-'");
                 flags = CF_INT;
             }
 
@@ -2725,7 +2854,7 @@ static void parsesub (ExprDesc* Expr)
             flags = typeadjust (Expr, &Expr2, 0);
         } else {
             /* OOPS */
-            Error ("Invalid operands for binary operator `-'");
+            Error ("Invalid operands for binary operator '-'");
             flags = CF_INT;
         }
 
@@ -2764,11 +2893,11 @@ static void hie6 (ExprDesc* Expr)
 /* Handle greater-than type comparators */
 {
     static const GenDesc hie6_ops [] = {
-        { TOK_LT,       GEN_NOPUSH,     g_lt    },
-        { TOK_LE,       GEN_NOPUSH,     g_le    },
-        { TOK_GE,       GEN_NOPUSH,     g_ge    },
-        { TOK_GT,       GEN_NOPUSH,     g_gt    },
-        { TOK_INVALID,  0,              0       }
+        { TOK_LT,       GEN_NOPUSH | GEN_NOFUNC,     g_lt    },
+        { TOK_LE,       GEN_NOPUSH | GEN_NOFUNC,     g_le    },
+        { TOK_GE,       GEN_NOPUSH | GEN_NOFUNC,     g_ge    },
+        { TOK_GT,       GEN_NOPUSH | GEN_NOFUNC,     g_gt    },
+        { TOK_INVALID,  0,                           0       }
     };
     hie_compare (hie6_ops, Expr, ShiftExpr);
 }
@@ -3192,7 +3321,7 @@ static void opeq (const GenDesc* Gen, ExprDesc* Expr, const char* Op)
 
     /* 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);
+        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.
         */
@@ -3309,7 +3438,7 @@ static void addsubeq (const GenDesc* Gen, ExprDesc *Expr, const char* Op)
     */
     hie1 (&Expr2);
     if (!IsClassInt (Expr2.Type)) {
-        Error ("Invalid right operand for binary operator `%s'", Op);
+        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.
         */