mirror of
https://github.com/cc65/cc65.git
synced 2025-08-08 22:25:28 +00:00
Rewrote type conversions
git-svn-id: svn://svn.cc65.org/cc65/trunk@2262 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
@@ -85,7 +85,7 @@ void WriteOutput (FILE* F)
|
|||||||
SymEntry* Entry;
|
SymEntry* Entry;
|
||||||
|
|
||||||
/* Output the global data segment */
|
/* Output the global data segment */
|
||||||
CHECK (CS_GetEntryCount (CS->Code) == 0);
|
CHECK (!HaveGlobalCode ());
|
||||||
OutputSegments (CS, F);
|
OutputSegments (CS, F);
|
||||||
|
|
||||||
/* Output all global or referenced functions */
|
/* Output all global or referenced functions */
|
||||||
|
@@ -6,9 +6,9 @@
|
|||||||
/* */
|
/* */
|
||||||
/* */
|
/* */
|
||||||
/* */
|
/* */
|
||||||
/* (C) 2002 Ullrich von Bassewitz */
|
/* (C) 2002-2003 Ullrich von Bassewitz */
|
||||||
/* Wacholderweg 14 */
|
/* R<EFBFBD>merstrasse 52 */
|
||||||
/* D-70597 Stuttgart */
|
/* D-70794 Filderstadt */
|
||||||
/* EMail: uz@cc65.org */
|
/* EMail: uz@cc65.org */
|
||||||
/* */
|
/* */
|
||||||
/* */
|
/* */
|
||||||
@@ -39,6 +39,7 @@
|
|||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "expr.h"
|
#include "expr.h"
|
||||||
#include "typecmp.h"
|
#include "typecmp.h"
|
||||||
|
#include "typeconv.h"
|
||||||
#include "assignment.h"
|
#include "assignment.h"
|
||||||
|
|
||||||
|
|
||||||
@@ -49,7 +50,7 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void Assignment (ExprDesc* lval)
|
int Assignment (ExprDesc* lval)
|
||||||
/* Parse an assignment */
|
/* Parse an assignment */
|
||||||
{
|
{
|
||||||
int k;
|
int k;
|
||||||
@@ -86,7 +87,7 @@ void Assignment (ExprDesc* lval)
|
|||||||
if (UseReg) {
|
if (UseReg) {
|
||||||
PushAddr (lval);
|
PushAddr (lval);
|
||||||
} else {
|
} else {
|
||||||
exprhs (0, 0, lval);
|
exprhs (0, 0, lval);
|
||||||
g_push (CF_PTR | CF_UNSIGNED, 0);
|
g_push (CF_PTR | CF_UNSIGNED, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,27 +148,26 @@ void Assignment (ExprDesc* lval)
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
/* Get the address on stack if needed */
|
/* Get the address on stack if needed */
|
||||||
PushAddr (lval);
|
PushAddr (lval);
|
||||||
|
|
||||||
/* Get the expression on the right of the '=' into the primary */
|
/* Read the expression on the right side of the '=' */
|
||||||
if (evalexpr (CF_NONE, hie1, &lval2) == 0) {
|
k = hie1 (&lval2);
|
||||||
/* Constant expression. Adjust the types */
|
|
||||||
assignadjust (ltype, &lval2);
|
/* Do type conversion if necessary */
|
||||||
/* Put the value into the primary register */
|
k = TypeConversion (&lval2, k, ltype);
|
||||||
exprhs (CF_NONE, 0, &lval2);
|
|
||||||
} else {
|
/* If necessary, load the value into the primary register */
|
||||||
/* Expression is not constant and already in the primary */
|
exprhs (CF_NONE, k, &lval2);
|
||||||
assignadjust (ltype, &lval2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Generate a store instruction */
|
/* Generate a store instruction */
|
||||||
Store (lval, 0);
|
Store (lval, 0);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Value is still in primary */
|
/* Value is still in primary and not an lvalue */
|
||||||
lval->Flags = E_MEXPR;
|
lval->Flags = E_MEXPR;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -6,9 +6,9 @@
|
|||||||
/* */
|
/* */
|
||||||
/* */
|
/* */
|
||||||
/* */
|
/* */
|
||||||
/* (C) 2002 Ullrich von Bassewitz */
|
/* (C) 2002-2003 Ullrich von Bassewitz */
|
||||||
/* Wacholderweg 14 */
|
/* R<EFBFBD>merstrasse 52 */
|
||||||
/* D-70597 Stuttgart */
|
/* D-70794 Filderstadt */
|
||||||
/* EMail: uz@cc65.org */
|
/* EMail: uz@cc65.org */
|
||||||
/* */
|
/* */
|
||||||
/* */
|
/* */
|
||||||
@@ -49,7 +49,7 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void Assignment (ExprDesc* lval);
|
int Assignment (ExprDesc* lval);
|
||||||
/* Parse an assignment */
|
/* Parse an assignment */
|
||||||
|
|
||||||
|
|
||||||
|
@@ -44,6 +44,7 @@
|
|||||||
#include "anonname.h"
|
#include "anonname.h"
|
||||||
#include "codegen.h"
|
#include "codegen.h"
|
||||||
#include "datatype.h"
|
#include "datatype.h"
|
||||||
|
#include "declare.h"
|
||||||
#include "declattr.h"
|
#include "declattr.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "expr.h"
|
#include "expr.h"
|
||||||
@@ -54,7 +55,7 @@
|
|||||||
#include "pragma.h"
|
#include "pragma.h"
|
||||||
#include "scanner.h"
|
#include "scanner.h"
|
||||||
#include "symtab.h"
|
#include "symtab.h"
|
||||||
#include "declare.h"
|
#include "typeconv.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1076,18 +1077,10 @@ static void ClosingCurlyBraces (unsigned BracesExpected)
|
|||||||
static unsigned ParseScalarInit (type* T)
|
static unsigned ParseScalarInit (type* T)
|
||||||
/* Parse initializaton for scalar data types. Return the number of data bytes. */
|
/* Parse initializaton for scalar data types. Return the number of data bytes. */
|
||||||
{
|
{
|
||||||
static const unsigned long Masks[] = {
|
|
||||||
0x000000FFUL, 0x0000FFFFUL, 0x00FFFFFFUL, 0xFFFFFFFFUL
|
|
||||||
};
|
|
||||||
unsigned BraceCount;
|
|
||||||
ExprDesc ED;
|
ExprDesc ED;
|
||||||
|
|
||||||
/* Get the size of the expected type */
|
|
||||||
unsigned Size = SizeOf (T);
|
|
||||||
CHECK (Size > 0 && Size <= sizeof(Masks)/sizeof(Masks[0]));
|
|
||||||
|
|
||||||
/* Optional opening brace */
|
/* Optional opening brace */
|
||||||
BraceCount = OpeningCurlyBraces (0);
|
unsigned BraceCount = OpeningCurlyBraces (0);
|
||||||
|
|
||||||
/* We warn if an initializer for a scalar contains braces, because this is
|
/* We warn if an initializer for a scalar contains braces, because this is
|
||||||
* quite unusual and often a sign for some problem in the input.
|
* quite unusual and often a sign for some problem in the input.
|
||||||
@@ -1096,13 +1089,9 @@ static unsigned ParseScalarInit (type* T)
|
|||||||
Warning ("Braces around scalar initializer");
|
Warning ("Braces around scalar initializer");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Expression */
|
/* Get the expression and convert it to the target type */
|
||||||
ConstExpr (&ED);
|
ConstExpr (&ED);
|
||||||
if ((ED.Flags & E_MCTYPE) == E_TCONST) {
|
TypeConversion (&ED, 0, T);
|
||||||
/* Make the const value the correct size */
|
|
||||||
ED.ConstVal &= Masks[Size-1];
|
|
||||||
}
|
|
||||||
assignadjust (T, &ED);
|
|
||||||
|
|
||||||
/* Output the data */
|
/* Output the data */
|
||||||
DefineData (&ED);
|
DefineData (&ED);
|
||||||
@@ -1111,7 +1100,7 @@ static unsigned ParseScalarInit (type* T)
|
|||||||
ClosingCurlyBraces (BraceCount);
|
ClosingCurlyBraces (BraceCount);
|
||||||
|
|
||||||
/* Done */
|
/* Done */
|
||||||
return Size;
|
return SizeOf (T);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1129,7 +1118,7 @@ static unsigned ParsePointerInit (type* T)
|
|||||||
/* Make the const value the correct size */
|
/* Make the const value the correct size */
|
||||||
ED.ConstVal &= 0xFFFF;
|
ED.ConstVal &= 0xFFFF;
|
||||||
}
|
}
|
||||||
assignadjust (T, &ED);
|
TypeConversion (&ED, 0, T);
|
||||||
|
|
||||||
/* Output the data */
|
/* Output the data */
|
||||||
DefineData (&ED);
|
DefineData (&ED);
|
||||||
@@ -1406,7 +1395,19 @@ static unsigned ParseInitInternal (type* T, int AllowFlexibleMembers)
|
|||||||
unsigned ParseInit (type* T)
|
unsigned ParseInit (type* T)
|
||||||
/* Parse initialization of variables. Return the number of data bytes. */
|
/* Parse initialization of variables. Return the number of data bytes. */
|
||||||
{
|
{
|
||||||
return ParseInitInternal (T, !ANSI);
|
/* Parse the initialization */
|
||||||
|
unsigned Size = ParseInitInternal (T, !ANSI);
|
||||||
|
|
||||||
|
/* The initialization may not generate code on global level, because code
|
||||||
|
* outside function scope will never get executed.
|
||||||
|
*/
|
||||||
|
if (HaveGlobalCode ()) {
|
||||||
|
Error ("Non constant initializers");
|
||||||
|
RemoveGlobalCode ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the size needed for the initialization */
|
||||||
|
return Size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
102
src/cc65/expr.c
102
src/cc65/expr.c
@@ -31,8 +31,8 @@
|
|||||||
#include "scanner.h"
|
#include "scanner.h"
|
||||||
#include "stdfunc.h"
|
#include "stdfunc.h"
|
||||||
#include "symtab.h"
|
#include "symtab.h"
|
||||||
#include "typecast.h"
|
|
||||||
#include "typecmp.h"
|
#include "typecmp.h"
|
||||||
|
#include "typeconv.h"
|
||||||
#include "expr.h"
|
#include "expr.h"
|
||||||
|
|
||||||
|
|
||||||
@@ -87,7 +87,7 @@ static GenDesc GenOASGN = { TOK_OR_ASSIGN, GEN_NOPUSH, g_or };
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static int hie0 (ExprDesc *lval);
|
int hie0 (ExprDesc *lval);
|
||||||
/* Parse comma operator. */
|
/* Parse comma operator. */
|
||||||
|
|
||||||
static int expr (int (*func) (ExprDesc*), ExprDesc *lval);
|
static int expr (int (*func) (ExprDesc*), ExprDesc *lval);
|
||||||
@@ -195,94 +195,6 @@ static unsigned typeadjust (ExprDesc* lhs, ExprDesc* rhs, int NoPush)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
unsigned assignadjust (type* lhst, ExprDesc* rhs)
|
|
||||||
/* Adjust the type of the right hand expression so that it can be assigned to
|
|
||||||
* the type on the left hand side. This function is used for assignment and
|
|
||||||
* for converting parameters in a function call. It returns the code generator
|
|
||||||
* flags for the operation. The type string of the right hand side will be
|
|
||||||
* set to the type of the left hand side.
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
/* Get the type of the right hand side. Treat function types as
|
|
||||||
* pointer-to-function
|
|
||||||
*/
|
|
||||||
type* rhst = rhs->Type;
|
|
||||||
if (IsTypeFunc (rhst)) {
|
|
||||||
rhst = PointerTo (rhst);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* After calling this function, rhs will have the type of the lhs */
|
|
||||||
rhs->Type = lhst;
|
|
||||||
|
|
||||||
/* First, do some type checking */
|
|
||||||
if (IsTypeVoid (lhst) || IsTypeVoid (rhst)) {
|
|
||||||
/* If one of the sides are of type void, output a more apropriate
|
|
||||||
* error message.
|
|
||||||
*/
|
|
||||||
Error ("Illegal type");
|
|
||||||
} else if (IsClassInt (lhst)) {
|
|
||||||
if (IsClassPtr (rhst)) {
|
|
||||||
/* Pointer -> int conversion */
|
|
||||||
Warning ("Converting pointer to integer without a cast");
|
|
||||||
} else if (IsClassInt (rhst)) {
|
|
||||||
/* Convert the rhs to the type of the lhs. */
|
|
||||||
unsigned flags = TypeOf (rhst);
|
|
||||||
if (rhs->Flags == E_MCONST) {
|
|
||||||
flags |= CF_CONST;
|
|
||||||
}
|
|
||||||
return g_typecast (TypeOf (lhst), flags);
|
|
||||||
} else {
|
|
||||||
Error ("Incompatible types");
|
|
||||||
}
|
|
||||||
} else if (IsClassPtr (lhst)) {
|
|
||||||
if (IsClassPtr (rhst)) {
|
|
||||||
/* 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 (lhst)) && !IsTypeVoid (Indirect (rhst))) {
|
|
||||||
/* Compare the types */
|
|
||||||
switch (TypeCmp (lhst, rhst)) {
|
|
||||||
|
|
||||||
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 (rhst)) {
|
|
||||||
/* Int to pointer assignment is valid only for constant zero */
|
|
||||||
if (rhs->Flags != E_MCONST || rhs->ConstVal != 0) {
|
|
||||||
Warning ("Converting integer to pointer without a cast");
|
|
||||||
}
|
|
||||||
} else if (IsTypeFuncPtr (lhst) && IsTypeFunc(rhst)) {
|
|
||||||
/* Assignment of function to function pointer is allowed, provided
|
|
||||||
* that both functions have the same parameter list.
|
|
||||||
*/
|
|
||||||
if (TypeCmp (Indirect (lhst), rhst) < TC_EQUAL) {
|
|
||||||
Error ("Incompatible types");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Error ("Incompatible types");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Error ("Incompatible types");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return an int value in all cases where the operands are not both ints */
|
|
||||||
return CF_INT;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void DefineData (ExprDesc* Expr)
|
void DefineData (ExprDesc* Expr)
|
||||||
/* Output a data definition for the given expression */
|
/* Output a data definition for the given expression */
|
||||||
{
|
{
|
||||||
@@ -655,8 +567,8 @@ static unsigned FunctionParamList (FuncDesc* Func)
|
|||||||
* convert the actual argument to the type needed.
|
* convert the actual argument to the type needed.
|
||||||
*/
|
*/
|
||||||
if (!Ellipsis) {
|
if (!Ellipsis) {
|
||||||
/* Promote the argument if needed */
|
/* Convert the argument to the parameter type if needed */
|
||||||
assignadjust (Param->Type, &lval);
|
TypeConversion (&lval, 0, Param->Type);
|
||||||
|
|
||||||
/* If we have a prototype, chars may be pushed as chars */
|
/* If we have a prototype, chars may be pushed as chars */
|
||||||
Flags |= CF_FORCECHAR;
|
Flags |= CF_FORCECHAR;
|
||||||
@@ -3022,12 +2934,10 @@ int hie1 (ExprDesc* lval)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static int hie0 (ExprDesc *lval)
|
int hie0 (ExprDesc *lval)
|
||||||
/* Parse comma operator. */
|
/* Parse comma operator. */
|
||||||
{
|
{
|
||||||
int k;
|
int k = hie1 (lval);
|
||||||
|
|
||||||
k = hie1 (lval);
|
|
||||||
while (CurTok.Tok == TOK_COMMA) {
|
while (CurTok.Tok == TOK_COMMA) {
|
||||||
NextToken ();
|
NextToken ();
|
||||||
k = hie1 (lval);
|
k = hie1 (lval);
|
||||||
|
@@ -42,13 +42,6 @@ void CheckBoolExpr (ExprDesc* lval);
|
|||||||
* if not.
|
* if not.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
unsigned assignadjust (type* lhst, ExprDesc* rhs);
|
|
||||||
/* Adjust the type of the right hand expression so that it can be assigned to
|
|
||||||
* the type on the left hand side. This function is used for assignment and
|
|
||||||
* for converting parameters in a function call. It returns the code generator
|
|
||||||
* flags for the operation.
|
|
||||||
*/
|
|
||||||
|
|
||||||
void exprhs (unsigned flags, int k, ExprDesc *lval);
|
void exprhs (unsigned flags, int k, ExprDesc *lval);
|
||||||
/* Put the result of an expression into the primary register */
|
/* Put the result of an expression into the primary register */
|
||||||
|
|
||||||
@@ -58,13 +51,8 @@ void Store (ExprDesc* lval, const type* StoreType);
|
|||||||
* is NULL, use lval->Type instead.
|
* is NULL, use lval->Type instead.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void expression1 (ExprDesc* lval);
|
int hie0 (ExprDesc *lval);
|
||||||
/* Evaluate an expression on level 1 (no comma operator) and put it into
|
/* Parse comma operator. */
|
||||||
* the primary register
|
|
||||||
*/
|
|
||||||
|
|
||||||
void expression (ExprDesc* lval);
|
|
||||||
/* Evaluate an expression and put it into the primary register */
|
|
||||||
|
|
||||||
int evalexpr (unsigned flags, int (*f) (ExprDesc*), ExprDesc* lval);
|
int evalexpr (unsigned flags, int (*f) (ExprDesc*), ExprDesc* lval);
|
||||||
/* Will evaluate an expression via the given function. If the result is a
|
/* Will evaluate an expression via the given function. If the result is a
|
||||||
@@ -73,6 +61,14 @@ int evalexpr (unsigned flags, int (*f) (ExprDesc*), ExprDesc* lval);
|
|||||||
* primary register and 1 is returned.
|
* primary register and 1 is returned.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
void expression1 (ExprDesc* lval);
|
||||||
|
/* Evaluate an expression on level 1 (no comma operator) and put it into
|
||||||
|
* the primary register
|
||||||
|
*/
|
||||||
|
|
||||||
|
void expression (ExprDesc* lval);
|
||||||
|
/* Evaluate an expression and put it into the primary register */
|
||||||
|
|
||||||
void ConstExpr (ExprDesc* lval);
|
void ConstExpr (ExprDesc* lval);
|
||||||
/* Get a constant value */
|
/* Get a constant value */
|
||||||
|
|
||||||
|
@@ -46,8 +46,9 @@
|
|||||||
#include "expr.h"
|
#include "expr.h"
|
||||||
#include "function.h"
|
#include "function.h"
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
#include "symtab.h"
|
|
||||||
#include "locals.h"
|
#include "locals.h"
|
||||||
|
#include "symtab.h"
|
||||||
|
#include "typeconv.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -62,7 +63,6 @@ static unsigned ParseRegisterDecl (Declaration* Decl, unsigned* SC, int Reg)
|
|||||||
* symbol data, which is the offset of the variable in the register bank.
|
* symbol data, which is the offset of the variable in the register bank.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
unsigned Flags;
|
|
||||||
unsigned InitLabel;
|
unsigned InitLabel;
|
||||||
|
|
||||||
/* Determine if this is a compound variable */
|
/* Determine if this is a compound variable */
|
||||||
@@ -95,8 +95,8 @@ static unsigned ParseRegisterDecl (Declaration* Decl, unsigned* SC, int Reg)
|
|||||||
|
|
||||||
/* Parse the initialization generating a memory image of the
|
/* Parse the initialization generating a memory image of the
|
||||||
* data in the RODATA segment. The function does return the size
|
* data in the RODATA segment. The function does return the size
|
||||||
* of the initialization data, which may be greater than the
|
* of the initialization data, which may be greater than the
|
||||||
* actual size of the type, if the type is a structure with a
|
* actual size of the type, if the type is a structure with a
|
||||||
* flexible array member that has been initialized. Since we must
|
* flexible array member that has been initialized. Since we must
|
||||||
* know the size of the data in advance for register variables,
|
* know the size of the data in advance for register variables,
|
||||||
* we cannot allow that here.
|
* we cannot allow that here.
|
||||||
@@ -110,27 +110,17 @@ static unsigned ParseRegisterDecl (Declaration* Decl, unsigned* SC, int Reg)
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
/* Setup the type flags for the assignment */
|
/* Parse the expression */
|
||||||
Flags = CF_NONE;
|
int k = hie1 (InitExprDesc (&lval));
|
||||||
if (Size == SIZEOF_CHAR) {
|
|
||||||
Flags |= CF_FORCECHAR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get the expression into the primary */
|
/* Convert it to the target type */
|
||||||
if (evalexpr (Flags, hie1, &lval) == 0) {
|
k = TypeConversion (&lval, k, Decl->Type);
|
||||||
/* Constant expression. Adjust the types */
|
|
||||||
assignadjust (Decl->Type, &lval);
|
/* Load the value into the primary */
|
||||||
Flags |= CF_CONST;
|
exprhs (CF_NONE, k, &lval);
|
||||||
/* Load it into the primary */
|
|
||||||
exprhs (Flags, 0, &lval);
|
|
||||||
} else {
|
|
||||||
/* Expression is not constant and in the primary */
|
|
||||||
assignadjust (Decl->Type, &lval);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Store the value into the variable */
|
/* Store the value into the variable */
|
||||||
Flags |= CF_REGVAR;
|
g_putstatic (CF_REGVAR | TypeOf (Decl->Type), Reg, 0);
|
||||||
g_putstatic (Flags | TypeOf (Decl->Type), Reg, 0);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -210,20 +200,28 @@ static unsigned ParseAutoDecl (Declaration* Decl, unsigned* SC)
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
int k;
|
||||||
|
|
||||||
/* Allocate previously reserved local space */
|
/* Allocate previously reserved local space */
|
||||||
F_AllocLocalSpace (CurrentFunc);
|
F_AllocLocalSpace (CurrentFunc);
|
||||||
|
|
||||||
/* Setup the type flags for the assignment */
|
/* Setup the type flags for the assignment */
|
||||||
Flags = (Size == SIZEOF_CHAR)? CF_FORCECHAR : CF_NONE;
|
Flags = (Size == SIZEOF_CHAR)? CF_FORCECHAR : CF_NONE;
|
||||||
|
|
||||||
/* Get the expression into the primary */
|
/* Parse the expression */
|
||||||
if (evalexpr (Flags, hie1, &lval) == 0) {
|
k = hie1 (InitExprDesc (&lval));
|
||||||
/* Constant expression. Adjust the types */
|
|
||||||
assignadjust (Decl->Type, &lval);
|
/* Convert it to the target type */
|
||||||
Flags |= CF_CONST;
|
k = TypeConversion (&lval, k, Decl->Type);
|
||||||
|
|
||||||
|
/* If the value is not const, load it into the primary.
|
||||||
|
* Otherwise pass the information to the code generator.
|
||||||
|
*/
|
||||||
|
if (k != 0 || lval.Flags != E_MCONST) {
|
||||||
|
exprhs (CF_NONE, k, &lval);
|
||||||
|
k = 0;
|
||||||
} else {
|
} else {
|
||||||
/* Expression is not constant and in the primary */
|
Flags |= CF_CONST;
|
||||||
assignadjust (Decl->Type, &lval);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Push the value */
|
/* Push the value */
|
||||||
@@ -286,24 +284,17 @@ static unsigned ParseAutoDecl (Declaration* Decl, unsigned* SC)
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
/* Setup the type flags for the assignment */
|
/* Parse the expression */
|
||||||
Flags = (Size == SIZEOF_CHAR)? CF_FORCECHAR : CF_NONE;
|
int k = hie1 (InitExprDesc (&lval));
|
||||||
|
|
||||||
/* Get the expression into the primary */
|
/* Convert it to the target type */
|
||||||
if (evalexpr (Flags, hie1, &lval) == 0) {
|
k = TypeConversion (&lval, k, Decl->Type);
|
||||||
/* Constant expression. Adjust the types */
|
|
||||||
assignadjust (Decl->Type, &lval);
|
/* Load the value into the primary */
|
||||||
Flags |= CF_CONST;
|
exprhs (CF_NONE, k, &lval);
|
||||||
/* Load it into the primary */
|
|
||||||
exprhs (Flags, 0, &lval);
|
|
||||||
} else {
|
|
||||||
/* Expression is not constant and in the primary */
|
|
||||||
assignadjust (Decl->Type, &lval);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Store the value into the variable */
|
/* Store the value into the variable */
|
||||||
g_putstatic (Flags | TypeOf (Decl->Type), SymData, 0);
|
g_putstatic (TypeOf (Decl->Type), SymData, 0);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mark the variable as referenced */
|
/* Mark the variable as referenced */
|
||||||
|
@@ -82,8 +82,8 @@ OBJS = anonname.o \
|
|||||||
symentry.o \
|
symentry.o \
|
||||||
symtab.o \
|
symtab.o \
|
||||||
textseg.o \
|
textseg.o \
|
||||||
typecast.o \
|
|
||||||
typecmp.o \
|
typecmp.o \
|
||||||
|
typeconv.o \
|
||||||
util.o
|
util.o
|
||||||
|
|
||||||
LIBS = $(COMMON)/common.a
|
LIBS = $(COMMON)/common.a
|
||||||
|
@@ -103,8 +103,8 @@ OBJS = anonname.obj \
|
|||||||
symentry.obj \
|
symentry.obj \
|
||||||
symtab.obj \
|
symtab.obj \
|
||||||
textseg.obj \
|
textseg.obj \
|
||||||
typecast.obj \
|
|
||||||
typecmp.obj \
|
typecmp.obj \
|
||||||
|
typeconv.obj \
|
||||||
util.obj
|
util.obj
|
||||||
|
|
||||||
LIBS = ..\common\common.lib
|
LIBS = ..\common\common.lib
|
||||||
|
@@ -224,6 +224,22 @@ void AddDataLine (const char* Format, ...)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int HaveGlobalCode (void)
|
||||||
|
/* Return true if the global code segment contains entries (which is an error) */
|
||||||
|
{
|
||||||
|
return (CS_GetEntryCount (GS->Code) > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void RemoveGlobalCode (void)
|
||||||
|
/* Remove all code from the global code segment. Used for error recovery. */
|
||||||
|
{
|
||||||
|
CS_DelEntries (GS->Code, 0, CS_GetEntryCount (GS->Code));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void OutputSegments (const Segments* S, FILE* F)
|
void OutputSegments (const Segments* S, FILE* F)
|
||||||
/* Output the given segments to the file */
|
/* Output the given segments to the file */
|
||||||
{
|
{
|
||||||
|
@@ -132,6 +132,12 @@ void AddCode (opc_t OPC, am_t AM, const char* Arg, struct CodeLabel* JumpTo);
|
|||||||
void AddDataLine (const char* Format, ...) attribute ((format (printf, 1, 2)));
|
void AddDataLine (const char* Format, ...) attribute ((format (printf, 1, 2)));
|
||||||
/* Add a line of data to the current data segment */
|
/* Add a line of data to the current data segment */
|
||||||
|
|
||||||
|
int HaveGlobalCode (void);
|
||||||
|
/* Return true if the global code segment contains entries (which is an error) */
|
||||||
|
|
||||||
|
void RemoveGlobalCode (void);
|
||||||
|
/* Remove all code from the global code segment. Used for error recovery. */
|
||||||
|
|
||||||
void OutputSegments (const Segments* S, FILE* F);
|
void OutputSegments (const Segments* S, FILE* F);
|
||||||
/* Output the given segments to the file */
|
/* Output the given segments to the file */
|
||||||
|
|
||||||
|
@@ -48,6 +48,7 @@
|
|||||||
#include "litpool.h"
|
#include "litpool.h"
|
||||||
#include "scanner.h"
|
#include "scanner.h"
|
||||||
#include "stdfunc.h"
|
#include "stdfunc.h"
|
||||||
|
#include "typeconv.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -106,35 +107,36 @@ static struct StdFuncDesc* FindFunc (const char* Name)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static unsigned ParseArg (type* Type, ExprDesc* pval)
|
static unsigned ParseArg (type* Type, ExprDesc* Arg)
|
||||||
/* Parse one argument but do not push it onto the stack. Return the code
|
/* Parse one argument but do not push it onto the stack. Return the code
|
||||||
* generator flags needed to do the actual push.
|
* generator flags needed to do the actual push.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
unsigned CFlags;
|
|
||||||
unsigned Flags;
|
|
||||||
|
|
||||||
/* Do some optimization: If we have a constant value to push,
|
|
||||||
* use a special function that may optimize.
|
|
||||||
*/
|
|
||||||
CFlags = CF_NONE;
|
|
||||||
if (CheckedSizeOf (Type) == 1) {
|
|
||||||
CFlags = CF_FORCECHAR;
|
|
||||||
}
|
|
||||||
Flags = CF_NONE;
|
|
||||||
if (evalexpr (CFlags, hie1, pval) == 0) {
|
|
||||||
/* A constant value */
|
|
||||||
Flags |= CF_CONST;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Promote the argument if needed */
|
|
||||||
assignadjust (Type, pval);
|
|
||||||
|
|
||||||
/* We have a prototype, so chars may be pushed as chars */
|
/* We have a prototype, so chars may be pushed as chars */
|
||||||
Flags |= CF_FORCECHAR;
|
unsigned Flags = CF_FORCECHAR;
|
||||||
|
|
||||||
|
/* Read the expression we're going to pass to the function */
|
||||||
|
int k = hie1 (InitExprDesc (Arg));
|
||||||
|
|
||||||
|
/* Convert this expression to the expected type */
|
||||||
|
k = TypeConversion (Arg, k, Type);
|
||||||
|
|
||||||
|
/* If the value is not a constant, load it into the primary */
|
||||||
|
if (k != 0 || Arg->Flags != E_MCONST) {
|
||||||
|
|
||||||
|
/* Load into the primary */
|
||||||
|
exprhs (CF_NONE, k, Arg);
|
||||||
|
k = 0;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/* Remember that we have a constant value */
|
||||||
|
Flags |= CF_CONST;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/* Use the type of the argument for the push */
|
/* Use the type of the argument for the push */
|
||||||
return (Flags | TypeOf (pval->Type));
|
return (Flags | TypeOf (Arg->Type));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -208,20 +210,17 @@ static void StdFunc_strlen (FuncDesc* F attribute ((unused)),
|
|||||||
ExprDesc* lval attribute ((unused)))
|
ExprDesc* lval attribute ((unused)))
|
||||||
/* Handle the strlen function */
|
/* Handle the strlen function */
|
||||||
{
|
{
|
||||||
static type ParamType[] = { T_PTR, T_SCHAR, T_END };
|
static type ParamType[] = { T_PTR, T_SCHAR, T_END };
|
||||||
|
int k;
|
||||||
ExprDesc Param;
|
ExprDesc Param;
|
||||||
unsigned CodeFlags;
|
unsigned CodeFlags;
|
||||||
unsigned long ParamName;
|
unsigned long ParamName;
|
||||||
|
|
||||||
/* Fetch the parameter */
|
|
||||||
int k = hie1 (InitExprDesc (&Param));
|
|
||||||
|
|
||||||
/* Setup the argument type string */
|
/* Setup the argument type string */
|
||||||
ParamType[1] = GetDefaultChar () | T_QUAL_CONST;
|
ParamType[1] = GetDefaultChar () | T_QUAL_CONST;
|
||||||
|
|
||||||
/* Convert the parameter type to the type needed, check for mismatches */
|
/* Fetch the parameter and convert it to the type needed */
|
||||||
assignadjust (ParamType, &Param);
|
k = TypeConversion (&Param, hie1 (InitExprDesc (&Param)), ParamType);
|
||||||
|
|
||||||
/* Check if the parameter is a constant array of some type, or a numeric
|
/* Check if the parameter is a constant array of some type, or a numeric
|
||||||
* address cast to a pointer.
|
* address cast to a pointer.
|
||||||
|
@@ -58,6 +58,7 @@
|
|||||||
#include "swstmt.h"
|
#include "swstmt.h"
|
||||||
#include "symtab.h"
|
#include "symtab.h"
|
||||||
#include "stmt.h"
|
#include "stmt.h"
|
||||||
|
#include "typeconv.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -89,13 +90,13 @@ static void CheckSemi (int* PendingToken)
|
|||||||
* error message if not found (plus some error recovery). If PendingToken is
|
* error message if not found (plus some error recovery). If PendingToken is
|
||||||
* NULL, it will the skip the token, otherwise it will store one to
|
* NULL, it will the skip the token, otherwise it will store one to
|
||||||
* PendingToken.
|
* PendingToken.
|
||||||
* This function is a special version of CheckTok with the addition of the
|
* This function is a special version of CheckTok with the addition of the
|
||||||
* error recovery.
|
* error recovery.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
int HaveToken = (CurTok.Tok == TOK_SEMI);
|
int HaveToken = (CurTok.Tok == TOK_SEMI);
|
||||||
if (!HaveToken) {
|
if (!HaveToken) {
|
||||||
Error ("`;' expected");
|
Error ("`;' expected");
|
||||||
/* Try to be smart about errors */
|
/* Try to be smart about errors */
|
||||||
if (CurTok.Tok == TOK_COLON || CurTok.Tok == TOK_COMMA) {
|
if (CurTok.Tok == TOK_COLON || CurTok.Tok == TOK_COMMA) {
|
||||||
HaveToken = 1;
|
HaveToken = 1;
|
||||||
@@ -256,7 +257,8 @@ static void WhileStatement (void)
|
|||||||
static void ReturnStatement (void)
|
static void ReturnStatement (void)
|
||||||
/* Handle the 'return' statement */
|
/* Handle the 'return' statement */
|
||||||
{
|
{
|
||||||
ExprDesc lval;
|
ExprDesc Expr;
|
||||||
|
int k;
|
||||||
|
|
||||||
NextToken ();
|
NextToken ();
|
||||||
if (CurTok.Tok != TOK_SEMI) {
|
if (CurTok.Tok != TOK_SEMI) {
|
||||||
@@ -266,12 +268,17 @@ static void ReturnStatement (void)
|
|||||||
Error ("Returning a value in function with return type void");
|
Error ("Returning a value in function with return type void");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Evaluate the return expression. Result will be in primary */
|
/* Evaluate the return expression */
|
||||||
expression (&lval);
|
k = hie0 (InitExprDesc (&Expr));
|
||||||
|
|
||||||
/* Convert the return value to the type of the function result */
|
/* Ignore the return expression if the function returns void */
|
||||||
if (!F_HasVoidReturn (CurrentFunc)) {
|
if (!F_HasVoidReturn (CurrentFunc)) {
|
||||||
assignadjust (F_GetReturnType (CurrentFunc), &lval);
|
|
||||||
|
/* Convert the return value to the type of the function result */
|
||||||
|
TypeConversion (&Expr, k, F_GetReturnType (CurrentFunc));
|
||||||
|
|
||||||
|
/* Load the value into the primary */
|
||||||
|
exprhs (CF_NONE, k, &Expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (!F_HasVoidReturn (CurrentFunc) && !F_HasOldStyleIntRet (CurrentFunc)) {
|
} else if (!F_HasVoidReturn (CurrentFunc) && !F_HasOldStyleIntRet (CurrentFunc)) {
|
||||||
|
@@ -1,213 +0,0 @@
|
|||||||
/*****************************************************************************/
|
|
||||||
/* */
|
|
||||||
/* typecast.c */
|
|
||||||
/* */
|
|
||||||
/* Handle type casts */
|
|
||||||
/* */
|
|
||||||
/* */
|
|
||||||
/* */
|
|
||||||
/* (C) 2002 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. */
|
|
||||||
/* */
|
|
||||||
/*****************************************************************************/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* cc65 */
|
|
||||||
#include "codegen.h"
|
|
||||||
#include "datatype.h"
|
|
||||||
#include "declare.h"
|
|
||||||
#include "error.h"
|
|
||||||
#include "expr.h"
|
|
||||||
#include "scanner.h"
|
|
||||||
#include "typecast.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
|
||||||
/* Code */
|
|
||||||
/*****************************************************************************/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int TypeCast (ExprDesc* lval)
|
|
||||||
/* Handle an explicit cast. The function returns true if the resulting
|
|
||||||
* expression is an lvalue and false if not.
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
int k;
|
|
||||||
type* OldType;
|
|
||||||
type NewType[MAXTYPELEN];
|
|
||||||
unsigned OldSize;
|
|
||||||
unsigned NewSize;
|
|
||||||
|
|
||||||
/* Skip the left paren */
|
|
||||||
NextToken ();
|
|
||||||
|
|
||||||
/* Read the type */
|
|
||||||
ParseType (NewType);
|
|
||||||
|
|
||||||
/* Closing paren */
|
|
||||||
ConsumeRParen ();
|
|
||||||
|
|
||||||
/* Read the expression we have to cast */
|
|
||||||
k = hie10 (lval);
|
|
||||||
|
|
||||||
/* If the expression is a function, treat it as pointer to function.
|
|
||||||
* If the expression is an array, treat it as pointer to first element.
|
|
||||||
*/
|
|
||||||
if (IsTypeFunc (lval->Type)) {
|
|
||||||
lval->Type = PointerTo (lval->Type);
|
|
||||||
} else if (IsTypeArray (lval->Type)) {
|
|
||||||
lval->Type = ArrayToPtr (lval->Type);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Remember the old type */
|
|
||||||
OldType = lval->Type;
|
|
||||||
|
|
||||||
/* If we're casting to void, we're done. Note: This does also cover a cast
|
|
||||||
* 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 cast 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);
|
|
||||||
|
|
||||||
/* Is this a cast of something into an integer? */
|
|
||||||
if (IsClassInt (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 */
|
|
||||||
exprhs (CF_NONE, k, lval);
|
|
||||||
|
|
||||||
/* Emit typecast code */
|
|
||||||
g_typecast (TypeOf (OldType), TypeOf (NewType));
|
|
||||||
|
|
||||||
/* Value is now in primary */
|
|
||||||
lval->Flags = E_MEXPR;
|
|
||||||
k = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
/* We have an rvalue. Check for a constant. */
|
|
||||||
if (lval->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 */
|
|
||||||
lval->ConstVal &= (0xFFFFFFFFUL >> (32 - NewBits));
|
|
||||||
|
|
||||||
/* If the new type is signed, sign extend the value */
|
|
||||||
if (!IsSignUnsigned (NewType)) {
|
|
||||||
if (lval->ConstVal & (0x01UL << (NewBits-1))) {
|
|
||||||
lval->ConstVal |= ((~0L) << NewBits);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} 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 */
|
|
||||||
exprhs (CF_NONE, k, lval);
|
|
||||||
|
|
||||||
/* Emit typecast code. */
|
|
||||||
g_typecast (TypeOf (OldType), TypeOf (NewType) | CF_FORCECHAR);
|
|
||||||
|
|
||||||
/* Value is now in primary */
|
|
||||||
lval->Flags = E_MEXPR;
|
|
||||||
k = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
/* All other stuff is handled equally */
|
|
||||||
if (NewSize != OldSize) {
|
|
||||||
/* Load the value into the primary */
|
|
||||||
exprhs (CF_NONE, k, lval);
|
|
||||||
|
|
||||||
/* Emit typecast code */
|
|
||||||
g_typecast (TypeOf (OldType), TypeOf (NewType) | CF_FORCECHAR);
|
|
||||||
|
|
||||||
/* Value is now in primary */
|
|
||||||
lval->Flags = E_MEXPR;
|
|
||||||
k = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ExitPoint:
|
|
||||||
/* The expression has always the new type */
|
|
||||||
ReplaceType (lval, NewType);
|
|
||||||
|
|
||||||
/* Done */
|
|
||||||
return k;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
300
src/cc65/typeconv.c
Normal file
300
src/cc65/typeconv.c
Normal file
@@ -0,0 +1,300 @@
|
|||||||
|
/*****************************************************************************/
|
||||||
|
/* */
|
||||||
|
/* 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. */
|
||||||
|
/* */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* 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 */
|
||||||
|
exprhs (CF_NONE, k, Expr);
|
||||||
|
|
||||||
|
/* Emit typecast code */
|
||||||
|
g_typecast (TypeOf (OldType), TypeOf (NewType));
|
||||||
|
|
||||||
|
/* 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))) {
|
||||||
|
Expr->ConstVal |= ((~0L) << NewBits);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} 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 */
|
||||||
|
exprhs (CF_NONE, k, Expr);
|
||||||
|
|
||||||
|
/* Emit typecast code. */
|
||||||
|
g_typecast (TypeOf (OldType), TypeOf (NewType) | CF_FORCECHAR);
|
||||||
|
|
||||||
|
/* 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");
|
||||||
|
} else {
|
||||||
|
/* Convert the rhs to the type of the lhs. */
|
||||||
|
k = DoConversion (Expr, k, NewType);
|
||||||
|
}
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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");
|
||||||
|
return k;
|
||||||
|
|
||||||
|
case TC_QUAL_DIFF:
|
||||||
|
Error ("Pointer types differ in type qualifiers");
|
||||||
|
return k;
|
||||||
|
|
||||||
|
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");
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Error ("Incompatible types");
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we come here, the conversion is ok, convert and return the result */
|
||||||
|
return DoConversion (Expr, k, NewType);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Invalid automatic conversion */
|
||||||
|
Error ("Incompatible types");
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@@ -1,14 +1,14 @@
|
|||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* */
|
/* */
|
||||||
/* typecast.h */
|
/* typeconv.h */
|
||||||
/* */
|
/* */
|
||||||
/* Handle type casts */
|
/* Handle type conversions */
|
||||||
/* */
|
/* */
|
||||||
/* */
|
/* */
|
||||||
/* */
|
/* */
|
||||||
/* (C) 2002 Ullrich von Bassewitz */
|
/* (C) 2002-2003 Ullrich von Bassewitz */
|
||||||
/* Wacholderweg 14 */
|
/* Römerstrasse 52 */
|
||||||
/* D-70597 Stuttgart */
|
/* D-70794 Filderstadt */
|
||||||
/* EMail: uz@cc65.org */
|
/* EMail: uz@cc65.org */
|
||||||
/* */
|
/* */
|
||||||
/* */
|
/* */
|
||||||
@@ -33,11 +33,11 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef TYPECAST_H
|
#ifndef TYPECONV_H
|
||||||
#define TYPECAST_H
|
#define TYPECONV_H
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* cc65 */
|
/* cc65 */
|
||||||
#include "exprdesc.h"
|
#include "exprdesc.h"
|
||||||
|
|
||||||
@@ -49,14 +49,20 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
int TypeCast (ExprDesc* lval);
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int TypeCast (ExprDesc* Expr);
|
||||||
/* Handle an explicit cast. The function returns true if the resulting
|
/* Handle an explicit cast. The function returns true if the resulting
|
||||||
* expression is an lvalue and false if not.
|
* expression is an lvalue and false if not.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* End of typecast.h */
|
/* End of typeconv.h */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
Reference in New Issue
Block a user