X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fcc65%2Fexpr.c;h=b0bc18d1481c5a4c3148c2506737e88002fc3e6c;hb=112ae0e3db511ddd92e769c11328646ebe2a6240;hp=fae902808dae7d3d0044666b49f1358cb47bb94a;hpb=878e4f13524e91fbcdc8c97cc461724231339483;p=cc65 diff --git a/src/cc65/expr.c b/src/cc65/expr.c index fae902808..b0bc18d14 100644 --- a/src/cc65/expr.c +++ b/src/cc65/expr.c @@ -1,5 +1,4 @@ -/* - * expr.c +/* expr.c * * Ullrich von Bassewitz, 21.06.1998 */ @@ -26,9 +25,13 @@ #include "function.h" #include "global.h" #include "litpool.h" +#include "loadexpr.h" #include "macrotab.h" #include "preproc.h" #include "scanner.h" +#include "shiftexpr.h" +#include "stackptr.h" +#include "standard.h" #include "stdfunc.h" #include "symtab.h" #include "typecmp.h" @@ -68,54 +71,72 @@ static GenDesc GenOASGN = { TOK_OR_ASSIGN, GEN_NOPUSH, g_or }; /*****************************************************************************/ -/* Function forwards */ +/* Helper functions */ /*****************************************************************************/ -void hie0 (ExprDesc *lval); -/* Parse comma operator. */ - -void expr (void (*Func) (ExprDesc*), ExprDesc *Expr); -/* Expression parser; func is either hie0 or hie1. */ - +static unsigned GlobalModeFlags (const ExprDesc* Expr) +/* 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 */ + return 0; + } +} -/*****************************************************************************/ -/* Helper functions */ -/*****************************************************************************/ +void ExprWithCheck (void (*Func) (ExprDesc*), ExprDesc* Expr) +/* Call an expression function with checks. */ +{ + /* Remember the stack pointer */ + int OldSP = StackPtr; + /* Call the expression function */ + (*Func) (Expr); -static unsigned GlobalModeFlags (unsigned flags) -/* Return the addressing mode flags for the variable with the given flags */ -{ - flags &= E_MCTYPE; - if (flags == E_TGLAB) { - /* External linkage */ - return CF_EXTERNAL; - } else if (flags == E_TREGISTER) { - /* Register variable */ - return CF_REGVAR; - } else { - /* Static */ - return CF_STATIC; + /* Do some checks if code generation is still constistent */ + if (StackPtr != OldSP) { + if (Debug) { + Error ("Code generation messed up: " + "StackPtr is %d, should be %d", + StackPtr, OldSP); + } else { + Internal ("Code generation messed up: " + "StackPtr is %d, should be %d", + StackPtr, OldSP); + } } } -static int IsNullPtr (ExprDesc* lval) -/* Return true if this is the NULL pointer constant */ +void MarkedExprWithCheck (void (*Func) (ExprDesc*), ExprDesc* Expr) +/* Call an expression function with checks and record start and end of the + * generated code. + */ { - return (IsClassInt (lval->Type) && /* Is it an int? */ - lval->Flags == E_MCONST && /* Is it constant? */ - lval->ConstVal == 0); /* And is it's value zero? */ + CodeMark Start, End; + GetCodePos (&Start); + ExprWithCheck (Func, Expr); + GetCodePos (&End); + ED_SetCodeRange (Expr, &Start, &End); } -static type* promoteint (type* lhst, type* rhst) +static Type* promoteint (Type* lhst, Type* rhst) /* In an expression with two ints, return the type of the result */ { /* Rules for integer types: @@ -127,7 +148,7 @@ static type* promoteint (type* lhst, type* rhst) if (IsSignUnsigned (lhst) || IsSignUnsigned (rhst)) { return type_ulong; } else { - return type_long; + return type_long; } } else { if (IsSignUnsigned (lhst) || IsSignUnsigned (rhst)) { @@ -154,12 +175,12 @@ static unsigned typeadjust (ExprDesc* lhs, ExprDesc* rhs, int NoPush) 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); - if (lhs->Flags == E_MCONST) { + if (ED_IsLocAbs (lhs)) { ltype |= CF_CONST; } if (NoPush) { @@ -167,7 +188,7 @@ static unsigned typeadjust (ExprDesc* lhs, ExprDesc* rhs, int NoPush) ltype |= CF_REG; } rtype = TypeOf (rhst); - if (rhs->Flags == E_MCONST) { + if (ED_IsLocAbs (rhs)) { rtype |= CF_CONST; } flags = g_typeadjust (ltype, rtype); @@ -181,136 +202,6 @@ static unsigned typeadjust (ExprDesc* lhs, ExprDesc* rhs, int NoPush) -void DefineData (ExprDesc* Expr) -/* Output a data definition for the given expression */ -{ - unsigned Flags = Expr->Flags; - - switch (Flags & E_MCTYPE) { - - case E_TCONST: - /* Number */ - g_defdata (TypeOf (Expr->Type) | CF_CONST, Expr->ConstVal, 0); - break; - - case E_TREGISTER: - /* Register variable. Taking the address is usually not - * allowed. - */ - if (IS_Get (&AllowRegVarAddr) == 0) { - Error ("Cannot take the address of a register variable"); - } - /* FALLTHROUGH */ - - case E_TGLAB: - case E_TLLAB: - /* Local or global symbol */ - g_defdata (GlobalModeFlags (Flags), Expr->Name, Expr->ConstVal); - break; - - case E_TLIT: - /* a literal of some kind */ - g_defdata (CF_STATIC, LiteralPoolLabel, Expr->ConstVal); - break; - - default: - Internal ("Unknown constant type: %04X", Flags); - } -} - - - -static void LoadConstant (unsigned Flags, ExprDesc* Expr) -/* Load the primary register with some constant value. */ -{ - switch (Expr->Flags & E_MCTYPE) { - - case E_TLOFFS: - g_leasp (Expr->ConstVal); - break; - - case E_TCONST: - /* Number constant */ - g_getimmed (Flags | TypeOf (Expr->Type) | CF_CONST, Expr->ConstVal, 0); - break; - - case E_TREGISTER: - /* Register variable. Taking the address is usually not - * allowed. - */ - if (IS_Get (&AllowRegVarAddr) == 0) { - Error ("Cannot take the address of a register variable"); - } - /* FALLTHROUGH */ - - case E_TGLAB: - case E_TLLAB: - /* Local or global symbol, load address */ - Flags |= GlobalModeFlags (Expr->Flags); - Flags &= ~CF_CONST; - g_getimmed (Flags, Expr->Name, Expr->ConstVal); - break; - - case E_TLIT: - /* Literal string */ - g_getimmed (CF_STATIC, LiteralPoolLabel, Expr->ConstVal); - break; - - default: - Internal ("Unknown constant type: %04X", Expr->Flags); - } -} - - - -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_SHR: - return (val1 >> val2); - case TOK_SHL: - 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 */ { @@ -325,25 +216,31 @@ static const GenDesc* FindGen (token_t Tok, const GenDesc* Table) -static int istypeexpr (void) -/* Return true if some sort of variable or type is waiting (helper for cast - * and sizeof() in hie10). +static int TypeSpecAhead (void) +/* Return true if some sort of type is waiting (helper for cast and sizeof() + * in hie10). */ { SymEntry* Entry; + /* There's a type waiting if: + * + * We have an opening paren, and + * a. the next token is a type, or + * b. the next token is a type qualifier, or + * c. the next token is a typedef'd type + */ return CurTok.Tok == TOK_LPAREN && ( - (NextTok.Tok >= TOK_FIRSTTYPE && NextTok.Tok <= TOK_LASTTYPE) || - (NextTok.Tok == TOK_CONST) || - (NextTok.Tok == TOK_VOLATILE) || - (NextTok.Tok == TOK_IDENT && - (Entry = FindSym (NextTok.Ident)) != 0 && + TokIsType (&NextTok) || + TokIsTypeQual (&NextTok) || + (NextTok.Tok == TOK_IDENT && + (Entry = FindSym (NextTok.Ident)) != 0 && SymIsTypeDef (Entry))); } -void PushAddr (ExprDesc* lval) +void PushAddr (const ExprDesc* Expr) /* 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 @@ -351,7 +248,7 @@ void PushAddr (ExprDesc* lval) */ { /* Get the address on stack if needed */ - if (lval->Flags != E_MREG && (lval->Flags & E_MEXPR)) { + if (ED_IsLocExpr (Expr)) { /* Push the address (always a pointer) */ g_push (CF_PTR, 0); } @@ -359,105 +256,25 @@ void PushAddr (ExprDesc* lval) -void ConstSubExpr (void (*Func) (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 - * a constant one to make sure there are no internal errors that result - * from this input error. +static void WarnConstCompareResult (void) +/* If the result of a comparison is constant, this is suspicious when not in + * preprocessor mode. */ { - Func (InitExprDesc (Expr)); - if (ED_IsLVal (Expr) != 0 || Expr->Flags != E_MCONST) { - Error ("Constant expression expected"); - /* To avoid any compiler errors, make the expression a valid const */ - ED_MakeConstInt (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 */ - ED_MakeConstInt (lval, 1); + if (!Preprocessing) { + Warning ("Result of comparison is constant"); } } /*****************************************************************************/ -/* code */ +/* code */ /*****************************************************************************/ -void ExprLoad (unsigned Flags, ExprDesc* Expr) -/* Place the result of an expression into the primary register if it is not - * already there. - */ -{ - int f; - - f = Expr->Flags; - if (ED_IsLVal (Expr)) { - /* Dereferenced lvalue */ - Flags |= TypeOf (Expr->Type); - if (Expr->Test & E_FORCETEST) { - Flags |= CF_TEST; - Expr->Test &= ~E_FORCETEST; - } - if (f & E_MGLOBAL) { - /* Reference to a global variable */ - Flags |= GlobalModeFlags (f); - g_getstatic (Flags, Expr->Name, Expr->ConstVal); - } else if (f & E_MLOCAL) { - /* Reference to a local variable */ - g_getlocal (Flags, Expr->ConstVal); - } else if (f & E_MCONST) { - /* Reference to an absolute address */ - g_getstatic (Flags | CF_ABSOLUTE, Expr->ConstVal, 0); - } else if (f == E_MEOFFS) { - /* Reference to address in primary with offset in Expr */ - g_getind (Flags, Expr->ConstVal); - } else if (f != E_MREG) { - /* Reference with address in primary */ - g_getind (Flags, 0); - } else if (Flags & CF_TEST) { - /* The value is already in the primary but needs a test */ - g_test (Flags); - } - } else { - /* An rvalue */ - if (f == E_MEOFFS) { - /* reference not storable */ - Flags |= TypeOf (Expr->Type); - g_inc (Flags | CF_CONST, Expr->ConstVal); - } else if ((f & E_MEXPR) == 0) { - /* Constant of some sort, load it into the primary */ - LoadConstant (Flags, Expr); - } - - /* Are we testing this value? */ - if (Expr->Test & E_FORCETEST) { - /* Yes, force a test */ - Flags |= TypeOf (Expr->Type); - g_test (Flags); - Expr->Test &= ~E_FORCETEST; - } - } -} - - - -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 @@ -489,23 +306,23 @@ static unsigned FunctionParamList (FuncDesc* Func) * (instead of pushing) is enabled. * */ - if (CodeSizeFactor >= 200) { + if (IS_Get (&CodeSizeFactor) >= 200) { /* 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 = oursp; + FrameOffs = StackPtr; g_space (FrameSize); - oursp -= FrameSize; + StackPtr -= FrameSize; } else { /* Don't use a preallocated frame */ FrameSize = 0; @@ -543,7 +360,7 @@ static unsigned FunctionParamList (FuncDesc* Func) 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. */ @@ -551,28 +368,37 @@ static unsigned FunctionParamList (FuncDesc* Func) } /* Evaluate the parameter expression */ - hie1 (InitExprDesc (&Expr)); + hie1 (&Expr); /* If we don't have an argument spec, accept anything, otherwise * convert the actual argument to the type needed. */ Flags = CF_NONE; if (!Ellipsis) { + /* Convert the argument to the parameter type if needed */ TypeConversion (&Expr, Param->Type); /* If we have a prototype, chars may be pushed as chars */ Flags |= CF_FORCECHAR; - } + + } else { + + /* No prototype available. Convert array to "pointer to first + * element", and function to "pointer to function". + */ + Expr.Type = PtrConversion (Expr.Type); + + } /* Load the value into the primary if it is not already there */ - ExprLoad (Flags, &Expr); + LoadExpr (Flags, &Expr); /* Use the type of the argument for the push */ 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. @@ -588,10 +414,10 @@ static unsigned FunctionParamList (FuncDesc* Func) } FrameOffs -= ArgSize; /* Store */ - g_putlocal (Flags | CF_NOKEEP, FrameOffs, Expr.ConstVal); + g_putlocal (Flags | CF_NOKEEP, FrameOffs, Expr.IVal); } else { /* Push the argument */ - g_push (Flags, Expr.ConstVal); + g_push (Flags, Expr.IVal); } /* Calculate total parameter size */ @@ -629,9 +455,9 @@ static void FunctionCall (ExprDesc* Expr) FuncDesc* Func; /* Function descriptor */ int IsFuncPtr; /* Flag */ unsigned ParamSize; /* Number of parameter bytes */ - CodeMark Mark = 0; /* Initialize to keep gcc silent */ + 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 */ @@ -645,7 +471,7 @@ static void FunctionCall (ExprDesc* Expr) 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 @@ -655,34 +481,46 @@ static void FunctionCall (ExprDesc* Expr) * For fastcall functions we do also need to place a copy of the * pointer on stack, since we cannot use a/x. */ - PtrOnStack = IsFastCall || ((Expr->Flags & (E_MGLOBAL | E_MLOCAL)) == 0); + PtrOnStack = IsFastcall || !ED_IsConst (Expr); if (PtrOnStack) { /* Not a global or local variable, or a fastcall function. Load * the pointer into the primary and mark it as an expression. */ - ExprLoad (CF_NONE, Expr); - Expr->Flags |= E_MEXPR; + LoadExpr (CF_NONE, Expr); + ED_MakeRValExpr (Expr); /* Remember the code position */ - Mark = GetCodePos (); + GetCodePos (&Mark); /* Push the pointer onto the stack and remember the offset */ g_push (CF_PTR, 0); - PtrOffs = oursp; + PtrOffs = StackPtr; } - /* Check for known standard functions and inline them if requested */ - } else if (IS_Get (&InlineStdFuncs) && IsStdFunc ((const char*) Expr->Name)) { + } else { + /* Check function attributes */ + if (Expr->Sym && SymHasAttr (Expr->Sym, atNoReturn)) { + /* For now, handle as if a return statement was encountered */ + F_ReturnFound (CurrentFunc); + } - /* Inline this function */ - HandleStdFunc (Func, Expr); - return; + /* 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 (); @@ -693,7 +531,7 @@ static void FunctionCall (ExprDesc* Expr) /* 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) { @@ -702,16 +540,15 @@ static void FunctionCall (ExprDesc* Expr) * stack pointer. */ if (ParamSize == 0) { - RemoveCode (Mark); - pop (CF_PTR); + RemoveCode (&Mark); PtrOnStack = 0; } else { - /* Load from the saved copy */ + /* Load from the saved copy */ g_getlocal (CF_PTR, PtrOffs); } } else { /* Load from original location */ - ExprLoad (CF_NONE, Expr); + LoadExpr (CF_NONE, Expr); } /* Call the function */ @@ -729,7 +566,7 @@ static void FunctionCall (ExprDesc* Expr) /* If we have a pointer on stack, remove it */ if (PtrOnStack) { - g_space (- (int) sizeofarg (CF_PTR)); + g_drop (SIZEOF_PTR); pop (CF_PTR); } @@ -742,6 +579,10 @@ static void FunctionCall (ExprDesc* Expr) g_call (TypeOf (Expr->Type), (const char*) Expr->Name, ParamSize); } + + /* The function result is an rvalue in the primary register */ + ED_MakeRValExpr (Expr); + Expr->Type = GetFuncReturn (Expr->Type); } @@ -752,33 +593,42 @@ static void Primary (ExprDesc* E) SymEntry* Sym; /* Initialize fields in the expression stucture */ - E->Test = 0; /* No test */ - E->Sym = 0; /* Symbol unknown */ + ED_Init (E); /* Character and integer constants. */ if (CurTok.Tok == TOK_ICONST || CurTok.Tok == TOK_CCONST) { - E->Flags = E_MCONST | E_TCONST | E_RVAL; + E->IVal = CurTok.IVal; + E->Flags = E_LOC_ABS | E_RTYPE_RVAL; E->Type = CurTok.Type; - E->ConstVal = CurTok.IVal; NextToken (); return; } + /* Floating point constant */ + if (CurTok.Tok == TOK_FCONST) { + E->FVal = CurTok.FVal; + E->Flags = E_LOC_ABS | E_RTYPE_RVAL; + E->Type = CurTok.Type; + NextToken (); + return; + } + /* Process parenthesized subexpression by calling the whole parser * recursively. */ if (CurTok.Tok == TOK_LPAREN) { - NextToken (); - hie0 (InitExprDesc (E)); + NextToken (); + hie0 (E); ConsumeRParen (); - return; + return; } /* 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) { - ED_MakeConstInt (E, 0); + NextToken (); + ED_MakeConstAbsInt (E, 0); return; } @@ -788,7 +638,7 @@ static void Primary (ExprDesc* E) if (Preprocessing) { /* Illegal expression in PP mode */ Error ("Preprocessor expression expected"); - ED_MakeConstInt (E, 1); + ED_MakeConstAbsInt (E, 1); return; } @@ -804,34 +654,32 @@ static void Primary (ExprDesc* E) /* We found the symbol - skip the name token */ NextToken (); - /* The expression type is the symbol type */ - E->Type = Sym->Type; - /* Check for illegal symbol types */ CHECK ((Sym->Flags & SC_LABEL) != SC_LABEL); if (Sym->Flags & SC_TYPE) { /* Cannot use type symbols */ Error ("Variable identifier expected"); /* Assume an int type to make E valid */ - E->Flags = E_MLOCAL | E_TLOFFS | E_LVAL; + E->Flags = E_LOC_STACK | E_RTYPE_LVAL; E->Type = type_int; - E->ConstVal = 0; return; } /* Mark the symbol as referenced */ Sym->Flags |= SC_REF; + /* The expression type is the symbol type */ + E->Type = Sym->Type; + /* Check for legal symbol types */ if ((Sym->Flags & SC_CONST) == SC_CONST) { /* Enum or some other numeric constant */ - E->Flags = E_MCONST | E_TCONST | E_RVAL; - E->ConstVal = Sym->V.ConstVal; + E->Flags = E_LOC_ABS | E_RTYPE_RVAL; + E->IVal = Sym->V.ConstVal; } else if ((Sym->Flags & SC_FUNC) == SC_FUNC) { /* Function */ - E->Flags = E_MGLOBAL | E_MCONST | E_TGLAB | E_RVAL; + E->Flags = E_LOC_GLOBAL | E_RTYPE_LVAL; E->Name = (unsigned long) Sym->Name; - E->ConstVal = 0; } else if ((Sym->Flags & SC_AUTO) == SC_AUTO) { /* Local variable. If this is a parameter for a variadic * function, we have to add some address calculations, and the @@ -840,41 +688,40 @@ static void Primary (ExprDesc* E) if ((Sym->Flags & SC_PARAM) == SC_PARAM && F_IsVariadic (CurrentFunc)) { /* Variadic parameter */ g_leavariadic (Sym->V.Offs - F_GetParamSize (CurrentFunc)); - E->Flags = E_MEXPR | E_LVAL; - E->ConstVal = 0; + E->Flags = E_LOC_EXPR | E_RTYPE_LVAL; } else { /* Normal parameter */ - E->Flags = E_MLOCAL | E_TLOFFS | E_LVAL; - E->ConstVal = Sym->V.Offs; + E->Flags = E_LOC_STACK | E_RTYPE_LVAL; + E->IVal = Sym->V.Offs; } } else if ((Sym->Flags & SC_REGISTER) == SC_REGISTER) { /* Register variable, zero page based */ - E->Flags = E_MGLOBAL | E_MCONST | E_TREGISTER | E_LVAL; + E->Flags = E_LOC_REGISTER | E_RTYPE_LVAL; E->Name = Sym->V.R.RegOffs; - E->ConstVal = 0; } else if ((Sym->Flags & SC_STATIC) == SC_STATIC) { /* Static variable */ if (Sym->Flags & (SC_EXTERN | SC_STORAGE)) { - E->Flags = E_MGLOBAL | E_MCONST | E_TGLAB | E_LVAL; + E->Flags = E_LOC_GLOBAL | E_RTYPE_LVAL; E->Name = (unsigned long) Sym->Name; } else { - E->Flags = E_MGLOBAL | E_MCONST | E_TLLAB | E_LVAL; + E->Flags = E_LOC_STATIC | E_RTYPE_LVAL; E->Name = Sym->V.Label; } - E->ConstVal = 0; } else { /* Local static variable */ - E->Flags = E_MGLOBAL | E_MCONST | E_TLLAB | E_LVAL; + E->Flags = E_LOC_STATIC | E_RTYPE_LVAL; E->Name = Sym->V.Offs; - E->ConstVal = 0; } - /* The following should not be necessary if the reference flag is - * set right above, but currently I do not oversee if it's really - * needed and the old code did it. - * ### + /* We've made all variables lvalues above. However, this is + * not always correct: An array is actually the address of its + * first element, which is a rvalue, and a function is a + * rvalue, too, because we cannot store anything in a function. + * So fix the flags depending on the type. */ - ED_SetValType (E, !IsTypeFunc (E->Type) && !IsTypeArray (E->Type)); + if (IsTypeArray (E->Type) || IsTypeFunc (E->Type)) { + ED_MakeRVal (E); + } } else { @@ -885,22 +732,26 @@ static void Primary (ExprDesc* E) /* 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_MGLOBAL | E_MCONST | E_TGLAB | E_RVAL; + E->Flags = E_LOC_GLOBAL | E_RTYPE_RVAL; E->Name = (unsigned long) Sym->Name; - E->ConstVal = 0; } else { /* Undeclared Variable */ Sym = AddLocalSym (Ident, type_int, SC_AUTO | SC_REF, 0); - E->Flags = E_MLOCAL | E_TLOFFS | E_LVAL; + E->Flags = E_LOC_STACK | E_RTYPE_LVAL; E->Type = type_int; - E->ConstVal = 0; Error ("Undefined symbol: `%s'", Ident); } @@ -908,35 +759,51 @@ static void Primary (ExprDesc* E) break; case TOK_SCONST: + case TOK_WCSCONST: /* String literal */ - E->Flags = E_MCONST | E_TLIT | E_RVAL; - E->ConstVal = CurTok.IVal; - E->Type = GetCharArrayType (GetLiteralPoolOffs () - CurTok.IVal); + E->LVal = UseLiteral (CurTok.SVal); + E->Type = GetCharArrayType (GetLiteralSize (CurTok.SVal)); + E->Flags = E_LOC_LITERAL | E_RTYPE_RVAL; + E->IVal = 0; + E->Name = GetLiteralLabel (CurTok.SVal); NextToken (); break; case TOK_ASM: /* ASM statement */ AsmStatement (); - E->Flags = E_MEXPR | E_RVAL; - E->ConstVal = 0; + E->Flags = E_LOC_EXPR | E_RTYPE_RVAL; E->Type = type_void; break; + case TOK_A: + /* Register pseudo variable */ + E->Type = type_uchar; + E->Flags = E_LOC_PRIMARY | E_RTYPE_LVAL; + NextToken (); + break; + case TOK_AX: + /* Register pseudo variable */ + E->Type = type_uint; + E->Flags = E_LOC_PRIMARY | E_RTYPE_LVAL; + NextToken (); + break; + case TOK_EAX: - /* __AX__ and __EAX__ pseudo values */ - E->Type = (CurTok.Tok == TOK_AX)? type_uint : type_ulong; - E->Flags = E_MREG | E_LVAL; /* May be used as lvalue */ - E->Test &= ~E_CC; - E->ConstVal = 0; + /* Register pseudo variable */ + E->Type = type_ulong; + E->Flags = E_LOC_PRIMARY | E_RTYPE_LVAL; NextToken (); break; default: - /* Illegal primary. */ + /* Illegal primary. Be sure to skip the token to avoid endless + * error loops. + */ Error ("Expression expected"); - ED_MakeConstInt (E, 1); + NextToken (); + ED_MakeConstAbsInt (E, 1); break; } } @@ -944,17 +811,15 @@ static void Primary (ExprDesc* E) static void ArrayRef (ExprDesc* Expr) -/* Handle an array reference */ +/* Handle an array reference. This function needs a rewrite. */ { - unsigned lflags; - unsigned rflags; - int ConstBaseAddr; - int ConstSubAddr; - ExprDesc lval2; - CodeMark Mark1; - CodeMark Mark2; - type* tptr1; - type* tptr2; + int ConstBaseAddr; + ExprDesc Subscript; + CodeMark Mark1; + CodeMark Mark2; + TypeCode Qualifiers; + Type* ElementType; + Type* tptr1; /* Skip the bracket */ @@ -967,210 +832,270 @@ static void ArrayRef (ExprDesc* Expr) * address. This is true for most arrays and will produce a lot better * code. Check if this is a const base address. */ - lflags = Expr->Flags & ~E_MCTYPE; - ConstBaseAddr = (lflags == E_MCONST) || /* Constant numeric address */ - (lflags & E_MGLOBAL) != 0 || /* Static array, or ... */ - lflags == E_MLOCAL; /* Local array */ + ConstBaseAddr = ED_IsRVal (Expr) && + (ED_IsLocConst (Expr) || ED_IsLocStack (Expr)); /* If we have a constant base, we delay the address fetch */ - Mark1 = GetCodePos (); - Mark2 = 0; /* Silence gcc */ + GetCodePos (&Mark1); if (!ConstBaseAddr) { /* Get a pointer to the array into the primary */ - ExprLoad (CF_NONE, Expr); + LoadExpr (CF_NONE, Expr); /* Get the array pointer on stack. Do not push more than 16 * bit, even if this value is greater, since we cannot handle * other than 16bit stuff when doing indexing. */ - Mark2 = GetCodePos (); + GetCodePos (&Mark2); g_push (CF_PTR, 0); } /* TOS now contains ptr to array elements. Get the subscript. */ - hie0 (&lval2); - if (ED_IsRVal (&lval2) && lval2.Flags == E_MCONST) { + 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 + * integer type, or we have an integer to the left, in which case the + * subscript must be a pointer/array. + * Since we do the necessary checking here, we can rely later on the + * correct types. + */ + Qualifiers = T_QUAL_NONE; + if (IsClassPtr (Expr->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); + } + if (IsTypeArray (Expr->Type)) { + Qualifiers = GetQualifier (Expr->Type); + } + ElementType = Indirect (Expr->Type); + } else if (IsClassInt (Expr->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)); + } else if (IsTypeArray (Subscript.Type)) { + Qualifiers = GetQualifier (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); + ElementType = Indirect (Expr->Type); + } + + /* The element type has the combined qualifiers from itself and the array, + * it is a member of (if any). + */ + if (GetQualifier (ElementType) != (GetQualifier (ElementType) | Qualifiers)) { + ElementType = TypeDup (ElementType); + ElementType->C |= Qualifiers; + } + + /* 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) && ED_CodeRangeIsEmpty (&Subscript)) { - /* The array subscript is a constant - remove value from stack */ + /* The array subscript is a numeric constant. If we had pushed the + * array base address onto the stack before, we can remove this value, + * since we can generate expression+offset. + */ if (!ConstBaseAddr) { - RemoveCode (Mark2); - pop (CF_PTR); + RemoveCode (&Mark2); } else { /* Get an array pointer into the primary */ - ExprLoad (CF_NONE, Expr); + LoadExpr (CF_NONE, Expr); } - if (IsClassPtr (tptr1)) { + if (IsClassPtr (Expr->Type)) { - /* Scale the subscript value according to element size */ - lval2.ConstVal *= CheckedPSizeOf (tptr1); + /* Lhs is pointer/array. Scale the subscript value according to + * the element size. + */ + Subscript.IVal *= CheckedSizeOf (ElementType); - /* Remove code for lhs load */ - RemoveCode (Mark1); + /* Remove the address load code */ + RemoveCode (&Mark1); - /* Handle constant base array on stack. Be sure NOT to - * handle pointers the same way, and check for character literals - * (both won't work). - */ - if (IsTypeArray (tptr1) && Expr->Flags != (E_MCONST | E_TLIT) && - ((Expr->Flags & ~E_MCTYPE) == E_MCONST || - (Expr->Flags & ~E_MCTYPE) == E_MLOCAL || - (Expr->Flags & E_MGLOBAL) != 0 || - (Expr->Flags == E_MEOFFS))) { - Expr->ConstVal += lval2.ConstVal; + /* In case of an array, we can adjust the offset of the expression + * already in Expr. If the base address was a constant, we can even + * remove the code that loaded the address into the primary. + */ + if (IsTypeArray (Expr->Type)) { - } else { - /* Pointer - load into primary and remember offset */ - if ((Expr->Flags & E_MEXPR) == 0 || ED_IsLVal (Expr)) { - ExprLoad (CF_NONE, Expr); - } - Expr->ConstVal = lval2.ConstVal; - Expr->Flags = E_MEOFFS; - } + /* Adjust the offset */ + Expr->IVal += Subscript.IVal; - /* Result is of element type */ - Expr->Type = Indirect (tptr1); + } else { - /* Done */ - goto end_array; + /* It's a pointer, so we do have to load it into the primary + * first (if it's not already there). + */ + if (ConstBaseAddr || ED_IsLVal (Expr)) { + LoadExpr (CF_NONE, Expr); + ED_MakeRValExpr (Expr); + } - } else if (IsClassPtr (tptr2 = lval2.Type)) { - /* Subscript is pointer, get element type */ - lval2.Type = Indirect (tptr2); + /* Use the offset */ + Expr->IVal = Subscript.IVal; + } - /* Scale the rhs value in the primary register */ - g_scale (TypeOf (tptr1), CheckedSizeOf (lval2.Type)); - /* */ - Expr->Type = lval2.Type; - } else { - Error ("Cannot subscript"); - } + } else { - /* Add the subscript. Since arrays are indexed by integers, - * we will ignore the true type of the subscript here and - * use always an int. - */ - g_inc (CF_INT | CF_CONST, lval2.ConstVal); + /* Scale the rhs value according to the element type */ + g_scale (TypeOf (tptr1), CheckedSizeOf (ElementType)); + + /* Add the subscript. Since arrays are indexed by integers, + * 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); + + } } else { /* Array subscript is not constant. Load it into the primary */ - Mark2 = GetCodePos (); - ExprLoad (CF_NONE, &lval2); - - tptr2 = lval2.Type; - if (IsClassPtr (tptr1)) { + GetCodePos (&Mark2); + LoadExpr (CF_NONE, &Subscript); - /* Get the element type */ - Expr->Type = Indirect (tptr1); + /* Do scaling */ + if (IsClassPtr (Expr->Type)) { - /* Indexing is based on int's, so we will just use the integer + /* Indexing is based on unsigneds, so we will just use the integer * portion of the index (which is in (e)ax, so there's no further * action required). */ - g_scale (CF_INT, CheckedSizeOf (Expr->Type)); - - } else if (IsClassPtr (tptr2)) { + g_scale (CF_INT, CheckedSizeOf (ElementType)); - /* Get the element type */ - lval2.Type = Indirect (tptr2); + } else { - /* Get the int value on top. If we go here, we're sure, - * both values are 16 bit (the first one was truncated - * if necessary and the second one is a pointer). - * Note: If ConstBaseAddr is true, we don't have a value on - * stack, so to "swap" both, just push the subscript. + /* Get the int value on top. If we come here, we're sure, both + * values are 16 bit (the first one was truncated if necessary + * and the second one is a pointer). Note: If ConstBaseAddr is + * true, we don't have a value on stack, so to "swap" both, just + * push the subscript. */ if (ConstBaseAddr) { - g_push (CF_INT, 0); - ExprLoad (CF_NONE, Expr); - ConstBaseAddr = 0; + g_push (CF_INT, 0); + LoadExpr (CF_NONE, Expr); + ConstBaseAddr = 0; } else { g_swap (CF_INT); } /* Scale it */ - g_scale (TypeOf (tptr1), CheckedSizeOf (lval2.Type)); - Expr->Type = lval2.Type; - } else { - Error ("Cannot subscript"); + g_scale (TypeOf (tptr1), CheckedSizeOf (ElementType)); + } - /* The offset is now in the primary register. It didn't have a + /* The offset is now in the primary register. It we didn't have a * constant base address for the lhs, the lhs address is already * on stack, and we must add the offset. If the base address was * constant, we call special functions to add the address to the * offset value. */ - if (!ConstBaseAddr) { - /* Add the subscript. Both values are int sized. */ + if (!ConstBaseAddr) { + + /* The array base address is on stack and the subscript is in the + * primary. Add both. + */ g_add (CF_INT, 0); - } else { - /* If the subscript has itself a constant address, it is 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. - */ - rflags = lval2.Flags & ~E_MCTYPE; - ConstSubAddr = (rflags == E_MCONST) || /* Constant numeric address */ - (rflags & E_MGLOBAL) != 0 || /* Static array, or ... */ - rflags == E_MLOCAL; /* Local array */ + } else { + + /* The subscript is in the primary, and the array base address is + * in Expr. If the subscript has itself a constant address, it is + * 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)) && + CheckedSizeOf (ElementType) == SIZEOF_CHAR) { + + unsigned Flags; - if (ConstSubAddr && CheckedSizeOf (Expr->Type) == SIZEOF_CHAR) { + /* Reverse the order of evaluation */ + if (CheckedSizeOf (Subscript.Type) == SIZEOF_CHAR) { + Flags = CF_CHAR; + } else { + Flags = CF_INT; + } + RemoveCode (&Mark2); - type* SavedType; + /* Get a pointer to the array into the primary. */ + LoadExpr (CF_NONE, Expr); - /* Reverse the order of evaluation */ - unsigned flags = (CheckedSizeOf (lval2.Type) == SIZEOF_CHAR)? CF_CHAR : CF_INT; - RemoveCode (Mark2); + /* Add the variable */ + if (ED_IsLocStack (&Subscript)) { + g_addlocal (Flags, Subscript.IVal); + } else { + Flags |= GlobalModeFlags (&Subscript); + g_addstatic (Flags, Subscript.Name, Subscript.IVal); + } + } else { - /* Get a pointer to the array into the primary. We have changed - * Type above but we need the original type to load the - * address, so restore it temporarily. - */ - SavedType = Expr->Type; - Expr->Type = tptr1; - ExprLoad (CF_NONE, Expr); - Expr->Type = SavedType; - - /* Add the variable */ - if (rflags == E_MLOCAL) { - g_addlocal (flags, lval2.ConstVal); - } else { - flags |= GlobalModeFlags (lval2.Flags); - g_addstatic (flags, lval2.Name, lval2.ConstVal); - } - } else { - if (lflags == E_MCONST) { - /* Constant numeric address. Just add it */ - g_inc (CF_INT | CF_UNSIGNED, Expr->ConstVal); - } else if (lflags == E_MLOCAL) { - /* Base address is a local variable address */ - if (IsTypeArray (tptr1)) { - g_addaddr_local (CF_INT, Expr->ConstVal); + 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->ConstVal); + g_addlocal (CF_PTR, Expr->IVal); } } else { /* Base address is a static variable address */ - unsigned flags = CF_INT; - flags |= GlobalModeFlags (Expr->Flags); - if (IsTypeArray (tptr1)) { - g_addaddr_static (flags, Expr->Name, Expr->ConstVal); + 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 { - g_addstatic (flags, Expr->Name, Expr->ConstVal); + /* Add the contents of the location */ + g_addstatic (Flags, Expr->Name, Expr->IVal); } } } + + } + + /* The result is an expression in the primary */ + ED_MakeRValExpr (Expr); + + } + + /* Result is of element type */ + Expr->Type = ElementType; + + /* An array element is actually a variable. So the rules for variables + * with respect to the reference type apply: If it's an array, it is + * a rvalue, otherwise it's an lvalue. (A function would also be a rvalue, + * but an array cannot contain functions). + */ + if (IsTypeArray (Expr->Type)) { + ED_MakeRVal (Expr); + } else { + ED_MakeLVal (Expr); } - Expr->Flags = E_MEXPR; -end_array: + + /* Consume the closing bracket */ ConsumeRBrack (); - ED_SetValType (Expr, !IsTypeArray (Expr->Type)); } @@ -1180,13 +1105,14 @@ static void StructRef (ExprDesc* Expr) { ident Ident; SymEntry* Field; - int Flags; + TypeCode Q; /* Skip the token and check for an identifier */ NextToken (); if (CurTok.Tok != TOK_IDENT) { Error ("Identifier expected"); - Expr->Type = type_int; + /* Make the expression an integer at address zero */ + ED_MakeConstAbs (Expr, 0, type_int); return; } @@ -1196,26 +1122,54 @@ static void StructRef (ExprDesc* Expr) Field = FindStructField (Expr->Type, Ident); if (Field == 0) { Error ("Struct/union has no field named `%s'", Ident); - Expr->Type = type_int; + /* Make the expression an integer at address zero */ + ED_MakeConstAbs (Expr, 0, type_int); return; } - /* If we have constant input data, the result is also constant */ - Flags = (Expr->Flags & ~E_MCTYPE); - if (Flags == E_MCONST || - (ED_IsRVal (Expr) && (Flags == E_MLOCAL || - (Flags & E_MGLOBAL) != 0 || - Expr->Flags == E_MEOFFS))) { - Expr->ConstVal += Field->V.Offs; + /* If we have a struct pointer that is an lvalue and not already in the + * primary, load it now. + */ + if (ED_IsLVal (Expr) && IsTypePtr (Expr->Type)) { + + /* Load into the primary */ + LoadExpr (CF_NONE, Expr); + + /* Make it an lvalue expression */ + ED_MakeLValExpr (Expr); + } + + /* Set the struct field offset */ + Expr->IVal += Field->V.Offs; + + /* The type is the type of the field plus any qualifiers from the struct */ + if (IsClassStruct (Expr->Type)) { + Q = GetQualifier (Expr->Type); } else { - if ((Flags & E_MEXPR) == 0 || ED_IsLVal (Expr)) { - ExprLoad (CF_NONE, Expr); - } - Expr->ConstVal = Field->V.Offs; - Expr->Flags = E_MEOFFS; + Q = GetQualifier (Indirect (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 + * a rvalue, otherwise it's an lvalue. (A function would also be a rvalue, + * but a struct field cannot be a function). + */ + if (IsTypeArray (Expr->Type)) { + ED_MakeRVal (Expr); + } 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); } - Expr->Type = Field->Type; - ED_SetValType (Expr, !IsTypeArray (Field->Type)); } @@ -1223,6 +1177,9 @@ static void StructRef (ExprDesc* Expr) 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); @@ -1239,28 +1196,24 @@ static void hie11 (ExprDesc *Expr) case TOK_LPAREN: /* Function call. */ - if (IsTypeFunc (Expr->Type) || IsTypeFuncPtr (Expr->Type)) { - - /* Call the function */ - FunctionCall (Expr); - - /* Result is in the primary register */ - Expr->Flags = E_MEXPR | E_RVAL; - - /* Set to result */ - Expr->Type = GetFuncReturn (Expr->Type); - - } else { + if (!IsTypeFunc (Expr->Type) && !IsTypeFuncPtr (Expr->Type)) { + /* Not a function */ Error ("Illegal function call"); - ED_MakeRVal (Expr); + /* 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, invent one. + */ + ED_MakeConstAbs (Expr, 0, GetImplicitFuncType ()); + Expr->Name = (long) IllegalFunc; } + /* Call the function */ + FunctionCall (Expr); break; case TOK_DOT: if (!IsClassStruct (Expr->Type)) { Error ("Struct expected"); } - ED_MakeRVal (Expr); /* #### ? */ StructRef (Expr); break; @@ -1284,169 +1237,312 @@ static void hie11 (ExprDesc *Expr) -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. - */ -{ - unsigned Flags; +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. + */ +{ + unsigned Flags; + + /* If StoreType was not given, use Expr->Type instead */ + if (StoreType == 0) { + StoreType = Expr->Type; + } + + /* Prepare the code generator flags */ + 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, Expr->IVal, 0); + break; + + case E_LOC_GLOBAL: + /* Global variable */ + 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, Expr->Name, Expr->IVal); + break; + + case E_LOC_REGISTER: + /* Register variable */ + g_putstatic (Flags, Expr->Name, Expr->IVal); + break; + + case E_LOC_STACK: + /* Value on the stack */ + g_putlocal (Flags, Expr->IVal, 0); + break; + + case E_LOC_PRIMARY: + /* The primary register (value is already there) */ + break; + + case E_LOC_EXPR: + /* An expression in the primary register */ + g_putind (Flags, Expr->IVal); + break; + + default: + Internal ("Invalid location in Store(): 0x%04X", ED_GetLoc (Expr)); + } + + /* Assume that each one of the stores will invalidate CC */ + ED_MarkAsUntested (Expr); +} + + + +static void PreInc (ExprDesc* Expr) +/* Handle the preincrement operators */ +{ + unsigned Flags; + unsigned long Val; + + /* Skip the operator token */ + NextToken (); + + /* Evaluate the expression and check that it is an lvalue */ + hie10 (Expr); + 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) | GlobalModeFlags (Expr) | CF_FORCECHAR | CF_CONST; + + /* Get the increment value in bytes */ + Val = IsTypePtr (Expr->Type)? CheckedPSizeOf (Expr->Type) : 1; + + /* Check the location of the data */ + switch (ED_GetLoc (Expr)) { + + case E_LOC_ABS: + /* Absolute: numeric address or const */ + g_addeqstatic (Flags, Expr->IVal, 0, Val); + break; + + case E_LOC_GLOBAL: + /* Global variable */ + 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, Expr->Name, Expr->IVal, Val); + break; + + case E_LOC_REGISTER: + /* Register variable */ + g_addeqstatic (Flags, Expr->Name, Expr->IVal, Val); + break; + + case E_LOC_STACK: + /* Value on the stack */ + g_addeqlocal (Flags, Expr->IVal, Val); + break; + + case E_LOC_PRIMARY: + /* The primary register */ + g_inc (Flags, Val); + break; + + case E_LOC_EXPR: + /* An expression in the primary register */ + g_addeqind (Flags, Expr->IVal, Val); + break; + + default: + Internal ("Invalid location in PreInc(): 0x%04X", ED_GetLoc (Expr)); + } + + /* Result is an expression, no reference */ + ED_MakeRValExpr (Expr); +} + + + +static void PreDec (ExprDesc* Expr) +/* Handle the predecrement operators */ +{ + unsigned Flags; + unsigned long Val; + + /* Skip the operator token */ + NextToken (); + + /* Evaluate the expression and check that it is an lvalue */ + hie10 (Expr); + 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) | GlobalModeFlags (Expr) | CF_FORCECHAR | CF_CONST; + + /* Get the increment value in bytes */ + Val = IsTypePtr (Expr->Type)? CheckedPSizeOf (Expr->Type) : 1; + + /* Check the location of the data */ + switch (ED_GetLoc (Expr)) { + + case E_LOC_ABS: + /* Absolute: numeric address or const */ + g_subeqstatic (Flags, Expr->IVal, 0, Val); + break; + + case E_LOC_GLOBAL: + /* Global variable */ + 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, Expr->Name, Expr->IVal, Val); + break; + + case E_LOC_REGISTER: + /* Register variable */ + g_subeqstatic (Flags, Expr->Name, Expr->IVal, Val); + break; + + case E_LOC_STACK: + /* Value on the stack */ + g_subeqlocal (Flags, Expr->IVal, Val); + break; + + case E_LOC_PRIMARY: + /* The primary register */ + g_inc (Flags, Val); + break; - unsigned f = lval->Flags; + case E_LOC_EXPR: + /* An expression in the primary register */ + g_subeqind (Flags, Expr->IVal, Val); + break; - /* 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); - if (lval->Test) { - /* Just testing */ - Flags |= CF_TEST; - } - - /* Generate code */ - g_putstatic (Flags, lval->Name, lval->ConstVal); - - } else if (f & E_MLOCAL) { - /* Store an auto variable */ - g_putlocal (Flags, lval->ConstVal, 0); - } else if (f == E_MEOFFS) { - /* Store indirect with offset */ - g_putind (Flags, lval->ConstVal); - } else if (f != E_MREG) { - if (f & E_MEXPR) { - /* Indirect without offset */ - g_putind (Flags, 0); - } else { - /* Store into absolute address */ - g_putstatic (Flags | CF_ABSOLUTE, lval->ConstVal, 0); - } + default: + Internal ("Invalid location in PreDec(): 0x%04X", ED_GetLoc (Expr)); } - /* Assume that each one of the stores will invalidate CC */ - lval->Test &= ~E_CC; + /* Result is an expression, no reference */ + ED_MakeRValExpr (Expr); } -static void PreIncDec (ExprDesc* Expr, void (*inc) (unsigned, unsigned long)) -/* Handle --i and ++i */ +static void PostInc (ExprDesc* Expr) +/* Handle the postincrement operator */ { - unsigned flags; - unsigned long val; + unsigned Flags; - /* Skip the operator token */ NextToken (); - /* Evaluate the expression and check that it is an lvalue */ - hie10 (Expr); - if (ED_IsRVal (Expr) == 0) { + /* The expression to increment must be an lvalue */ + if (!ED_IsLVal (Expr)) { Error ("Invalid lvalue"); - return; + return; } - /* Get the data type */ - flags = TypeOf (Expr->Type) | CF_FORCECHAR | CF_CONST; + /* We cannot modify const values */ + if (IsQualConst (Expr->Type)) { + Error ("Increment of read-only variable"); + } - /* Get the increment value in bytes */ - val = (Expr->Type[0] == T_PTR)? CheckedPSizeOf (Expr->Type) : 1; - - /* Check for special addressing modes */ - if (Expr->Flags & E_MGLOBAL) { - /* Global address */ - flags |= GlobalModeFlags (Expr->Flags); - if (inc == g_inc) { - g_addeqstatic (flags, Expr->Name, Expr->ConstVal, val); - } else { - g_subeqstatic (flags, Expr->Name, Expr->ConstVal, val); - } - } else if (Expr->Flags & E_MLOCAL) { - /* Local address */ - if (inc == g_inc) { - g_addeqlocal (flags, Expr->ConstVal, val); - } else { - g_subeqlocal (flags, Expr->ConstVal, val); - } - } else if (Expr->Flags & E_MCONST) { - /* Constant absolute address */ - flags |= CF_ABSOLUTE; - if (inc == g_inc) { - g_addeqstatic (flags, Expr->ConstVal, 0, val); - } else { - g_subeqstatic (flags, Expr->ConstVal, 0, val); - } - } else if (Expr->Flags & E_MEXPR) { - /* Address in a/x, check if we have an offset */ - unsigned Offs = (Expr->Flags == E_MEOFFS)? Expr->ConstVal : 0; - if (inc == g_inc) { - g_addeqind (flags, Offs, val); - } else { - g_subeqind (flags, Offs, val); - } - } else { + /* Get the data type */ + Flags = TypeOf (Expr->Type); - /* Use generic code. Push the address if needed */ - PushAddr (Expr); + /* Push the address if needed */ + PushAddr (Expr); - /* Fetch the value */ - ExprLoad (CF_NONE, Expr); + /* Fetch the value and save it (since it's the result of the expression) */ + LoadExpr (CF_NONE, Expr); + g_save (Flags | CF_FORCECHAR); - /* Increment value in primary */ - inc (flags, val); + /* 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); + /* Store the result back */ + Store (Expr, 0); - } + /* Restore the original value in the primary register */ + g_restore (Flags | CF_FORCECHAR); - /* Result is an expression, no reference */ - Expr->Flags = E_MEXPR | E_RVAL; + /* The result is always an expression, no reference */ + ED_MakeRValExpr (Expr); } -static void PostIncDec (ExprDesc* Expr, void (*inc) (unsigned, unsigned long)) -/* Handle i-- and i++ */ +static void PostDec (ExprDesc* Expr) +/* Handle the postdecrement operator */ { - unsigned flags; + unsigned Flags; NextToken (); /* The expression to increment must be an lvalue */ - if (ED_IsRVal (Expr)) { + 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); + 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) */ - ExprLoad (CF_NONE, Expr); - g_save (flags | CF_FORCECHAR); + LoadExpr (CF_NONE, Expr); + g_save (Flags | CF_FORCECHAR); /* If we have a pointer expression, increment by the size of the type */ - if (Expr->Type[0] == T_PTR) { - inc (flags | CF_CONST | CF_FORCECHAR, CheckedSizeOf (Expr->Type + 1)); + if (IsTypePtr (Expr->Type)) { + 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 */ Store (Expr, 0); /* Restore the original value in the primary register */ - g_restore (flags | CF_FORCECHAR); + g_restore (Flags | CF_FORCECHAR); /* The result is always an expression, no reference */ - Expr->Flags = E_MEXPR | E_RVAL; + ED_MakeRValExpr (Expr); } @@ -1454,7 +1550,7 @@ static void PostIncDec (ExprDesc* Expr, void (*inc) (unsigned, unsigned long)) static void UnaryOp (ExprDesc* Expr) /* Handle unary -/+ and ~ */ { - unsigned flags; + unsigned Flags; /* Remember the operator token and skip it */ token_t Tok = CurTok.Tok; @@ -1463,32 +1559,38 @@ static void UnaryOp (ExprDesc* Expr) /* Get the expression */ hie10 (Expr); + /* We can only handle integer types */ + if (!IsClassInt (Expr->Type)) { + Error ("Argument must have integer type"); + ED_MakeConstAbsInt (Expr, 1); + } + /* Check for a constant expression */ - if (ED_IsRVal (Expr) && (Expr->Flags & E_MCONST) != 0) { + if (ED_IsConstAbs (Expr)) { /* Value is constant */ switch (Tok) { - case TOK_MINUS: Expr->ConstVal = -Expr->ConstVal; break; - case TOK_PLUS: break; - case TOK_COMP: Expr->ConstVal = ~Expr->ConstVal; break; + case TOK_MINUS: Expr->IVal = -Expr->IVal; break; + case TOK_PLUS: break; + case TOK_COMP: Expr->IVal = ~Expr->IVal; break; default: Internal ("Unexpected token: %d", Tok); } } else { /* Value is not constant */ - ExprLoad (CF_NONE, Expr); + LoadExpr (CF_NONE, Expr); /* Get the type of the expression */ - flags = TypeOf (Expr->Type); + Flags = TypeOf (Expr->Type); /* Handle the operation */ switch (Tok) { - case TOK_MINUS: g_neg (flags); break; + case TOK_MINUS: g_neg (Flags); break; case TOK_PLUS: break; - case TOK_COMP: g_com (flags); break; - default: Internal ("Unexpected token: %d", Tok); + case TOK_COMP: g_com (Flags); break; + default: Internal ("Unexpected token: %d", Tok); } /* The result is a rvalue in the primary */ - Expr->Flags = E_MEXPR | E_RVAL; + ED_MakeRValExpr (Expr); } } @@ -1497,14 +1599,16 @@ static void UnaryOp (ExprDesc* Expr) void hie10 (ExprDesc* Expr) /* Handle ++, --, !, unary - etc. */ { + unsigned long Size; + switch (CurTok.Tok) { case TOK_INC: - PreIncDec (Expr, g_inc); + PreInc (Expr); break; case TOK_DEC: - PostIncDec (Expr, g_dec); + PreDec (Expr); break; case TOK_PLUS: @@ -1517,25 +1621,31 @@ void hie10 (ExprDesc* Expr) NextToken (); if (evalexpr (CF_NONE, hie10, Expr) == 0) { /* Constant expression */ - Expr->ConstVal = !Expr->ConstVal; + Expr->IVal = !Expr->IVal; } else { g_bneg (TypeOf (Expr->Type)); - Expr->Test |= E_CC; /* bneg will set cc */ - Expr->Flags = E_MEXPR | E_RVAL; /* say it's an expr */ + ED_MakeRValExpr (Expr); + ED_TestDone (Expr); /* bneg will set cc */ } break; case TOK_STAR: NextToken (); - if (evalexpr (CF_NONE, hie10, Expr) != 0) { - /* Expression is not const, indirect value loaded into primary */ - Expr->Flags = E_MEXPR | E_RVAL; - Expr->ConstVal = 0; /* Offset is zero now */ - } + ExprWithCheck (hie10, Expr); + if (ED_IsLVal (Expr) || !(ED_IsLocConst (Expr) || ED_IsLocStack (Expr))) { + /* Not a const, load it into the primary and make it a + * calculated value. + */ + LoadExpr (CF_NONE, Expr); + 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 { @@ -1544,49 +1654,53 @@ void hie10 (ExprDesc* Expr) } else { Error ("Illegal indirection"); } + /* The * operator yields an lvalue */ ED_MakeLVal (Expr); } break; case TOK_AND: NextToken (); - hie10 (Expr); + ExprWithCheck (hie10, Expr); /* 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 (istypeexpr ()) { - type Type[MAXTYPELEN]; + if (TypeSpecAhead ()) { + Type T[MAXTYPELEN]; NextToken (); - Expr->ConstVal = CheckedSizeOf (ParseType (Type)); + Size = CheckedSizeOf (ParseType (T)); ConsumeRParen (); } else { /* Remember the output queue pointer */ - CodeMark Mark = GetCodePos (); + CodeMark Mark; + GetCodePos (&Mark); hie10 (Expr); - Expr->ConstVal = CheckedSizeOf (Expr->Type); + Size = CheckedSizeOf (Expr->Type); /* Remove any generated code */ - RemoveCode (Mark); + RemoveCode (&Mark); } - Expr->Flags = E_MCONST | E_TCONST | E_RVAL; - Expr->Type = type_uint; - Expr->Test &= ~E_CC; + ED_MakeConstAbs (Expr, Size, type_size_t); + ED_MarkAsUntested (Expr); break; default: - if (istypeexpr ()) { + if (TypeSpecAhead ()) { /* A typecast */ TypeCast (Expr); @@ -1597,10 +1711,10 @@ void hie10 (ExprDesc* Expr) 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; } } @@ -1611,16 +1725,16 @@ void hie10 (ExprDesc* Expr) static void hie_internal (const GenDesc* Ops, /* List of generators */ - ExprDesc* Expr, /* parent expr's lval */ + ExprDesc* Expr, void (*hienext) (ExprDesc*), - int* UsedGen) /* next higher level */ + int* UsedGen) /* Helper function */ { - ExprDesc lval2; + ExprDesc Expr2; CodeMark Mark1; CodeMark Mark2; const GenDesc* Gen; - token_t Tok; /* The operator token */ + token_t Tok; /* The operator token */ unsigned ltype, type; int rconst; /* Operand is a constant */ @@ -1636,6 +1750,8 @@ static void hie_internal (const GenDesc* Ops, /* List of generators */ /* 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 */ @@ -1643,39 +1759,119 @@ static void hie_internal (const GenDesc* Ops, /* List of generators */ NextToken (); /* Get the lhs on stack */ - Mark1 = GetCodePos (); + GetCodePos (&Mark1); ltype = TypeOf (Expr->Type); - if (ED_IsRVal (Expr) && Expr->Flags == E_MCONST) { + if (ED_IsConstAbs (Expr)) { /* Constant value */ - Mark2 = GetCodePos (); - g_push (ltype | CF_CONST, Expr->ConstVal); + GetCodePos (&Mark2); + g_push (ltype | CF_CONST, Expr->IVal); } else { /* Value not constant */ - ExprLoad (CF_NONE, Expr); - Mark2 = GetCodePos (); + LoadExpr (CF_NONE, Expr); + GetCodePos (&Mark2); g_push (ltype, 0); } /* Get the right hand side */ - rconst = (evalexpr (CF_NONE, hienext, &lval2) == 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 (lval2.Type)) { + if (!IsClassInt (Expr2.Type)) { Error ("Integer expression expected"); } /* Check for const operands */ - if (ED_IsRVal (Expr) && Expr->Flags == E_MCONST && rconst) { + if (ED_IsConstAbs (Expr) && rconst) { /* Both operands are constant, remove the generated code */ - RemoveCode (Mark1); - pop (ltype); - - /* Evaluate the result */ - Expr->ConstVal = kcalc (Tok, Expr->ConstVal, lval2.ConstVal); + RemoveCode (&Mark1); /* Get the type of the result */ - Expr->Type = promoteint (Expr->Type, lval2.Type); + 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 { @@ -1683,33 +1879,32 @@ static void hie_internal (const GenDesc* Ops, /* List of generators */ * expects the lhs in the primary, remove the push of the primary * now. */ - unsigned rtype = TypeOf (lval2.Type); + unsigned rtype = TypeOf (Expr2.Type); type = 0; if (rconst) { /* Second value is constant - check for div */ type |= CF_CONST; rtype |= CF_CONST; - if (Tok == TOK_DIV && lval2.ConstVal == 0) { + if (Tok == TOK_DIV && Expr2.IVal == 0) { Error ("Division by zero"); - } else if (Tok == TOK_MOD && lval2.ConstVal == 0) { + } else if (Tok == TOK_MOD && Expr2.IVal == 0) { Error ("Modulo operation with zero"); } if ((Gen->Flags & GEN_NOPUSH) != 0) { - RemoveCode (Mark2); - pop (ltype); + RemoveCode (&Mark2); ltype |= CF_REG; /* Value is in register */ } } /* Determine the type of the operation result. */ type |= g_typeadjust (ltype, rtype); - Expr->Type = promoteint (Expr->Type, lval2.Type); + Expr->Type = promoteint (Expr->Type, Expr2.Type); /* Generate code */ - Gen->Func (type, lval2.ConstVal); + Gen->Func (type, Expr2.IVal); /* We have a rvalue in the primary now */ - Expr->Flags = E_MEXPR | E_RVAL; + ED_MakeRValExpr (Expr); } } } @@ -1717,76 +1912,126 @@ static void hie_internal (const GenDesc* Ops, /* List of generators */ static void hie_compare (const GenDesc* Ops, /* List of generators */ - ExprDesc* Expr, /* parent expr's lval */ + ExprDesc* Expr, void (*hienext) (ExprDesc*)) /* Helper function for the compare operators */ { - ExprDesc lval2; + ExprDesc Expr2; + CodeMark Mark0; 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 */ + GetCodePos (&Mark0); hienext (Expr); while ((Gen = FindGen (CurTok.Tok, Ops)) != 0) { + /* Remember the generator function */ + void (*GenFunc) (unsigned, unsigned long) = Gen->Func; + /* Remember the operator token, then skip it */ - tok = CurTok.Tok; + Tok = CurTok.Tok; NextToken (); /* Get the lhs on stack */ - Mark1 = GetCodePos (); + GetCodePos (&Mark1); ltype = TypeOf (Expr->Type); - if (ED_IsRVal (Expr) && Expr->Flags == E_MCONST) { + if (ED_IsConstAbs (Expr)) { /* Constant value */ - Mark2 = GetCodePos (); - g_push (ltype | CF_CONST, Expr->ConstVal); + GetCodePos (&Mark2); + g_push (ltype | CF_CONST, Expr->IVal); } else { /* Value not constant */ - ExprLoad (CF_NONE, Expr); - Mark2 = GetCodePos (); + LoadExpr (CF_NONE, Expr); + GetCodePos (&Mark2); g_push (ltype, 0); } /* Get the right hand side */ - rconst = (evalexpr (CF_NONE, hienext, &lval2) == 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 (lval2.Type) && !(IsClassPtr(lval2.Type) && IsNullPtr(Expr))) { - Error ("Incompatible types"); + if (!IsClassInt (Expr2.Type) && !(IsClassPtr(Expr2.Type) && ED_IsNullPtr(Expr))) { + Error ("Incompatible types"); } } else if (IsClassPtr (Expr->Type)) { - if (IsClassPtr (lval2.Type)) { - /* Both pointers are allowed in comparison if they point to - * the same type, or if one of them is a void pointer. + 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. */ - type* left = Indirect (Expr->Type); - type* right = Indirect (lval2.Type); - if (TypeCmp (left, right) < TC_EQUAL && *left != T_VOID && *right != T_VOID) { - /* Incomatible pointers */ - Error ("Incompatible types"); - } - } else if (!IsNullPtr (&lval2)) { - 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"); } } /* Check for const operands */ - if (ED_IsRVal (Expr) && Expr->Flags == E_MCONST && rconst) { + if (ED_IsConstAbs (Expr) && rconst) { - /* Both operands are constant, remove the generated code */ - RemoveCode (Mark1); - pop (ltype); + /* If the result is constant, this is suspicious when not in + * preprocessor mode. + */ + WarnConstCompareResult (); + + /* 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); + } - /* Evaluate the result */ - Expr->ConstVal = kcalc (tok, Expr->ConstVal, lval2.ConstVal); + } else { - } 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 { + + /* Determine the signedness of the operands */ + int LeftSigned = IsSignSigned (Expr->Type); + int RightSigned = IsSignSigned (Expr2.Type); /* If the right hand side is constant, and the generator function * expects the lhs in the primary, remove the push of the primary @@ -1796,41 +2041,195 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */ if (rconst) { flags |= CF_CONST; if ((Gen->Flags & GEN_NOPUSH) != 0) { - RemoveCode (Mark2); - pop (ltype); + RemoveCode (&Mark2); ltype |= CF_REG; /* Value is in register */ } } - /* Determine the type of the operation result. If the left - * operand is of type char and the right is a constant, or - * if both operands are of type char, we will encode the - * operation as char operation. Otherwise the default - * promotions are used. - */ - if (IsTypeChar (Expr->Type) && (IsTypeChar (lval2.Type) || rconst)) { - flags |= CF_CHAR; - if (IsSignUnsigned (Expr->Type) || IsSignUnsigned (lval2.Type)) { - flags |= CF_UNSIGNED; - } - if (rconst) { - flags |= CF_FORCECHAR; - } + /* Determine the type of the operation. */ + if (IsTypeChar (Expr->Type) && rconst) { + + /* Left side is unsigned char, right side is constant. + * Determine the minimum and maximum values + */ + int LeftMin, LeftMax; + if (LeftSigned) { + LeftMin = -128; + LeftMax = 127; + } else { + LeftMin = 0; + LeftMax = 255; + } + /* An integer value is always represented as a signed in the + * ExprDesc structure. This may lead to false results below, + * if it is actually unsigned, but interpreted as signed + * because of the representation. Fortunately, in this case, + * the actual value doesn't matter, since it's always greater + * than what can be represented in a char. So correct the + * value accordingly. + */ + if (!RightSigned && Expr2.IVal < 0) { + /* Correct the value so it is an unsigned. It will then + * anyway match one of the cases below. + */ + Expr2.IVal = LeftMax + 1; + } + + /* Comparing a char against a constant may have a constant + * result. + */ + switch (Tok) { + + case TOK_EQ: + if (Expr2.IVal < LeftMin || Expr2.IVal > LeftMax) { + ED_MakeConstAbsInt (Expr, 0); + WarnConstCompareResult (); + RemoveCode (&Mark0); + goto Done; + } + break; + + case TOK_NE: + if (Expr2.IVal < LeftMin || Expr2.IVal > LeftMax) { + ED_MakeConstAbsInt (Expr, 1); + WarnConstCompareResult (); + RemoveCode (&Mark0); + goto Done; + } + break; + + case TOK_LT: + if (Expr2.IVal <= LeftMin || Expr2.IVal > LeftMax) { + ED_MakeConstAbsInt (Expr, Expr2.IVal > LeftMax); + WarnConstCompareResult (); + RemoveCode (&Mark0); + goto Done; + } + break; + + case TOK_LE: + if (Expr2.IVal < LeftMin || Expr2.IVal >= LeftMax) { + ED_MakeConstAbsInt (Expr, Expr2.IVal >= LeftMax); + WarnConstCompareResult (); + RemoveCode (&Mark0); + goto Done; + } + break; + + case TOK_GE: + if (Expr2.IVal <= LeftMin || Expr2.IVal > LeftMax) { + ED_MakeConstAbsInt (Expr, Expr2.IVal <= LeftMin); + WarnConstCompareResult (); + RemoveCode (&Mark0); + goto Done; + } + break; + + case TOK_GT: + if (Expr2.IVal < LeftMin || Expr2.IVal >= LeftMax) { + ED_MakeConstAbsInt (Expr, Expr2.IVal < LeftMin); + WarnConstCompareResult (); + RemoveCode (&Mark0); + goto Done; + } + break; + + default: + Internal ("hie_compare: got token 0x%X\n", Tok); + } + + /* If the result is not already constant (as evaluated in the + * switch above), we can execute the operation as a char op, + * since the right side constant is in a valid range. + */ + flags |= (CF_CHAR | CF_FORCECHAR); + if (!LeftSigned) { + flags |= CF_UNSIGNED; + } + + } else if (IsTypeChar (Expr->Type) && IsTypeChar (Expr2.Type) && + GetSignedness (Expr->Type) == GetSignedness (Expr2.Type)) { + + /* Both are chars with the same signedness. We can encode the + * operation as a char operation. + */ + flags |= CF_CHAR; + if (rconst) { + flags |= CF_FORCECHAR; + } + if (!LeftSigned) { + flags |= CF_UNSIGNED; + } } else { - unsigned rtype = TypeOf (lval2.Type) | (flags & CF_CONST); + unsigned rtype = TypeOf (Expr2.Type) | (flags & CF_CONST); flags |= g_typeadjust (ltype, rtype); } + /* If the left side is an unsigned and the right is a constant, + * we may be able to change the compares to something more + * effective. + */ + if (!LeftSigned && rconst) { + + switch (Tok) { + + case TOK_LT: + if (Expr2.IVal == 1) { + /* An unsigned compare to one means that the value + * must be zero. + */ + GenFunc = g_eq; + Expr2.IVal = 0; + } + break; + + case TOK_LE: + if (Expr2.IVal == 0) { + /* An unsigned compare to zero means that the value + * must be zero. + */ + GenFunc = g_eq; + } + break; + + case TOK_GE: + if (Expr2.IVal == 1) { + /* An unsigned compare to one means that the value + * must not be zero. + */ + GenFunc = g_ne; + Expr2.IVal = 0; + } + break; + + case TOK_GT: + if (Expr2.IVal == 0) { + /* An unsigned compare to zero means that the value + * must not be zero. + */ + GenFunc = g_ne; + } + break; + + default: + break; + + } + + } + /* Generate code */ - Gen->Func (flags, lval2.ConstVal); - Expr->Flags = E_MEXPR | E_RVAL; + GenFunc (flags, Expr2.IVal); + + /* The result is an rvalue in the primary */ + ED_MakeRValExpr (Expr); } /* Result type is always int */ Expr->Type = type_int; - /* Condition codes are set */ - Expr->Test |= E_CC; +Done: /* Condition codes are set */ + ED_TestDone (Expr); } } @@ -1858,11 +2257,11 @@ static void parseadd (ExprDesc* Expr) * result of the expression on return. */ { - ExprDesc lval2; + 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 */ @@ -1873,40 +2272,40 @@ static void parseadd (ExprDesc* Expr) flags = 0; /* Check for constness on both sides */ - if (ED_IsRVal (Expr) && (Expr->Flags & E_MCONST) != 0) { + if (ED_IsConst (Expr)) { - /* The left hand side is a constant. Good. Get rhs */ - hie9 (&lval2); - if (ED_IsRVal (&lval2) && lval2.Flags == E_MCONST) { + /* The left hand side is a constant of some sort. Good. Get rhs */ + hie9 (&Expr2); + if (ED_IsConstAbs (&Expr2)) { - /* Right hand side is also constant. Get the rhs type */ - rhst = lval2.Type; + /* Right hand side is a constant numeric value. Get the rhs type */ + rhst = Expr2.Type; /* Both expressions are constants. Check for pointer arithmetic */ if (IsClassPtr (lhst) && IsClassInt (rhst)) { - /* Left is pointer, right is int, must scale rhs */ - Expr->ConstVal += lval2.ConstVal * CheckedPSizeOf (lhst); - /* Result type is a pointer */ + /* Left is pointer, right is int, must scale rhs */ + Expr->IVal += Expr2.IVal * CheckedPSizeOf (lhst); + /* Result type is a pointer */ } else if (IsClassInt (lhst) && IsClassPtr (rhst)) { - /* Left is int, right is pointer, must scale lhs */ - Expr->ConstVal = Expr->ConstVal * CheckedPSizeOf (rhst) + lval2.ConstVal; - /* Result type is a pointer */ - Expr->Type = lval2.Type; + /* 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; } else if (IsClassInt (lhst) && IsClassInt (rhst)) { - /* Integer addition */ - Expr->ConstVal += lval2.ConstVal; - typeadjust (Expr, &lval2, 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. */ - ExprLoad (CF_NONE, &lval2); + LoadExpr (CF_NONE, &Expr2); /* Beware: The check above (for lhs) lets not only pass numeric * constants, but also constant addresses (labels), maybe even @@ -1914,15 +2313,15 @@ static void parseadd (ExprDesc* Expr) */ /* First, get the rhs type. */ - rhst = lval2.Type; + rhst = Expr2.Type; /* Setup flags */ - if (Expr->Flags == E_MCONST) { + if (ED_IsLocAbs (Expr)) { /* A numerical constant */ flags |= CF_CONST; } else { /* Constant address label */ - flags |= GlobalModeFlags (Expr->Flags) | CF_CONSTADDR; + flags |= GlobalModeFlags (Expr) | CF_CONSTADDR; } /* Check for pointer arithmetic */ @@ -1932,12 +2331,12 @@ static void parseadd (ExprDesc* Expr) /* Operate on pointers, result type is a pointer */ flags |= CF_PTR; /* Generate the code for the add */ - if (Expr->Flags == E_MCONST) { + if (ED_GetLoc (Expr) == E_LOC_ABS) { /* Numeric constant */ - g_inc (flags, Expr->ConstVal); + g_inc (flags, Expr->IVal); } else { /* Constant address */ - g_addaddr_static (flags, Expr->Name, Expr->ConstVal); + g_addaddr_static (flags, Expr->Name, Expr->IVal); } } else if (IsClassInt (lhst) && IsClassPtr (rhst)) { @@ -1946,68 +2345,71 @@ static void parseadd (ExprDesc* Expr) /* Operate on pointers, result type is a pointer */ flags |= CF_PTR; - Expr->Type = lval2.Type; + Expr->Type = Expr2.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 (Expr->Flags == E_MCONST) { + if (ED_IsLocAbs (Expr)) { /* Numeric constant, scale lhs */ - Expr->ConstVal *= ScaleFactor; + Expr->IVal *= ScaleFactor; /* Generate the code for the add */ - g_inc (flags, Expr->ConstVal); + g_inc (flags, Expr->IVal); } else if (ScaleFactor == 1) { /* Constant address but no need to scale */ - g_addaddr_static (flags, Expr->Name, Expr->ConstVal); + g_addaddr_static (flags, Expr->Name, Expr->IVal); } else { /* Constant address that must be scaled */ - g_push (TypeOf (lval2.Type), 0); /* rhs --> stack */ - g_getimmed (flags, Expr->Name, Expr->ConstVal); + g_push (TypeOf (Expr2.Type), 0); /* rhs --> stack */ + g_getimmed (flags, Expr->Name, Expr->IVal); g_scale (CF_PTR, ScaleFactor); g_add (CF_PTR, 0); } } else if (IsClassInt (lhst) && IsClassInt (rhst)) { /* Integer addition */ - flags |= typeadjust (Expr, &lval2, 1); + flags |= typeadjust (Expr, &Expr2, 1); /* Generate the code for the add */ - if (Expr->Flags == E_MCONST) { + if (ED_IsLocAbs (Expr)) { /* Numeric constant */ - g_inc (flags, Expr->ConstVal); + g_inc (flags, Expr->IVal); } else { /* Constant address */ - g_addaddr_static (flags, Expr->Name, Expr->ConstVal); + g_addaddr_static (flags, Expr->Name, Expr->IVal); } } else { /* OOPS */ Error ("Invalid operands for binary operator `+'"); + flags = CF_INT; } /* Result is a rvalue in primary register */ - Expr->Flags = E_MEXPR | E_RVAL; + ED_MakeRValExpr (Expr); } } else { /* Left hand side is not constant. Get the value onto the stack. */ - ExprLoad (CF_NONE, Expr); /* --> primary register */ - Mark = GetCodePos (); + LoadExpr (CF_NONE, Expr); /* --> primary register */ + GetCodePos (&Mark); g_push (TypeOf (Expr->Type), 0); /* --> stack */ /* Evaluate the rhs */ - if (evalexpr (CF_NONE, hie9, &lval2) == 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 = lval2.Type; + rhst = Expr2.Type; /* Remove pushed value from stack */ - RemoveCode (Mark); - pop (TypeOf (Expr->Type)); + RemoveCode (&Mark); /* Check for pointer arithmetic */ if (IsClassPtr (lhst) && IsClassInt (rhst)) { /* Left is pointer, right is int, must scale rhs */ - lval2.ConstVal *= CheckedPSizeOf (lhst); + Expr2.IVal *= CheckedPSizeOf (lhst); /* Operate on pointers, result type is a pointer */ flags = CF_PTR; } else if (IsClassInt (lhst) && IsClassPtr (rhst)) { @@ -2015,22 +2417,26 @@ static void parseadd (ExprDesc* Expr) g_scale (CF_INT | CF_CONST, CheckedPSizeOf (rhst)); /* Operate on pointers, result type is a pointer */ flags = CF_PTR; - Expr->Type = lval2.Type; + Expr->Type = Expr2.Type; } else if (IsClassInt (lhst) && IsClassInt (rhst)) { /* Integer addition */ - flags = typeadjust (Expr, &lval2, 1); + flags = typeadjust (Expr, &Expr2, 1); } else { /* OOPS */ Error ("Invalid operands for binary operator `+'"); + flags = CF_INT; } /* Generate code for the add */ - g_inc (flags | CF_CONST, lval2.ConstVal); + g_inc (flags | CF_CONST, Expr2.IVal); } else { + /* Not constant, load into the primary */ + LoadExpr (CF_NONE, &Expr2); + /* lhs and rhs are not constant. Get the rhs type. */ - rhst = lval2.Type; + rhst = Expr2.Type; /* Check for pointer arithmetic */ if (IsClassPtr (lhst) && IsClassInt (rhst)) { @@ -2045,7 +2451,7 @@ static void parseadd (ExprDesc* Expr) g_scale (CF_INT, CheckedPSizeOf (rhst)); /* Operate on pointers, result type is a pointer */ flags = CF_PTR; - Expr->Type = lval2.Type; + Expr->Type = Expr2.Type; } else if (IsClassInt (lhst) && IsClassInt (rhst)) { /* Integer addition. Note: Result is never constant. * Problem here is that typeadjust does not know if the @@ -2056,10 +2462,11 @@ static void parseadd (ExprDesc* Expr) * whole parser is such a mess that I fear to break anything * when trying to apply another solution. */ - flags = typeadjust (Expr, &lval2, 0) & ~CF_CONST; + 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 */ @@ -2068,11 +2475,11 @@ static void parseadd (ExprDesc* Expr) } /* Result is a rvalue in primary register */ - Expr->Flags = E_MEXPR | E_RVAL; + ED_MakeRValExpr (Expr); } /* Condition codes not set */ - Expr->Test &= ~E_CC; + ED_MarkAsUntested (Expr); } @@ -2084,13 +2491,13 @@ static void parsesub (ExprDesc* Expr) * result of the expression on return. */ { - ExprDesc lval2; - 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 */ + 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 */ 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 */ @@ -2098,67 +2505,66 @@ static void parsesub (ExprDesc* Expr) /* 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 */ - Mark1 = GetCodePos (); - ExprLoad (CF_NONE, Expr); /* --> primary register */ - Mark2 = GetCodePos (); + GetCodePos (&Mark1); + LoadExpr (CF_NONE, Expr); /* --> primary register */ + GetCodePos (&Mark2); g_push (TypeOf (lhst), 0); /* --> stack */ /* Parse the right hand side */ - if (evalexpr (CF_NONE, hie9, &lval2) == 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 = lval2.Type; + rhst = Expr2.Type; /* Check left hand side */ - if (ED_IsRVal (Expr) && (Expr->Flags & E_MCONST) != 0) { + if (ED_IsConstAbs (Expr)) { /* Both sides are constant, remove generated code */ - RemoveCode (Mark1); - pop (TypeOf (lhst)); /* Clean up the stack */ + RemoveCode (&Mark1); /* Check for pointer arithmetic */ if (IsClassPtr (lhst) && IsClassInt (rhst)) { /* Left is pointer, right is int, must scale rhs */ - Expr->ConstVal -= lval2.ConstVal * CheckedPSizeOf (lhst); + Expr->IVal -= Expr2.IVal * CheckedPSizeOf (lhst); /* Operate on pointers, result type is a pointer */ } 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 { - Expr->ConstVal = (Expr->ConstVal - lval2.ConstVal) / + Expr->IVal = (Expr->IVal - Expr2.IVal) / CheckedPSizeOf (lhst); } /* Operate on pointers, result type is an integer */ Expr->Type = type_int; } else if (IsClassInt (lhst) && IsClassInt (rhst)) { /* Integer subtraction */ - typeadjust (Expr, &lval2, 1); - Expr->ConstVal -= lval2.ConstVal; + typeadjust (Expr, &Expr2, 1); + Expr->IVal -= Expr2.IVal; } else { /* OOPS */ Error ("Invalid operands for binary operator `-'"); } /* Result is constant, condition codes not set */ - /* Expr->Flags = E_MCONST; ### */ - Expr->Test &= ~E_CC; + ED_MarkAsUntested (Expr); } else { /* Left hand side is not constant, right hand side is. * Remove pushed value from stack. */ - RemoveCode (Mark2); - pop (TypeOf (lhst)); + RemoveCode (&Mark2); if (IsClassPtr (lhst) && IsClassInt (rhst)) { /* Left is pointer, right is int, must scale rhs */ - lval2.ConstVal *= CheckedPSizeOf (lhst); + Expr2.IVal *= CheckedPSizeOf (lhst); /* Operate on pointers, result type is a pointer */ flags = CF_PTR; } else if (IsClassPtr (lhst) && IsClassPtr (rhst)) { @@ -2168,65 +2574,70 @@ static void parsesub (ExprDesc* Expr) } 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)) { /* Integer subtraction */ - flags = typeadjust (Expr, &lval2, 1); + flags = typeadjust (Expr, &Expr2, 1); } else { /* OOPS */ Error ("Invalid operands for binary operator `-'"); + flags = CF_INT; } /* Do the subtraction */ - g_dec (flags | CF_CONST, lval2.ConstVal); + 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 */ - Expr->Flags = E_MEXPR | E_RVAL; - Expr->Test &= ~E_CC; + /* 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 = lval2.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 (Expr->Flags == E_MCONST) { - Expr->Flags = E_MEXPR | E_RVAL; + if (ED_IsLocAbs (Expr)) { + ED_MakeRValExpr (Expr); } /* Adjust operand types */ - flags = typeadjust (Expr, &lval2, 0); + 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) */ @@ -2238,14 +2649,14 @@ static void parsesub (ExprDesc* Expr) } /* Result is a rvalue in the primary register */ - Expr->Flags = E_MEXPR | E_RVAL; - Expr->Test &= ~E_CC; + ED_MakeRValExpr (Expr); + ED_MarkAsUntested (Expr); } } -static void hie8 (ExprDesc* Expr) +void hie8 (ExprDesc* Expr) /* Process + and - binary operators. */ { hie9 (Expr); @@ -2260,22 +2671,6 @@ static void hie8 (ExprDesc* Expr) - -static void hie7 (ExprDesc* Expr) -/* Parse << and >>. */ -{ - static const GenDesc hie7_ops [] = { - { TOK_SHL, GEN_NOPUSH, g_asl }, - { TOK_SHR, GEN_NOPUSH, g_asr }, - { TOK_INVALID, 0, 0 } - }; - int UsedGen; - - hie_internal (hie7_ops, Expr, hie8, &UsedGen); -} - - - static void hie6 (ExprDesc* Expr) /* Handle greater-than type comparators */ { @@ -2286,7 +2681,7 @@ static void hie6 (ExprDesc* Expr) { TOK_GT, GEN_NOPUSH, g_gt }, { TOK_INVALID, 0, 0 } }; - hie_compare (hie6_ops, Expr, hie7); + hie_compare (hie6_ops, Expr, ShiftExpr); } @@ -2351,31 +2746,19 @@ static void hieAndPP (ExprDesc* Expr) * called recursively from the preprocessor. */ { - ExprDesc lval2; + ExprDesc Expr2; - ConstSubExpr (hie2, Expr); + ConstAbsIntExpr (hie2, Expr); while (CurTok.Tok == TOK_BOOL_AND) { - /* Left hand side must be an int */ - if (!IsClassInt (Expr->Type)) { - Error ("Left hand side must be of integer type"); - ED_MakeConstInt (Expr, 1); - } - /* Skip the && */ NextToken (); /* Get rhs */ - ConstSubExpr (hie2, &lval2); - - /* Since we are in PP mode, all we know about is integers */ - if (!IsClassInt (lval2.Type)) { - Error ("Right hand side must be of integer type"); - ED_MakeConstInt (&lval2, 1); - } + ConstAbsIntExpr (hie2, &Expr2); /* Combine the two */ - Expr->ConstVal = (Expr->ConstVal && lval2.ConstVal); + Expr->IVal = (Expr->IVal && Expr2.IVal); } } @@ -2386,31 +2769,19 @@ static void hieOrPP (ExprDesc *Expr) * called recursively from the preprocessor. */ { - ExprDesc lval2; + ExprDesc Expr2; - ConstSubExpr (hieAndPP, Expr); + ConstAbsIntExpr (hieAndPP, Expr); while (CurTok.Tok == TOK_BOOL_OR) { - /* Left hand side must be an int */ - if (!IsClassInt (Expr->Type)) { - Error ("Left hand side must be of integer type"); - ED_MakeConstInt (Expr, 1); - } - /* Skip the && */ NextToken (); /* Get rhs */ - ConstSubExpr (hieAndPP, &lval2); - - /* Since we are in PP mode, all we know about is integers */ - if (!IsClassInt (lval2.Type)) { - Error ("Right hand side must be of integer type"); - ED_MakeConstInt (&lval2, 1); - } + ConstAbsIntExpr (hieAndPP, &Expr2); /* Combine the two */ - Expr->ConstVal = (Expr->ConstVal || lval2.ConstVal); + Expr->IVal = (Expr->IVal || Expr2.IVal); } } @@ -2419,8 +2790,8 @@ static void hieOrPP (ExprDesc *Expr) static void hieAnd (ExprDesc* Expr, unsigned TrueLab, int* BoolOp) /* Process "exp && exp" */ { - int lab; - ExprDesc lval2; + int FalseLab; + ExprDesc Expr2; hie2 (Expr); if (CurTok.Tok == TOK_BOOL_AND) { @@ -2429,18 +2800,18 @@ static void hieAnd (ExprDesc* Expr, unsigned TrueLab, int* BoolOp) *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 ((Expr->Test & E_CC) == 0) { - Expr->Test |= E_FORCETEST; + if (!ED_IsTested (Expr)) { + ED_MarkForTest (Expr); } /* Load the value */ - ExprLoad (CF_FORCECHAR, 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) { @@ -2449,15 +2820,15 @@ static void hieAnd (ExprDesc* Expr, unsigned TrueLab, int* BoolOp) NextToken (); /* Get rhs */ - hie2 (&lval2); - if ((lval2.Test & E_CC) == 0) { - lval2.Test |= E_FORCETEST; + hie2 (&Expr2); + if (!ED_IsTested (&Expr2)) { + ED_MarkForTest (&Expr2); } - ExprLoad (CF_FORCECHAR, &lval2); + LoadExpr (CF_FORCECHAR, &Expr2); /* 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); @@ -2465,11 +2836,11 @@ static void hieAnd (ExprDesc* Expr, unsigned TrueLab, int* BoolOp) } /* Define the false jump label here */ - g_defcodelabel (lab); + g_defcodelabel (FalseLab); /* The result is an rvalue in primary */ - Expr->Flags = E_MEXPR | E_RVAL; - Expr->Test |= E_CC; /* Condition codes are set */ + ED_MakeRValExpr (Expr); + ED_TestDone (Expr); /* Condition codes are set */ } } @@ -2478,10 +2849,10 @@ static void hieAnd (ExprDesc* Expr, unsigned TrueLab, int* BoolOp) static void hieOr (ExprDesc *Expr) /* Process "exp || exp". */ { - ExprDesc lval2; - int BoolOp = 0; /* Did we have a boolean op? */ - int AndOp; /* Did we have a && operation? */ - unsigned TrueLab; /* Jump to this label if true */ + ExprDesc Expr2; + int BoolOp = 0; /* Did we have a boolean op? */ + int AndOp; /* Did we have a && operation? */ + unsigned TrueLab; /* Jump to this label if true */ unsigned DoneLab; /* Get a label */ @@ -2494,12 +2865,12 @@ static void hieOr (ExprDesc *Expr) if (CurTok.Tok == TOK_BOOL_OR) { /* If the expr hasn't set condition codes, set the force-test flag */ - if ((Expr->Test & E_CC) == 0) { - Expr->Test |= E_FORCETEST; + if (!ED_IsTested (Expr)) { + ED_MarkForTest (Expr); } /* Get first expr */ - ExprLoad (CF_FORCECHAR, Expr); + LoadExpr (CF_FORCECHAR, Expr); /* For each expression jump to TrueLab if true. Beware: If we * had && operators, the jump is already in place! @@ -2519,11 +2890,11 @@ static void hieOr (ExprDesc *Expr) /* Get a subexpr */ AndOp = 0; - hieAnd (&lval2, TrueLab, &AndOp); - if ((lval2.Test & E_CC) == 0) { - lval2.Test |= E_FORCETEST; + hieAnd (&Expr2, TrueLab, &AndOp); + if (!ED_IsTested (&Expr2)) { + ED_MarkForTest (&Expr2); } - ExprLoad (CF_FORCECHAR, &lval2); + LoadExpr (CF_FORCECHAR, &Expr2); /* If there is more to come, add shortcut boolean eval. */ g_truejump (CF_NONE, TrueLab); @@ -2531,8 +2902,8 @@ static void hieOr (ExprDesc *Expr) } /* The result is an rvalue in primary */ - Expr->Flags = E_MEXPR | E_RVAL; - Expr->Test |= E_CC; /* Condition codes are set */ + ED_MakeRValExpr (Expr); + ED_TestDone (Expr); /* Condition codes are set */ } /* If we really had boolean ops, generate the end sequence */ @@ -2551,13 +2922,14 @@ static void hieOr (ExprDesc *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 */ @@ -2570,40 +2942,47 @@ static void hieQuest (ExprDesc* Expr) /* Check if it's a ternary expression */ if (CurTok.Tok == TOK_QUEST) { NextToken (); - if ((Expr->Test & E_CC) == 0) { - /* Condition codes not set, force a test */ - Expr->Test |= E_FORCETEST; + if (!ED_IsTested (Expr)) { + /* Condition codes not set, request a test */ + ED_MarkForTest (Expr); } - ExprLoad (CF_NONE, Expr); - labf = GetLocalLabel (); - g_falsejump (CF_NONE, labf); + LoadExpr (CF_NONE, Expr); + 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. */ - expr (hie1, &Expr2); - Expr2IsNULL = IsNullPtr (&Expr2); + ExprWithCheck (hie1, &Expr2); + Expr2IsNULL = ED_IsNullPtr (&Expr2); if (!IsTypeVoid (Expr2.Type)) { /* Load it into the primary */ - ExprLoad (CF_NONE, &Expr2); - Expr2.Flags = E_MEXPR | E_RVAL; + 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. */ - expr (hie1, &Expr3); - Expr3IsNULL = IsNullPtr (&Expr3); + ExprWithCheck (hie1, &Expr3); + Expr3IsNULL = ED_IsNullPtr (&Expr3); if (!IsTypeVoid (Expr3.Type)) { /* Load it into the primary */ - ExprLoad (CF_NONE, &Expr3); - Expr3.Flags = E_MEXPR | E_RVAL; + LoadExpr (CF_NONE, &Expr3); + ED_MakeRValExpr (&Expr3); + Expr3.Type = PtrConversion (Expr3.Type); } /* Check if any conversions are needed, if so, do them. @@ -2621,27 +3000,27 @@ static void hieQuest (ExprDesc* Expr) */ 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 */ @@ -2664,60 +3043,83 @@ static void hieQuest (ExprDesc* Expr) 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 */ - Expr->Flags = E_MEXPR | E_RVAL; + ED_MakeRValExpr (Expr); Expr->Type = ResultType; } } -static void opeq (const GenDesc* Gen, ExprDesc* Expr) +static void opeq (const GenDesc* Gen, ExprDesc* Expr, const char* Op) /* Process "op=" operators. */ { - ExprDesc lval2; + ExprDesc Expr2; unsigned flags; CodeMark Mark; int MustScale; - NextToken (); - if (ED_IsRVal (Expr)) { + /* op= can only be used with lvalues */ + if (!ED_IsLVal (Expr)) { Error ("Invalid lvalue in assignment"); 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"); + /* Continue. Wrong code will be generated, but the compiler won't + * break, so this is the best error recovery. + */ + } + + /* Skip the operator token */ + NextToken (); + /* Determine the type of the lhs */ flags = TypeOf (Expr->Type); - MustScale = (Gen->Func == g_add || Gen->Func == g_sub) && - Expr->Type [0] == T_PTR; + MustScale = (Gen->Func == g_add || Gen->Func == g_sub) && IsTypePtr (Expr->Type); /* Get the lhs address on stack (if needed) */ PushAddr (Expr); /* Fetch the lhs into the primary register if needed */ - ExprLoad (CF_NONE, Expr); + LoadExpr (CF_NONE, Expr); /* Bring the lhs on stack */ - Mark = GetCodePos (); + GetCodePos (&Mark); g_push (flags, 0); /* Evaluate the rhs */ - if (evalexpr (CF_NONE, hie1, &lval2) == 0) { - /* The resulting value is a constant. If the generator has the NOPUSH - * flag set, don't push the lhs. - */ - if (Gen->Flags & GEN_NOPUSH) { - RemoveCode (Mark); - pop (flags); + 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. + */ + if (Gen->Flags & GEN_NOPUSH) { + RemoveCode (&Mark); } if (MustScale) { /* lhs is a pointer, scale rhs */ - lval2.ConstVal *= CheckedSizeOf (Expr->Type+1); + Expr2.IVal *= CheckedSizeOf (Expr->Type+1); } /* If the lhs is character sized, the operation may be later done @@ -2729,17 +3131,27 @@ static void opeq (const GenDesc* Gen, ExprDesc* Expr) /* Special handling for add and sub - some sort of a hack, but short code */ if (Gen->Func == g_add) { - g_inc (flags | CF_CONST, lval2.ConstVal); + g_inc (flags | CF_CONST, Expr2.IVal); } else if (Gen->Func == g_sub) { - g_dec (flags | CF_CONST, lval2.ConstVal); + g_dec (flags | CF_CONST, Expr2.IVal); } else { - Gen->Func (flags | CF_CONST, lval2.ConstVal); + 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 (lval2.Type), CheckedSizeOf (Expr->Type+1)); + g_scale (TypeOf (Expr2.Type), CheckedSizeOf (Expr->Type+1)); } /* If the lhs is character sized, the operation may be later done @@ -2750,111 +3162,147 @@ static void opeq (const GenDesc* Gen, ExprDesc* Expr) } /* Adjust the types of the operands if needed */ - Gen->Func (g_typeadjust (flags, TypeOf (lval2.Type)), 0); + Gen->Func (g_typeadjust (flags, TypeOf (Expr2.Type)), 0); } Store (Expr, 0); - Expr->Flags = E_MEXPR | E_RVAL; + ED_MakeRValExpr (Expr); } -static void addsubeq (const GenDesc* Gen, ExprDesc *Expr) +static void addsubeq (const GenDesc* Gen, ExprDesc *Expr, const char* Op) /* Process the += and -= operators */ { - ExprDesc lval2; + ExprDesc Expr2; unsigned lflags; unsigned rflags; int MustScale; + /* 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, Op); + return; + } + /* We must have an lvalue */ if (ED_IsRVal (Expr)) { Error ("Invalid lvalue in assignment"); return; } - /* We're currently only able to handle some adressing modes */ - if ((Expr->Flags & E_MGLOBAL) == 0 && /* Global address? */ - (Expr->Flags & E_MLOCAL) == 0 && /* Local address? */ - (Expr->Flags & E_MCONST) == 0) { /* Constant address? */ - /* Use generic routine */ - opeq (Gen, Expr); - 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"); + /* Continue. Wrong code will be generated, but the compiler won't + * break, so this is the best error recovery. + */ } /* Skip the operator */ NextToken (); /* Check if we have a pointer expression and must scale rhs */ - MustScale = (Expr->Type [0] == T_PTR); + MustScale = IsTypePtr (Expr->Type); /* Initialize the code generator flags */ lflags = 0; rflags = 0; - /* Evaluate the rhs */ - hie1 (&lval2); - if (ED_IsRVal (&lval2) && lval2.Flags == E_MCONST) { - /* The resulting value is a constant. */ - if (MustScale) { - /* lhs is a pointer, scale rhs */ - lval2.ConstVal *= CheckedSizeOf (Expr->Type+1); - } + /* 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) { + Expr2.IVal *= CheckedSizeOf (Indirect (Expr->Type)); + } rflags |= CF_CONST; lflags |= CF_CONST; } else { /* Not constant, load into the primary */ - ExprLoad (CF_NONE, &lval2); + LoadExpr (CF_NONE, &Expr2); if (MustScale) { /* lhs is a pointer, scale rhs */ - g_scale (TypeOf (lval2.Type), CheckedSizeOf (Expr->Type+1)); + g_scale (TypeOf (Expr2.Type), CheckedSizeOf (Indirect (Expr->Type))); } } /* Setup the code generator flags */ - lflags |= TypeOf (Expr->Type) | CF_FORCECHAR; - rflags |= TypeOf (lval2.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); - /* Output apropriate code */ - if (Expr->Flags & E_MGLOBAL) { - /* Static variable */ - lflags |= GlobalModeFlags (Expr->Flags); - if (Gen->Tok == TOK_PLUS_ASSIGN) { - g_addeqstatic (lflags, Expr->Name, Expr->ConstVal, lval2.ConstVal); - } else { - g_subeqstatic (lflags, Expr->Name, Expr->ConstVal, lval2.ConstVal); - } - } else if (Expr->Flags & E_MLOCAL) { - /* ref to localvar */ - if (Gen->Tok == TOK_PLUS_ASSIGN) { - g_addeqlocal (lflags, Expr->ConstVal, lval2.ConstVal); - } else { - g_subeqlocal (lflags, Expr->ConstVal, lval2.ConstVal); - } - } else if (Expr->Flags & E_MCONST) { - /* ref to absolute address */ - lflags |= CF_ABSOLUTE; - if (Gen->Tok == TOK_PLUS_ASSIGN) { - g_addeqstatic (lflags, Expr->ConstVal, 0, lval2.ConstVal); - } else { - g_subeqstatic (lflags, Expr->ConstVal, 0, lval2.ConstVal); - } - } else if (Expr->Flags & E_MEXPR) { - /* Address in a/x. */ - if (Gen->Tok == TOK_PLUS_ASSIGN) { - g_addeqind (lflags, Expr->ConstVal, lval2.ConstVal); - } else { - g_subeqind (lflags, Expr->ConstVal, lval2.ConstVal); - } - } else { - Internal ("Invalid addressing mode"); + /* Output apropriate code depending on the location */ + switch (ED_GetLoc (Expr)) { + + case E_LOC_ABS: + /* Absolute: numeric address or const */ + if (Gen->Tok == TOK_PLUS_ASSIGN) { + g_addeqstatic (lflags, Expr->Name, Expr->IVal, Expr2.IVal); + } else { + g_subeqstatic (lflags, Expr->Name, Expr->IVal, Expr2.IVal); + } + break; + + case E_LOC_GLOBAL: + /* Global variable */ + if (Gen->Tok == TOK_PLUS_ASSIGN) { + g_addeqstatic (lflags, Expr->Name, Expr->IVal, Expr2.IVal); + } else { + g_subeqstatic (lflags, Expr->Name, Expr->IVal, Expr2.IVal); + } + break; + + case E_LOC_STATIC: + case E_LOC_LITERAL: + /* Static variable or literal in the literal pool */ + if (Gen->Tok == TOK_PLUS_ASSIGN) { + g_addeqstatic (lflags, Expr->Name, Expr->IVal, Expr2.IVal); + } else { + g_subeqstatic (lflags, Expr->Name, Expr->IVal, Expr2.IVal); + } + break; + + case E_LOC_REGISTER: + /* Register variable */ + if (Gen->Tok == TOK_PLUS_ASSIGN) { + g_addeqstatic (lflags, Expr->Name, Expr->IVal, Expr2.IVal); + } else { + g_subeqstatic (lflags, Expr->Name, Expr->IVal, Expr2.IVal); + } + break; + + case E_LOC_STACK: + /* Value on the stack */ + if (Gen->Tok == TOK_PLUS_ASSIGN) { + g_addeqlocal (lflags, Expr->IVal, Expr2.IVal); + } else { + g_subeqlocal (lflags, Expr->IVal, Expr2.IVal); + } + break; + + default: + Internal ("Invalid location in Store(): 0x%04X", ED_GetLoc (Expr)); } /* Expression is a rvalue in the primary now */ - Expr->Flags = E_MEXPR | E_RVAL; + ED_MakeRValExpr (Expr); } @@ -2870,43 +3318,43 @@ void hie1 (ExprDesc* Expr) 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: @@ -2930,104 +3378,82 @@ void hie0 (ExprDesc *Expr) 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 - * result is not constant, ExprLoad is called to bring the value into the + * constant, 0 is returned and the value is put in the Expr struct. If the + * result is not constant, LoadExpr is called to bring the value into the * primary register and 1 is returned. */ { /* Evaluate */ - Func (Expr); + ExprWithCheck (Func, Expr); /* Check for a constant expression */ - if (ED_IsRVal (Expr) && Expr->Flags == E_MCONST) { + if (ED_IsConstAbs (Expr)) { /* Constant expression */ return 0; } else { /* Not constant, load into the primary */ - ExprLoad (Flags, Expr); + LoadExpr (Flags, Expr); return 1; } } -void expr (void (*Func) (ExprDesc*), ExprDesc *Expr) -/* Expression parser; func is either hie0 or hie1. */ +void Expression0 (ExprDesc* Expr) +/* Evaluate an expression via hie0 and put the result into the primary register */ { - /* Remember the stack pointer */ - int savsp = oursp; - - /* Call the expression function */ - (*Func) (Expr); - - /* Do some checks if code generation is still constistent */ - if (savsp != oursp) { - if (Debug) { - fprintf (stderr, "oursp != savesp (%d != %d)\n", oursp, savsp); - } else { - Internal ("oursp != savsp (%d != %d)", oursp, savsp); - } - } + ExprWithCheck (hie0, Expr); + LoadExpr (CF_NONE, Expr); } -void expression1 (ExprDesc* Expr) -/* Evaluate an expression on level 1 (no comma operator) and put it into - * the primary register +void ConstExpr (void (*Func) (ExprDesc*), ExprDesc* Expr) +/* Will evaluate an expression via the given function. If the result is not + * a constant of some sort, a diagnostic will be printed, and the value is + * replaced by a constant one to make sure there are no internal errors that + * result from this input error. */ { - expr (hie1, InitExprDesc (Expr)); - ExprLoad (CF_NONE, Expr); -} - - - -void expression0 (ExprDesc* Expr) -/* Evaluate an expression via hie0 and put it into the primary register */ -{ - expr (hie0, InitExprDesc (Expr)); - ExprLoad (CF_NONE, Expr); -} - - - -void ConstExpr (ExprDesc* lval) -/* Get a constant value */ -{ - expr (hie1, InitExprDesc (lval)); - if (ED_IsLVal (lval) || (lval->Flags & E_MCONST) == 0) { + ExprWithCheck (Func, Expr); + if (!ED_IsConst (Expr)) { Error ("Constant expression expected"); /* To avoid any compiler errors, make the expression a valid const */ - ED_MakeConstInt (lval, 1); + ED_MakeConstAbsInt (Expr, 1); } } -void ConstIntExpr (ExprDesc* Val) -/* Get a constant int value */ +void BoolExpr (void (*Func) (ExprDesc*), ExprDesc* Expr) +/* Will evaluate an expression via the given function. If the result is not + * something that may be evaluated in a boolean context, a diagnostic will be + * printed, and the value is replaced by a constant one to make sure there + * are no internal errors that result from this input error. + */ { - expr (hie1, InitExprDesc (Val)); - if (ED_IsLVal (Val) || - (Val->Flags & E_MCONST) == 0 || - !IsClassInt (Val->Type)) { - Error ("Constant integer expression expected"); - /* To avoid any compiler errors, make the expression a valid const */ - ED_MakeConstInt (Val, 1); + ExprWithCheck (Func, Expr); + if (!ED_IsBool (Expr)) { + Error ("Boolean expression expected"); + /* To avoid any compiler errors, make the expression a valid int */ + ED_MakeConstAbsInt (Expr, 1); } } -void intexpr (ExprDesc* lval) -/* Get an integer expression */ +void ConstAbsIntExpr (void (*Func) (ExprDesc*), ExprDesc* Expr) +/* Will evaluate an expression via the given function. If the result is not + * a constant numeric integer value, a diagnostic will be printed, and the + * value is replaced by a constant one to make sure there are no internal + * errors that result from this input error. + */ { - expression0 (lval); - if (!IsClassInt (lval->Type)) { - Error ("Integer expression expected"); - /* To avoid any compiler errors, make the expression a valid int */ - ED_MakeConstInt (lval, 1); + ExprWithCheck (Func, Expr); + if (!ED_IsConstAbsInt (Expr)) { + Error ("Constant integer expression expected"); + /* To avoid any compiler errors, make the expression a valid const */ + ED_MakeConstAbsInt (Expr, 1); } }