/* */
/* */
/* */
-/* (C) 2002-2003 Ullrich von Bassewitz */
-/* Römerstrasse 52 */
+/* (C) 2002-2008 Ullrich von Bassewitz */
+/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
/* */
+/* common */
+#include "shift.h"
+
/* cc65 */
#include "codegen.h"
#include "datatype.h"
#include "declare.h"
#include "error.h"
#include "expr.h"
+#include "loadexpr.h"
#include "scanner.h"
#include "typecmp.h"
#include "typeconv.h"
/*****************************************************************************/
-/* Code */
+/* Code */
/*****************************************************************************/
-static void DoPtrConversions (ExprDesc* Expr)
-/* If the expression is a function, convert it to pointer to function.
- * If the expression is an array, convert it to pointer to first element.
- */
-{
- if (IsTypeFunc (Expr->Type)) {
- Expr->Type = PointerTo (Expr->Type);
- } else if (IsTypeArray (Expr->Type)) {
- Expr->Type = ArrayToPtr (Expr->Type);
- }
-}
-
-
-
-static int DoConversion (ExprDesc* Expr, int k, type* NewType)
+static void DoConversion (ExprDesc* Expr, const Type* NewType)
/* Emit code to convert the given expression to a new type. */
{
- type* OldType;
+ Type* OldType;
unsigned OldSize;
unsigned NewSize;
* conversion void -> void.
*/
if (IsTypeVoid (NewType)) {
- k = 0; /* Never an lvalue */
+ ED_MakeRVal (Expr); /* Never an lvalue */
goto ExitPoint;
}
NewSize = CheckedSizeOf (NewType);
/* lvalue? */
- if (k != 0) {
+ if (ED_IsLVal (Expr)) {
/* We have an lvalue. If the new size is smaller than the new one,
* we don't need to do anything. The compiler will generate code
*/
if (NewSize > OldSize) {
/* Load the value into the primary */
- ExprLoad (CF_NONE, k, Expr);
+ LoadExpr (CF_NONE, Expr);
/* Emit typecast code */
- g_typecast (TypeOf (NewType), TypeOf (OldType));
+ g_typecast (TypeOf (NewType), TypeOf (OldType) | CF_FORCECHAR);
- /* Value is now in primary */
- Expr->Flags = E_MEXPR;
- k = 0;
+ /* Value is now in primary and an rvalue */
+ ED_MakeRValExpr (Expr);
}
- } else {
+ } else if (ED_IsLocAbs (Expr)) {
- /* We have an rvalue. Check for a constant. */
- if (Expr->Flags == E_MCONST) {
+ /* A cast of a constant numeric value to another type. Be sure
+ * to handle sign extension correctly.
+ */
- /* A cast of a constant to an integer. Be sure to handle sign
- * extension correctly.
- */
+ /* Get the current and new size of the value */
+ unsigned OldBits = OldSize * 8;
+ unsigned NewBits = NewSize * 8;
- /* Get the current and new size of the value */
- unsigned OldBits = OldSize * 8;
- unsigned NewBits = NewSize * 8;
+ /* Check if the new datatype will have a smaller range. If it
+ * has a larger range, things are ok, since the value is
+ * internally already represented by a long.
+ */
+ if (NewBits <= OldBits) {
- /* Check if the new datatype will have a smaller range. If it
- * has a larger range, things are ok, since the value is
- * internally already represented by a long.
- */
- if (NewBits <= OldBits) {
-
- /* Cut the value to the new size */
- Expr->ConstVal &= (0xFFFFFFFFUL >> (32 - NewBits));
-
- /* If the new type is signed, sign extend the value */
- if (!IsSignUnsigned (NewType)) {
- if (Expr->ConstVal & (0x01UL << (NewBits-1))) {
- /* Beware: NewBits may be 32, in which case a shift
- * creates undefined behaviour if a long does also
- * have 32 bits. So apply a somewhat complex special
- * handling.
- */
- unsigned long SignBits = ~0UL;
- SignBits <<= (NewBits / 2);
- NewBits -= (NewBits / 2);
- SignBits <<= NewBits;
- Expr->ConstVal |= SignBits;
- }
+ /* Cut the value to the new size */
+ Expr->IVal &= (0xFFFFFFFFUL >> (32 - NewBits));
+
+ /* If the new type is signed, sign extend the value */
+ if (IsSignSigned (NewType)) {
+ if (Expr->IVal & (0x01UL << (NewBits-1))) {
+ /* Beware: Use the safe shift routine here. */
+ Expr->IVal |= shl_l (~0UL, NewBits);
}
}
+ }
- } else {
+ } else {
- /* The value is not a constant. If the sizes of the types are
- * not equal, add conversion code. Be sure to convert chars
- * correctly.
- */
- if (OldSize != NewSize) {
+ /* The value is not a constant. If the sizes of the types are
+ * not equal, add conversion code. Be sure to convert chars
+ * correctly.
+ */
+ if (OldSize != NewSize) {
- /* Load the value into the primary */
- ExprLoad (CF_NONE, k, Expr);
+ /* Load the value into the primary */
+ LoadExpr (CF_NONE, Expr);
- /* Emit typecast code. */
- g_typecast (TypeOf (NewType) | CF_FORCECHAR, TypeOf (OldType));
+ /* Emit typecast code. */
+ g_typecast (TypeOf (NewType), TypeOf (OldType) | CF_FORCECHAR);
- /* Value is now in primary */
- Expr->Flags = E_MEXPR;
- k = 0;
- }
+ /* Value is now a rvalue in the primary */
+ ED_MakeRValExpr (Expr);
}
}
ExitPoint:
/* The expression has always the new type */
ReplaceType (Expr, NewType);
-
- /* Done */
- return k;
}
-int TypeConversion (ExprDesc* Expr, int k, type* NewType)
+void TypeConversion (ExprDesc* Expr, Type* NewType)
/* Do an automatic conversion of the given expression to the new type. Output
* warnings or errors where this automatic conversion is suspicious or
* impossible.
*/
{
- /* Get the type of the right hand side. Treat function types as
- * pointer-to-function
- */
- DoPtrConversions (Expr);
+#if 0
+ /* Debugging */
+ printf ("Expr:\n=======================================\n");
+ PrintExprDesc (stdout, Expr);
+ printf ("Type:\n=======================================\n");
+ PrintType (stdout, NewType);
+ printf ("\n");
+ PrintRawType (stdout, NewType);
+#endif
/* First, do some type checking */
if (IsTypeVoid (NewType) || IsTypeVoid (Expr->Type)) {
- /* If one of the sides are of type void, output a more apropriate
- * error message.
- */
- Error ("Illegal type");
- return k;
+ /* If one of the sides are of type void, output a more apropriate
+ * error message.
+ */
+ Error ("Illegal type");
}
- /* Handle conversions to int type */
- if (IsClassInt (NewType)) {
- if (IsClassPtr (Expr->Type)) {
- /* Pointer -> int conversion */
- Warning ("Converting pointer to integer without a cast");
- } else if (!IsClassInt (Expr->Type)) {
- Error ("Incompatible types");
- }
-
- /* Do a conversion regardless of errors and return the result. */
- return DoConversion (Expr, k, NewType);
+ /* If Expr is a function, convert it to pointer to function */
+ if (IsTypeFunc(Expr->Type)) {
+ Expr->Type = PointerTo (Expr->Type);
}
- /* Handle conversions to pointer type */
- if (IsClassPtr (NewType)) {
- if (IsClassPtr (Expr->Type)) {
- /* Pointer to pointer assignment is valid, if:
- * - both point to the same types, or
- * - the rhs pointer is a void pointer, or
- * - the lhs pointer is a void pointer.
- */
- if (!IsTypeVoid (Indirect (NewType)) && !IsTypeVoid (Indirect (Expr->Type))) {
- /* Compare the types */
- switch (TypeCmp (NewType, Expr->Type)) {
-
- case TC_INCOMPATIBLE:
- Error ("Incompatible pointer types");
- break;
-
- case TC_QUAL_DIFF:
- Error ("Pointer types differ in type qualifiers");
- break;
-
- default:
- /* Ok */
- break;
- }
- }
- } else if (IsClassInt (Expr->Type)) {
- /* Int to pointer assignment is valid only for constant zero */
- if (Expr->Flags != E_MCONST || Expr->ConstVal != 0) {
- Warning ("Converting integer to pointer without a cast");
- }
- } else if (IsTypeFuncPtr (NewType) && IsTypeFunc(Expr->Type)) {
- /* Assignment of function to function pointer is allowed, provided
- * that both functions have the same parameter list.
- */
- if (TypeCmp (Indirect (NewType), Expr->Type) < TC_EQUAL) {
- Error ("Incompatible types");
- }
- } else {
- Error ("Incompatible types");
- }
-
- /* Do the conversion even in case of errors */
- return DoConversion (Expr, k, NewType);
+ /* If both types are equal, no conversion is needed */
+ if (TypeCmp (Expr->Type, NewType) >= TC_EQUAL) {
+ /* We're already done */
+ return;
+ }
+
+ /* Check for conversion problems */
+ if (IsClassInt (NewType)) {
+
+ /* Handle conversions to int type */
+ if (IsClassPtr (Expr->Type)) {
+ /* Pointer -> int conversion. Convert array to pointer */
+ if (IsTypeArray (Expr->Type)) {
+ Expr->Type = ArrayToPtr (Expr->Type);
+ }
+ Warning ("Converting pointer to integer without a cast");
+ } else if (!IsClassInt (Expr->Type) && !IsClassFloat (Expr->Type)) {
+ Error ("Incompatible types");
+ }
+
+ } else if (IsClassFloat (NewType)) {
+
+ if (!IsClassFloat (Expr->Type) && !IsClassInt (Expr->Type)) {
+ Error ("Incompatible types");
+ }
+
+ } else if (IsClassPtr (NewType)) {
+
+ /* Handle conversions to pointer type */
+ if (IsClassPtr (Expr->Type)) {
+
+ /* Convert array to pointer */
+ if (IsTypeArray (Expr->Type)) {
+ Expr->Type = ArrayToPtr (Expr->Type);
+ }
+
+ /* Pointer to pointer assignment is valid, if:
+ * - both point to the same types, or
+ * - the rhs pointer is a void pointer, or
+ * - the lhs pointer is a void pointer.
+ */
+ if (!IsTypeVoid (Indirect (NewType)) && !IsTypeVoid (Indirect (Expr->Type))) {
+ /* Compare the types */
+ switch (TypeCmp (NewType, Expr->Type)) {
+
+ case TC_INCOMPATIBLE:
+ Error ("Incompatible pointer types");
+ break;
+
+ case TC_QUAL_DIFF:
+ Error ("Pointer types differ in type qualifiers");
+ break;
+
+ default:
+ /* Ok */
+ break;
+ }
+ }
+
+ } else if (IsClassInt (Expr->Type)) {
+ /* Int to pointer assignment is valid only for constant zero */
+ if (!ED_IsConstAbsInt (Expr) || Expr->IVal != 0) {
+ Warning ("Converting integer to pointer without a cast");
+ }
+ } else {
+ Error ("Incompatible types");
+ }
+
+ } else {
+
+ /* Invalid automatic conversion */
+ Error ("Incompatible types");
}
- /* Invalid automatic conversion */
- Error ("Incompatible types");
- return DoConversion (Expr, k, NewType);
+ /* Do the actual conversion */
+ DoConversion (Expr, NewType);
}
-int TypeCast (ExprDesc* Expr)
-/* Handle an explicit cast. The function returns true if the resulting
- * expression is an lvalue and false if not.
- */
+void TypeCast (ExprDesc* Expr)
+/* Handle an explicit cast. */
{
- int k;
- type NewType[MAXTYPELEN];
+ Type NewType[MAXTYPELEN];
/* Skip the left paren */
NextToken ();
ConsumeRParen ();
/* Read the expression we have to cast */
- k = hie10 (Expr);
+ hie10 (Expr);
/* Convert functions and arrays to "pointer to" object */
- DoPtrConversions (Expr);
+ Expr->Type = PtrConversion (Expr->Type);
- /* Convert the value and return the result. */
- return DoConversion (Expr, k, NewType);
+ /* Convert the value. */
+ DoConversion (Expr, NewType);
}
-
-
-