Work on better type casts - not yet finished
git-svn-id: svn://svn.cc65.org/cc65/trunk@1476 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
parent
571ea849d9
commit
5548b6fd56
6 changed files with 288 additions and 105 deletions
117
src/cc65/expr.c
117
src/cc65/expr.c
|
@ -31,6 +31,7 @@
|
|||
#include "scanner.h"
|
||||
#include "stdfunc.h"
|
||||
#include "symtab.h"
|
||||
#include "typecast.h"
|
||||
#include "typecmp.h"
|
||||
#include "expr.h"
|
||||
|
||||
|
@ -86,9 +87,6 @@ static GenDesc GenOASGN = { TOK_OR_ASSIGN, GEN_NOPUSH, g_or };
|
|||
|
||||
|
||||
|
||||
static int hie10 (ExprDesc* lval);
|
||||
/* Handle ++, --, !, unary - etc. */
|
||||
|
||||
static int expr (int (*func) (ExprDesc*), ExprDesc *lval);
|
||||
/* Expression parser; func is either hie0 or hie1. */
|
||||
|
||||
|
@ -501,7 +499,7 @@ void exprhs (unsigned flags, int k, ExprDesc *lval)
|
|||
f = lval->Flags;
|
||||
if (k) {
|
||||
/* Dereferenced lvalue */
|
||||
flags |= TypeOf (lval->Type);
|
||||
flags |= TypeOf (lval->Type);
|
||||
if (lval->Test & E_FORCETEST) {
|
||||
flags |= CF_TEST;
|
||||
lval->Test &= ~E_FORCETEST;
|
||||
|
@ -529,10 +527,11 @@ void exprhs (unsigned flags, int k, ExprDesc *lval)
|
|||
/* Constant of some sort, load it into the primary */
|
||||
lconst (flags, lval);
|
||||
}
|
||||
if (lval->Test & E_FORCETEST) { /* we testing this value? */
|
||||
/* debug... */
|
||||
/* Are we testing this value? */
|
||||
if (lval->Test & E_FORCETEST) {
|
||||
/* Yes, force a test */
|
||||
flags |= TypeOf (lval->Type);
|
||||
g_test (flags); /* yes, force a test */
|
||||
g_test (flags);
|
||||
lval->Test &= ~E_FORCETEST;
|
||||
}
|
||||
}
|
||||
|
@ -1234,7 +1233,7 @@ static int arrayref (int k, ExprDesc* lval)
|
|||
/* Constant numeric address. Just add it */
|
||||
g_inc (CF_INT | CF_UNSIGNED, lval->ConstVal);
|
||||
} else if (lflags == E_MLOCAL) {
|
||||
/* Base address is a local variable address */
|
||||
/* Base address is a local variable address */
|
||||
if (IsTypeArray (tptr1)) {
|
||||
g_addaddr_local (CF_INT, lval->ConstVal);
|
||||
} else {
|
||||
|
@ -1291,8 +1290,8 @@ static int structref (int k, ExprDesc* lval)
|
|||
flags = lval->Flags & ~E_MCTYPE;
|
||||
if (flags == E_MCONST ||
|
||||
(k == 0 && (flags == E_MLOCAL ||
|
||||
(flags & E_MGLOBAL) != 0 ||
|
||||
lval->Flags == E_MEOFFS))) {
|
||||
(flags & E_MGLOBAL) != 0 ||
|
||||
lval->Flags == E_MEOFFS))) {
|
||||
lval->ConstVal += Field->V.Offs;
|
||||
} else {
|
||||
if ((flags & E_MEXPR) == 0 || k != 0) {
|
||||
|
@ -1490,7 +1489,7 @@ static void pre_incdec (ExprDesc* lval, void (*inc) (unsigned, unsigned long))
|
|||
|
||||
|
||||
|
||||
static void post_incdec (ExprDesc *lval, int k, void (*inc) (unsigned, unsigned long))
|
||||
static void post_incdec (ExprDesc* lval, int k, void (*inc) (unsigned, unsigned long))
|
||||
/* Handle i-- and i++ */
|
||||
{
|
||||
unsigned flags;
|
||||
|
@ -1564,99 +1563,7 @@ static void unaryop (int tok, ExprDesc* lval)
|
|||
|
||||
|
||||
|
||||
static int typecast (ExprDesc* lval)
|
||||
/* Handle an explicit cast */
|
||||
{
|
||||
int k;
|
||||
type Type[MAXTYPELEN];
|
||||
|
||||
/* Skip the left paren */
|
||||
NextToken ();
|
||||
|
||||
/* Read the type */
|
||||
ParseType (Type);
|
||||
|
||||
/* 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 (IsTypeFunc (lval->Type)) {
|
||||
lval->Type = PointerTo (lval->Type);
|
||||
}
|
||||
|
||||
/* Check for a constant on the right side */
|
||||
if (k == 0 && lval->Flags == E_MCONST) {
|
||||
|
||||
/* A cast of a constant to something else. If the new type is an int,
|
||||
* be sure to handle the size extension correctly. If the new type is
|
||||
* not an int, the cast is implementation specific anyway, so leave
|
||||
* the value alone.
|
||||
*/
|
||||
if (IsClassInt (Type)) {
|
||||
|
||||
/* Get the current and new size of the value */
|
||||
unsigned OldBits = CheckedSizeOf (lval->Type) * 8;
|
||||
unsigned NewBits = CheckedSizeOf (Type) * 8;
|
||||
|
||||
/* Check if the new datatype will have a smaller range */
|
||||
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 (Type)) {
|
||||
lval->ConstVal |= ((~0L) << NewBits);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/* Sign extend the value if needed */
|
||||
if (!IsSignUnsigned (lval->Type) && !IsSignUnsigned (Type)) {
|
||||
if (lval->ConstVal & (0x01UL << (OldBits-1))) {
|
||||
lval->ConstVal |= ((~0L) << OldBits);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/* Not a constant. Be sure to ignore casts to void */
|
||||
if (!IsTypeVoid (Type)) {
|
||||
|
||||
/* If the size does not change, leave the value alone. Otherwise,
|
||||
* we have to load the value into the primary and generate code to
|
||||
* cast the value in the primary register.
|
||||
*/
|
||||
if (SizeOf (Type) != SizeOf (lval->Type)) {
|
||||
|
||||
/* Load the value into the primary */
|
||||
exprhs (CF_NONE, k, lval);
|
||||
|
||||
/* Emit typecast code */
|
||||
g_typecast (TypeOf (Type), TypeOf (lval->Type));
|
||||
|
||||
/* Value is now in primary */
|
||||
lval->Flags = E_MEXPR;
|
||||
k = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* In any case, use the new type */
|
||||
lval->Type = TypeDup (Type);
|
||||
|
||||
/* Done */
|
||||
return k;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int hie10 (ExprDesc* lval)
|
||||
int hie10 (ExprDesc* lval)
|
||||
/* Handle ++, --, !, unary - etc. */
|
||||
{
|
||||
int k;
|
||||
|
@ -1747,7 +1654,7 @@ static int hie10 (ExprDesc* lval)
|
|||
default:
|
||||
if (istypeexpr ()) {
|
||||
/* A cast */
|
||||
return typecast (lval);
|
||||
return TypeCast (lval);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -107,6 +107,9 @@ void boolexpr (ExprDesc* lval);
|
|||
void test (unsigned label, int cond);
|
||||
/* Generate code to perform test and jump if false. */
|
||||
|
||||
int hie10 (ExprDesc* lval);
|
||||
/* Handle ++, --, !, unary - etc. */
|
||||
|
||||
int hie1 (ExprDesc* lval);
|
||||
/* Parse first level of expression hierarchy. */
|
||||
|
||||
|
|
|
@ -81,6 +81,7 @@ OBJS = anonname.o \
|
|||
symentry.o \
|
||||
symtab.o \
|
||||
textseg.o \
|
||||
typecast.o \
|
||||
typecmp.o \
|
||||
util.o
|
||||
|
||||
|
|
|
@ -126,6 +126,7 @@ OBJS = anonname.obj \
|
|||
symentry.obj \
|
||||
symtab.obj \
|
||||
textseg.obj \
|
||||
typecast.obj \
|
||||
typecmp.obj \
|
||||
util.obj
|
||||
|
||||
|
@ -209,6 +210,7 @@ FILE swstmt.obj
|
|||
FILE symentry.obj
|
||||
FILE symtab.obj
|
||||
FILE textseg.obj
|
||||
FILE typecast.obj
|
||||
FILE typecmp.obj
|
||||
FILE util.obj
|
||||
LIBRARY ..\common\common.lib
|
||||
|
|
212
src/cc65/typecast.c
Normal file
212
src/cc65/typecast.c
Normal file
|
@ -0,0 +1,212 @@
|
|||
/*****************************************************************************/
|
||||
/* */
|
||||
/* typecast.c */
|
||||
/* */
|
||||
/* Handle type casts */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 2002 Ullrich von Bassewitz */
|
||||
/* Wacholderweg 14 */
|
||||
/* D-70597 Stuttgart */
|
||||
/* 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 (IsTypeFunc (lval->Type)) {
|
||||
lval->Type = PointerTo (lval->Type);
|
||||
}
|
||||
|
||||
/* Remember the old type and use the new one */
|
||||
OldType = lval->Type;
|
||||
lval->Type = TypeDup (NewType);
|
||||
|
||||
/* If we're casting to void, we're done. Note: This does also cover a cast
|
||||
* void -> void.
|
||||
*/
|
||||
if (IsTypeVoid (NewType)) {
|
||||
return 0; /* Never an lvalue */
|
||||
}
|
||||
|
||||
/* Don't allow casts from void to something else. The new type is already
|
||||
* set which should avoid more errors, but code will not get generated
|
||||
* because of the error.
|
||||
*/
|
||||
if (IsTypeVoid (OldType)) {
|
||||
Error ("Cannot cast from `void' to something else");
|
||||
return k;
|
||||
}
|
||||
|
||||
/* 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 (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)) {
|
||||
lval->ConstVal |= ((~0L) << NewBits);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/* Sign extend the value if needed */
|
||||
if (!IsSignUnsigned (OldType) && !IsSignUnsigned (NewType)) {
|
||||
if (lval->ConstVal & (0x01UL << (OldBits-1))) {
|
||||
lval->ConstVal |= ((~0L) << OldBits);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} 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. ### CHARS */
|
||||
g_typecast (TypeOf (OldType), TypeOf (NewType));
|
||||
|
||||
/* 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));
|
||||
|
||||
/* Value is now in primary */
|
||||
lval->Flags = E_MEXPR;
|
||||
k = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Done */
|
||||
return k;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
58
src/cc65/typecast.h
Normal file
58
src/cc65/typecast.h
Normal file
|
@ -0,0 +1,58 @@
|
|||
/*****************************************************************************/
|
||||
/* */
|
||||
/* typecast.h */
|
||||
/* */
|
||||
/* Handle type casts */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 2002 Ullrich von Bassewitz */
|
||||
/* Wacholderweg 14 */
|
||||
/* D-70597 Stuttgart */
|
||||
/* 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. */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
#ifndef TYPECAST_H
|
||||
#define 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.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* End of typecast.h */
|
||||
#endif
|
||||
|
||||
|
||||
|
Loading…
Add table
Reference in a new issue