From 81f94afd5ca9e84124d4743d1c631c028e6be754 Mon Sep 17 00:00:00 2001 From: cuz Date: Mon, 11 Aug 2003 20:18:30 +0000 Subject: [PATCH] Rewrote type conversions git-svn-id: svn://svn.cc65.org/cc65/trunk@2262 b7a2c559-68d2-44c3-8de9-860c34a00d81 --- src/cc65/asmcode.c | 2 +- src/cc65/assignment.c | 36 ++-- src/cc65/assignment.h | 8 +- src/cc65/declare.c | 39 ++-- src/cc65/expr.c | 102 +--------- src/cc65/expr.h | 24 +-- src/cc65/locals.c | 79 ++++---- src/cc65/make/gcc.mak | 2 +- src/cc65/make/watcom.mak | 2 +- src/cc65/segments.c | 16 ++ src/cc65/segments.h | 6 + src/cc65/stdfunc.c | 61 +++--- src/cc65/stmt.c | 21 +- src/cc65/typecast.c | 213 -------------------- src/cc65/typeconv.c | 300 ++++++++++++++++++++++++++++ src/cc65/{typecast.h => typeconv.h} | 26 ++- 16 files changed, 478 insertions(+), 459 deletions(-) delete mode 100644 src/cc65/typecast.c create mode 100644 src/cc65/typeconv.c rename src/cc65/{typecast.h => typeconv.h} (80%) diff --git a/src/cc65/asmcode.c b/src/cc65/asmcode.c index 788dd5bec..776e36f67 100644 --- a/src/cc65/asmcode.c +++ b/src/cc65/asmcode.c @@ -85,7 +85,7 @@ void WriteOutput (FILE* F) SymEntry* Entry; /* Output the global data segment */ - CHECK (CS_GetEntryCount (CS->Code) == 0); + CHECK (!HaveGlobalCode ()); OutputSegments (CS, F); /* Output all global or referenced functions */ diff --git a/src/cc65/assignment.c b/src/cc65/assignment.c index 3427468ea..a6f00ac13 100644 --- a/src/cc65/assignment.c +++ b/src/cc65/assignment.c @@ -6,9 +6,9 @@ /* */ /* */ /* */ -/* (C) 2002 Ullrich von Bassewitz */ -/* Wacholderweg 14 */ -/* D-70597 Stuttgart */ +/* (C) 2002-2003 Ullrich von Bassewitz */ +/* Römerstrasse 52 */ +/* D-70794 Filderstadt */ /* EMail: uz@cc65.org */ /* */ /* */ @@ -39,6 +39,7 @@ #include "error.h" #include "expr.h" #include "typecmp.h" +#include "typeconv.h" #include "assignment.h" @@ -49,7 +50,7 @@ -void Assignment (ExprDesc* lval) +int Assignment (ExprDesc* lval) /* Parse an assignment */ { int k; @@ -86,7 +87,7 @@ void Assignment (ExprDesc* lval) if (UseReg) { PushAddr (lval); } else { - exprhs (0, 0, lval); + exprhs (0, 0, lval); g_push (CF_PTR | CF_UNSIGNED, 0); } @@ -147,27 +148,26 @@ void Assignment (ExprDesc* lval) } else { - /* Get the address on stack if needed */ - PushAddr (lval); + /* Get the address on stack if needed */ + PushAddr (lval); - /* Get the expression on the right of the '=' into the primary */ - if (evalexpr (CF_NONE, hie1, &lval2) == 0) { - /* Constant expression. Adjust the types */ - assignadjust (ltype, &lval2); - /* Put the value into the primary register */ - exprhs (CF_NONE, 0, &lval2); - } else { - /* Expression is not constant and already in the primary */ - assignadjust (ltype, &lval2); - } + /* Read the expression on the right side of the '=' */ + k = hie1 (&lval2); + + /* Do type conversion if necessary */ + k = TypeConversion (&lval2, k, ltype); + + /* If necessary, load the value into the primary register */ + exprhs (CF_NONE, k, &lval2); /* Generate a store instruction */ Store (lval, 0); } - /* Value is still in primary */ + /* Value is still in primary and not an lvalue */ lval->Flags = E_MEXPR; + return 0; } diff --git a/src/cc65/assignment.h b/src/cc65/assignment.h index dee5f7f17..68c17bffd 100644 --- a/src/cc65/assignment.h +++ b/src/cc65/assignment.h @@ -6,9 +6,9 @@ /* */ /* */ /* */ -/* (C) 2002 Ullrich von Bassewitz */ -/* Wacholderweg 14 */ -/* D-70597 Stuttgart */ +/* (C) 2002-2003 Ullrich von Bassewitz */ +/* Römerstrasse 52 */ +/* D-70794 Filderstadt */ /* EMail: uz@cc65.org */ /* */ /* */ @@ -49,7 +49,7 @@ -void Assignment (ExprDesc* lval); +int Assignment (ExprDesc* lval); /* Parse an assignment */ diff --git a/src/cc65/declare.c b/src/cc65/declare.c index 93760bc82..59a618dac 100644 --- a/src/cc65/declare.c +++ b/src/cc65/declare.c @@ -44,6 +44,7 @@ #include "anonname.h" #include "codegen.h" #include "datatype.h" +#include "declare.h" #include "declattr.h" #include "error.h" #include "expr.h" @@ -54,7 +55,7 @@ #include "pragma.h" #include "scanner.h" #include "symtab.h" -#include "declare.h" +#include "typeconv.h" @@ -1076,18 +1077,10 @@ static void ClosingCurlyBraces (unsigned BracesExpected) static unsigned ParseScalarInit (type* T) /* 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; - /* Get the size of the expected type */ - unsigned Size = SizeOf (T); - CHECK (Size > 0 && Size <= sizeof(Masks)/sizeof(Masks[0])); - /* Optional opening brace */ - BraceCount = OpeningCurlyBraces (0); + unsigned BraceCount = OpeningCurlyBraces (0); /* 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. @@ -1096,13 +1089,9 @@ static unsigned ParseScalarInit (type* T) Warning ("Braces around scalar initializer"); } - /* Expression */ + /* Get the expression and convert it to the target type */ ConstExpr (&ED); - if ((ED.Flags & E_MCTYPE) == E_TCONST) { - /* Make the const value the correct size */ - ED.ConstVal &= Masks[Size-1]; - } - assignadjust (T, &ED); + TypeConversion (&ED, 0, T); /* Output the data */ DefineData (&ED); @@ -1111,7 +1100,7 @@ static unsigned ParseScalarInit (type* T) ClosingCurlyBraces (BraceCount); /* Done */ - return Size; + return SizeOf (T); } @@ -1129,7 +1118,7 @@ static unsigned ParsePointerInit (type* T) /* Make the const value the correct size */ ED.ConstVal &= 0xFFFF; } - assignadjust (T, &ED); + TypeConversion (&ED, 0, T); /* Output the data */ DefineData (&ED); @@ -1406,7 +1395,19 @@ static unsigned ParseInitInternal (type* T, int AllowFlexibleMembers) unsigned ParseInit (type* T) /* 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; } diff --git a/src/cc65/expr.c b/src/cc65/expr.c index b71d2d670..89e708e0d 100644 --- a/src/cc65/expr.c +++ b/src/cc65/expr.c @@ -31,8 +31,8 @@ #include "scanner.h" #include "stdfunc.h" #include "symtab.h" -#include "typecast.h" #include "typecmp.h" +#include "typeconv.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. */ 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) /* 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. */ if (!Ellipsis) { - /* Promote the argument if needed */ - assignadjust (Param->Type, &lval); + /* Convert the argument to the parameter type if needed */ + TypeConversion (&lval, 0, Param->Type); /* If we have a prototype, chars may be pushed as chars */ Flags |= CF_FORCECHAR; @@ -3022,12 +2934,10 @@ int hie1 (ExprDesc* lval) -static int hie0 (ExprDesc *lval) +int hie0 (ExprDesc *lval) /* Parse comma operator. */ { - int k; - - k = hie1 (lval); + int k = hie1 (lval); while (CurTok.Tok == TOK_COMMA) { NextToken (); k = hie1 (lval); diff --git a/src/cc65/expr.h b/src/cc65/expr.h index efd1777e6..3398e7c27 100644 --- a/src/cc65/expr.h +++ b/src/cc65/expr.h @@ -42,13 +42,6 @@ void CheckBoolExpr (ExprDesc* lval); * 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); /* 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. */ -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 */ +int hie0 (ExprDesc *lval); +/* Parse comma operator. */ int evalexpr (unsigned flags, int (*f) (ExprDesc*), ExprDesc* lval); /* 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. */ +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); /* Get a constant value */ diff --git a/src/cc65/locals.c b/src/cc65/locals.c index 9f4c05088..00d15d1bc 100644 --- a/src/cc65/locals.c +++ b/src/cc65/locals.c @@ -46,8 +46,9 @@ #include "expr.h" #include "function.h" #include "global.h" -#include "symtab.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. */ { - unsigned Flags; unsigned InitLabel; /* 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 * data in the RODATA segment. The function does return the size - * of the initialization data, which may be greater than the - * actual size of the type, if the type is a structure with a + * of the initialization data, which may be greater than the + * actual size of the type, if the type is a structure with a * flexible array member that has been initialized. Since we must * know the size of the data in advance for register variables, * we cannot allow that here. @@ -110,27 +110,17 @@ static unsigned ParseRegisterDecl (Declaration* Decl, unsigned* SC, int Reg) } else { - /* Setup the type flags for the assignment */ - Flags = CF_NONE; - if (Size == SIZEOF_CHAR) { - Flags |= CF_FORCECHAR; - } + /* Parse the expression */ + int k = hie1 (InitExprDesc (&lval)); - /* Get the expression into the primary */ - if (evalexpr (Flags, hie1, &lval) == 0) { - /* Constant expression. Adjust the types */ - assignadjust (Decl->Type, &lval); - Flags |= CF_CONST; - /* Load it into the primary */ - exprhs (Flags, 0, &lval); - } else { - /* Expression is not constant and in the primary */ - assignadjust (Decl->Type, &lval); - } + /* Convert it to the target type */ + k = TypeConversion (&lval, k, Decl->Type); + + /* Load the value into the primary */ + exprhs (CF_NONE, k, &lval); /* Store the value into the variable */ - Flags |= CF_REGVAR; - g_putstatic (Flags | TypeOf (Decl->Type), Reg, 0); + g_putstatic (CF_REGVAR | TypeOf (Decl->Type), Reg, 0); } @@ -210,20 +200,28 @@ static unsigned ParseAutoDecl (Declaration* Decl, unsigned* SC) } else { + int k; + /* Allocate previously reserved local space */ F_AllocLocalSpace (CurrentFunc); /* Setup the type flags for the assignment */ Flags = (Size == SIZEOF_CHAR)? CF_FORCECHAR : CF_NONE; - /* Get the expression into the primary */ - if (evalexpr (Flags, hie1, &lval) == 0) { - /* Constant expression. Adjust the types */ - assignadjust (Decl->Type, &lval); - Flags |= CF_CONST; + /* Parse the expression */ + k = hie1 (InitExprDesc (&lval)); + + /* Convert it to the target type */ + 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 { - /* Expression is not constant and in the primary */ - assignadjust (Decl->Type, &lval); + Flags |= CF_CONST; } /* Push the value */ @@ -286,24 +284,17 @@ static unsigned ParseAutoDecl (Declaration* Decl, unsigned* SC) } else { - /* Setup the type flags for the assignment */ - Flags = (Size == SIZEOF_CHAR)? CF_FORCECHAR : CF_NONE; + /* Parse the expression */ + int k = hie1 (InitExprDesc (&lval)); - /* Get the expression into the primary */ - if (evalexpr (Flags, hie1, &lval) == 0) { - /* Constant expression. Adjust the types */ - assignadjust (Decl->Type, &lval); - Flags |= CF_CONST; - /* Load it into the primary */ - exprhs (Flags, 0, &lval); - } else { - /* Expression is not constant and in the primary */ - assignadjust (Decl->Type, &lval); - } + /* Convert it to the target type */ + k = TypeConversion (&lval, k, Decl->Type); + + /* Load the value into the primary */ + exprhs (CF_NONE, k, &lval); /* 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 */ diff --git a/src/cc65/make/gcc.mak b/src/cc65/make/gcc.mak index 968a20b23..b87785b0b 100644 --- a/src/cc65/make/gcc.mak +++ b/src/cc65/make/gcc.mak @@ -82,8 +82,8 @@ OBJS = anonname.o \ symentry.o \ symtab.o \ textseg.o \ - typecast.o \ typecmp.o \ + typeconv.o \ util.o LIBS = $(COMMON)/common.a diff --git a/src/cc65/make/watcom.mak b/src/cc65/make/watcom.mak index fceb1963c..20c6bb737 100644 --- a/src/cc65/make/watcom.mak +++ b/src/cc65/make/watcom.mak @@ -103,8 +103,8 @@ OBJS = anonname.obj \ symentry.obj \ symtab.obj \ textseg.obj \ - typecast.obj \ typecmp.obj \ + typeconv.obj \ util.obj LIBS = ..\common\common.lib diff --git a/src/cc65/segments.c b/src/cc65/segments.c index dd7817b88..dabb4a4a6 100644 --- a/src/cc65/segments.c +++ b/src/cc65/segments.c @@ -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) /* Output the given segments to the file */ { diff --git a/src/cc65/segments.h b/src/cc65/segments.h index e7590ee14..81496ed1f 100644 --- a/src/cc65/segments.h +++ b/src/cc65/segments.h @@ -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))); /* 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); /* Output the given segments to the file */ diff --git a/src/cc65/stdfunc.c b/src/cc65/stdfunc.c index 219ad4706..40d74f692 100644 --- a/src/cc65/stdfunc.c +++ b/src/cc65/stdfunc.c @@ -48,6 +48,7 @@ #include "litpool.h" #include "scanner.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 * 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 */ - 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 */ - 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))) /* Handle the strlen function */ { - static type ParamType[] = { T_PTR, T_SCHAR, T_END }; - - ExprDesc Param; - unsigned CodeFlags; + static type ParamType[] = { T_PTR, T_SCHAR, T_END }; + int k; + ExprDesc Param; + unsigned CodeFlags; unsigned long ParamName; - /* Fetch the parameter */ - int k = hie1 (InitExprDesc (&Param)); - /* Setup the argument type string */ ParamType[1] = GetDefaultChar () | T_QUAL_CONST; - /* Convert the parameter type to the type needed, check for mismatches */ - assignadjust (ParamType, &Param); + /* Fetch the parameter and convert it to the type needed */ + k = TypeConversion (&Param, hie1 (InitExprDesc (&Param)), ParamType); /* Check if the parameter is a constant array of some type, or a numeric * address cast to a pointer. diff --git a/src/cc65/stmt.c b/src/cc65/stmt.c index 408297a18..6a18b43b3 100644 --- a/src/cc65/stmt.c +++ b/src/cc65/stmt.c @@ -58,6 +58,7 @@ #include "swstmt.h" #include "symtab.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 * NULL, it will the skip the token, otherwise it will store one to * 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. */ { int HaveToken = (CurTok.Tok == TOK_SEMI); if (!HaveToken) { - Error ("`;' expected"); + Error ("`;' expected"); /* Try to be smart about errors */ if (CurTok.Tok == TOK_COLON || CurTok.Tok == TOK_COMMA) { HaveToken = 1; @@ -256,7 +257,8 @@ static void WhileStatement (void) static void ReturnStatement (void) /* Handle the 'return' statement */ { - ExprDesc lval; + ExprDesc Expr; + int k; NextToken (); if (CurTok.Tok != TOK_SEMI) { @@ -266,12 +268,17 @@ static void ReturnStatement (void) Error ("Returning a value in function with return type void"); } - /* Evaluate the return expression. Result will be in primary */ - expression (&lval); + /* Evaluate the return expression */ + 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)) { - 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)) { diff --git a/src/cc65/typecast.c b/src/cc65/typecast.c deleted file mode 100644 index 7e0c36df8..000000000 --- a/src/cc65/typecast.c +++ /dev/null @@ -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; -} - - - - - - diff --git a/src/cc65/typeconv.c b/src/cc65/typeconv.c new file mode 100644 index 000000000..38ac2013f --- /dev/null +++ b/src/cc65/typeconv.c @@ -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); +} + + + diff --git a/src/cc65/typecast.h b/src/cc65/typeconv.h similarity index 80% rename from src/cc65/typecast.h rename to src/cc65/typeconv.h index bca3b1ae5..51d4a76e1 100644 --- a/src/cc65/typecast.h +++ b/src/cc65/typeconv.h @@ -1,14 +1,14 @@ /*****************************************************************************/ /* */ -/* typecast.h */ +/* typeconv.h */ /* */ -/* Handle type casts */ +/* Handle type conversions */ /* */ /* */ /* */ -/* (C) 2002 Ullrich von Bassewitz */ -/* Wacholderweg 14 */ -/* D-70597 Stuttgart */ +/* (C) 2002-2003 Ullrich von Bassewitz */ +/* Römerstrasse 52 */ +/* D-70794 Filderstadt */ /* EMail: uz@cc65.org */ /* */ /* */ @@ -33,11 +33,11 @@ -#ifndef TYPECAST_H -#define TYPECAST_H +#ifndef TYPECONV_H +#define TYPECONV_H + - /* cc65 */ #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 * expression is an lvalue and false if not. */ -/* End of typecast.h */ +/* End of typeconv.h */ #endif