/*****************************************************************************/
-/* Helper functions */
+/* Helper functions */
/*****************************************************************************/
/* Return the addressing mode flags for the given expression */
{
switch (ED_GetLoc (Expr)) {
+ case E_LOC_ABS: return CF_ABSOLUTE;
case E_LOC_GLOBAL: return CF_EXTERNAL;
case E_LOC_STATIC: return CF_STATIC;
case E_LOC_REGISTER: return CF_REGVAR;
+ case E_LOC_STACK: return CF_NONE;
+ case E_LOC_PRIMARY: return CF_NONE;
+ case E_LOC_EXPR: return CF_NONE;
+ case E_LOC_LITERAL: return CF_STATIC; /* Same as static */
default:
Internal ("GlobalModeFlags: Invalid location flags value: 0x%04X", Expr->Flags);
/* NOTREACHED */
-void ExprWithCheck (void (*Func) (ExprDesc*), ExprDesc *Expr)
+void ExprWithCheck (void (*Func) (ExprDesc*), ExprDesc* Expr)
/* Call an expression function with checks. */
{
/* Remember the stack pointer */
+void MarkedExprWithCheck (void (*Func) (ExprDesc*), ExprDesc* Expr)
+/* Call an expression function with checks and record start and end of the
+ * generated code.
+ */
+{
+ CodeMark Start, End;
+ GetCodePos (&Start);
+ ExprWithCheck (Func, Expr);
+ GetCodePos (&End);
+ ED_SetCodeRange (Expr, &Start, &End);
+}
+
+
+
static Type* promoteint (Type* lhst, Type* rhst)
/* In an expression with two ints, return the type of the result */
{
/*****************************************************************************/
-/* code */
+/* code */
/*****************************************************************************/
-static unsigned FunctionParamList (FuncDesc* Func)
+static unsigned FunctionParamList (FuncDesc* Func, int IsFastcall)
/* Parse a function parameter list and pass the parameters to the called
* function. Depending on several criteria this may be done by just pushing
* each parameter separately, or creating the parameter frame once and then
/* Calculate the number and size of the parameters */
FrameParams = Func->ParamCount;
FrameSize = Func->ParamSize;
- if (FrameParams > 0 && (Func->Flags & FD_FASTCALL) != 0) {
+ if (FrameParams > 0 && IsFastcall) {
/* Last parameter is not pushed */
FrameSize -= CheckedSizeOf (Func->LastParam->Type);
--FrameParams;
Flags |= TypeOf (Expr.Type);
/* If this is a fastcall function, don't push the last argument */
- if (ParamCount != Func->ParamCount || (Func->Flags & FD_FASTCALL) == 0) {
+ if (ParamCount != Func->ParamCount || !IsFastcall) {
unsigned ArgSize = sizeofarg (Flags);
if (FrameSize > 0) {
/* We have the space already allocated, store in the frame.
unsigned ParamSize; /* Number of parameter bytes */
CodeMark Mark;
int PtrOffs = 0; /* Offset of function pointer on stack */
- int IsFastCall = 0; /* True if it's a fast call function */
+ int IsFastcall = 0; /* True if it's a fast call function */
int PtrOnStack = 0; /* True if a pointer copy is on stack */
/* Skip the left paren */
if (IsFuncPtr) {
/* Check wether it's a fastcall function that has parameters */
- IsFastCall = IsFastCallFunc (Expr->Type + 1) && (Func->ParamCount > 0);
+ IsFastcall = IsQualFastcall (Expr->Type + 1) && (Func->ParamCount > 0);
/* Things may be difficult, depending on where the function pointer
* resides. If the function pointer is an expression of some sort
* For fastcall functions we do also need to place a copy of the
* pointer on stack, since we cannot use a/x.
*/
- PtrOnStack = IsFastCall || !ED_IsConst (Expr);
+ PtrOnStack = IsFastcall || !ED_IsConst (Expr);
if (PtrOnStack) {
/* Not a global or local variable, or a fastcall function. Load
PtrOffs = StackPtr;
}
- /* Check for known standard functions and inline them */
- } else if (Expr->Name != 0) {
- int StdFunc = FindStdFunc ((const char*) Expr->Name);
- if (StdFunc >= 0) {
- /* Inline this function */
- HandleStdFunc (StdFunc, Func, Expr);
- return;
+ } else {
+ /* Check for known standard functions and inline them */
+ if (Expr->Name != 0) {
+ int StdFunc = FindStdFunc ((const char*) Expr->Name);
+ if (StdFunc >= 0) {
+ /* Inline this function */
+ HandleStdFunc (StdFunc, Func, Expr);
+ return;
+ }
}
+
+ /* If we didn't inline the function, get fastcall info */
+ IsFastcall = IsQualFastcall (Expr->Type);
}
/* Parse the parameter list */
- ParamSize = FunctionParamList (Func);
+ ParamSize = FunctionParamList (Func, IsFastcall);
/* We need the closing paren here */
ConsumeRParen ();
/* If the function is not a fastcall function, load the pointer to
* the function into the primary.
*/
- if (!IsFastCall) {
+ if (!IsFastcall) {
/* Not a fastcall function - we may use the primary */
if (PtrOnStack) {
break;
case TOK_SCONST:
+ case TOK_WCSCONST:
/* String literal */
E->Type = GetCharArrayType (GetLiteralPoolOffs () - CurTok.IVal);
E->Flags = E_LOC_LITERAL | E_RTYPE_RVAL;
break;
default:
- /* Illegal primary. */
+ /* Illegal primary. Be sure to skip the token to avoid endless
+ * error loops.
+ */
Error ("Expression expected");
+ NextToken ();
ED_MakeConstAbsInt (E, 1);
break;
}
/* Handle an array reference. This function needs a rewrite. */
{
int ConstBaseAddr;
- ExprDesc SubScript;
+ ExprDesc Subscript;
CodeMark Mark1;
CodeMark Mark2;
Type* ElementType;
}
/* TOS now contains ptr to array elements. Get the subscript. */
- ExprWithCheck (hie0, &SubScript);
+ MarkedExprWithCheck (hie0, &Subscript);
/* Check the types of array and subscript. We can either have a
* pointer/array to the left, in which case the subscript must be of an
* correct types.
*/
if (IsClassPtr (Expr->Type)) {
- if (!IsClassInt (SubScript.Type)) {
+ if (!IsClassInt (Subscript.Type)) {
Error ("Array subscript is not an integer");
/* To avoid any compiler errors, make the expression a valid int */
- ED_MakeConstAbsInt (&SubScript, 0);
+ ED_MakeConstAbsInt (&Subscript, 0);
}
ElementType = Indirect (Expr->Type);
} else if (IsClassInt (Expr->Type)) {
- if (!IsClassPtr (SubScript.Type)) {
+ if (!IsClassPtr (Subscript.Type)) {
Error ("Subscripted value is neither array nor pointer");
/* To avoid compiler errors, make the subscript a char[] at
* address 0.
*/
- ED_MakeConstAbs (&SubScript, 0, GetCharArrayType (1));
+ ED_MakeConstAbs (&Subscript, 0, GetCharArrayType (1));
}
- ElementType = Indirect (SubScript.Type);
+ ElementType = Indirect (Subscript.Type);
} else {
Error ("Cannot subscript");
/* To avoid compiler errors, fake both the array and the subscript, so
* we can just proceed.
*/
ED_MakeConstAbs (Expr, 0, GetCharArrayType (1));
- ED_MakeConstAbsInt (&SubScript, 0);
+ ED_MakeConstAbsInt (&Subscript, 0);
ElementType = Indirect (Expr->Type);
}
+ /* If the subscript is a bit-field, load it and make it an rvalue */
+ if (ED_IsBitField (&Subscript)) {
+ LoadExpr (CF_NONE, &Subscript);
+ ED_MakeRValExpr (&Subscript);
+ }
+
/* Check if the subscript is constant absolute value */
- if (ED_IsConstAbs (&SubScript)) {
+ if (ED_IsConstAbs (&Subscript) && ED_CodeRangeIsEmpty (&Subscript)) {
/* The array subscript is a numeric constant. If we had pushed the
* array base address onto the stack before, we can remove this value,
/* Lhs is pointer/array. Scale the subscript value according to
* the element size.
*/
- SubScript.IVal *= CheckedSizeOf (ElementType);
+ Subscript.IVal *= CheckedSizeOf (ElementType);
/* Remove the address load code */
RemoveCode (&Mark1);
if (IsTypeArray (Expr->Type)) {
/* Adjust the offset */
- Expr->IVal += SubScript.IVal;
+ Expr->IVal += Subscript.IVal;
} else {
}
/* Use the offset */
- Expr->IVal = SubScript.IVal;
+ Expr->IVal = Subscript.IVal;
}
} else {
* we will ignore the true type of the subscript here and
* use always an int. #### Use offset but beware of LoadExpr!
*/
- g_inc (CF_INT | CF_CONST, SubScript.IVal);
+ g_inc (CF_INT | CF_CONST, Subscript.IVal);
}
/* Array subscript is not constant. Load it into the primary */
GetCodePos (&Mark2);
- LoadExpr (CF_NONE, &SubScript);
+ LoadExpr (CF_NONE, &Subscript);
/* Do scaling */
if (IsClassPtr (Expr->Type)) {
* subscript was not scaled, that is, if this was a byte array
* or pointer.
*/
- if ((ED_IsLocConst (&SubScript) || ED_IsLocStack (&SubScript)) &&
+ if ((ED_IsLocConst (&Subscript) || ED_IsLocStack (&Subscript)) &&
CheckedSizeOf (ElementType) == SIZEOF_CHAR) {
unsigned Flags;
/* Reverse the order of evaluation */
- if (CheckedSizeOf (SubScript.Type) == SIZEOF_CHAR) {
+ if (CheckedSizeOf (Subscript.Type) == SIZEOF_CHAR) {
Flags = CF_CHAR;
} else {
Flags = CF_INT;
LoadExpr (CF_NONE, Expr);
/* Add the variable */
- if (ED_IsLocStack (&SubScript)) {
- g_addlocal (Flags, SubScript.IVal);
+ if (ED_IsLocStack (&Subscript)) {
+ g_addlocal (Flags, Subscript.IVal);
} else {
- Flags |= GlobalModeFlags (&SubScript);
- g_addstatic (Flags, SubScript.Name, SubScript.IVal);
+ Flags |= GlobalModeFlags (&Subscript);
+ g_addstatic (Flags, Subscript.Name, Subscript.IVal);
}
} else {
{
ident Ident;
SymEntry* Field;
+ TypeCode Q;
/* Skip the token and check for an identifier */
NextToken ();
/* Set the struct field offset */
Expr->IVal += Field->V.Offs;
- /* The type is now the type of the field */
- Expr->Type = Field->Type;
+ /* The type is the type of the field plus any qualifiers from the struct */
+ Q = GetQualifier (Expr->Type);
+ if (GetQualifier (Field->Type) == (GetQualifier (Field->Type) | Q)) {
+ Expr->Type = Field->Type;
+ } else {
+ Expr->Type = TypeDup (Field->Type);
+ Expr->Type->C |= Q;
+ }
/* An struct member is actually a variable. So the rules for variables
* with respect to the reference type apply: If it's an array, it is
} else {
ED_MakeLVal (Expr);
}
+
+ /* Make the expression a bit field if necessary */
+ if (SymIsBitField (Field)) {
+ ED_MakeBitField (Expr, Field->V.B.BitOffs, Field->V.B.BitWidth);
+ }
}
}
/* Prepare the code generator flags */
- Flags = TypeOf (StoreType);
+ Flags = TypeOf (StoreType) | GlobalModeFlags (Expr);
/* Do the store depending on the location */
switch (ED_GetLoc (Expr)) {
case E_LOC_ABS:
/* Absolute: numeric address or const */
- g_putstatic (Flags | CF_ABSOLUTE, Expr->IVal, 0);
+ g_putstatic (Flags, Expr->IVal, 0);
break;
case E_LOC_GLOBAL:
/* Global variable */
- g_putstatic (Flags | CF_EXTERNAL, Expr->Name, Expr->IVal);
+ g_putstatic (Flags, Expr->Name, Expr->IVal);
break;
case E_LOC_STATIC:
case E_LOC_LITERAL:
/* Static variable or literal in the literal pool */
- g_putstatic (Flags | CF_STATIC, Expr->Name, Expr->IVal);
+ g_putstatic (Flags, Expr->Name, Expr->IVal);
break;
case E_LOC_REGISTER:
/* Register variable */
- g_putstatic (Flags | CF_REGVAR, Expr->Name, Expr->IVal);
+ g_putstatic (Flags, Expr->Name, Expr->IVal);
break;
case E_LOC_STACK:
case E_LOC_PRIMARY:
/* The primary register (value is already there) */
- /* ### Do we need a test here if the flag is set? */
break;
case E_LOC_EXPR:
return;
}
+ /* We cannot modify const values */
+ if (IsQualConst (Expr->Type)) {
+ Error ("Increment of read-only variable");
+ }
+
/* Get the data type */
- Flags = TypeOf (Expr->Type) | CF_FORCECHAR | CF_CONST;
+ Flags = TypeOf (Expr->Type) | GlobalModeFlags (Expr) | CF_FORCECHAR | CF_CONST;
/* Get the increment value in bytes */
Val = IsTypePtr (Expr->Type)? CheckedPSizeOf (Expr->Type) : 1;
case E_LOC_ABS:
/* Absolute: numeric address or const */
- g_addeqstatic (Flags | CF_ABSOLUTE, Expr->IVal, 0, Val);
+ g_addeqstatic (Flags, Expr->IVal, 0, Val);
break;
case E_LOC_GLOBAL:
/* Global variable */
- g_addeqstatic (Flags | CF_EXTERNAL, Expr->Name, Expr->IVal, Val);
+ g_addeqstatic (Flags, Expr->Name, Expr->IVal, Val);
break;
case E_LOC_STATIC:
case E_LOC_LITERAL:
/* Static variable or literal in the literal pool */
- g_addeqstatic (Flags | CF_STATIC, Expr->Name, Expr->IVal, Val);
+ g_addeqstatic (Flags, Expr->Name, Expr->IVal, Val);
break;
case E_LOC_REGISTER:
/* Register variable */
- g_addeqstatic (Flags | CF_REGVAR, Expr->Name, Expr->IVal, Val);
+ g_addeqstatic (Flags, Expr->Name, Expr->IVal, Val);
break;
case E_LOC_STACK:
return;
}
+ /* We cannot modify const values */
+ if (IsQualConst (Expr->Type)) {
+ Error ("Decrement of read-only variable");
+ }
+
/* Get the data type */
- Flags = TypeOf (Expr->Type) | CF_FORCECHAR | CF_CONST;
+ Flags = TypeOf (Expr->Type) | GlobalModeFlags (Expr) | CF_FORCECHAR | CF_CONST;
/* Get the increment value in bytes */
Val = IsTypePtr (Expr->Type)? CheckedPSizeOf (Expr->Type) : 1;
case E_LOC_ABS:
/* Absolute: numeric address or const */
- g_subeqstatic (Flags | CF_ABSOLUTE, Expr->IVal, 0, Val);
+ g_subeqstatic (Flags, Expr->IVal, 0, Val);
break;
case E_LOC_GLOBAL:
/* Global variable */
- g_subeqstatic (Flags | CF_EXTERNAL, Expr->Name, Expr->IVal, Val);
+ g_subeqstatic (Flags, Expr->Name, Expr->IVal, Val);
break;
case E_LOC_STATIC:
case E_LOC_LITERAL:
/* Static variable or literal in the literal pool */
- g_subeqstatic (Flags | CF_STATIC, Expr->Name, Expr->IVal, Val);
+ g_subeqstatic (Flags, Expr->Name, Expr->IVal, Val);
break;
case E_LOC_REGISTER:
/* Register variable */
- g_subeqstatic (Flags | CF_REGVAR, Expr->Name, Expr->IVal, Val);
+ g_subeqstatic (Flags, Expr->Name, Expr->IVal, Val);
break;
case E_LOC_STACK:
-static void PostIncDec (ExprDesc* Expr, void (*inc) (unsigned, unsigned long))
-/* Handle i-- and i++ */
+static void PostInc (ExprDesc* Expr)
+/* Handle the postincrement operator */
{
unsigned Flags;
return;
}
+ /* We cannot modify const values */
+ if (IsQualConst (Expr->Type)) {
+ Error ("Increment of read-only variable");
+ }
+
/* Get the data type */
Flags = TypeOf (Expr->Type);
/* If we have a pointer expression, increment by the size of the type */
if (IsTypePtr (Expr->Type)) {
- inc (Flags | CF_CONST | CF_FORCECHAR, CheckedSizeOf (Expr->Type + 1));
+ g_inc (Flags | CF_CONST | CF_FORCECHAR, CheckedSizeOf (Expr->Type + 1));
} else {
- inc (Flags | CF_CONST | CF_FORCECHAR, 1);
+ g_inc (Flags | CF_CONST | CF_FORCECHAR, 1);
+ }
+
+ /* Store the result back */
+ Store (Expr, 0);
+
+ /* Restore the original value in the primary register */
+ g_restore (Flags | CF_FORCECHAR);
+
+ /* The result is always an expression, no reference */
+ ED_MakeRValExpr (Expr);
+}
+
+
+
+static void PostDec (ExprDesc* Expr)
+/* Handle the postdecrement operator */
+{
+ unsigned Flags;
+
+ NextToken ();
+
+ /* The expression to increment must be an lvalue */
+ if (!ED_IsLVal (Expr)) {
+ Error ("Invalid lvalue");
+ return;
+ }
+
+ /* We cannot modify const values */
+ if (IsQualConst (Expr->Type)) {
+ Error ("Decrement of read-only variable");
+ }
+
+ /* Get the data type */
+ Flags = TypeOf (Expr->Type);
+
+ /* Push the address if needed */
+ PushAddr (Expr);
+
+ /* Fetch the value and save it (since it's the result of the expression) */
+ LoadExpr (CF_NONE, Expr);
+ g_save (Flags | CF_FORCECHAR);
+
+ /* If we have a pointer expression, increment by the size of the type */
+ if (IsTypePtr (Expr->Type)) {
+ g_dec (Flags | CF_CONST | CF_FORCECHAR, CheckedSizeOf (Expr->Type + 1));
+ } else {
+ g_dec (Flags | CF_CONST | CF_FORCECHAR, 1);
}
/* Store the result back */
ED_MakeRValExpr (Expr);
}
/* If the expression is already a pointer to function, the
- * additional dereferencing operator must be ignored.
+ * additional dereferencing operator must be ignored. A function
+ * itself is represented as "pointer to function", so any number
+ * of dereference operators is legal, since the result will
+ * always be converted to "pointer to function".
*/
- if (IsTypeFuncPtr (Expr->Type)) {
+ if (IsTypeFuncPtr (Expr->Type) || IsTypeFunc (Expr->Type)) {
/* Expression not storable */
ED_MakeRVal (Expr);
} else {
} else {
Error ("Illegal indirection");
}
+ /* The * operator yields an lvalue */
ED_MakeLVal (Expr);
}
break;
*/
if (ED_IsRVal (Expr) && !IsTypeFunc (Expr->Type) && !IsTypeArray (Expr->Type)) {
Error ("Illegal address");
- } else {
+ } else {
+ if (ED_IsBitField (Expr)) {
+ Error ("Cannot take address of bit-field");
+ /* Do it anyway, just to avoid further warnings */
+ Expr->Flags &= ~E_BITFIELD;
+ }
Expr->Type = PointerTo (Expr->Type);
+ /* The & operator yields an rvalue */
ED_MakeRVal (Expr);
}
break;
hie11 (Expr);
/* Handle post increment */
- if (CurTok.Tok == TOK_INC) {
- PostIncDec (Expr, g_inc);
- } else if (CurTok.Tok == TOK_DEC) {
- PostIncDec (Expr, g_dec);
+ switch (CurTok.Tok) {
+ case TOK_INC: PostInc (Expr); break;
+ case TOK_DEC: PostDec (Expr); break;
+ default: break;
}
}
}
/* Get the right hand side */
- rconst = (evalexpr (CF_NONE, hienext, &Expr2) == 0);
+ MarkedExprWithCheck (hienext, &Expr2);
+
+ /* Check for a constant expression */
+ rconst = (ED_IsConstAbs (&Expr2) && ED_CodeRangeIsEmpty (&Expr2));
+ if (!rconst) {
+ /* Not constant, load into the primary */
+ LoadExpr (CF_NONE, &Expr2);
+ }
/* Check the type of the rhs */
if (!IsClassInt (Expr2.Type)) {
}
/* Get the right hand side */
- rconst = (evalexpr (CF_NONE, hienext, &Expr2) == 0);
+ MarkedExprWithCheck (hienext, &Expr2);
+
+ /* Check for a constant expression */
+ rconst = (ED_IsConstAbs (&Expr2) && ED_CodeRangeIsEmpty (&Expr2));
+ if (!rconst) {
+ /* Not constant, load into the primary */
+ LoadExpr (CF_NONE, &Expr2);
+ }
/* Make sure, the types are compatible */
if (IsClassInt (Expr->Type)) {
if (!IsClassInt (Expr2.Type) && !(IsClassPtr(Expr2.Type) && ED_IsNullPtr(Expr))) {
- Error ("Incompatible types");
+ Error ("Incompatible types");
}
} else if (IsClassPtr (Expr->Type)) {
if (IsClassPtr (Expr2.Type)) {
- /* Both pointers are allowed in comparison if they point to
- * the same type, or if one of them is a void pointer.
+ /* Both pointers are allowed in comparison if they point to
+ * the same type, or if one of them is a void pointer.
*/
Type* left = Indirect (Expr->Type);
- Type* right = Indirect (Expr2.Type);
- if (TypeCmp (left, right) < TC_EQUAL && left->C != T_VOID && right->C != T_VOID) {
- /* Incomatible pointers */
+ Type* right = Indirect (Expr2.Type);
+ if (TypeCmp (left, right) < TC_EQUAL && left->C != T_VOID && right->C != T_VOID) {
+ /* Incomatible pointers */
Error ("Incompatible types");
}
} else if (!ED_IsNullPtr (&Expr2)) {
- Error ("Incompatible types");
+ Error ("Incompatible types");
}
}
/* Check for const operands */
if (ED_IsConstAbs (Expr) && rconst) {
+ /* If the result is constant, this is suspicious when not in
+ * preprocessor mode.
+ */
+ if (!Preprocessing) {
+ Warning ("Result of comparison is constant");
+ }
+
/* Both operands are constant, remove the generated code */
RemoveCode (&Mark1);
if (rconst) {
flags |= CF_CONST;
if ((Gen->Flags & GEN_NOPUSH) != 0) {
- RemoveCode (&Mark2);
+ RemoveCode (&Mark2);
ltype |= CF_REG; /* Value is in register */
}
}
/* Both expressions are constants. Check for pointer arithmetic */
if (IsClassPtr (lhst) && IsClassInt (rhst)) {
- /* Left is pointer, right is int, must scale rhs */
+ /* Left is pointer, right is int, must scale rhs */
Expr->IVal += Expr2.IVal * CheckedPSizeOf (lhst);
- /* Result type is a pointer */
+ /* Result type is a pointer */
} else if (IsClassInt (lhst) && IsClassPtr (rhst)) {
- /* Left is int, right is pointer, must scale lhs */
+ /* Left is int, right is pointer, must scale lhs */
Expr->IVal = Expr->IVal * CheckedPSizeOf (rhst) + Expr2.IVal;
- /* Result type is a pointer */
- Expr->Type = Expr2.Type;
+ /* Result type is a pointer */
+ Expr->Type = Expr2.Type;
} else if (IsClassInt (lhst) && IsClassInt (rhst)) {
- /* Integer addition */
- Expr->IVal += Expr2.IVal;
- typeadjust (Expr, &Expr2, 1);
+ /* Integer addition */
+ Expr->IVal += Expr2.IVal;
+ typeadjust (Expr, &Expr2, 1);
} else {
/* OOPS */
- Error ("Invalid operands for binary operator `+'");
+ Error ("Invalid operands for binary operator `+'");
}
} else {
*/
if (ED_IsLocAbs (Expr)) {
/* Numeric constant, scale lhs */
- Expr->IVal *= ScaleFactor;
+ Expr->IVal *= ScaleFactor;
/* Generate the code for the add */
g_inc (flags, Expr->IVal);
} else if (ScaleFactor == 1) {
g_push (TypeOf (Expr->Type), 0); /* --> stack */
/* Evaluate the rhs */
- if (evalexpr (CF_NONE, hie9, &Expr2) == 0) {
+ MarkedExprWithCheck (hie9, &Expr2);
+
+ /* Check for a constant rhs expression */
+ if (ED_IsConstAbs (&Expr2) && ED_CodeRangeIsEmpty (&Expr2)) {
/* Right hand side is a constant. Get the rhs type */
rhst = Expr2.Type;
} else {
+ /* Not constant, load into the primary */
+ LoadExpr (CF_NONE, &Expr2);
+
/* lhs and rhs are not constant. Get the rhs type. */
rhst = Expr2.Type;
flags = typeadjust (Expr, &Expr2, 0) & ~CF_CONST;
} else {
/* OOPS */
- Error ("Invalid operands for binary operator `+'");
+ Error ("Invalid operands for binary operator `+'");
flags = CF_INT;
}
g_push (TypeOf (lhst), 0); /* --> stack */
/* Parse the right hand side */
- if (evalexpr (CF_NONE, hie9, &Expr2) == 0) {
+ MarkedExprWithCheck (hie9, &Expr2);
+
+ /* Check for a constant rhs expression */
+ if (ED_IsConstAbs (&Expr2) && ED_CodeRangeIsEmpty (&Expr2)) {
/* The right hand side is constant. Get the rhs type. */
rhst = Expr2.Type;
} else {
rscale = CheckedPSizeOf (lhst);
}
- /* Operate on pointers, result type is an integer */
+ /* Operate on pointers, result type is an integer */
flags = CF_PTR;
Expr->Type = type_int;
} else if (IsClassInt (lhst) && IsClassInt (rhst)) {
/* Do the subtraction */
g_dec (flags | CF_CONST, Expr2.IVal);
- /* If this was a pointer subtraction, we must scale the result */
- if (rscale != 1) {
- g_scale (flags, -rscale);
- }
+ /* If this was a pointer subtraction, we must scale the result */
+ if (rscale != 1) {
+ g_scale (flags, -rscale);
+ }
- /* Result is a rvalue in the primary register */
- ED_MakeRValExpr (Expr);
- ED_MarkAsUntested (Expr);
+ /* Result is a rvalue in the primary register */
+ ED_MakeRValExpr (Expr);
+ ED_MarkAsUntested (Expr);
- }
+ }
} else {
- /* Right hand side is not constant. Get the rhs type. */
- rhst = Expr2.Type;
+ /* Not constant, load into the primary */
+ LoadExpr (CF_NONE, &Expr2);
+
+ /* Right hand side is not constant. Get the rhs type. */
+ rhst = Expr2.Type;
/* Check for pointer arithmetic */
- if (IsClassPtr (lhst) && IsClassInt (rhst)) {
+ if (IsClassPtr (lhst) && IsClassInt (rhst)) {
/* Left is pointer, right is int, must scale rhs */
- g_scale (CF_INT, CheckedPSizeOf (lhst));
- /* Operate on pointers, result type is a pointer */
- flags = CF_PTR;
- } else if (IsClassPtr (lhst) && IsClassPtr (rhst)) {
- /* Left is pointer, right is pointer, must scale result */
- if (TypeCmp (Indirect (lhst), Indirect (rhst)) < TC_QUAL_DIFF) {
- Error ("Incompatible pointer types");
- } else {
- rscale = CheckedPSizeOf (lhst);
- }
- /* Operate on pointers, result type is an integer */
- flags = CF_PTR;
- Expr->Type = type_int;
+ g_scale (CF_INT, CheckedPSizeOf (lhst));
+ /* Operate on pointers, result type is a pointer */
+ flags = CF_PTR;
+ } else if (IsClassPtr (lhst) && IsClassPtr (rhst)) {
+ /* Left is pointer, right is pointer, must scale result */
+ if (TypeCmp (Indirect (lhst), Indirect (rhst)) < TC_QUAL_DIFF) {
+ Error ("Incompatible pointer types");
+ } else {
+ rscale = CheckedPSizeOf (lhst);
+ }
+ /* Operate on pointers, result type is an integer */
+ flags = CF_PTR;
+ Expr->Type = type_int;
} else if (IsClassInt (lhst) && IsClassInt (rhst)) {
/* Integer subtraction. If the left hand side descriptor says that
* the lhs is const, we have to remove this mark, since this is no
* longer true, lhs is on stack instead.
*/
if (ED_IsLocAbs (Expr)) {
- ED_MakeRValExpr (Expr);
+ ED_MakeRValExpr (Expr);
}
/* Adjust operand types */
flags = typeadjust (Expr, &Expr2, 0);
static void hieAnd (ExprDesc* Expr, unsigned TrueLab, int* BoolOp)
/* Process "exp && exp" */
{
- int lab;
+ int FalseLab;
ExprDesc Expr2;
hie2 (Expr);
*BoolOp = 1;
/* Get a label that we will use for false expressions */
- lab = GetLocalLabel ();
+ FalseLab = GetLocalLabel ();
/* If the expr hasn't set condition codes, set the force-test flag */
if (!ED_IsTested (Expr)) {
LoadExpr (CF_FORCECHAR, Expr);
/* Generate the jump */
- g_falsejump (CF_NONE, lab);
+ g_falsejump (CF_NONE, FalseLab);
/* Parse more boolean and's */
while (CurTok.Tok == TOK_BOOL_AND) {
/* Do short circuit evaluation */
if (CurTok.Tok == TOK_BOOL_AND) {
- g_falsejump (CF_NONE, lab);
+ g_falsejump (CF_NONE, FalseLab);
} else {
/* Last expression - will evaluate to true */
g_truejump (CF_NONE, TrueLab);
}
/* Define the false jump label here */
- g_defcodelabel (lab);
+ g_defcodelabel (FalseLab);
/* The result is an rvalue in primary */
ED_MakeRValExpr (Expr);
static void hieQuest (ExprDesc* Expr)
/* Parse the ternary operator */
{
- int labf;
- int labt;
+ int FalseLab;
+ int TrueLab;
+ CodeMark TrueCodeEnd;
ExprDesc Expr2; /* Expression 2 */
ExprDesc Expr3; /* Expression 3 */
int Expr2IsNULL; /* Expression 2 is a NULL pointer */
ED_MarkForTest (Expr);
}
LoadExpr (CF_NONE, Expr);
- labf = GetLocalLabel ();
- g_falsejump (CF_NONE, labf);
+ FalseLab = GetLocalLabel ();
+ g_falsejump (CF_NONE, FalseLab);
/* Parse second expression. Remember for later if it is a NULL pointer
* expression, then load it into the primary.
/* Load it into the primary */
LoadExpr (CF_NONE, &Expr2);
ED_MakeRValExpr (&Expr2);
+ Expr2.Type = PtrConversion (Expr2.Type);
}
- labt = GetLocalLabel ();
+
+ /* Remember the current code position */
+ GetCodePos (&TrueCodeEnd);
+
+ /* Jump around the evaluation of the third expression */
+ TrueLab = GetLocalLabel ();
ConsumeColon ();
- g_jump (labt);
+ g_jump (TrueLab);
/* Jump here if the first expression was false */
- g_defcodelabel (labf);
+ g_defcodelabel (FalseLab);
- /* Parse second expression. Remember for later if it is a NULL pointer
+ /* Parse third expression. Remember for later if it is a NULL pointer
* expression, then load it into the primary.
*/
ExprWithCheck (hie1, &Expr3);
/* Load it into the primary */
LoadExpr (CF_NONE, &Expr3);
ED_MakeRValExpr (&Expr3);
+ Expr3.Type = PtrConversion (Expr3.Type);
}
/* Check if any conversions are needed, if so, do them.
*/
if (IsClassInt (Expr2.Type) && IsClassInt (Expr3.Type)) {
+ CodeMark CvtCodeStart;
+ CodeMark CvtCodeEnd;
+
+
/* Get common type */
ResultType = promoteint (Expr2.Type, Expr3.Type);
/* Convert the third expression to this type if needed */
TypeConversion (&Expr3, 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 */
-
- /* The jump for expr2 goes here */
- g_defcodelabel (labt);
-
- /* Create the typecast code for expr2 */
+ /* Emit conversion code for the second expression, but remember
+ * where it starts end ends.
+ */
+ GetCodePos (&CvtCodeStart);
TypeConversion (&Expr2, ResultType);
+ GetCodePos (&CvtCodeEnd);
- /* Jump here around the typecase code. */
- g_defcodelabel (labf);
- labt = 0; /* Mark other label as invalid */
+ /* If we had conversion code, move it to the right place */
+ if (!CodeRangeIsEmpty (&CvtCodeStart, &CvtCodeEnd)) {
+ MoveCode (&CvtCodeStart, &CvtCodeEnd, &TrueCodeEnd);
+ }
} else if (IsClassPtr (Expr2.Type) && IsClassPtr (Expr3.Type)) {
/* Must point to same type */
ResultType = Expr2.Type; /* Doesn't matter here */
}
- /* If we don't have the label defined until now, do it */
- if (labt) {
- g_defcodelabel (labt);
- }
+ /* Define the final label */
+ g_defcodelabel (TrueLab);
/* Setup the target expression */
ED_MakeRValExpr (Expr);
-static void opeq (const GenDesc* Gen, ExprDesc* Expr)
+static void opeq (const GenDesc* Gen, ExprDesc* Expr, const char* Op)
/* Process "op=" operators. */
{
ExprDesc Expr2;
return;
}
+ /* The left side must not be const qualified */
+ if (IsQualConst (Expr->Type)) {
+ Error ("Assignment to const");
+ }
+
/* There must be an integer or pointer on the left side */
if (!IsClassInt (Expr->Type) && !IsTypePtr (Expr->Type)) {
Error ("Invalid left operand type");
g_push (flags, 0);
/* Evaluate the rhs */
- if (evalexpr (CF_NONE, hie1, &Expr2) == 0) {
+ MarkedExprWithCheck (hie1, &Expr2);
+
+ /* The rhs must be an integer (or a float, but we don't support that yet */
+ if (!IsClassInt (Expr2.Type)) {
+ Error ("Invalid right operand for binary operator `%s'", Op);
+ /* Continue. Wrong code will be generated, but the compiler won't
+ * break, so this is the best error recovery.
+ */
+ }
+
+ /* Check for a constant expression */
+ if (ED_IsConstAbs (&Expr2) && ED_CodeRangeIsEmpty (&Expr2)) {
/* The resulting value is a constant. If the generator has the NOPUSH
* flag set, don't push the lhs.
*/
} else if (Gen->Func == g_sub) {
g_dec (flags | CF_CONST, Expr2.IVal);
} else {
+ if (Expr2.IVal == 0) {
+ /* Check for div by zero/mod by zero */
+ if (Gen->Func == g_div) {
+ Error ("Division by zero");
+ } else if (Gen->Func == g_mod) {
+ Error ("Modulo operation with zero");
+ }
+ }
Gen->Func (flags | CF_CONST, Expr2.IVal);
}
} else {
- /* rhs is not constant and already in the primary register */
+
+ /* rhs is not constant. Load into the primary */
+ LoadExpr (CF_NONE, &Expr2);
if (MustScale) {
/* lhs is a pointer, scale rhs */
g_scale (TypeOf (Expr2.Type), CheckedSizeOf (Expr->Type+1));
-static void addsubeq (const GenDesc* Gen, ExprDesc *Expr)
+static void addsubeq (const GenDesc* Gen, ExprDesc *Expr, const char* Op)
/* Process the += and -= operators */
{
ExprDesc Expr2;
/* We're currently only able to handle some adressing modes */
if (ED_GetLoc (Expr) == E_LOC_EXPR || ED_GetLoc (Expr) == E_LOC_PRIMARY) {
/* Use generic routine */
- opeq (Gen, Expr);
+ opeq (Gen, Expr, Op);
return;
}
return;
}
+ /* The left side must not be const qualified */
+ if (IsQualConst (Expr->Type)) {
+ Error ("Assignment to const");
+ }
+
/* There must be an integer or pointer on the left side */
if (!IsClassInt (Expr->Type) && !IsTypePtr (Expr->Type)) {
Error ("Invalid left operand type");
lflags = 0;
rflags = 0;
- /* Evaluate the rhs */
+ /* Evaluate the rhs. We expect an integer here, since float is not
+ * supported
+ */
hie1 (&Expr2);
+ if (!IsClassInt (Expr2.Type)) {
+ Error ("Invalid right operand for binary operator `%s'", Op);
+ /* Continue. Wrong code will be generated, but the compiler won't
+ * break, so this is the best error recovery.
+ */
+ }
if (ED_IsConstAbs (&Expr2)) {
/* The resulting value is a constant. Scale it. */
if (MustScale) {
}
/* Setup the code generator flags */
- lflags |= TypeOf (Expr->Type) | CF_FORCECHAR;
- rflags |= TypeOf (Expr2.Type);
+ lflags |= TypeOf (Expr->Type) | GlobalModeFlags (Expr) | CF_FORCECHAR;
+ rflags |= TypeOf (Expr2.Type) | CF_FORCECHAR;
/* Convert the type of the lhs to that of the rhs */
g_typecast (lflags, rflags);
case E_LOC_ABS:
/* Absolute: numeric address or const */
- lflags |= CF_ABSOLUTE;
if (Gen->Tok == TOK_PLUS_ASSIGN) {
g_addeqstatic (lflags, Expr->Name, Expr->IVal, Expr2.IVal);
} else {
case E_LOC_GLOBAL:
/* Global variable */
- lflags |= CF_EXTERNAL;
if (Gen->Tok == TOK_PLUS_ASSIGN) {
g_addeqstatic (lflags, Expr->Name, Expr->IVal, Expr2.IVal);
} else {
case E_LOC_STATIC:
case E_LOC_LITERAL:
/* Static variable or literal in the literal pool */
- lflags |= CF_STATIC;
if (Gen->Tok == TOK_PLUS_ASSIGN) {
g_addeqstatic (lflags, Expr->Name, Expr->IVal, Expr2.IVal);
} else {
case E_LOC_REGISTER:
/* Register variable */
- lflags |= CF_REGVAR;
if (Gen->Tok == TOK_PLUS_ASSIGN) {
g_addeqstatic (lflags, Expr->Name, Expr->IVal, Expr2.IVal);
} else {
break;
case TOK_PLUS_ASSIGN:
- addsubeq (&GenPASGN, Expr);
+ addsubeq (&GenPASGN, Expr, "+=");
break;
case TOK_MINUS_ASSIGN:
- addsubeq (&GenSASGN, Expr);
+ addsubeq (&GenSASGN, Expr, "-=");
break;
case TOK_MUL_ASSIGN:
- opeq (&GenMASGN, Expr);
+ opeq (&GenMASGN, Expr, "*=");
break;
case TOK_DIV_ASSIGN:
- opeq (&GenDASGN, Expr);
+ opeq (&GenDASGN, Expr, "/=");
break;
case TOK_MOD_ASSIGN:
- opeq (&GenMOASGN, Expr);
+ opeq (&GenMOASGN, Expr, "%=");
break;
case TOK_SHL_ASSIGN:
- opeq (&GenSLASGN, Expr);
+ opeq (&GenSLASGN, Expr, "<<=");
break;
case TOK_SHR_ASSIGN:
- opeq (&GenSRASGN, Expr);
+ opeq (&GenSRASGN, Expr, ">>=");
break;
case TOK_AND_ASSIGN:
- opeq (&GenAASGN, Expr);
+ opeq (&GenAASGN, Expr, "&=");
break;
case TOK_XOR_ASSIGN:
- opeq (&GenXOASGN, Expr);
+ opeq (&GenXOASGN, Expr, "^=");
break;
case TOK_OR_ASSIGN:
- opeq (&GenOASGN, Expr);
+ opeq (&GenOASGN, Expr, "|=");
break;
default: