/* Predefined type strings */
+type type_schar[] = { T_SCHAR, T_END };
type type_uchar[] = { T_UCHAR, T_END };
type type_int[] = { T_INT, T_END };
type type_uint[] = { T_UINT, T_END };
+type* IntPromotion (type* T)
+/* Apply the integer promotions to T and return the result. The returned type
+ * string may be T if there is no need to change it.
+ */
+{
+ /* We must have an int to apply int promotions */
+ PRECONDITION (IsClassInt (T));
+
+ /* An integer can represent all values from either signed or unsigned char,
+ * so convert chars to int and leave all other types alone.
+ */
+ if (IsTypeChar (T)) {
+ return type_int;
+ } else {
+ return T;
+ }
+}
+
+
+
#define SIZEOF_PTR 2
/* Predefined type strings */
+extern type type_schar[];
extern type type_uchar[];
extern type type_int[];
extern type type_uint[];
type* GetElementType (type* T);
/* Return the element type of the given array type. */
+type* IntPromotion (type* T);
+/* Apply the integer promotions to T and return the result. The returned type
+ * string may be T if there is no need to change it.
+ */
+
/* End of datatype.h */
-/*****************************************************************************/
-/* Function forwards */
-/*****************************************************************************/
-
-
-
-void hie0 (ExprDesc *lval);
-/* Parse comma operator. */
-
-
-
/*****************************************************************************/
/* Helper functions */
/*****************************************************************************/
}
}
-
+
void ExprWithCheck (void (*Func) (ExprDesc*), ExprDesc *Expr)
/* Call an expression function with checks. */
-static void hie8 (ExprDesc* Expr)
+void hie8 (ExprDesc* Expr)
/* Process + and - binary operators. */
{
hie9 (Expr);
static void hie7 (ExprDesc* Expr)
-/* Parse << and >>. */
+/* Parse the << and >> operators. */
{
- static const GenDesc hie7_ops [] = {
- { TOK_SHL, GEN_NOPUSH, g_asl },
- { TOK_SHR, GEN_NOPUSH, g_asr },
- { TOK_INVALID, 0, 0 }
- };
- int UsedGen;
+ ExprDesc Expr2;
+ CodeMark Mark1;
+ CodeMark Mark2;
+ token_t Tok; /* The operator token */
+ unsigned ltype, rtype, flags;
+ int rconst; /* Operand is a constant */
+
+
+ /* Evaluate the lhs */
+ ExprWithCheck (hie8, Expr);
+
+ while (CurTok.Tok == TOK_SHL || CurTok.Tok == TOK_SHR) {
+
+ /* All operators that call this function expect an int on the lhs */
+ if (!IsClassInt (Expr->Type)) {
+ Error ("Integer expression expected");
+ ED_MakeConstAbsInt (Expr, 1);
+ }
- hie_internal (hie7_ops, Expr, hie8, &UsedGen);
+ /* Remember the operator token, then skip it */
+ Tok = CurTok.Tok;
+ NextToken ();
+
+ /* Get the lhs on stack */
+ Mark1 = GetCodePos ();
+ ltype = TypeOf (Expr->Type);
+ if (ED_IsConstAbs (Expr)) {
+ /* Constant value */
+ Mark2 = GetCodePos ();
+ g_push (ltype | CF_CONST, Expr->IVal);
+ } else {
+ /* Value not constant */
+ LoadExpr (CF_NONE, Expr);
+ Mark2 = GetCodePos ();
+ g_push (ltype, 0);
+ }
+
+ /* Get the right hand side */
+ ExprWithCheck (hie8, &Expr2);
+
+ /* Check the type of the rhs */
+ if (!IsClassInt (Expr2.Type)) {
+ Error ("Integer expression expected");
+ ED_MakeConstAbsInt (&Expr2, 1);
+ }
+
+ /* Check for a constant right side expression */
+ rconst = ED_IsConstAbs (&Expr2);
+ if (!rconst) {
+
+ /* Not constant, load into the primary */
+ LoadExpr (CF_NONE, &Expr2);
+
+ } else {
+
+ /* If the right hand side is constant, we can check a lot of
+ * things:
+ */
+
+ /* If the shift count is zero, nothing happens */
+ if (Expr2.IVal == 0) {
+
+ /* Result is already in Expr, remove the generated code */
+ RemoveCode (Mark1);
+ pop (ltype);
+
+ /* Done */
+ goto Next;
+ }
+
+ /* If the left hand side is a constant, the result is constant */
+ if (ED_IsConstAbs (Expr)) {
+
+ /* Evaluate the result */
+ Expr->IVal = kcalc (Tok, Expr->IVal, Expr2.IVal);
+
+ /* Both operands are constant, remove the generated code */
+ RemoveCode (Mark1);
+ pop (ltype);
+
+ /* Done */
+ goto Next;
+ }
+
+ /* If we're shifting to the left, and the shift count is larger
+ * or equal than the bit count of the integer type, the result
+ * is zero.
+ */
+ if (Tok == TOK_SHL && Expr2.IVal >= (long) SizeOf (Expr->Type) * 8) {
+
+ /* Set the result */
+ ED_MakeConstAbs (Expr, 0, Expr->Type);
+
+ /* Result is zero, remove the generated code */
+ RemoveCode (Mark1);
+ pop (ltype);
+
+ /* Done */
+ goto Next;
+ }
+
+ /* If we're shifting an integer or unsigned to the right, the
+ * lhs has a const address, and the shift count is larger than 8,
+ * we can load just the high byte as a char with the correct
+ * signedness, and reduce the shift count by 8. If the remaining
+ * shift count is zero, we're done.
+ */
+ if (Tok == TOK_SHR &&
+ IsTypeInt (Expr->Type) &&
+ ED_IsLVal (Expr) &&
+ (ED_IsLocConst (Expr) || ED_IsLocStack (Expr)) &&
+ Expr2.IVal >= 8) {
+
+ type* OldType;
+
+ /* Increase the address by one and decrease the shift count */
+ ++Expr->IVal;
+ Expr2.IVal -= 8;
+
+ /* Replace the type of the expression temporarily by the
+ * corresponding char type.
+ */
+ OldType = Expr->Type;
+ if (IsSignUnsigned (Expr->Type)) {
+ Expr->Type = type_uchar;
+ } else {
+ Expr->Type = type_schar;
+ }
+
+ /* Remove the generated load code */
+ RemoveCode (Mark1);
+ pop (ltype);
+
+ /* Generate again code for the load */
+ LoadExpr (CF_NONE, Expr);
+
+ /* Reset the type */
+ Expr->Type = OldType;
+
+ /* If the shift count is now zero, we're done */
+ if (Expr2.IVal == 0) {
+ /* Be sure to mark the value as in the primary */
+ goto Loaded;
+ }
+
+ /* Otherwise generate code to push the value */
+ Mark2 = GetCodePos ();
+ g_push (ltype, 0);
+ }
+
+ }
+
+ /* If the right hand side is a constant, remove the push of the
+ * primary register.
+ */
+ rtype = TypeOf (Expr2.Type);
+ flags = 0;
+ if (rconst) {
+ flags |= CF_CONST;
+ rtype |= CF_CONST;
+ RemoveCode (Mark2);
+ pop (ltype);
+ ltype |= CF_REG; /* Value is in register */
+ }
+
+ /* Determine the type of the operation result. */
+ flags |= g_typeadjust (ltype, rtype);
+
+ /* Generate code */
+ switch (Tok) {
+ case TOK_SHL: g_asl (flags, Expr2.IVal); break;
+ case TOK_SHR: g_asr (flags, Expr2.IVal); break;
+ default: break;
+ }
+
+Loaded:
+ /* We have a rvalue in the primary now */
+ ED_MakeRValExpr (Expr);
+
+Next:
+ /* Get the type of the result */
+ Expr->Type = promoteint (Expr->Type, Expr2.Type);
+ }
}
* is NULL, use lval->Type instead.
*/
-void hie0 (ExprDesc* Expr);
-/* Parse comma operator. */
-
int evalexpr (unsigned flags, void (*Func) (ExprDesc*), ExprDesc* Expr);
/* Will evaluate an expression via the given function. If the result is a
* constant, 0 is returned and the value is put in the lval struct. If the
void hie10 (ExprDesc* lval);
/* Handle ++, --, !, unary - etc. */
+void hie8 (ExprDesc* Expr);
+/* Process + and - binary operators. */
+
void hie1 (ExprDesc* lval);
/* Parse first level of expression hierarchy. */
+void hie0 (ExprDesc* Expr);
+/* Parse comma operator. */
+
void DefineData (ExprDesc* lval);
/* Output a data definition for the given expression */
Expr->Flags |= (E_LOC_EXPR | E_RTYPE_LVAL);
Expr->Name = 0;
Expr->IVal = 0; /* No offset */
- Expr->FVal = 0.0;
+ Expr->FVal = 0.0;
return Expr;
}
-int ED_IsConstAbs (const ExprDesc* Expr)
-/* Return true if the expression denotes a constant absolute value. This can be
- * a numeric constant, cast to any type.
- */
-{
- return (Expr->Flags & (E_MASK_LOC|E_MASK_RTYPE)) == (E_LOC_ABS|E_RTYPE_RVAL);
-}
-
-
-
int ED_IsConstAbsInt (const ExprDesc* Expr)
/* Return true if the expression is a constant (numeric) integer. */
{
* similar.
*/
-int ED_IsConstAbs (const ExprDesc* Expr);
+#if defined(HAVE_INLINE)
+INLINE int ED_IsConstAbs (const ExprDesc* Expr)
/* Return true if the expression denotes a constant absolute value. This can be
* a numeric constant, cast to any type.
*/
+{
+ return (Expr->Flags & (E_MASK_LOC|E_MASK_RTYPE)) == (E_LOC_ABS|E_RTYPE_RVAL);
+}
+#else
+# define ED_IsConstAbs(E) \
+ (((E)->Flags & (E_MASK_LOC|E_MASK_RTYPE)) == (E_LOC_ABS|E_RTYPE_RVAL))
+#endif
int ED_IsConstAbsInt (const ExprDesc* Expr);
/* Return true if the expression is a constant (numeric) integer. */
-
-/* C pre-processor functions */
-
+/*
+ * C pre-processor functions.
+ * Portions of this code are copyright (C) 1989 John R. Dunning.
+ * See copyleft.jrd for license information.
+ */
+
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
-/*
- * preproc.h
- *
- * Ullrich von Bassewitz, 07.06.1998
- */
+/*****************************************************************************/
+/* */
+/* preproc.h */
+/* */
+/* C preprocessor */
+/* */
+/* */
+/* */
+/* (C) 1998-2004 Ullrich von Bassewitz */
+/* Römerstraße 52 */
+/* D-70794 Filderstadt */
+/* EMail: uz@cc65.org */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
-/* Set when the pp calls expr() recursively */
+/* Set when the preprocessor calls ConstExpr() recursively */
extern unsigned char Preprocessing;
Error ("Illegal type");
}
+ /* If both types are equal, no conversion is needed */
+ if (TypeCmp (Expr->Type, NewType) >= TC_EQUAL) {
+ /* We're already done */
+ return;
+ }
+
/* Check for conversion problems */
if (IsClassInt (NewType)) {
if (IsClassPtr (Expr->Type)) {
/* Pointer -> int conversion */
Warning ("Converting pointer to integer without a cast");
- } else if (!IsClassInt (Expr->Type)) {
+ } else if (!IsClassInt (Expr->Type) && !IsClassFloat (Expr->Type)) {
Error ("Incompatible types");
}
+ } else if (IsClassFloat (NewType)) {
+
+ if (!IsClassFloat (Expr->Type) && !IsClassInt (Expr->Type)) {
+ Error ("Incompatible types");
+ }
+
} else if (IsClassPtr (NewType)) {
/* Handle conversions to pointer type */
/* Pointer to pointer assignment is valid, if:
* - both point to the same types, or
* - the rhs pointer is a void pointer, or
- * - the lhs pointer is a void pointer.
+ * - the lhs pointer is a void pointer.
*/
- if (!IsTypeVoid (Indirect (NewType)) && !IsTypeVoid (Indirect (Expr->Type))) {
- /* Compare the types */
- switch (TypeCmp (NewType, Expr->Type)) {
-
- case TC_INCOMPATIBLE:
- Error ("Incompatible pointer types");
- break;
-
- case TC_QUAL_DIFF:
- Error ("Pointer types differ in type qualifiers");
- break;
-
- default:
- /* Ok */
- break;
- }
- }
+ if (!IsTypeVoid (Indirect (NewType)) && !IsTypeVoid (Indirect (Expr->Type))) {
+ /* Compare the types */
+ switch (TypeCmp (NewType, Expr->Type)) {
+
+ 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 (Expr->Type)) {
/* Int to pointer assignment is valid only for constant zero */
if (!ED_IsConstAbsInt (Expr) || Expr->IVal != 0) {
Warning ("Converting integer to pointer without a cast");
}
- } else if (IsTypeFuncPtr (NewType) && IsTypeFunc(Expr->Type)) {
- /* Assignment of function to function pointer is allowed, provided
- * that both functions have the same parameter list.
- */
- if (TypeCmp (Indirect (NewType), Expr->Type) < TC_EQUAL) {
- Error ("Incompatible types");
- }
+ } else if (IsTypeFuncPtr (NewType) && IsTypeFunc(Expr->Type)) {
+ /* Assignment of function to function pointer is allowed, provided
+ * that both functions have the same parameter list.
+ */
+ if (TypeCmp (Indirect (NewType), Expr->Type) < TC_EQUAL) {
+ Error ("Incompatible types");
+ }
} else {
- Error ("Incompatible types");
- }
+ Error ("Incompatible types");
+ }
} else {