#include "scanner.h"
#include "shiftexpr.h"
#include "stackptr.h"
+#include "standard.h"
#include "stdfunc.h"
#include "symtab.h"
#include "typecmp.h"
/*****************************************************************************/
-/* Helper functions */
+/* Helper functions */
/*****************************************************************************/
-static unsigned GlobalModeFlags (unsigned Flags)
-/* Return the addressing mode flags for the variable with the given flags */
+static unsigned GlobalModeFlags (const ExprDesc* Expr)
+/* Return the addressing mode flags for the given expression */
{
- switch (Flags & E_MASK_LOC) {
+ 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 flags value: %u", Flags);
+ Internal ("GlobalModeFlags: Invalid location flags value: 0x%04X", Expr->Flags);
/* NOTREACHED */
return 0;
}
-void ExprWithCheck (void (*Func) (ExprDesc*), ExprDesc *Expr)
+void ExprWithCheck (void (*Func) (ExprDesc*), ExprDesc* Expr)
/* Call an expression function with checks. */
{
/* Remember the stack pointer */
-static type* promoteint (type* lhst, type* rhst)
+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 */
{
/* Rules for integer types:
if (IsSignUnsigned (lhst) || IsSignUnsigned (rhst)) {
return type_ulong;
} else {
- return type_long;
+ return type_long;
}
} else {
if (IsSignUnsigned (lhst) || IsSignUnsigned (rhst)) {
unsigned flags;
/* Get the type strings */
- type* lhst = lhs->Type;
- type* rhst = rhs->Type;
+ Type* lhst = lhs->Type;
+ Type* rhst = rhs->Type;
/* Generate type adjustment code if needed */
ltype = TypeOf (lhst);
-static int kcalc (token_t tok, long val1, long val2)
-/* Calculate an operation with left and right operand constant. */
-{
- switch (tok) {
- case TOK_EQ:
- return (val1 == val2);
- case TOK_NE:
- return (val1 != val2);
- case TOK_LT:
- return (val1 < val2);
- case TOK_LE:
- return (val1 <= val2);
- case TOK_GE:
- return (val1 >= val2);
- case TOK_GT:
- return (val1 > val2);
- case TOK_OR:
- return (val1 | val2);
- case TOK_XOR:
- return (val1 ^ val2);
- case TOK_AND:
- return (val1 & val2);
- case TOK_STAR:
- return (val1 * val2);
- case TOK_DIV:
- if (val2 == 0) {
- Error ("Division by zero");
- return 0x7FFFFFFF;
- }
- return (val1 / val2);
- case TOK_MOD:
- if (val2 == 0) {
- Error ("Modulo operation with zero");
- return 0;
- }
- return (val1 % val2);
- default:
- Internal ("kcalc: got token 0x%X\n", tok);
- return 0;
- }
-}
-
-
-
static const GenDesc* FindGen (token_t Tok, const GenDesc* Table)
/* Find a token in a generator table */
{
/*****************************************************************************/
-/* 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;
}
- /* Do we have more than one parameter in the frame? */
+ /* Do we have more than one parameter in the frame? */
if (FrameParams > 1) {
/* Okeydokey, setup the frame */
FrameOffs = StackPtr;
if ((Func->Flags & FD_VARIADIC) == 0) {
/* End of param list reached, no ellipsis */
Error ("Too many arguments in function call");
- }
+ }
/* Assume an ellipsis even in case of errors to avoid an error
* message for each other argument.
*/
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) {
RemoveCode (&Mark);
PtrOnStack = 0;
} else {
- /* Load from the saved copy */
+ /* Load from the saved copy */
g_getlocal (CF_PTR, PtrOffs);
}
} else {
* is an undefined macro and replace it by a constant value of zero.
*/
if (Preprocessing && CurTok.Tok == TOK_IDENT) {
+ NextToken ();
ED_MakeConstAbsInt (E, 0);
return;
}
/* IDENT is either an auto-declared function or an undefined variable. */
if (CurTok.Tok == TOK_LPAREN) {
- /* Declare a function returning int. For that purpose, prepare a
- * function signature for a function having an empty param list
- * and returning int.
+ /* C99 doesn't allow calls to undefined functions, so
+ * generate an error and otherwise a warning. Declare a
+ * function returning int. For that purpose, prepare a
+ * function signature for a function having an empty param
+ * list and returning int.
*/
- Warning ("Function call without a prototype");
+ if (IS_Get (&Standard) >= STD_C99) {
+ Error ("Call to undefined function `%s'", Ident);
+ } else {
+ Warning ("Call to undefined function `%s'", Ident);
+ }
Sym = AddGlobalSym (Ident, GetImplicitFuncType(), SC_EXTERN | SC_REF | SC_FUNC);
E->Type = Sym->Type;
E->Flags = E_LOC_GLOBAL | E_RTYPE_RVAL;
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;
- type* tptr1;
+ Type* ElementType;
+ Type* tptr1;
/* Skip the bracket */
* address. This is true for most arrays and will produce a lot better
* code. Check if this is a const base address.
*/
- ConstBaseAddr = ED_IsRVal (Expr) &&
+ ConstBaseAddr = ED_IsRVal (Expr) &&
(ED_IsLocConst (Expr) || ED_IsLocStack (Expr));
/* If we have a constant base, we delay the address fetch */
}
/* 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)) {
* constant, we call special functions to add the address to the
* offset value.
*/
- if (!ConstBaseAddr) {
+ if (!ConstBaseAddr) {
/* The array base address is on stack and the subscript is in the
* primary. Add both.
* often a better idea to reverse again the order of the
* evaluation. This will generate better code if the subscript is
* a byte sized variable. But beware: This is only possible if the
- * subscript was not scaled, that is, if this was a byte array
- * or pointer.
- */
- if ((ED_IsLocConst (&SubScript) || ED_IsLocStack (&SubScript)) &&
+ * subscript was not scaled, that is, if this was a byte array
+ * or pointer.
+ */
+ if ((ED_IsLocConst (&Subscript) || ED_IsLocStack (&Subscript)) &&
CheckedSizeOf (ElementType) == SIZEOF_CHAR) {
unsigned Flags;
- /* Reverse the order of evaluation */
- if (CheckedSizeOf (SubScript.Type) == SIZEOF_CHAR) {
+ /* Reverse the order of evaluation */
+ if (CheckedSizeOf (Subscript.Type) == SIZEOF_CHAR) {
Flags = CF_CHAR;
} else {
Flags = CF_INT;
}
RemoveCode (&Mark2);
- /* Get a pointer to the array into the primary. */
- LoadExpr (CF_NONE, Expr);
+ /* Get a pointer to the array into the primary. */
+ LoadExpr (CF_NONE, Expr);
- /* Add the variable */
- if (ED_IsLocStack (&SubScript)) {
- g_addlocal (Flags, SubScript.IVal);
- } else {
- Flags |= GlobalModeFlags (SubScript.Flags);
- g_addstatic (Flags, SubScript.Name, SubScript.IVal);
- }
- } else {
- if (ED_IsLocAbs (Expr)) {
- /* Constant numeric address. Just add it */
- g_inc (CF_INT, Expr->IVal);
- } else if (ED_IsLocStack (Expr)) {
- /* Base address is a local variable address */
- if (IsTypeArray (Expr->Type)) {
- g_addaddr_local (CF_INT, Expr->IVal);
+ /* Add the variable */
+ if (ED_IsLocStack (&Subscript)) {
+ g_addlocal (Flags, Subscript.IVal);
+ } else {
+ Flags |= GlobalModeFlags (&Subscript);
+ g_addstatic (Flags, Subscript.Name, Subscript.IVal);
+ }
+ } else {
+
+ if (ED_IsLocAbs (Expr)) {
+ /* Constant numeric address. Just add it */
+ g_inc (CF_INT, Expr->IVal);
+ } else if (ED_IsLocStack (Expr)) {
+ /* Base address is a local variable address */
+ if (IsTypeArray (Expr->Type)) {
+ g_addaddr_local (CF_INT, Expr->IVal);
} else {
- g_addlocal (CF_PTR, Expr->IVal);
+ g_addlocal (CF_PTR, Expr->IVal);
}
} else {
/* Base address is a static variable address */
- unsigned Flags = CF_INT | GlobalModeFlags (Expr->Flags);
- if (IsTypeArray (Expr->Type)) {
+ unsigned Flags = CF_INT | GlobalModeFlags (Expr);
+ if (ED_IsRVal (Expr)) {
+ /* Add the address of the location */
g_addaddr_static (Flags, Expr->Name, Expr->IVal);
} else {
+ /* Add the contents of the location */
g_addstatic (Flags, Expr->Name, Expr->IVal);
}
}
{
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);
+ }
}
static void hie11 (ExprDesc *Expr)
/* Handle compound types (structs and arrays) */
{
+ /* Name value used in invalid function calls */
+ static const char IllegalFunc[] = "illegal_function_call";
+
/* Evaluate the lhs */
Primary (Expr);
Error ("Illegal function call");
/* Force the type to be a implicitly defined function, one
* returning an int and taking any number of arguments.
- * Since we don't have a name, place it at absolute address
- * zero.
+ * Since we don't have a name, invent one.
*/
ED_MakeConstAbs (Expr, 0, GetImplicitFuncType ());
+ Expr->Name = (long) IllegalFunc;
}
/* Call the function */
FunctionCall (Expr);
-void Store (ExprDesc* Expr, const type* StoreType)
+void Store (ExprDesc* Expr, const Type* StoreType)
/* Store the primary register into the location denoted by Expr. If StoreType
* is given, use this type when storing instead of Expr->Type. If StoreType
* is NULL, use Expr->Type instead.
}
/* 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;
+
+ 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 ("Increment 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_inc (Flags | CF_CONST | CF_FORCECHAR, CheckedSizeOf (Expr->Type + 1));
+ } else {
+ 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;
return;
}
+ /* We cannot modify const values */
+ if (IsQualConst (Expr->Type)) {
+ Error ("Decrement 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_dec (Flags | CF_CONST | CF_FORCECHAR, CheckedSizeOf (Expr->Type + 1));
} else {
- inc (Flags | CF_CONST | CF_FORCECHAR, 1);
+ 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;
/* The & operator may be applied to any lvalue, and it may be
* applied to functions, even if they're no lvalues.
*/
- if (ED_IsRVal (Expr) && !IsTypeFunc (Expr->Type)) {
- /* Allow the & operator with an array */
- if (!IsTypeArray (Expr->Type)) {
- Error ("Illegal address");
- }
- } else {
+ if (ED_IsRVal (Expr) && !IsTypeFunc (Expr->Type) && !IsTypeArray (Expr->Type)) {
+ Error ("Illegal address");
+ } 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;
case TOK_SIZEOF:
NextToken ();
if (TypeSpecAhead ()) {
- type Type[MAXTYPELEN];
+ Type T[MAXTYPELEN];
NextToken ();
- Size = CheckedSizeOf (ParseType (Type));
+ Size = CheckedSizeOf (ParseType (T));
ConsumeRParen ();
} else {
/* Remember the output queue pointer */
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;
}
}
/* All operators that call this function expect an int on the lhs */
if (!IsClassInt (Expr->Type)) {
Error ("Integer expression expected");
+ /* To avoid further errors, make Expr a valid int expression */
+ ED_MakeConstAbsInt (Expr, 1);
}
/* Remember the operator token, then skip it */
}
/* 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)) {
/* Both operands are constant, remove the generated code */
RemoveCode (&Mark1);
- /* Evaluate the result */
- Expr->IVal = kcalc (Tok, Expr->IVal, Expr2.IVal);
-
/* Get the type of the result */
Expr->Type = promoteint (Expr->Type, Expr2.Type);
+ /* Handle the op differently for signed and unsigned types */
+ if (IsSignSigned (Expr->Type)) {
+
+ /* Evaluate the result for signed operands */
+ signed long Val1 = Expr->IVal;
+ signed long Val2 = Expr2.IVal;
+ switch (Tok) {
+ case TOK_OR:
+ Expr->IVal = (Val1 | Val2);
+ break;
+ case TOK_XOR:
+ Expr->IVal = (Val1 ^ Val2);
+ break;
+ case TOK_AND:
+ Expr->IVal = (Val1 & Val2);
+ break;
+ case TOK_STAR:
+ Expr->IVal = (Val1 * Val2);
+ break;
+ case TOK_DIV:
+ if (Val2 == 0) {
+ Error ("Division by zero");
+ Expr->IVal = 0x7FFFFFFF;
+ } else {
+ Expr->IVal = (Val1 / Val2);
+ }
+ break;
+ case TOK_MOD:
+ if (Val2 == 0) {
+ Error ("Modulo operation with zero");
+ Expr->IVal = 0;
+ } else {
+ Expr->IVal = (Val1 % Val2);
+ }
+ break;
+ default:
+ Internal ("hie_internal: got token 0x%X\n", Tok);
+ }
+ } else {
+
+ /* Evaluate the result for unsigned operands */
+ unsigned long Val1 = Expr->IVal;
+ unsigned long Val2 = Expr2.IVal;
+ switch (Tok) {
+ case TOK_OR:
+ Expr->IVal = (Val1 | Val2);
+ break;
+ case TOK_XOR:
+ Expr->IVal = (Val1 ^ Val2);
+ break;
+ case TOK_AND:
+ Expr->IVal = (Val1 & Val2);
+ break;
+ case TOK_STAR:
+ Expr->IVal = (Val1 * Val2);
+ break;
+ case TOK_DIV:
+ if (Val2 == 0) {
+ Error ("Division by zero");
+ Expr->IVal = 0xFFFFFFFF;
+ } else {
+ Expr->IVal = (Val1 / Val2);
+ }
+ break;
+ case TOK_MOD:
+ if (Val2 == 0) {
+ Error ("Modulo operation with zero");
+ Expr->IVal = 0;
+ } else {
+ Expr->IVal = (Val1 % Val2);
+ }
+ break;
+ default:
+ Internal ("hie_internal: got token 0x%X\n", Tok);
+ }
+ }
+
} else {
/* If the right hand side is constant, and the generator function
CodeMark Mark1;
CodeMark Mark2;
const GenDesc* Gen;
- token_t tok; /* The operator token */
+ token_t Tok; /* The operator token */
unsigned ltype;
int rconst; /* Operand is a constant */
while ((Gen = FindGen (CurTok.Tok, Ops)) != 0) {
/* Remember the operator token, then skip it */
- tok = CurTok.Tok;
+ Tok = CurTok.Tok;
NextToken ();
/* Get the lhs on stack */
}
/* 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 != T_VOID && *right != T_VOID) {
- /* Incomatible pointers */
- Error ("Incompatible types");
- }
+ 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 */
+ Error ("Incompatible types");
+ }
} else if (!ED_IsNullPtr (&Expr2)) {
- Error ("Incompatible types");
+ Error ("Incompatible types");
}
}
/* Check for const operands */
if (ED_IsConstAbs (Expr) && rconst) {
- /* Both operands are constant, remove the generated code */
- RemoveCode (&Mark1);
+ /* If the result is constant, this is suspicious when not in
+ * preprocessor mode.
+ */
+ if (!Preprocessing) {
+ Warning ("Result of comparison is constant");
+ }
- /* Evaluate the result */
- Expr->IVal = kcalc (tok, Expr->IVal, Expr2.IVal);
+ /* Both operands are constant, remove the generated code */
+ RemoveCode (&Mark1);
+
+ /* Determine if this is a signed or unsigned compare */
+ if (IsClassInt (Expr->Type) && IsSignSigned (Expr->Type) &&
+ IsClassInt (Expr2.Type) && IsSignSigned (Expr2.Type)) {
+
+ /* Evaluate the result for signed operands */
+ signed long Val1 = Expr->IVal;
+ signed long Val2 = Expr2.IVal;
+ switch (Tok) {
+ case TOK_EQ: Expr->IVal = (Val1 == Val2); break;
+ case TOK_NE: Expr->IVal = (Val1 != Val2); break;
+ case TOK_LT: Expr->IVal = (Val1 < Val2); break;
+ case TOK_LE: Expr->IVal = (Val1 <= Val2); break;
+ case TOK_GE: Expr->IVal = (Val1 >= Val2); break;
+ case TOK_GT: Expr->IVal = (Val1 > Val2); break;
+ default: Internal ("hie_compare: got token 0x%X\n", Tok);
+ }
+
+ } else {
+
+ /* Evaluate the result for unsigned operands */
+ unsigned long Val1 = Expr->IVal;
+ unsigned long Val2 = Expr2.IVal;
+ switch (Tok) {
+ case TOK_EQ: Expr->IVal = (Val1 == Val2); break;
+ case TOK_NE: Expr->IVal = (Val1 != Val2); break;
+ case TOK_LT: Expr->IVal = (Val1 < Val2); break;
+ case TOK_LE: Expr->IVal = (Val1 <= Val2); break;
+ case TOK_GE: Expr->IVal = (Val1 >= Val2); break;
+ case TOK_GT: Expr->IVal = (Val1 > Val2); break;
+ default: Internal ("hie_compare: got token 0x%X\n", Tok);
+ }
+ }
} else {
if (rconst) {
flags |= CF_CONST;
if ((Gen->Flags & GEN_NOPUSH) != 0) {
- RemoveCode (&Mark2);
+ RemoveCode (&Mark2);
ltype |= CF_REG; /* Value is in register */
}
}
ExprDesc Expr2;
unsigned flags; /* Operation flags */
CodeMark Mark; /* Remember code position */
- type* lhst; /* Type of left hand side */
- type* rhst; /* Type of right hand side */
+ Type* lhst; /* Type of left hand side */
+ Type* rhst; /* Type of right hand side */
/* Skip the PLUS token */
/* 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 {
+ } else {
/* lhs is a constant and rhs is not constant. Load rhs into
* the primary.
flags |= CF_CONST;
} else {
/* Constant address label */
- flags |= GlobalModeFlags (Expr->Flags) | CF_CONSTADDR;
+ flags |= GlobalModeFlags (Expr) | CF_CONSTADDR;
}
/* Check for pointer arithmetic */
*/
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) {
} else {
/* OOPS */
Error ("Invalid operands for binary operator `+'");
+ flags = CF_INT;
}
/* Result is a rvalue in primary register */
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 {
/* OOPS */
Error ("Invalid operands for binary operator `+'");
+ flags = CF_INT;
}
/* Generate code for the add */
} 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;
}
/* Generate code for the add */
*/
{
ExprDesc Expr2;
- unsigned flags; /* Operation flags */
- type* lhst; /* Type of left hand side */
- type* rhst; /* Type of right hand side */
- CodeMark Mark1; /* Save position of output queue */
+ unsigned flags; /* Operation flags */
+ Type* lhst; /* Type of left hand side */
+ Type* rhst; /* Type of right hand side */
+ CodeMark Mark1; /* Save position of output queue */
CodeMark Mark2; /* Another position in the queue */
- int rscale; /* Scale factor for the result */
+ int rscale; /* Scale factor for the result */
/* Skip the MINUS token */
/* Get the left hand side type, initialize operation flags */
lhst = Expr->Type;
- flags = 0;
rscale = 1; /* Scale by 1, that is, don't scale */
/* Remember the output queue position, then bring the value onto the stack */
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)) {
} else {
/* OOPS */
Error ("Invalid operands for binary operator `-'");
+ flags = CF_INT;
}
/* 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);
} else {
/* OOPS */
Error ("Invalid operands for binary operator `-'");
+ flags = CF_INT;
}
/* Generate code for the sub (the & is a hack here) */
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 */
int Expr3IsNULL; /* Expression 3 is a NULL pointer */
- type* ResultType; /* Type of result */
+ Type* ResultType; /* Type of result */
/* Call the lower level eval routine */
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: