2003-08-11 20:18:30 +00:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/* */
|
|
|
|
|
/* typeconv.c */
|
|
|
|
|
/* */
|
|
|
|
|
/* Handle type conversions */
|
|
|
|
|
/* */
|
|
|
|
|
/* */
|
|
|
|
|
/* */
|
|
|
|
|
/* (C) 2002-2003 Ullrich von Bassewitz */
|
|
|
|
|
/* R<>merstrasse 52 */
|
|
|
|
|
/* D-70794 Filderstadt */
|
|
|
|
|
/* EMail: uz@cc65.org */
|
|
|
|
|
/* */
|
|
|
|
|
/* */
|
|
|
|
|
/* This software is provided 'as-is', without any expressed or implied */
|
|
|
|
|
/* warranty. In no event will the authors be held liable for any damages */
|
|
|
|
|
/* arising from the use of this software. */
|
|
|
|
|
/* */
|
|
|
|
|
/* Permission is granted to anyone to use this software for any purpose, */
|
|
|
|
|
/* including commercial applications, and to alter it and redistribute it */
|
|
|
|
|
/* freely, subject to the following restrictions: */
|
|
|
|
|
/* */
|
|
|
|
|
/* 1. The origin of this software must not be misrepresented; you must not */
|
|
|
|
|
/* claim that you wrote the original software. If you use this software */
|
|
|
|
|
/* in a product, an acknowledgment in the product documentation would be */
|
|
|
|
|
/* appreciated but is not required. */
|
|
|
|
|
/* 2. Altered source versions must be plainly marked as such, and must not */
|
|
|
|
|
/* be misrepresented as being the original software. */
|
|
|
|
|
/* 3. This notice may not be removed or altered from any source */
|
|
|
|
|
/* distribution. */
|
|
|
|
|
/* */
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-11-11 09:44:19 +00:00
|
|
|
|
/* common */
|
|
|
|
|
#include "shift.h"
|
|
|
|
|
|
2003-08-11 20:18:30 +00:00
|
|
|
|
/* cc65 */
|
|
|
|
|
#include "codegen.h"
|
|
|
|
|
#include "datatype.h"
|
|
|
|
|
#include "declare.h"
|
|
|
|
|
#include "error.h"
|
|
|
|
|
#include "expr.h"
|
|
|
|
|
#include "scanner.h"
|
|
|
|
|
#include "typecmp.h"
|
|
|
|
|
#include "typeconv.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/* 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)
|
|
|
|
|
/* Emit code to convert the given expression to a new type. */
|
|
|
|
|
{
|
|
|
|
|
type* OldType;
|
|
|
|
|
unsigned OldSize;
|
|
|
|
|
unsigned NewSize;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Remember the old type */
|
|
|
|
|
OldType = Expr->Type;
|
|
|
|
|
|
|
|
|
|
/* If we're converting to void, we're done. Note: This does also cover a
|
|
|
|
|
* conversion void -> void.
|
|
|
|
|
*/
|
|
|
|
|
if (IsTypeVoid (NewType)) {
|
|
|
|
|
k = 0; /* Never an lvalue */
|
|
|
|
|
goto ExitPoint;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Don't allow casts from void to something else. */
|
|
|
|
|
if (IsTypeVoid (OldType)) {
|
|
|
|
|
Error ("Cannot convert from `void' to something else");
|
|
|
|
|
goto ExitPoint;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Get the sizes of the types. Since we've excluded void types, checking
|
|
|
|
|
* for known sizes makes sense here.
|
|
|
|
|
*/
|
|
|
|
|
OldSize = CheckedSizeOf (OldType);
|
|
|
|
|
NewSize = CheckedSizeOf (NewType);
|
|
|
|
|
|
|
|
|
|
/* lvalue? */
|
|
|
|
|
if (k != 0) {
|
|
|
|
|
|
|
|
|
|
/* 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
|
|
|
|
|
* to load only the portion of the value that is actually needed.
|
|
|
|
|
* This works only on a little endian architecture, but that's
|
|
|
|
|
* what we support.
|
|
|
|
|
* If both sizes are equal, do also leave the value alone.
|
|
|
|
|
* If the new size is larger, we must convert the value.
|
|
|
|
|
*/
|
|
|
|
|
if (NewSize > OldSize) {
|
|
|
|
|
/* Load the value into the primary */
|
2003-08-29 09:16:28 +00:00
|
|
|
|
ExprLoad (CF_NONE, k, Expr);
|
2003-08-11 20:18:30 +00:00
|
|
|
|
|
|
|
|
|
/* Emit typecast code */
|
2003-08-19 20:31:10 +00:00
|
|
|
|
g_typecast (TypeOf (NewType), TypeOf (OldType));
|
2003-08-11 20:18:30 +00:00
|
|
|
|
|
|
|
|
|
/* Value is now in primary */
|
|
|
|
|
Expr->Flags = E_MEXPR;
|
|
|
|
|
k = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
/* We have an rvalue. Check for a constant. */
|
|
|
|
|
if (Expr->Flags == E_MCONST) {
|
|
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
|
|
|
|
|
/* 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))) {
|
2003-11-11 09:44:19 +00:00
|
|
|
|
/* Beware: Use the safe shift routine here. */
|
|
|
|
|
Expr->ConstVal |= shl_l (~0UL, NewBits);
|
2003-08-11 20:18:30 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} 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) {
|
|
|
|
|
|
|
|
|
|
/* Load the value into the primary */
|
2003-08-29 09:16:28 +00:00
|
|
|
|
ExprLoad (CF_NONE, k, Expr);
|
2003-08-11 20:18:30 +00:00
|
|
|
|
|
|
|
|
|
/* Emit typecast code. */
|
2003-08-19 20:31:10 +00:00
|
|
|
|
g_typecast (TypeOf (NewType) | CF_FORCECHAR, TypeOf (OldType));
|
2003-08-11 20:18:30 +00:00
|
|
|
|
|
|
|
|
|
/* Value is now in primary */
|
|
|
|
|
Expr->Flags = E_MEXPR;
|
|
|
|
|
k = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ExitPoint:
|
|
|
|
|
/* The expression has always the new type */
|
|
|
|
|
ReplaceType (Expr, NewType);
|
|
|
|
|
|
|
|
|
|
/* Done */
|
|
|
|
|
return k;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int TypeConversion (ExprDesc* Expr, int k, 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);
|
|
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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");
|
2003-08-17 15:20:18 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Do a conversion regardless of errors and return the result. */
|
|
|
|
|
return DoConversion (Expr, k, NewType);
|
2003-08-11 20:18:30 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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");
|
2003-08-17 15:20:18 +00:00
|
|
|
|
break;
|
2003-08-11 20:18:30 +00:00
|
|
|
|
|
|
|
|
|
case TC_QUAL_DIFF:
|
|
|
|
|
Error ("Pointer types differ in type qualifiers");
|
2003-08-17 15:20:18 +00:00
|
|
|
|
break;
|
2003-08-11 20:18:30 +00:00
|
|
|
|
|
|
|
|
|
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");
|
|
|
|
|
}
|
|
|
|
|
|
2003-08-17 15:20:18 +00:00
|
|
|
|
/* Do the conversion even in case of errors */
|
2003-08-11 20:18:30 +00:00
|
|
|
|
return DoConversion (Expr, k, NewType);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Invalid automatic conversion */
|
|
|
|
|
Error ("Incompatible types");
|
2003-08-17 15:20:18 +00:00
|
|
|
|
return DoConversion (Expr, k, NewType);
|
2003-08-11 20:18:30 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int TypeCast (ExprDesc* Expr)
|
|
|
|
|
/* Handle an explicit cast. The function returns true if the resulting
|
|
|
|
|
* expression is an lvalue and false if not.
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
int k;
|
|
|
|
|
type NewType[MAXTYPELEN];
|
|
|
|
|
|
|
|
|
|
/* Skip the left paren */
|
|
|
|
|
NextToken ();
|
|
|
|
|
|
|
|
|
|
/* Read the type */
|
|
|
|
|
ParseType (NewType);
|
|
|
|
|
|
|
|
|
|
/* Closing paren */
|
|
|
|
|
ConsumeRParen ();
|
|
|
|
|
|
|
|
|
|
/* Read the expression we have to cast */
|
|
|
|
|
k = hie10 (Expr);
|
|
|
|
|
|
|
|
|
|
/* Convert functions and arrays to "pointer to" object */
|
|
|
|
|
DoPtrConversions (Expr);
|
|
|
|
|
|
|
|
|
|
/* Convert the value and return the result. */
|
|
|
|
|
return DoConversion (Expr, k, NewType);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-11-11 09:44:19 +00:00
|
|
|
|
|