From 5548b6fd56c8dc5a203804ce63db9649aab37abb Mon Sep 17 00:00:00 2001 From: cuz Date: Fri, 1 Nov 2002 15:16:16 +0000 Subject: [PATCH] Work on better type casts - not yet finished git-svn-id: svn://svn.cc65.org/cc65/trunk@1476 b7a2c559-68d2-44c3-8de9-860c34a00d81 --- src/cc65/expr.c | 117 +++------------------ src/cc65/expr.h | 3 + src/cc65/make/gcc.mak | 1 + src/cc65/make/watcom.mak | 2 + src/cc65/typecast.c | 212 +++++++++++++++++++++++++++++++++++++++ src/cc65/typecast.h | 58 +++++++++++ 6 files changed, 288 insertions(+), 105 deletions(-) create mode 100644 src/cc65/typecast.c create mode 100644 src/cc65/typecast.h diff --git a/src/cc65/expr.c b/src/cc65/expr.c index b43f748bf..3142ad93b 100644 --- a/src/cc65/expr.c +++ b/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); } } diff --git a/src/cc65/expr.h b/src/cc65/expr.h index fabd91b40..7933a7f4d 100644 --- a/src/cc65/expr.h +++ b/src/cc65/expr.h @@ -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. */ diff --git a/src/cc65/make/gcc.mak b/src/cc65/make/gcc.mak index 7446bb8d0..62a9e36cf 100644 --- a/src/cc65/make/gcc.mak +++ b/src/cc65/make/gcc.mak @@ -81,6 +81,7 @@ OBJS = anonname.o \ symentry.o \ symtab.o \ textseg.o \ + typecast.o \ typecmp.o \ util.o diff --git a/src/cc65/make/watcom.mak b/src/cc65/make/watcom.mak index b55980c18..af17be50a 100644 --- a/src/cc65/make/watcom.mak +++ b/src/cc65/make/watcom.mak @@ -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 diff --git a/src/cc65/typecast.c b/src/cc65/typecast.c new file mode 100644 index 000000000..ec1111a80 --- /dev/null +++ b/src/cc65/typecast.c @@ -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; +} + + + + + + diff --git a/src/cc65/typecast.h b/src/cc65/typecast.h new file mode 100644 index 000000000..b6086d6b4 --- /dev/null +++ b/src/cc65/typecast.h @@ -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 + + + -- 2.39.5