X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fcc65%2Fexpr.c;h=02b5d78e26c5a9bc4435a7705a44a74b42fbd67d;hb=aef8789873bd008d42aa50330ca98488fad91b31;hp=b71d2d6709d06d16b9926210dc42141496ef933e;hpb=73dfa23c987d8a7f1154801b85c171f9e01dcd58;p=cc65 diff --git a/src/cc65/expr.c b/src/cc65/expr.c index b71d2d670..02b5d78e2 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 */ { @@ -501,48 +413,54 @@ void CheckBoolExpr (ExprDesc* lval) -void exprhs (unsigned flags, int k, ExprDesc* lval) +void exprhs (unsigned Flags, int k, ExprDesc* Expr) /* Put the result of an expression into the primary register */ { int f; - f = lval->Flags; + f = Expr->Flags; if (k) { /* Dereferenced lvalue */ - flags |= TypeOf (lval->Type); - if (lval->Test & E_FORCETEST) { - flags |= CF_TEST; - lval->Test &= ~E_FORCETEST; + Flags |= TypeOf (Expr->Type); + if (Expr->Test & E_FORCETEST) { + Flags |= CF_TEST; + Expr->Test &= ~E_FORCETEST; } - if (f & E_MGLOBAL) { /* ref to globalvar */ - /* Generate code */ - flags |= GlobalModeFlags (f); - g_getstatic (flags, lval->Name, lval->ConstVal); + if (f & E_MGLOBAL) { + /* Reference to a global variable */ + Flags |= GlobalModeFlags (f); + g_getstatic (Flags, Expr->Name, Expr->ConstVal); } else if (f & E_MLOCAL) { - /* ref to localvar */ - g_getlocal (flags, lval->ConstVal); + /* Reference to a local variable */ + g_getlocal (Flags, Expr->ConstVal); } else if (f & E_MCONST) { - /* ref to absolute address */ - g_getstatic (flags | CF_ABSOLUTE, lval->ConstVal, 0); + /* Reference to an absolute address */ + g_getstatic (Flags | CF_ABSOLUTE, Expr->ConstVal, 0); } else if (f == E_MEOFFS) { - g_getind (flags, lval->ConstVal); + /* Reference to address in primary with offset in Expr */ + g_getind (Flags, Expr->ConstVal); } else if (f != E_MREG) { - g_getind (flags, 0); + /* Reference with address in primary */ + g_getind (Flags, 0); + } + } else { + /* An rvalue */ + if (f == E_MEOFFS) { + /* reference not storable */ + Flags |= TypeOf (Expr->Type); + g_inc (Flags | CF_CONST, Expr->ConstVal); + } else if ((f & E_MEXPR) == 0) { + /* Constant of some sort, load it into the primary */ + LoadConstant (Flags, Expr); } - } else if (f == E_MEOFFS) { - /* reference not storable */ - flags |= TypeOf (lval->Type); - g_inc (flags | CF_CONST, lval->ConstVal); - } else if ((f & E_MEXPR) == 0) { - /* Constant of some sort, load it into the primary */ - LoadConstant (flags, lval); } + /* Are we testing this value? */ - if (lval->Test & E_FORCETEST) { + if (Expr->Test & E_FORCETEST) { /* Yes, force a test */ - flags |= TypeOf (lval->Type); - g_test (flags); - lval->Test &= ~E_FORCETEST; + Flags |= TypeOf (Expr->Type); + g_test (Flags); + Expr->Test &= ~E_FORCETEST; } } @@ -655,8 +573,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; @@ -677,9 +595,17 @@ static unsigned FunctionParamList (FuncDesc* Func) } else { unsigned ArgSize = sizeofarg (Flags); if (FrameSize > 0) { - /* We have the space already allocated, store in the frame */ - CHECK (FrameSize >= ArgSize); - FrameSize -= ArgSize; + /* We have the space already allocated, store in the frame. + * Because of invalid type conversions (that have produced an + * error before), we can end up here with a non aligned stack + * frame. Since no output will be generated anyway, handle + * these cases gracefully instead of doing a CHECK. + */ + if (FrameSize >= ArgSize) { + FrameSize -= ArgSize; + } else { + FrameSize = 0; + } FrameOffs -= ArgSize; /* Store */ g_putlocal (Flags | CF_NOKEEP, FrameOffs, lval.ConstVal); @@ -2656,48 +2582,58 @@ static int hieOr (ExprDesc *lval) -static int hieQuest (ExprDesc *lval) -/* Parse "lvalue ? exp : exp" */ +static int hieQuest (ExprDesc* lval) +/* Parse the ternary operator */ { - int k; - int labf; - int labt; - ExprDesc lval2; /* Expression 2 */ - ExprDesc lval3; /* Expression 3 */ - type* type2; /* Type of expression 2 */ - type* type3; /* Type of expression 3 */ - type* rtype; /* Type of result */ + int k1, k2, k3; + int labf; + int labt; + ExprDesc Expr2; /* Expression 2 */ + ExprDesc Expr3; /* Expression 3 */ + int Expr2IsNULL; /* Expression 2 is a NULL pointer */ + int Expr3IsNULL; /* Expression 3 is a NULL pointer */ + type* ResultType; /* Type of result */ - k = Preprocessing? hieOrPP (lval) : hieOr (lval); + k1 = Preprocessing? hieOrPP (lval) : hieOr (lval); if (CurTok.Tok == TOK_QUEST) { NextToken (); if ((lval->Test & E_CC) == 0) { /* Condition codes not set, force a test */ lval->Test |= E_FORCETEST; } - exprhs (CF_NONE, k, lval); + exprhs (CF_NONE, k1, lval); labf = GetLocalLabel (); g_falsejump (CF_NONE, labf); - /* Parse second expression */ - k = expr (hie1, &lval2); - type2 = lval2.Type; - if (!IsTypeVoid (lval2.Type)) { + /* Parse second expression. Remember for later if it is a NULL pointer + * expression, then load it into the primary. + */ + k2 = expr (hie1, &Expr2); + Expr2IsNULL = IsNullPtr (&Expr2); + if (!IsTypeVoid (Expr2.Type)) { /* Load it into the primary */ - exprhs (CF_NONE, k, &lval2); + exprhs (CF_NONE, k2, &Expr2); + Expr2.Flags = E_MEXPR; + k2 = 0; } labt = GetLocalLabel (); ConsumeColon (); g_jump (labt); - /* Parse the third expression */ + /* Jump here if the first expression was false */ g_defcodelabel (labf); - k = expr (hie1, &lval3); - type3 = lval3.Type; - if (!IsTypeVoid (lval3.Type)) { + + /* Parse second expression. Remember for later if it is a NULL pointer + * expression, then load it into the primary. + */ + k3 = expr (hie1, &Expr3); + Expr3IsNULL = IsNullPtr (&Expr3); + if (!IsTypeVoid (Expr3.Type)) { /* Load it into the primary */ - exprhs (CF_NONE, k, &lval3); + exprhs (CF_NONE, k3, &Expr3); + Expr3.Flags = E_MEXPR; + k3 = 0; } /* Check if any conversions are needed, if so, do them. @@ -2713,62 +2649,62 @@ static int hieQuest (ExprDesc *lval) * type void. * - all other cases are flagged by an error. */ - if (IsClassInt (type2) && IsClassInt (type3)) { + if (IsClassInt (Expr2.Type) && IsClassInt (Expr3.Type)) { /* Get common type */ - rtype = promoteint (type2, type3); + ResultType = promoteint (Expr2.Type, Expr3.Type); /* Convert the third expression to this type if needed */ - g_typecast (TypeOf (rtype), TypeOf (type3)); + TypeConversion (&Expr3, k3, ResultType); /* Setup a new label so that the expr3 code will jump around * the type cast code for expr2. */ labf = GetLocalLabel (); /* Get new label */ - g_jump (labf); /* Jump around code */ + g_jump (labf); /* Jump around code */ /* The jump for expr2 goes here */ g_defcodelabel (labt); /* Create the typecast code for expr2 */ - g_typecast (TypeOf (rtype), TypeOf (type2)); + TypeConversion (&Expr2, k2, ResultType); /* Jump here around the typecase code. */ g_defcodelabel (labf); - labt = 0; /* Mark other label as invalid */ + labt = 0; /* Mark other label as invalid */ - } else if (IsClassPtr (type2) && IsClassPtr (type3)) { + } else if (IsClassPtr (Expr2.Type) && IsClassPtr (Expr3.Type)) { /* Must point to same type */ - if (TypeCmp (Indirect (type2), Indirect (type3)) < TC_EQUAL) { - Error ("Incompatible pointer types"); + if (TypeCmp (Indirect (Expr2.Type), Indirect (Expr3.Type)) < TC_EQUAL) { + Error ("Incompatible pointer types"); } /* Result has the common type */ - rtype = lval2.Type; - } else if (IsClassPtr (type2) && IsNullPtr (&lval3)) { + ResultType = Expr2.Type; + } else if (IsClassPtr (Expr2.Type) && Expr3IsNULL) { /* Result type is pointer, no cast needed */ - rtype = lval2.Type; - } else if (IsNullPtr (&lval2) && IsClassPtr (type3)) { + ResultType = Expr2.Type; + } else if (Expr2IsNULL && IsClassPtr (Expr3.Type)) { /* Result type is pointer, no cast needed */ - rtype = lval3.Type; - } else if (IsTypeVoid (type2) && IsTypeVoid (type3)) { + ResultType = Expr3.Type; + } else if (IsTypeVoid (Expr2.Type) && IsTypeVoid (Expr3.Type)) { /* Result type is void */ - rtype = lval3.Type; - } else { - Error ("Incompatible types"); - rtype = lval2.Type; /* Doesn't matter here */ - } + ResultType = Expr3.Type; + } else { + Error ("Incompatible types"); + ResultType = Expr2.Type; /* Doesn't matter here */ + } - /* If we don't have the label defined until now, do it */ - if (labt) { - g_defcodelabel (labt); - } + /* If we don't have the label defined until now, do it */ + if (labt) { + g_defcodelabel (labt); + } - /* Setup the target expression */ + /* Setup the target expression */ lval->Flags = E_MEXPR; - lval->Type = rtype; - k = 0; + lval->Type = ResultType; + k1 = 0; } - return k; + return k1; } @@ -2860,7 +2796,7 @@ static void addsubeq (const GenDesc* Gen, ExprDesc *lval, int k) ExprDesc lval2; unsigned lflags; unsigned rflags; - int MustScale; + int MustScale; /* We must have an lvalue */ @@ -2889,16 +2825,18 @@ static void addsubeq (const GenDesc* Gen, ExprDesc *lval, int k) rflags = 0; /* Evaluate the rhs */ - if (evalexpr (CF_NONE, hie1, &lval2) == 0) { + k = hie1 (&lval2); + if (k == 0 && lval2.Flags == E_MCONST) { /* The resulting value is a constant. */ if (MustScale) { /* lhs is a pointer, scale rhs */ lval2.ConstVal *= CheckedSizeOf (lval->Type+1); } rflags |= CF_CONST; - lflags |= CF_CONST; + lflags |= CF_CONST; } else { - /* rhs is not constant and already in the primary register */ + /* Not constant, load into the primary */ + exprhs (CF_NONE, k, &lval2); if (MustScale) { /* lhs is a pointer, scale rhs */ g_scale (TypeOf (lval2.Type), CheckedSizeOf (lval->Type+1)); @@ -2909,7 +2847,7 @@ static void addsubeq (const GenDesc* Gen, ExprDesc *lval, int k) lflags |= TypeOf (lval->Type) | CF_FORCECHAR; rflags |= TypeOf (lval2.Type); - /* Cast the rhs to the type of the lhs */ + /* Convert the type of the lhs to that of the rhs */ g_typecast (lflags, rflags); /* Output apropriate code */ @@ -3022,12 +2960,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);