#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
/* common */
#include "check.h"
+#include "debugflag.h"
#include "xmalloc.h"
/* cc65 */
#include "asmcode.h"
#include "asmlabel.h"
#include "asmstmt.h"
+#include "assignment.h"
#include "codegen.h"
-#include "datatype.h"
#include "declare.h"
#include "error.h"
#include "funcdesc.h"
#include "scanner.h"
#include "stdfunc.h"
#include "symtab.h"
+#include "typecast.h"
#include "typecmp.h"
#include "expr.h"
-static int hie10 (ExprDesc* lval);
-/* Handle ++, --, !, unary - etc. */
+static int hie0 (ExprDesc *lval);
+/* Parse comma operator. */
+
+static int expr (int (*func) (ExprDesc*), ExprDesc *lval);
+/* Expression parser; func is either hie0 or hie1. */
-static void lconst (unsigned Flags, ExprDesc* Expr)
+static void LoadConstant (unsigned Flags, ExprDesc* Expr)
/* Load the primary register with some constant value. */
{
switch (Expr->Flags & E_MCTYPE) {
-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) {
(NextTok.Tok == TOK_CONST) ||
(NextTok.Tok == TOK_IDENT &&
(Entry = FindSym (NextTok.Ident)) != 0 &&
- IsTypeDef (Entry)));
+ SymIsTypeDef (Entry)));
}
-static void PushAddr (ExprDesc* lval)
+void PushAddr (ExprDesc* lval)
/* If the expression contains an address that was somehow evaluated,
* push this address on the stack. This is a helper function for all
* sorts of implicit or explicit assignment functions where the lvalue
{
/* Get the address on stack if needed */
if (lval->Flags != E_MREG && (lval->Flags & E_MEXPR)) {
- /* Push the address (always a pointer) */
- g_push (CF_PTR, 0);
+ /* Push the address (always a pointer) */
+ g_push (CF_PTR, 0);
}
}
-static void MakeConstIntExpr (ExprDesc* Expr, long Value)
-/* Make Expr a constant integer expression with the given value */
-{
- Expr->Flags = E_MCONST;
- Expr->Type = type_int;
- Expr->ConstVal = Value;
-}
-
-
-
void ConstSubExpr (int (*F) (ExprDesc*), ExprDesc* Expr)
/* Will evaluate an expression via the given function. If the result is not
* a constant, a diagnostic will be printed, and the value is replaced by
* from this input error.
*/
{
- memset (Expr, 0, sizeof (*Expr));
+ InitExprDesc (Expr);
if (F (Expr) != 0 || Expr->Flags != E_MCONST) {
Error ("Constant expression expected");
/* To avoid any compiler errors, make the expression a valid const */
- MakeConstIntExpr (Expr, 1);
+ MakeConstIntExpr (Expr, 1);
+ }
+}
+
+
+
+void CheckBoolExpr (ExprDesc* lval)
+/* Check if the given expression is a boolean expression, output a diagnostic
+ * if not.
+ */
+{
+ /* If it's an integer, it's ok. If it's not an integer, but a pointer,
+ * the pointer used in a boolean context is also ok
+ */
+ if (!IsClassInt (lval->Type) && !IsClassPtr (lval->Type)) {
+ Error ("Boolean expression expected");
+ /* To avoid any compiler errors, make the expression a valid int */
+ MakeConstIntExpr (lval, 1);
}
}
-void exprhs (unsigned flags, int k, ExprDesc *lval)
+void exprhs (unsigned flags, int k, ExprDesc* lval)
/* Put the result of an expression into the primary register */
{
int f;
f = lval->Flags;
if (k) {
/* Dereferenced lvalue */
- flags |= TypeOf (lval->Type);
+ flags |= TypeOf (lval->Type);
if (lval->Test & E_FORCETEST) {
flags |= CF_TEST;
lval->Test &= ~E_FORCETEST;
g_inc (flags | CF_CONST, lval->ConstVal);
} else if ((f & E_MEXPR) == 0) {
/* Constant of some sort, load it into the primary */
- lconst (flags, lval);
+ LoadConstant (flags, lval);
}
- if (lval->Test & E_FORCETEST) { /* we testing this value? */
- /* debug... */
+ /* Are we testing this value? */
+ if (lval->Test & E_FORCETEST) {
+ /* Yes, force a test */
flags |= TypeOf (lval->Type);
- g_test (flags); /* yes, force a test */
+ g_test (flags);
lval->Test &= ~E_FORCETEST;
}
}
*/
if (CurTok.Tok == TOK_LPAREN) {
NextToken ();
- memset (lval, 0, sizeof (*lval)); /* Remove any attributes */
+ InitExprDesc (lval); /* Remove any attributes */
k = hie0 (lval);
ConsumeRParen ();
return k;
}
+ /* If we run into an identifier in preprocessing mode, we assume that this
+ * is an undefined macro and replace it by a constant value of zero.
+ */
+ if (Preprocessing && CurTok.Tok == TOK_IDENT) {
+ MakeConstIntExpr (lval, 0);
+ return 0;
+ }
+
/* All others may only be used if the expression evaluation is not called
* recursively by the preprocessor.
*/
/* Check for legal symbol types */
if ((Sym->Flags & SC_CONST) == SC_CONST) {
/* Enum or some other numeric constant */
- lval->Flags = E_MCONST;
+ lval->Flags = E_MCONST | E_TCONST;
lval->ConstVal = Sym->V.ConstVal;
return 0;
} else if ((Sym->Flags & SC_FUNC) == SC_FUNC) {
lval->Flags = E_MLOCAL | E_TLOFFS;
lval->ConstVal = Sym->V.Offs;
}
+ } else if ((Sym->Flags & SC_REGISTER) == SC_REGISTER) {
+ /* Register variable, zero page based */
+ lval->Flags = E_MGLOBAL | E_MCONST | E_TREGISTER;
+ lval->Name = Sym->V.R.RegOffs;
+ lval->ConstVal = 0;
} else if ((Sym->Flags & SC_STATIC) == SC_STATIC) {
/* Static variable */
if (Sym->Flags & (SC_EXTERN | SC_STORAGE)) {
lval->Name = Sym->V.Label;
}
lval->ConstVal = 0;
- } else if ((Sym->Flags & SC_REGISTER) == SC_REGISTER) {
- /* Register variable, zero page based */
- lval->Flags = E_MGLOBAL | E_MCONST | E_TREGISTER;
- lval->Name = Sym->V.Offs;
- lval->ConstVal = 0;
} else {
/* Local static variable */
lval->Flags = E_MGLOBAL | E_MCONST | E_TLLAB;
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 ||
(rflags & E_MGLOBAL) != 0 || /* Static array, or ... */
rflags == E_MLOCAL; /* Local array */
- if (ConstSubAddr && CheckedSizeOf (lval->Type) == 1) {
+ if (ConstSubAddr && CheckedSizeOf (lval->Type) == SIZEOF_CHAR) {
type* SavedType;
/* Reverse the order of evaluation */
- unsigned flags = (CheckedSizeOf (lval2.Type) == 1)? CF_CHAR : CF_INT;
+ unsigned flags = (CheckedSizeOf (lval2.Type) == SIZEOF_CHAR)? CF_CHAR : CF_INT;
RemoveCode (Mark2);
/* Get a pointer to the array into the primary. We have changed
if (rflags == E_MLOCAL) {
g_addlocal (flags, lval2.ConstVal);
} else {
- flags |= GlobalModeFlags (lval2.Flags);
+ flags |= GlobalModeFlags (lval2.Flags);
g_addstatic (flags, lval2.Name, lval2.ConstVal);
}
} else {
/* Constant numeric address. Just add it */
g_inc (CF_INT | CF_UNSIGNED, lval->ConstVal);
} else if (lflags == E_MLOCAL) {
- /* Base address is a local variable address */
- if (IsTypeArray (tptr1)) {
+ /* Base address is a local variable address */
+ if (IsTypeArray (tptr1)) {
g_addaddr_local (CF_INT, lval->ConstVal);
- } else {
+ } else {
g_addlocal (CF_PTR, lval->ConstVal);
- }
+ }
} else {
/* Base address is a static variable address */
unsigned flags = CF_INT;
- flags |= GlobalModeFlags (lval->Flags);
- if (IsTypeArray (tptr1)) {
+ flags |= GlobalModeFlags (lval->Flags);
+ if (IsTypeArray (tptr1)) {
g_addaddr_static (flags, lval->Name, lval->ConstVal);
- } else {
- g_addstatic (flags, lval->Name, lval->ConstVal);
- }
+ } else {
+ g_addstatic (flags, lval->Name, lval->ConstVal);
+ }
}
}
}
flags = lval->Flags & ~E_MCTYPE;
if (flags == E_MCONST ||
(k == 0 && (flags == E_MLOCAL ||
- (flags & E_MGLOBAL) != 0 ||
- lval->Flags == E_MEOFFS))) {
+ (flags & E_MGLOBAL) != 0 ||
+ lval->Flags == E_MEOFFS))) {
lval->ConstVal += Field->V.Offs;
} else {
if ((flags & E_MEXPR) == 0 || k != 0) {
-static void store (ExprDesc* lval)
-/* Store primary reg into this reference */
+void Store (ExprDesc* lval, const type* StoreType)
+/* Store the primary register into the location denoted by lval. If StoreType
+ * is given, use this type when storing instead of lval->Type. If StoreType
+ * is NULL, use lval->Type instead.
+ */
{
- int f;
- unsigned flags;
+ unsigned Flags;
- f = lval->Flags;
- flags = TypeOf (lval->Type);
+ unsigned f = lval->Flags;
+
+ /* If StoreType was not given, use lval->Type instead */
+ if (StoreType == 0) {
+ StoreType = lval->Type;
+ }
+
+ /* Get the code generator flags */
+ Flags = TypeOf (StoreType);
if (f & E_MGLOBAL) {
- flags |= GlobalModeFlags (f);
+ Flags |= GlobalModeFlags (f);
if (lval->Test) {
- /* Just testing */
- flags |= CF_TEST;
- }
+ /* Just testing */
+ Flags |= CF_TEST;
+ }
/* Generate code */
- g_putstatic (flags, lval->Name, lval->ConstVal);
+ g_putstatic (Flags, lval->Name, lval->ConstVal);
} else if (f & E_MLOCAL) {
- g_putlocal (flags, lval->ConstVal, 0);
+ /* Store an auto variable */
+ g_putlocal (Flags, lval->ConstVal, 0);
} else if (f == E_MEOFFS) {
- g_putind (flags, lval->ConstVal);
+ /* Store indirect with offset */
+ g_putind (Flags, lval->ConstVal);
} else if (f != E_MREG) {
if (f & E_MEXPR) {
- g_putind (flags, 0);
+ /* Indirect without offset */
+ g_putind (Flags, 0);
} else {
/* Store into absolute address */
- g_putstatic (flags | CF_ABSOLUTE, lval->ConstVal, 0);
+ g_putstatic (Flags | CF_ABSOLUTE, lval->ConstVal, 0);
}
}
inc (flags, val);
/* Store the result back */
- store (lval);
+ Store (lval, 0);
} else {
-static void post_incdec (ExprDesc *lval, int k, void (*inc) (unsigned, unsigned long))
+static void post_incdec (ExprDesc* lval, int k, void (*inc) (unsigned, unsigned long))
/* Handle i-- and i++ */
{
unsigned flags;
}
/* Store the result back */
- store (lval);
+ Store (lval, 0);
/* Restore the original value */
g_restore (flags | CF_FORCECHAR);
-static int typecast (ExprDesc* lval)
-/* Handle an explicit cast */
-{
- int k;
- type Type[MAXTYPELEN];
-
- /* Skip the left paren */
- NextToken ();
-
- /* Read the type */
- ParseType (Type);
-
- /* Closing paren */
- ConsumeRParen ();
-
- /* Read the expression we have to cast */
- k = hie10 (lval);
-
- /* If the expression is a function, treat it as pointer-to-function */
- if (IsTypeFunc (lval->Type)) {
- lval->Type = PointerTo (lval->Type);
- }
-
- /* Check for a constant on the right side */
- if (k == 0 && lval->Flags == E_MCONST) {
-
- /* A cast of a constant to something else. If the new type is an int,
- * be sure to handle the size extension correctly. If the new type is
- * not an int, the cast is implementation specific anyway, so leave
- * the value alone.
- */
- if (IsClassInt (Type)) {
-
- /* Get the current and new size of the value */
- unsigned OldSize = CheckedSizeOf (lval->Type);
- unsigned NewSize = CheckedSizeOf (Type);
- unsigned OldBits = OldSize * 8;
- unsigned NewBits = NewSize * 8;
-
- /* Check if the new datatype will have a smaller range */
- if (NewSize < OldSize) {
-
- /* Cut the value to the new size */
- lval->ConstVal &= (0xFFFFFFFFUL >> (32 - NewBits));
-
- /* If the new value is signed, sign extend the value */
- if (!IsSignUnsigned (Type)) {
- lval->ConstVal |= ((~0L) << NewBits);
- }
-
- } else if (NewSize > OldSize) {
-
- /* Sign extend the value if needed */
- if (!IsSignUnsigned (Type) && !IsSignUnsigned (lval->Type)) {
- if (lval->ConstVal & (0x01UL << (OldBits-1))) {
- lval->ConstVal |= ((~0L) << OldBits);
- }
- }
- }
- }
-
- } else {
-
- /* Not a constant. Be sure to ignore casts to void */
- if (!IsTypeVoid (Type)) {
-
- /* If the size does not change, leave the value alone. Otherwise,
- * we have to load the value into the primary and generate code to
- * cast the value in the primary register.
- */
- if (SizeOf (Type) != SizeOf (lval->Type)) {
-
- /* Load the value into the primary */
- exprhs (CF_NONE, k, lval);
-
- /* Mark the lhs as const to avoid a manipulation of TOS */
- g_typecast (TypeOf (Type) | CF_CONST, TypeOf (lval->Type));
-
- /* Value is now in primary */
- lval->Flags = E_MEXPR;
- k = 0;
- }
- }
- }
-
- /* In any case, use the new type */
- lval->Type = TypeDup (Type);
-
- /* Done */
- return k;
-}
-
-
-
-static int hie10 (ExprDesc* lval)
+int hie10 (ExprDesc* lval)
/* Handle ++, --, !, unary - etc. */
{
int k;
case TOK_BOOL_NOT:
NextToken ();
if (evalexpr (CF_NONE, hie10, lval) == 0) {
- /* Constant expression */
- lval->ConstVal = !lval->ConstVal;
+ /* Constant expression */
+ lval->ConstVal = !lval->ConstVal;
} else {
- g_bneg (TypeOf (lval->Type));
- lval->Test |= E_CC; /* bneg will set cc */
- lval->Flags = E_MEXPR; /* say it's an expr */
+ g_bneg (TypeOf (lval->Type));
+ lval->Test |= E_CC; /* bneg will set cc */
+ lval->Flags = E_MEXPR; /* say it's an expr */
}
return 0; /* expr not storable */
case TOK_STAR:
NextToken ();
if (evalexpr (CF_NONE, hie10, lval) != 0) {
- /* Expression is not const, indirect value loaded into primary */
- lval->Flags = E_MEXPR;
- lval->ConstVal = 0; /* Offset is zero now */
+ /* Expression is not const, indirect value loaded into primary */
+ lval->Flags = E_MEXPR;
+ lval->ConstVal = 0; /* Offset is zero now */
}
- t = lval->Type;
- if (IsClassPtr (t)) {
- lval->Type = Indirect (t);
- } else {
- Error ("Illegal indirection");
- }
- return 1;
+ /* If the expression is already a pointer to function, the
+ * additional dereferencing operator must be ignored.
+ */
+ if (IsTypeFuncPtr (lval->Type)) {
+ /* Expression not storable */
+ return 0;
+ } else {
+ if (IsClassPtr (lval->Type)) {
+ lval->Type = Indirect (lval->Type);
+ } else {
+ Error ("Illegal indirection");
+ }
+ return 1;
+ }
+ break;
case TOK_AND:
NextToken ();
* applied to functions, even if they're no lvalues.
*/
if (k == 0 && !IsTypeFunc (lval->Type)) {
- /* Allow the & operator with an array */
- if (!IsTypeArray (lval->Type)) {
- Error ("Illegal address");
- }
+ /* Allow the & operator with an array */
+ if (!IsTypeArray (lval->Type)) {
+ Error ("Illegal address");
+ }
} else {
- t = TypeAlloc (TypeLen (lval->Type) + 2);
- t [0] = T_PTR;
- TypeCpy (t + 1, lval->Type);
- lval->Type = t;
+ t = TypeAlloc (TypeLen (lval->Type) + 2);
+ t [0] = T_PTR;
+ TypeCpy (t + 1, lval->Type);
+ lval->Type = t;
}
return 0;
case TOK_SIZEOF:
NextToken ();
if (istypeexpr ()) {
- type Type[MAXTYPELEN];
- NextToken ();
- lval->ConstVal = CheckedSizeOf (ParseType (Type));
- ConsumeRParen ();
+ type Type[MAXTYPELEN];
+ NextToken ();
+ lval->ConstVal = CheckedSizeOf (ParseType (Type));
+ ConsumeRParen ();
} else {
- /* Remember the output queue pointer */
- CodeMark Mark = GetCodePos ();
- hie10 (lval);
+ /* Remember the output queue pointer */
+ CodeMark Mark = GetCodePos ();
+ hie10 (lval);
lval->ConstVal = CheckedSizeOf (lval->Type);
- /* Remove any generated code */
- RemoveCode (Mark);
+ /* Remove any generated code */
+ RemoveCode (Mark);
}
lval->Flags = E_MCONST | E_TCONST;
lval->Type = type_uint;
default:
if (istypeexpr ()) {
- /* A cast */
- return typecast (lval);
+ /* A cast */
+ return TypeCast (lval);
}
}
static int hie_internal (const GenDesc** ops, /* List of generators */
ExprDesc* lval, /* parent expr's lval */
int (*hienext) (ExprDesc*),
- int* UsedGen) /* next higher level */
+ int* UsedGen) /* next higher level */
/* Helper function */
{
int k;
g_scale (CF_INT, CheckedPSizeOf (lhst));
/* Operate on pointers, result type is a pointer */
flags |= CF_PTR;
- /* Generate the code for the add */
- if (lval->Flags == E_MCONST) {
- /* Numeric constant */
- g_inc (flags, lval->ConstVal);
- } else {
- /* Constant address */
- g_addaddr_static (flags, lval->Name, lval->ConstVal);
- }
+ /* Generate the code for the add */
+ if (lval->Flags == E_MCONST) {
+ /* Numeric constant */
+ g_inc (flags, lval->ConstVal);
+ } else {
+ /* Constant address */
+ g_addaddr_static (flags, lval->Name, lval->ConstVal);
+ }
} else if (IsClassInt (lhst) && IsClassPtr (rhst)) {
/* Left is int, right is pointer, must scale lhs. */
- unsigned ScaleFactor = CheckedPSizeOf (rhst);
+ unsigned ScaleFactor = CheckedPSizeOf (rhst);
/* Operate on pointers, result type is a pointer */
- flags |= CF_PTR;
- lval->Type = lval2.Type;
-
- /* Since we do already have rhs in the primary, if lhs is
- * not a numeric constant, and the scale factor is not one
- * (no scaling), we must take the long way over the stack.
- */
- if (lval->Flags == E_MCONST) {
- /* Numeric constant, scale lhs */
- lval->ConstVal *= ScaleFactor;
- /* Generate the code for the add */
- g_inc (flags, lval->ConstVal);
- } else if (ScaleFactor == 1) {
- /* Constant address but no need to scale */
- g_addaddr_static (flags, lval->Name, lval->ConstVal);
- } else {
- /* Constant address that must be scaled */
+ flags |= CF_PTR;
+ lval->Type = lval2.Type;
+
+ /* Since we do already have rhs in the primary, if lhs is
+ * not a numeric constant, and the scale factor is not one
+ * (no scaling), we must take the long way over the stack.
+ */
+ if (lval->Flags == E_MCONST) {
+ /* Numeric constant, scale lhs */
+ lval->ConstVal *= ScaleFactor;
+ /* Generate the code for the add */
+ g_inc (flags, lval->ConstVal);
+ } else if (ScaleFactor == 1) {
+ /* Constant address but no need to scale */
+ g_addaddr_static (flags, lval->Name, lval->ConstVal);
+ } else {
+ /* Constant address that must be scaled */
g_push (TypeOf (lval2.Type), 0); /* rhs --> stack */
- g_getimmed (flags, lval->Name, lval->ConstVal);
- g_scale (CF_PTR, ScaleFactor);
- g_add (CF_PTR, 0);
- }
+ g_getimmed (flags, lval->Name, lval->ConstVal);
+ g_scale (CF_PTR, ScaleFactor);
+ g_add (CF_PTR, 0);
+ }
} else if (IsClassInt (lhst) && IsClassInt (rhst)) {
/* Integer addition */
flags |= typeadjust (lval, &lval2, 1);
- /* Generate the code for the add */
- if (lval->Flags == E_MCONST) {
- /* Numeric constant */
- g_inc (flags, lval->ConstVal);
- } else {
- /* Constant address */
- g_addaddr_static (flags, lval->Name, lval->ConstVal);
- }
+ /* Generate the code for the add */
+ if (lval->Flags == E_MCONST) {
+ /* Numeric constant */
+ g_inc (flags, lval->ConstVal);
+ } else {
+ /* Constant address */
+ g_addaddr_static (flags, lval->Name, lval->ConstVal);
+ }
} else {
/* OOPS */
Error ("Invalid operands for binary operator `+'");
flags = CF_PTR;
lval->Type = lval2.Type;
} else if (IsClassInt (lhst) && IsClassInt (rhst)) {
- /* Integer addition */
- flags = typeadjust (lval, &lval2, 0);
+ /* Integer addition. Note: Result is never constant.
+ * Problem here is that typeadjust does not know if the
+ * variable is an rvalue or lvalue, so if both operands
+ * are dereferenced constant numeric addresses, typeadjust
+ * thinks the operation works on constants. Removing
+ * CF_CONST here means handling the symptoms, however, the
+ * whole parser is such a mess that I fear to break anything
+ * when trying to apply another solution.
+ */
+ flags = typeadjust (lval, &lval2, 0) & ~CF_CONST;
} else {
/* OOPS */
Error ("Invalid operands for binary operator `+'");
type* type2; /* Type of expression 2 */
type* type3; /* Type of expression 3 */
type* rtype; /* Type of result */
- CodeMark Mark1; /* Save position in output code */
- CodeMark Mark2; /* Save position in output code */
-
k = Preprocessing? hieOrPP (lval) : hieOr (lval);
labf = GetLocalLabel ();
g_falsejump (CF_NONE, labf);
- /* Parse second and third expression */
- expression1 (&lval2);
+ /* Parse second expression */
+ k = expr (hie1, &lval2);
+ type2 = lval2.Type;
+ if (!IsTypeVoid (lval2.Type)) {
+ /* Load it into the primary */
+ exprhs (CF_NONE, k, &lval2);
+ }
labt = GetLocalLabel ();
ConsumeColon ();
g_jump (labt);
+
+ /* Parse the third expression */
g_defcodelabel (labf);
- expression1 (&lval3);
+ k = expr (hie1, &lval3);
+ type3 = lval3.Type;
+ if (!IsTypeVoid (lval3.Type)) {
+ /* Load it into the primary */
+ exprhs (CF_NONE, k, &lval3);
+ }
/* Check if any conversions are needed, if so, do them.
* Conversion rules for ?: expression are:
* - if one of the expressions is a pointer and the other is
* a zero constant, the resulting type is that of the pointer
* type.
+ * - if both expressions are void expressions, the result is of
+ * type void.
* - all other cases are flagged by an error.
*/
- type2 = lval2.Type;
- type3 = lval3.Type;
if (IsClassInt (type2) && IsClassInt (type3)) {
/* Get common type */
* the type cast code for expr2.
*/
labf = GetLocalLabel (); /* Get new label */
- Mark1 = GetCodePos (); /* Remember current position */
g_jump (labf); /* Jump around code */
/* The jump for expr2 goes here */
g_defcodelabel (labt);
/* Create the typecast code for expr2 */
- Mark2 = GetCodePos (); /* Remember position */
g_typecast (TypeOf (rtype), TypeOf (type2));
/* Jump here around the typecase code. */
} else if (IsClassPtr (type2) && IsClassPtr (type3)) {
/* Must point to same type */
if (TypeCmp (Indirect (type2), Indirect (type3)) < TC_EQUAL) {
- Error ("Incompatible pointer types");
+ Error ("Incompatible pointer types");
}
/* Result has the common type */
rtype = lval2.Type;
} else if (IsNullPtr (&lval2) && IsClassPtr (type3)) {
/* Result type is pointer, no cast needed */
rtype = lval3.Type;
+ } else if (IsTypeVoid (type2) && IsTypeVoid (type3)) {
+ /* Result type is void */
+ rtype = lval3.Type;
} else {
Error ("Incompatible types");
rtype = lval2.Type; /* Doesn't matter here */
/* If the lhs is character sized, the operation may be later done
* with characters.
*/
- if (CheckedSizeOf (lval->Type) == 1) {
+ if (CheckedSizeOf (lval->Type) == SIZEOF_CHAR) {
flags |= CF_FORCECHAR;
}
/* If the lhs is character sized, the operation may be later done
* with characters.
*/
- if (CheckedSizeOf (lval->Type) == 1) {
+ if (CheckedSizeOf (lval->Type) == SIZEOF_CHAR) {
flags |= CF_FORCECHAR;
}
/* Adjust the types of the operands if needed */
Gen->Func (g_typeadjust (flags, TypeOf (lval2.Type)), 0);
}
- store (lval);
+ Store (lval, 0);
lval->Flags = E_MEXPR;
}
-static void Assignment (ExprDesc* lval)
-/* Parse an assignment */
-{
- int k;
- ExprDesc lval2;
- unsigned flags;
- type* ltype = lval->Type;
-
- /* Check for assignment to const */
- if (IsQualConst (ltype)) {
- Error ("Assignment to const");
- }
-
- /* cc65 does not have full support for handling structs by value. Since
- * assigning structs is one of the more useful operations from this
- * family, allow it here.
- */
- if (IsClassStruct (ltype)) {
-
- /* Bring the address of the lhs into the primary and push it */
- exprhs (0, 0, lval);
- g_push (CF_PTR | CF_UNSIGNED, 0);
-
- /* Get the expression on the right of the '=' into the primary */
- k = hie1 (&lval2);
- if (k) {
- /* Get the address */
- exprhs (0, 0, &lval2);
- }
-
- /* Push the address (or whatever is in ax in case of errors) */
- g_push (CF_PTR | CF_UNSIGNED, 0);
-
- /* Check for equality of the structs */
- if (TypeCmp (ltype, lval2.Type) < TC_STRICT_COMPATIBLE) {
- Error ("Incompatible types");
- }
-
- /* Load the size of the struct into the primary */
- g_getimmed (CF_INT | CF_UNSIGNED | CF_CONST, CheckedSizeOf (ltype), 0);
-
- /* Call the memcpy function */
- g_call (CF_FIXARGC, "memcpy", 4);
-
- } else {
-
- /* Get the address on stack if needed */
- PushAddr (lval);
-
- /* No struct, setup flags for the load */
- flags = CheckedSizeOf (ltype) == 1? CF_FORCECHAR : CF_NONE;
-
- /* Get the expression on the right of the '=' into the primary */
- if (evalexpr (flags, hie1, &lval2) == 0) {
- /* Constant expression. Adjust the types */
- assignadjust (ltype, &lval2);
- /* Put the value into the primary register */
- lconst (flags, &lval2);
- } else {
- /* Expression is not constant and already in the primary */
- assignadjust (ltype, &lval2);
- }
-
- /* Generate a store instruction */
- store (lval);
-
- }
-
- /* Value is still in primary */
- lval->Flags = E_MEXPR;
-}
-
-
-
int hie1 (ExprDesc* lval)
/* Parse first level of expression hierarchy. */
{
-int hie0 (ExprDesc *lval)
+static int hie0 (ExprDesc *lval)
/* Parse comma operator. */
{
int k;
-int expr (int (*func) (ExprDesc*), ExprDesc *lval)
+static int expr (int (*func) (ExprDesc*), ExprDesc *lval)
/* Expression parser; func is either hie0 or hie1. */
{
int k;
* the primary register
*/
{
- memset (lval, 0, sizeof (*lval));
+ InitExprDesc (lval);
exprhs (CF_NONE, expr (hie1, lval), lval);
}
void expression (ExprDesc* lval)
/* Evaluate an expression and put it into the primary register */
{
- memset (lval, 0, sizeof (*lval));
+ InitExprDesc (lval);
exprhs (CF_NONE, expr (hie0, lval), lval);
}
void ConstExpr (ExprDesc* lval)
/* Get a constant value */
{
- memset (lval, 0, sizeof (*lval));
+ InitExprDesc (lval);
if (expr (hie1, lval) != 0 || (lval->Flags & E_MCONST) == 0) {
Error ("Constant expression expected");
/* To avoid any compiler errors, make the expression a valid const */
void ConstIntExpr (ExprDesc* Val)
/* Get a constant int value */
{
- memset (Val, 0, sizeof (*Val));
+ InitExprDesc (Val);
if (expr (hie1, Val) != 0 ||
(Val->Flags & E_MCONST) == 0 ||
!IsClassInt (Val->Type)) {
-void boolexpr (ExprDesc* lval)
-/* Get a boolean expression */
-{
- /* Read an expression */
- expression (lval);
-
- /* If it's an integer, it's ok. If it's not an integer, but a pointer,
- * the pointer used in a boolean context is also ok
- */
- if (!IsClassInt (lval->Type) && !IsClassPtr (lval->Type)) {
- Error ("Boolean expression expected");
- /* To avoid any compiler errors, make the expression a valid int */
- MakeConstIntExpr (lval, 1);
- }
-}
-
-
-
-void test (unsigned label, int cond)
-/* Generate code to perform test and jump if false. */
+void Test (unsigned Label, int Invert)
+/* Evaluate a boolean test expression and jump depending on the result of
+ * the test and on Invert.
+ */
{
int k;
ExprDesc lval;
- /* Eat the parenthesis */
- ConsumeLParen ();
+ /* Evaluate the expression */
+ k = expr (hie0, InitExprDesc (&lval));
- /* Prepare the expression, setup labels */
- memset (&lval, 0, sizeof (lval));
+ /* Check for a boolean expression */
+ CheckBoolExpr (&lval);
- /* Generate code to eval the expr */
- k = expr (hie0, &lval);
+ /* Check for a constant expression */
if (k == 0 && lval.Flags == E_MCONST) {
+
/* Constant rvalue */
- if (cond == 0 && lval.ConstVal == 0) {
- g_jump (label);
+ if (!Invert && lval.ConstVal == 0) {
+ g_jump (Label);
Warning ("Unreachable code");
- } else if (cond && lval.ConstVal) {
- g_jump (label);
+ } else if (Invert && lval.ConstVal != 0) {
+ g_jump (Label);
}
- ConsumeRParen ();
- return;
- }
- /* If the expr hasn't set condition codes, set the force-test flag */
- if ((lval.Test & E_CC) == 0) {
- lval.Test |= E_FORCETEST;
- }
+ } else {
- /* Load the value into the primary register */
- exprhs (CF_FORCECHAR, k, &lval);
+ /* If the expr hasn't set condition codes, set the force-test flag */
+ if ((lval.Test & E_CC) == 0) {
+ lval.Test |= E_FORCETEST;
+ }
- /* Generate the jump */
- if (cond) {
- g_truejump (CF_NONE, label);
- } else {
- /* Special case (putting this here is a small hack - but hey, the
- * compiler itself is one big hack...): If a semicolon follows, we
- * don't have a statement and may omit the jump.
- */
- if (CurTok.Tok != TOK_SEMI) {
- g_falsejump (CF_NONE, label);
- }
+ /* Load the value into the primary register */
+ exprhs (CF_FORCECHAR, k, &lval);
+
+ /* Generate the jump */
+ if (Invert) {
+ g_truejump (CF_NONE, Label);
+ } else {
+ g_falsejump (CF_NONE, Label);
+ }
}
+}
+
+
+
+void TestInParens (unsigned Label, int Invert)
+/* Evaluate a boolean test expression in parenthesis and jump depending on
+ * the result of the test * and on Invert.
+ */
+{
+ /* Eat the parenthesis */
+ ConsumeLParen ();
+
+ /* Do the test */
+ Test (Label, Invert);
/* Check for the closing brace */
ConsumeRParen ();
-