#include "scanner.h"
#include "stdfunc.h"
#include "symtab.h"
-#include "typecast.h"
#include "typecmp.h"
+#include "typeconv.h"
#include "expr.h"
-static int hie0 (ExprDesc *lval);
+int hie0 (ExprDesc *lval);
/* Parse comma operator. */
static int expr (int (*func) (ExprDesc*), ExprDesc *lval);
-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)) {
- Error ("Incompatible types");
- } else {
- /* 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 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 */
{
-static int kcalc (int tok, long val1, long val2)
+static int kcalc (token_t tok, long val1, long val2)
/* Calculate an operation with left and right operand constant. */
{
switch (tok) {
-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;
}
}
* each parameter separately, or creating the parameter frame once and then
* storing into this frame.
* The function returns the size of the parameters pushed.
- */
+ */
{
ExprDesc lval;
FrameSize = Func->ParamSize;
if (FrameParams > 0 && (Func->Flags & FD_FASTCALL) != 0) {
/* Last parameter is not pushed */
- const SymEntry* LastParam = Func->SymTab->SymTail;
- FrameSize -= CheckedSizeOf (LastParam->Type);
+ FrameSize -= CheckedSizeOf (Func->LastParam->Type);
--FrameParams;
}
* 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;
} 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);
RemoveCode (Mark1);
/* Handle constant base array on stack. Be sure NOT to
- * handle pointers the same way, this won't work.
+ * handle pointers the same way, and check for character literals
+ * (both won't work).
*/
- if (IsTypeArray (tptr1) &&
+ if (IsTypeArray (tptr1) && lval->Flags != (E_MCONST | E_TLIT) &&
((lval->Flags & ~E_MCTYPE) == E_MCONST ||
(lval->Flags & ~E_MCTYPE) == E_MLOCAL ||
(lval->Flags & E_MGLOBAL) != 0 ||
-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.
* 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;
}
ExprDesc lval2;
unsigned lflags;
unsigned rflags;
- int MustScale;
+ int MustScale;
/* We must have an lvalue */
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));
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 */
-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);