X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fcc65%2Fexpr.c;h=cc3fab011db0a9af2829dbed261cd37c9d298652;hb=763a35911411adbe46e07b57b6161205a51e16b6;hp=a269359021c7fad151a4e7da5e19776af3326036;hpb=8f057fd84d35db427d779b6295be5f9308c275a2;p=cc65 diff --git a/src/cc65/expr.c b/src/cc65/expr.c index a26935902..cc3fab011 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 */ @@ -8,18 +7,18 @@ #include #include -#include /* common */ #include "check.h" +#include "debugflag.h" #include "xmalloc.h" /* cc65 */ #include "asmcode.h" #include "asmlabel.h" #include "asmstmt.h" +#include "assignment.h" #include "codegen.h" -#include "datatype.h" #include "declare.h" #include "error.h" #include "funcdesc.h" @@ -32,6 +31,7 @@ #include "stdfunc.h" #include "symtab.h" #include "typecmp.h" +#include "typeconv.h" #include "expr.h" @@ -53,20 +53,6 @@ typedef struct { } GenDesc; /* Descriptors for the operations */ -static GenDesc GenMUL = { TOK_STAR, GEN_NOPUSH, g_mul }; -static GenDesc GenDIV = { TOK_DIV, GEN_NOPUSH, g_div }; -static GenDesc GenMOD = { TOK_MOD, GEN_NOPUSH, g_mod }; -static GenDesc GenASL = { TOK_SHL, GEN_NOPUSH, g_asl }; -static GenDesc GenASR = { TOK_SHR, GEN_NOPUSH, g_asr }; -static GenDesc GenLT = { TOK_LT, GEN_NOPUSH, g_lt }; -static GenDesc GenLE = { TOK_LE, GEN_NOPUSH, g_le }; -static GenDesc GenGE = { TOK_GE, GEN_NOPUSH, g_ge }; -static GenDesc GenGT = { TOK_GT, GEN_NOPUSH, g_gt }; -static GenDesc GenEQ = { TOK_EQ, GEN_NOPUSH, g_eq }; -static GenDesc GenNE = { TOK_NE, GEN_NOPUSH, g_ne }; -static GenDesc GenAND = { TOK_AND, GEN_NOPUSH, g_and }; -static GenDesc GenXOR = { TOK_XOR, GEN_NOPUSH, g_xor }; -static GenDesc GenOR = { TOK_OR, GEN_NOPUSH, g_or }; static GenDesc GenPASGN = { TOK_PLUS_ASSIGN, GEN_NOPUSH, g_add }; static GenDesc GenSASGN = { TOK_MINUS_ASSIGN, GEN_NOPUSH, g_sub }; static GenDesc GenMASGN = { TOK_MUL_ASSIGN, GEN_NOPUSH, g_mul }; @@ -86,8 +72,8 @@ static GenDesc GenOASGN = { TOK_OR_ASSIGN, GEN_NOPUSH, g_or }; -static int hie10 (ExprDesc* lval); -/* Handle ++, --, !, unary - etc. */ +void hie0 (ExprDesc *lval); +/* Parse comma operator. */ @@ -97,30 +83,40 @@ static int hie10 (ExprDesc* lval); -static unsigned GlobalModeFlags (unsigned flags) +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; + switch (Flags & E_MASK_LOC) { + case E_LOC_GLOBAL: return CF_EXTERNAL; + case E_LOC_STATIC: return CF_STATIC; + case E_LOC_REGISTER: return CF_REGVAR; + default: + Internal ("GlobalModeFlags: Invalid flags value: %u", Flags); } } -static int IsNullPtr (ExprDesc* lval) -/* Return true if this is the NULL pointer constant */ +static void ExprWithCheck (void (*Func) (ExprDesc*), ExprDesc *Expr) +/* Call an expression function with checks. */ { - return (IsClassInt (lval->Type) && /* Is it an int? */ - lval->Flags == E_MCONST && /* Is it constant? */ - lval->ConstVal == 0); /* And is it's value zero? */ + /* Remember the stack pointer */ + int OldSP = StackPtr; + + /* Call the expression function */ + (*Func) (Expr); + + /* Do some checks if code generation is still constistent */ + if (StackPtr != OldSP) { + if (Debug) { + fprintf (stderr, + "Code generation messed up!\n" + "StackPtr is %d, should be %d", + StackPtr, OldSP); + } else { + Internal ("StackPtr is %d, should be %d\n", StackPtr, OldSP); + } + } } @@ -169,7 +165,7 @@ static unsigned typeadjust (ExprDesc* lhs, ExprDesc* rhs, int NoPush) /* Generate type adjustment code if needed */ ltype = TypeOf (lhst); - if (lhs->Flags == E_MCONST) { + if (ED_IsLocAbs (lhs)) { ltype |= CF_CONST; } if (NoPush) { @@ -177,7 +173,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); @@ -191,179 +187,86 @@ static unsigned typeadjust (ExprDesc* lhs, ExprDesc* rhs, int NoPush) -unsigned assignadjust (type* lhst, ExprDesc* rhs) -/* Adjust the type of the right hand expression so that it can be assigned to - * the type on the left hand side. This function is used for assignment and - * for converting parameters in a function call. It returns the code generator - * flags for the operation. The type string of the right hand side will be - * set to the type of the left hand side. - */ -{ - /* Get the type of the right hand side. Treat function types as - * pointer-to-function - */ - type* rhst = rhs->Type; - if (IsTypeFunc (rhst)) { - rhst = PointerTo (rhst); - } - - /* After calling this function, rhs will have the type of the lhs */ - rhs->Type = lhst; - - /* First, do some type checking */ - if (IsTypeVoid (lhst) || IsTypeVoid (rhst)) { - /* If one of the sides are of type void, output a more apropriate - * error message. - */ - Error ("Illegal type"); - } else if (IsClassInt (lhst)) { - if (IsClassPtr (rhst)) { - /* Pointer -> int conversion */ - Warning ("Converting pointer to integer without a cast"); - } else if (!IsClassInt (rhst)) { - Error ("Incompatible types"); - } else { - /* Adjust the int types. To avoid manipulation of TOS mark lhs - * as const. - */ - unsigned flags = TypeOf (rhst); - if (rhs->Flags == E_MCONST) { - flags |= CF_CONST; - } - return g_typeadjust (TypeOf (lhst) | CF_CONST, flags); - } - } else if (IsClassPtr (lhst)) { - if (IsClassPtr (rhst)) { - /* Pointer to pointer assignment is valid, if: - * - both point to the same types, or - * - the rhs pointer is a void pointer, or - * - the lhs pointer is a void pointer. - */ - if (!IsTypeVoid (Indirect (lhst)) && !IsTypeVoid (Indirect (rhst))) { - /* Compare the types */ - switch (TypeCmp (lhst, rhst)) { - - case TC_INCOMPATIBLE: - Error ("Incompatible pointer types"); - break; - - case TC_QUAL_DIFF: - Error ("Pointer types differ in type qualifiers"); - break; - - default: - /* Ok */ - break; - } - } - } else if (IsClassInt (rhst)) { - /* Int to pointer assignment is valid only for constant zero */ - if (rhs->Flags != E_MCONST || rhs->ConstVal != 0) { - Warning ("Converting integer to pointer without a cast"); - } - } else if (IsTypeFuncPtr (lhst) && IsTypeFunc(rhst)) { - /* Assignment of function to function pointer is allowed, provided - * that both functions have the same parameter list. - */ - if (TypeCmp (Indirect (lhst), rhst) < TC_EQUAL) { - Error ("Incompatible types"); - } - } else { - Error ("Incompatible types"); - } - } else { - Error ("Incompatible types"); - } - - /* Return an int value in all cases where the operands are not both ints */ - return CF_INT; -} - - - -void DefineData (ExprDesc* lval) +void DefineData (ExprDesc* Expr) /* Output a data definition for the given expression */ { - unsigned flags = lval->Flags; + switch (ED_GetLoc (Expr)) { - switch (flags & E_MCTYPE) { + case E_LOC_ABS: + /* Absolute: numeric address or const */ + g_defdata (TypeOf (Expr->Type) | CF_CONST, Expr->Val, 0); + break; - case E_TCONST: - /* Number */ - g_defdata (TypeOf (lval->Type) | CF_CONST, lval->ConstVal, 0); - break; + case E_LOC_GLOBAL: + /* Global variable */ + g_defdata (CF_EXTERNAL, Expr->Name, Expr->Val); + break; - case E_TREGISTER: + case E_LOC_STATIC: + case E_LOC_LITERAL: + /* Static variable or literal in the literal pool */ + g_defdata (CF_STATIC, Expr->Name, Expr->Val); + break; + + case E_LOC_REGISTER: /* Register variable. Taking the address is usually not * allowed. */ - if (!AllowRegVarAddr) { + 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), lval->Name, lval->ConstVal); - break; - - case E_TLIT: - /* a literal of some kind */ - g_defdata (CF_STATIC, LiteralPoolLabel, lval->ConstVal); - break; + g_defdata (CF_REGVAR, Expr->Name, Expr->Val); + break; default: - Internal ("Unknown constant type: %04X", flags); + Internal ("Unknown constant type: 0x%04X", ED_GetLoc (Expr)); } } -static void lconst (unsigned flags, ExprDesc* lval) -/* Load primary reg with some constant value. */ +static void LoadConstant (unsigned Flags, ExprDesc* Expr) +/* Load the primary register with some constant value. */ { - switch (lval->Flags & E_MCTYPE) { - - case E_TLOFFS: - g_leasp (lval->ConstVal); - break; + switch (ED_GetLoc (Expr)) { - case E_TCONST: + case E_LOC_ABS: /* Number constant */ - g_getimmed (flags | TypeOf (lval->Type) | CF_CONST, lval->ConstVal, 0); + g_getimmed (Flags | TypeOf (Expr->Type) | CF_CONST, Expr->Val, 0); + break; + + case E_LOC_GLOBAL: + /* Global symbol, load address */ + g_getimmed ((Flags | CF_EXTERNAL) & ~CF_CONST, Expr->Name, Expr->Val); + break; + + case E_LOC_STATIC: + case E_LOC_LITERAL: + /* Static symbol or literal, load address */ + g_getimmed ((Flags | CF_STATIC) & ~CF_CONST, Expr->Name, Expr->Val); break; - case E_TREGISTER: + case E_LOC_REGISTER: /* Register variable. Taking the address is usually not * allowed. */ - if (!AllowRegVarAddr) { + 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 (lval->Flags); - flags &= ~CF_CONST; - g_getimmed (flags, lval->Name, lval->ConstVal); - break; + g_getimmed ((Flags | CF_REGVAR) & ~CF_CONST, Expr->Name, Expr->Val); - case E_TLIT: - /* Literal string */ - g_getimmed (CF_STATIC, LiteralPoolLabel, lval->ConstVal); - break; + case E_LOC_STACK: + g_leasp (Expr->Val); + break; default: - Internal ("Unknown constant type: %04X", lval->Flags); + Internal ("Unknown constant type: %04X", Expr->Flags); } } -static int kcalc (int tok, long val1, long val2) +static int kcalc (token_t tok, long val1, long val2) /* Calculate an operation with left and right operand constant. */ { switch (tok) { @@ -411,12 +314,12 @@ static int kcalc (int tok, long val1, long val2) -static GenDesc* FindGen (token_t Tok, GenDesc** Table) +static const GenDesc* FindGen (token_t Tok, const GenDesc* Table) +/* Find a token in a generator table */ { - GenDesc* G; - while ((G = *Table) != 0) { - if (G->Tok == Tok) { - return G; + while (Table->Tok != TOK_INVALID) { + if (Table->Tok == Tok) { + return Table; } ++Table; } @@ -425,24 +328,31 @@ static GenDesc* FindGen (token_t Tok, 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_IDENT && - (Entry = FindSym (NextTok.Ident)) != 0 && - IsTypeDef (Entry))); + TokIsType (&NextTok) || + TokIsTypeQual (&NextTok) || + (NextTok.Tok == TOK_IDENT && + (Entry = FindSym (NextTok.Ident)) != 0 && + SymIsTypeDef (Entry))); } -static 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 @@ -450,36 +360,9 @@ static void PushAddr (ExprDesc* lval) */ { /* Get the address on stack if needed */ - if (lval->Flags != E_MREG && (lval->Flags & E_MEXPR)) { - /* Push the address (always a pointer) */ - g_push (CF_PTR, 0); - } -} - - - -static void MakeConstIntExpr (ExprDesc* Expr, long Value) -/* Make Expr a constant integer expression with the given value */ -{ - Expr->Flags = E_MCONST; - Expr->Type = type_int; - Expr->ConstVal = 1; -} - - - -void ConstSubExpr (int (*F) (ExprDesc*), ExprDesc* Expr) -/* Will evaluate an expression via the given function. If the result is not - * a constant, a diagnostic will be printed, and the value is replaced by - * a constant one to make sure there are no internal errors that result - * from this input error. - */ -{ - memset (Expr, 0, sizeof (*Expr)); - if (F (Expr) != 0 || Expr->Flags != E_MCONST) { - Error ("Constant expression expected"); - /* To avoid any compiler errors, make the expression a valid const */ - MakeConstIntExpr (Expr, 1); + if (ED_IsLocExpr (Expr)) { + /* Push the address (always a pointer) */ + g_push (CF_PTR, 0); } } @@ -491,47 +374,86 @@ void ConstSubExpr (int (*F) (ExprDesc*), ExprDesc* Expr) -void exprhs (unsigned flags, int k, ExprDesc *lval) -/* Put the result of an expression into the primary register */ +void ExprLoad (unsigned Flags, ExprDesc* Expr) +/* Place the result of an expression into the primary register if it is not + * already there. + */ { - int f; + if (ED_IsLVal (Expr)) { - f = lval->Flags; - if (k) { /* Dereferenced lvalue */ - flags |= TypeOf (lval->Type); - if (lval->Test & E_FORCETEST) { - flags |= CF_TEST; - lval->Test &= ~E_FORCETEST; + Flags |= TypeOf (Expr->Type); + if (Expr->Test & E_FORCETEST) { + Flags |= CF_TEST; + Expr->Test &= ~E_FORCETEST; } - if (f & E_MGLOBAL) { /* ref to globalvar */ - /* Generate code */ - flags |= GlobalModeFlags (f); - g_getstatic (flags, lval->Name, lval->ConstVal); - } else if (f & E_MLOCAL) { - /* ref to localvar */ - g_getlocal (flags, lval->ConstVal); - } else if (f & E_MCONST) { - /* ref to absolute address */ - g_getstatic (flags | CF_ABSOLUTE, lval->ConstVal, 0); - } else if (f == E_MEOFFS) { - g_getind (flags, lval->ConstVal); - } else if (f != E_MREG) { - g_getind (flags, 0); + + switch (ED_GetLoc (Expr)) { + + case E_LOC_ABS: + /* Absolute: numeric address or const */ + g_getstatic (Flags | CF_ABSOLUTE, Expr->Val, 0); + break; + + case E_LOC_GLOBAL: + /* Global variable */ + g_getstatic (Flags | CF_EXTERNAL, Expr->Name, Expr->Val); + break; + + case E_LOC_STATIC: + case E_LOC_LITERAL: + /* Static variable or literal in the literal pool */ + g_getstatic (Flags | CF_STATIC, Expr->Name, Expr->Val); + break; + + case E_LOC_REGISTER: + /* Register variable */ + g_getstatic (Flags | CF_REGVAR, Expr->Name, Expr->Val); + break; + + case E_LOC_STACK: + /* Value on the stack */ + g_getlocal (Flags, Expr->Val); + break; + + case E_LOC_PRIMARY: + /* The primary register - just test if necessary */ + if (Flags & CF_TEST) { + g_test (Flags); + } + break; + + case E_LOC_EXPR: + /* Reference to address in primary with offset in Expr */ + g_getind (Flags, Expr->Val); + break; + + default: + Internal ("Invalid location in ExprLoad: 0x%04X", ED_GetLoc (Expr)); + } + + } else { + /* An rvalue */ + if (ED_IsLocExpr (Expr)) { + if (Expr->Val != 0) { + /* We have an expression in the primary plus a constant + * offset. Adjust the value in the primary accordingly. + */ + Flags |= TypeOf (Expr->Type); + g_inc (Flags | CF_CONST, Expr->Val); + } + } else { + /* Constant of some sort, load it into the primary */ + LoadConstant (Flags, Expr); } - } else if (f == E_MEOFFS) { - /* reference not storable */ - flags |= TypeOf (lval->Type); - g_inc (flags | CF_CONST, lval->ConstVal); - } else if ((f & E_MEXPR) == 0) { - /* Constant of some sort, load it into the primary */ - lconst (flags, lval); - } - if (lval->Test & E_FORCETEST) { /* we testing this value? */ - /* debug... */ - flags |= TypeOf (lval->Type); - g_test (flags); /* yes, force a test */ - lval->Test &= ~E_FORCETEST; + + /* 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; + } } } @@ -545,7 +467,7 @@ static unsigned FunctionParamList (FuncDesc* Func) * The function returns the size of the parameters pushed. */ { - ExprDesc lval; + ExprDesc Expr; /* Initialize variables */ SymEntry* Param = 0; /* Keep gcc silent */ @@ -564,6 +486,10 @@ static unsigned FunctionParamList (FuncDesc* Func) * stack frame at once gives usually larger code). * - we have more than one parameter to push (don't count the last param * for __fastcall__ functions). + * + * The FrameSize variable will contain a value > 0 if storing into a frame + * (instead of pushing) is enabled. + * */ if (CodeSizeFactor >= 200) { @@ -572,17 +498,16 @@ static unsigned FunctionParamList (FuncDesc* Func) FrameSize = Func->ParamSize; if (FrameParams > 0 && (Func->Flags & FD_FASTCALL) != 0) { /* Last parameter is not pushed */ - const SymEntry* LastParam = Func->SymTab->SymTail; - FrameSize -= SizeOf (LastParam->Type); + FrameSize -= CheckedSizeOf (Func->LastParam->Type); --FrameParams; } /* 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; @@ -592,7 +517,6 @@ static unsigned FunctionParamList (FuncDesc* Func) /* Parse the actual parameter list */ while (CurTok.Tok != TOK_RPAREN) { - unsigned CFlags; unsigned Flags; /* Count arguments */ @@ -628,54 +552,48 @@ static unsigned FunctionParamList (FuncDesc* Func) Ellipsis = 1; } - /* Do some optimization: If we have a constant value to push, - * use a special function that may optimize. - */ - CFlags = CF_NONE; - if (!Ellipsis && SizeOf (Param->Type) == 1) { - CFlags = CF_FORCECHAR; - } - Flags = CF_NONE; - if (evalexpr (CFlags, hie1, &lval) == 0) { - /* A constant value */ - Flags |= CF_CONST; - } + /* Evaluate the parameter expression */ + 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) { - /* Promote the argument if needed */ - assignadjust (Param->Type, &lval); + /* 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; } + /* Load the value into the primary if it is not already there */ + ExprLoad (Flags, &Expr); + /* Use the type of the argument for the push */ - Flags |= TypeOf (lval.Type); + 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) { - /* Just load the argument into the primary. This is only needed if - * we have a constant argument, otherwise the value is already in - * the primary. - */ - if (Flags & CF_CONST) { - exprhs (CF_FORCECHAR, 0, &lval); - } - } else { + if (ParamCount != Func->ParamCount || (Func->Flags & FD_FASTCALL) == 0) { unsigned ArgSize = sizeofarg (Flags); if (FrameSize > 0) { - /* We have the space already allocated, store in the frame */ - CHECK (FrameSize >= ArgSize); - FrameSize -= ArgSize; + /* We have the space already allocated, store in the frame. + * Because of invalid type conversions (that have produced an + * error before), we can end up here with a non aligned stack + * frame. Since no output will be generated anyway, handle + * these cases gracefully instead of doing a CHECK. + */ + if (FrameSize >= ArgSize) { + FrameSize -= ArgSize; + } else { + FrameSize = 0; + } FrameOffs -= ArgSize; /* Store */ - g_putlocal (Flags | CF_NOKEEP, FrameOffs, lval.ConstVal); + g_putlocal (Flags | CF_NOKEEP, FrameOffs, Expr.Val); } else { /* Push the argument */ - g_push (Flags, lval.ConstVal); + g_push (Flags, Expr.Val); } /* Calculate total parameter size */ @@ -707,73 +625,150 @@ static unsigned FunctionParamList (FuncDesc* Func) -static void FunctionCall (ExprDesc* lval) -/* Perform a function call. Called from hie11, this routine will - * either call the named function, or the function pointer in a/x. - */ +static void FunctionCall (ExprDesc* Expr) +/* Perform a function call. */ { - FuncDesc* Func; /* Function descriptor */ - unsigned ParamSize; /* Number of parameter bytes */ - CodeMark Mark; + FuncDesc* Func; /* Function descriptor */ + int IsFuncPtr; /* Flag */ + int StdFunc; /* Standard function index */ + unsigned ParamSize; /* Number of parameter bytes */ + CodeMark Mark = 0; /* Initialize to keep gcc silent */ + int PtrOffs = 0; /* Offset of function pointer on stack */ + 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 */ + NextToken (); /* Get a pointer to the function descriptor from the type string */ - Func = GetFuncDesc (lval->Type); + Func = GetFuncDesc (Expr->Type); + + /* Handle function pointers transparently */ + IsFuncPtr = IsTypeFuncPtr (Expr->Type); + if (IsFuncPtr) { + + /* Check wether it's a fastcall function that has parameters */ + IsFastCall = IsFastCallFunc (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 + * (not a local or global variable), we have to evaluate this + * expression now and save the result for later. Since calls to + * function pointers may be nested, we must save it onto the stack. + * For fastcall functions we do also need to place a copy of the + * pointer on stack, since we cannot use a/x. + */ + PtrOnStack = IsFastCall || !ED_IsConst (Expr); + if (PtrOnStack) { - /* Initialize vars to keep gcc silent */ - Mark = 0; + /* 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); + ED_MakeRValExpr (Expr); - /* Check if this is a function pointer. If so, save it. If not, check for - * special known library functions that may be inlined. - */ - if (lval->Flags & E_MEXPR) { - /* Function pointer is in primary register, save it */ - Mark = GetCodePos (); - g_save (CF_PTR); - } else if (InlineStdFuncs && IsStdFunc ((const char*) lval->Name)) { - /* Inline this function */ - HandleStdFunc (lval); + /* Remember the code position */ + Mark = GetCodePos (); + + /* Push the pointer onto the stack and remember the offset */ + g_push (CF_PTR, 0); + PtrOffs = StackPtr; + } + + /* Check for known standard functions and inline them if requested */ + } else if (IS_Get (&InlineStdFuncs) && + (StdFunc = FindStdFunc ((const char*) Expr->Name)) >= 0) { + + /* Inline this function */ + HandleStdFunc (StdFunc, Func, Expr); return; + } /* Parse the parameter list */ ParamSize = FunctionParamList (Func); - /* We need the closing bracket here */ + /* We need the closing paren here */ ConsumeRParen (); - /* */ - if (lval->Flags & E_MEXPR) { - /* Function called via pointer: Restore it and call function */ - if (ParamSize != 0) { - g_restore (CF_PTR); - } else { - /* We had no parameters - remove save code */ - RemoveCode (Mark); + /* Special handling for function pointers */ + if (IsFuncPtr) { + + /* If the function is not a fastcall function, load the pointer to + * the function into the primary. + */ + if (!IsFastCall) { + + /* Not a fastcall function - we may use the primary */ + if (PtrOnStack) { + /* If we have no parameters, the pointer is still in the + * primary. Remove the code to push it and correct the + * stack pointer. + */ + if (ParamSize == 0) { + RemoveCode (Mark); + pop (CF_PTR); + PtrOnStack = 0; + } else { + /* Load from the saved copy */ + g_getlocal (CF_PTR, PtrOffs); + } + } else { + /* Load from original location */ + ExprLoad (CF_NONE, Expr); + } + + /* Call the function */ + g_callind (TypeOf (Expr->Type+1), ParamSize, PtrOffs); + + } else { + + /* Fastcall function. We cannot use the primary for the function + * pointer and must therefore use an offset to the stack location. + * Since fastcall functions may never be variadic, we can use the + * index register for this purpose. + */ + g_callind (CF_LOCAL, ParamSize, PtrOffs); } - g_callind (TypeOf (lval->Type), ParamSize); + + /* If we have a pointer on stack, remove it */ + if (PtrOnStack) { + g_space (- (int) sizeofarg (CF_PTR)); + pop (CF_PTR); + } + + /* Skip T_PTR */ + ++Expr->Type; + } else { - g_call (TypeOf (lval->Type), (const char*) lval->Name, ParamSize); + + /* Normal function */ + 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); } -static int primary (ExprDesc* lval) +static void Primary (ExprDesc* E) /* This is the lowest level of the expression parser. */ { - int k; + SymEntry* Sym; - /* not a test at all, yet */ - lval->Test = 0; + /* Initialize fields in the expression stucture */ + ED_Init (E); /* Character and integer constants. */ if (CurTok.Tok == TOK_ICONST || CurTok.Tok == TOK_CCONST) { - lval->Flags = E_MCONST | E_TCONST; - lval->Type = CurTok.Type; - lval->ConstVal = CurTok.IVal; + E->Flags = E_LOC_ABS | E_RTYPE_RVAL; + E->Type = CurTok.Type; + E->Val = CurTok.IVal; NextToken (); - return 0; + return; } /* Process parenthesized subexpression by calling the whole parser @@ -781,10 +776,17 @@ static int primary (ExprDesc* lval) */ if (CurTok.Tok == TOK_LPAREN) { NextToken (); - memset (lval, 0, sizeof (*lval)); /* Remove any attributes */ - k = hie0 (lval); + hie0 (E); ConsumeRParen (); - return k; + 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_MakeConstAbsInt (E, 0); + return; } /* All others may only be used if the expression evaluation is not called @@ -793,199 +795,196 @@ static int primary (ExprDesc* lval) if (Preprocessing) { /* Illegal expression in PP mode */ Error ("Preprocessor expression expected"); - MakeConstIntExpr (lval, 1); - return 0; - } - - /* Identifier? */ - if (CurTok.Tok == TOK_IDENT) { - - SymEntry* Sym; - ident Ident; - - /* Get a pointer to the symbol table entry */ - Sym = FindSym (CurTok.Ident); - - /* Is the symbol known? */ - if (Sym) { - - /* We found the symbol - skip the name token */ - NextToken (); - - /* The expression type is the symbol type */ - lval->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 lval valid */ - lval->Flags = E_MLOCAL | E_TLOFFS; - lval->Type = type_int; - lval->ConstVal = 0; - return 0; - } - - /* Check for legal symbol types */ - if ((Sym->Flags & SC_CONST) == SC_CONST) { - /* Enum or some other numeric constant */ - lval->Flags = E_MCONST; - lval->ConstVal = Sym->V.ConstVal; - return 0; - } else if ((Sym->Flags & SC_FUNC) == SC_FUNC) { - /* Function */ - lval->Flags = E_MGLOBAL | E_MCONST | E_TGLAB; - lval->Name = (unsigned long) Sym->Name; - lval->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 - * address is not const. - */ - if ((Sym->Flags & SC_PARAM) == SC_PARAM && IsVariadic (CurrentFunc)) { - /* Variadic parameter */ - g_leavariadic (Sym->V.Offs - GetParamSize (CurrentFunc)); - lval->Flags = E_MEXPR; - lval->ConstVal = 0; - } else { - /* Normal parameter */ - lval->Flags = E_MLOCAL | E_TLOFFS; - lval->ConstVal = Sym->V.Offs; - } - } else if ((Sym->Flags & SC_STATIC) == SC_STATIC) { - /* Static variable */ - if (Sym->Flags & (SC_EXTERN | SC_STORAGE)) { - lval->Flags = E_MGLOBAL | E_MCONST | E_TGLAB; - lval->Name = (unsigned long) Sym->Name; - } else { - lval->Flags = E_MGLOBAL | E_MCONST | E_TLLAB; - lval->Name = Sym->V.Label; - } - lval->ConstVal = 0; - } else if ((Sym->Flags & SC_REGISTER) == SC_REGISTER) { - /* Register variable, zero page based */ - lval->Flags = E_MGLOBAL | E_MCONST | E_TREGISTER; - lval->Name = Sym->V.Offs; - lval->ConstVal = 0; - } else { - /* Local static variable */ - lval->Flags = E_MGLOBAL | E_MCONST | E_TLLAB; - lval->Name = Sym->V.Offs; - lval->ConstVal = 0; - } - - /* The symbol is referenced now */ - Sym->Flags |= SC_REF; - if (IsTypeFunc (lval->Type) || IsTypeArray (lval->Type)) { - return 0; - } - return 1; - } - - /* We did not find the symbol. Remember the name, then skip it */ - strcpy (Ident, CurTok.Ident); - NextToken (); - - /* 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. - */ - Warning ("Function call without a prototype"); - Sym = AddGlobalSym (Ident, GetImplicitFuncType(), SC_EXTERN | SC_REF | SC_FUNC); - lval->Type = Sym->Type; - lval->Flags = E_MGLOBAL | E_MCONST | E_TGLAB; - lval->Name = (unsigned long) Sym->Name; - lval->ConstVal = 0; - return 0; - - } else { - - /* Undeclared Variable */ - Sym = AddLocalSym (Ident, type_int, SC_AUTO | SC_REF, 0); - lval->Flags = E_MLOCAL | E_TLOFFS; - lval->Type = type_int; - lval->ConstVal = 0; - Error ("Undefined symbol: `%s'", Ident); - return 1; - - } - } - - /* String literal? */ - if (CurTok.Tok == TOK_SCONST) { - lval->Flags = E_MCONST | E_TLIT; - lval->ConstVal = CurTok.IVal; - lval->Type = GetCharArrayType (strlen (GetLiteral (CurTok.IVal))); - NextToken (); - return 0; + ED_MakeConstAbsInt (E, 1); + return; } - /* ASM statement? */ - if (CurTok.Tok == TOK_ASM) { - AsmStatement (); - lval->Type = type_void; - lval->Flags = E_MEXPR; - lval->ConstVal = 0; - return 0; - } + switch (CurTok.Tok) { - /* __AX__ and __EAX__ pseudo values? */ - if (CurTok.Tok == TOK_AX || CurTok.Tok == TOK_EAX) { - lval->Type = (CurTok.Tok == TOK_AX)? type_uint : type_ulong; - lval->Flags = E_MREG; - lval->Test &= ~E_CC; - lval->ConstVal = 0; - NextToken (); - return 1; /* May be used as lvalue */ + case TOK_IDENT: + /* Identifier. Get a pointer to the symbol table entry */ + Sym = E->Sym = FindSym (CurTok.Ident); + + /* Is the symbol known? */ + if (Sym) { + + /* We found the symbol - skip the name token */ + NextToken (); + + /* 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_LOC_STACK | E_RTYPE_LVAL; + E->Type = type_int; + 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_LOC_ABS | E_RTYPE_RVAL; + E->Val = Sym->V.ConstVal; + } else if ((Sym->Flags & SC_FUNC) == SC_FUNC) { + /* Function */ + E->Flags = E_LOC_GLOBAL | E_RTYPE_LVAL; + E->Name = (unsigned long) Sym->Name; + } 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 + * address is not const. + */ + if ((Sym->Flags & SC_PARAM) == SC_PARAM && F_IsVariadic (CurrentFunc)) { + /* Variadic parameter */ + g_leavariadic (Sym->V.Offs - F_GetParamSize (CurrentFunc)); + E->Flags = E_LOC_EXPR | E_RTYPE_LVAL; + } else { + /* Normal parameter */ + E->Flags = E_LOC_STACK | E_RTYPE_LVAL; + E->Val = Sym->V.Offs; + } + } else if ((Sym->Flags & SC_REGISTER) == SC_REGISTER) { + /* Register variable, zero page based */ + E->Flags = E_LOC_REGISTER | E_RTYPE_LVAL; + E->Name = Sym->V.R.RegOffs; + } else if ((Sym->Flags & SC_STATIC) == SC_STATIC) { + /* Static variable */ + if (Sym->Flags & (SC_EXTERN | SC_STORAGE)) { + E->Flags = E_LOC_GLOBAL | E_RTYPE_LVAL; + E->Name = (unsigned long) Sym->Name; + } else { + E->Flags = E_LOC_STATIC | E_RTYPE_LVAL; + E->Name = Sym->V.Label; + } + } else { + /* Local static variable */ + E->Flags = E_LOC_STATIC | E_RTYPE_LVAL; + E->Name = Sym->V.Offs; + } + + /* 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. + */ + if (IsTypeArray (E->Type) || IsTypeFunc (E->Type)) { + ED_MakeRVal (E); + } + + } else { + + /* We did not find the symbol. Remember the name, then skip it */ + ident Ident; + strcpy (Ident, CurTok.Ident); + NextToken (); + + /* 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. + */ + Warning ("Function call without a prototype"); + Sym = AddGlobalSym (Ident, GetImplicitFuncType(), SC_EXTERN | SC_REF | SC_FUNC); + E->Type = Sym->Type; + E->Flags = E_LOC_GLOBAL | E_RTYPE_RVAL; + E->Name = (unsigned long) Sym->Name; + } else { + /* Undeclared Variable */ + Sym = AddLocalSym (Ident, type_int, SC_AUTO | SC_REF, 0); + E->Flags = E_LOC_STACK | E_RTYPE_LVAL; + E->Type = type_int; + Error ("Undefined symbol: `%s'", Ident); + } + + } + break; + + case TOK_SCONST: + /* String literal */ + E->Type = GetCharArrayType (GetLiteralPoolOffs () - CurTok.IVal); + E->Flags = E_LOC_LITERAL | E_RTYPE_RVAL; + E->Val = CurTok.IVal; + E->Name = LiteralPoolLabel; + NextToken (); + break; + + case TOK_ASM: + /* ASM statement */ + AsmStatement (); + 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: + /* Register pseudo variable */ + E->Type = type_ulong; + E->Flags = E_LOC_PRIMARY | E_RTYPE_LVAL; + NextToken (); + break; + + default: + /* Illegal primary. */ + Error ("Expression expected"); + ED_MakeConstAbsInt (E, 1); + break; } - - /* Illegal primary. */ - Error ("Expression expected"); - MakeConstIntExpr (lval, 1); - return 0; } -static int arrayref (int k, ExprDesc* lval) +static void ArrayRef (ExprDesc* Expr) /* Handle an array reference */ { - unsigned lflags; - unsigned rflags; - int ConstBaseAddr; - int ConstSubAddr; - int l; - ExprDesc lval2; - CodeMark Mark1; - CodeMark Mark2; - type* tptr1; - type* tptr2; + int ConstBaseAddr; + ExprDesc SubScript; + CodeMark Mark1; + CodeMark Mark2; + type* ElementType; + type* tptr1; /* Skip the bracket */ NextToken (); /* Get the type of left side */ - tptr1 = lval->Type; + tptr1 = Expr->Type; /* We can apply a special treatment for arrays that have a const base * address. This is true for most arrays and will produce a lot better * code. Check if this is a const base address. */ - lflags = lval->Flags & ~E_MCTYPE; - ConstBaseAddr = (lflags == E_MCONST) || /* Constant numeric address */ - (lflags & E_MGLOBAL) != 0 || /* Static array, or ... */ - lflags == E_MLOCAL; /* Local array */ + ConstBaseAddr = (ED_IsLocConst (Expr) || ED_IsLocStack (Expr)); /* If we have a constant base, we delay the address fetch */ Mark1 = GetCodePos (); - Mark2 = 0; /* Silence gcc */ + Mark2 = 0; /* Silence gcc */ if (!ConstBaseAddr) { /* Get a pointer to the array into the primary */ - exprhs (CF_NONE, k, lval); + ExprLoad (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 @@ -996,767 +995,834 @@ static int arrayref (int k, ExprDesc* lval) } /* TOS now contains ptr to array elements. Get the subscript. */ - l = hie0 (&lval2); - if (l == 0 && lval2.Flags == E_MCONST) { - - /* The array subscript is a constant - remove value from stack */ + ExprWithCheck (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. + */ + 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); + } + 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)); + } + 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); + } + + /* Check if the subscript is constant absolute value */ + if (ED_IsConstAbs (&SubScript)) { + + /* The array subscript is a numeric constant. If we had pushed the + * array base address onto the stack before, we can remove this value, + * since we can generate expression+offset. + */ if (!ConstBaseAddr) { RemoveCode (Mark2); pop (CF_PTR); } else { /* Get an array pointer into the primary */ - exprhs (CF_NONE, k, lval); + ExprLoad (CF_NONE, Expr); } - if (IsClassPtr (tptr1)) { + if (IsClassPtr (Expr->Type)) { - /* Scale the subscript value according to element size */ - lval2.ConstVal *= PSizeOf (tptr1); + /* Lhs is pointer/array. Scale the subscript value according to + * the element size. + */ + SubScript.Val *= 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, this won't work. - */ - if (IsTypeArray (tptr1) && - ((lval->Flags & ~E_MCTYPE) == E_MCONST || - (lval->Flags & ~E_MCTYPE) == E_MLOCAL || - (lval->Flags & E_MGLOBAL) != 0 || - (lval->Flags == E_MEOFFS))) { - lval->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 ((lval->Flags & E_MEXPR) == 0 || k != 0) { - exprhs (CF_NONE, k, lval); - } - lval->ConstVal = lval2.ConstVal; - lval->Flags = E_MEOFFS; - } + /* Adjust the offset */ + Expr->Val += SubScript.Val; - /* Result is of element type */ - lval->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) { + ExprLoad (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->Val = SubScript.Val; + } - /* Scale the rhs value in the primary register */ - g_scale (TypeOf (tptr1), SizeOf (lval2.Type)); - /* */ - lval->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 ExprLoad! + */ + g_inc (CF_INT | CF_CONST, SubScript.Val); + + } } else { /* Array subscript is not constant. Load it into the primary */ Mark2 = GetCodePos (); - exprhs (CF_NONE, l, &lval2); - - tptr2 = lval2.Type; - if (IsClassPtr (tptr1)) { + ExprLoad (CF_NONE, &SubScript); - /* Get the element type */ - lval->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, SizeOf (lval->Type)); + g_scale (CF_INT, CheckedSizeOf (ElementType)); - } else if (IsClassPtr (tptr2)) { - - /* 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); - exprhs (CF_NONE, k, lval); - ConstBaseAddr = 0; + g_push (CF_INT, 0); + ExprLoad (CF_NONE, Expr); + ConstBaseAddr = 0; } else { g_swap (CF_INT); } /* Scale it */ - g_scale (TypeOf (tptr1), SizeOf (lval2.Type)); - lval->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. */ + + /* 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 + } 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. */ - rflags = lval2.Flags & ~E_MCTYPE; - ConstSubAddr = (rflags == E_MCONST) || /* Constant numeric address */ - (rflags & E_MGLOBAL) != 0 || /* Static array, or ... */ - rflags == E_MLOCAL; /* Local array */ - - if (ConstSubAddr && SizeOf (lval->Type) == 1) { + if ((ED_IsLocConst (&SubScript) || ED_IsLocStack (&SubScript)) && + CheckedSizeOf (ElementType) == SIZEOF_CHAR) { - type* SavedType; + unsigned Flags; /* Reverse the order of evaluation */ - unsigned flags = (SizeOf (lval2.Type) == 1)? CF_CHAR : CF_INT; + if (CheckedSizeOf (SubScript.Type) == SIZEOF_CHAR) { + Flags = CF_CHAR; + } else { + Flags = CF_INT; + } RemoveCode (Mark2); - /* 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 = lval->Type; - lval->Type = tptr1; - exprhs (CF_NONE, k, lval); - lval->Type = SavedType; + /* Get a pointer to the array into the primary. */ + ExprLoad (CF_NONE, Expr); /* Add the variable */ - if (rflags == E_MLOCAL) { - g_addlocal (flags, lval2.ConstVal); + if (ED_IsLocStack (&SubScript)) { + g_addlocal (Flags, SubScript.Val); } else { - flags |= GlobalModeFlags (lval2.Flags); - g_addstatic (flags, lval2.Name, lval2.ConstVal); + Flags |= GlobalModeFlags (SubScript.Flags); + g_addstatic (Flags, SubScript.Name, SubScript.Val); } } else { - if (lflags == E_MCONST) { + if (ED_IsLocAbs (Expr)) { /* Constant numeric address. Just add it */ - g_inc (CF_INT | CF_UNSIGNED, lval->ConstVal); - } else if (lflags == E_MLOCAL) { - /* Base address is a local variable address */ - if (IsTypeArray (tptr1)) { - g_addaddr_local (CF_INT, lval->ConstVal); - } else { - g_addlocal (CF_PTR, lval->ConstVal); - } + g_inc (CF_INT, Expr->Val); + } else if (ED_IsLocStack (Expr)) { + /* Base address is a local variable address */ + if (IsTypeArray (Expr->Type)) { + g_addaddr_local (CF_INT, Expr->Val); + } else { + g_addlocal (CF_PTR, Expr->Val); + } } else { /* Base address is a static variable address */ - unsigned flags = CF_INT; - flags |= GlobalModeFlags (lval->Flags); - if (IsTypeArray (tptr1)) { - g_addaddr_static (flags, lval->Name, lval->ConstVal); - } else { - g_addstatic (flags, lval->Name, lval->ConstVal); - } + unsigned Flags = CF_INT | GlobalModeFlags (Expr->Flags); + if (IsTypeArray (Expr->Type)) { + g_addaddr_static (Flags, Expr->Name, Expr->Val); + } else { + g_addstatic (Flags, Expr->Name, Expr->Val); + } } } + + } + + /* 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); } - lval->Flags = E_MEXPR; -end_array: - ConsumeRBrack (); - return !IsTypeArray (lval->Type); + /* Consume the closing bracket */ + ConsumeRBrack (); } -static int structref (int k, ExprDesc* lval) +static void StructRef (ExprDesc* Expr) /* Process struct field after . or ->. */ { ident Ident; SymEntry* Field; - int flags; /* Skip the token and check for an identifier */ NextToken (); if (CurTok.Tok != TOK_IDENT) { Error ("Identifier expected"); - lval->Type = type_int; - return 0; + Expr->Type = type_int; + return; } /* Get the symbol table entry and check for a struct field */ strcpy (Ident, CurTok.Ident); NextToken (); - Field = FindStructField (lval->Type, Ident); + Field = FindStructField (Expr->Type, Ident); if (Field == 0) { Error ("Struct/union has no field named `%s'", Ident); - lval->Type = type_int; - return 0; + Expr->Type = type_int; + return; } - /* If we have constant input data, the result is also constant */ - flags = lval->Flags & ~E_MCTYPE; - if (flags == E_MCONST || - (k == 0 && (flags == E_MLOCAL || - (flags & E_MGLOBAL) != 0 || - lval->Flags == E_MEOFFS))) { - lval->ConstVal += Field->V.Offs; + /* If we have a struct pointer that is not already in the primary, load + * it now. + */ + if (IsTypePtr (Expr->Type)) { + + /* Load into the primary */ + ExprLoad (CF_NONE, Expr); + + /* Make it an lvalue expression */ + ED_MakeLValExpr (Expr); + } + + /* Set the struct field offset */ + Expr->Val += Field->V.Offs; + + /* The type is now the type of the field */ + Expr->Type = Field->Type; + + /* 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 { - if ((flags & E_MEXPR) == 0 || k != 0) { - exprhs (CF_NONE, k, lval); - } - lval->ConstVal = Field->V.Offs; - lval->Flags = E_MEOFFS; + ED_MakeLVal (Expr); } - lval->Type = Field->Type; - return !IsTypeArray (Field->Type); } -static int hie11 (ExprDesc *lval) +static void hie11 (ExprDesc *Expr) /* Handle compound types (structs and arrays) */ { - int k; - type* tptr; - + /* Evaluate the lhs */ + Primary (Expr); + + /* Check for a rhs */ + while (CurTok.Tok == TOK_LBRACK || CurTok.Tok == TOK_LPAREN || + CurTok.Tok == TOK_DOT || CurTok.Tok == TOK_PTR_REF) { + + switch (CurTok.Tok) { + + case TOK_LBRACK: + /* Array reference */ + ArrayRef (Expr); + break; + + case TOK_LPAREN: + /* Function call. */ + if (!IsTypeFunc (Expr->Type) && !IsTypeFuncPtr (Expr->Type)) { + /* Not a function */ + Error ("Illegal function call"); + /* Force the type to be a implicitly defined function, one + * returning an int and taking any number of arguments. + * Since we don't have a name, place it at absolute address + * zero. + */ + ED_MakeConstAbs (Expr, 0, GetImplicitFuncType ()); + } + /* Call the function */ + FunctionCall (Expr); + break; + + case TOK_DOT: + if (!IsClassStruct (Expr->Type)) { + Error ("Struct expected"); + } + StructRef (Expr); + break; + + case TOK_PTR_REF: + /* If we have an array, convert it to pointer to first element */ + if (IsTypeArray (Expr->Type)) { + Expr->Type = ArrayToPtr (Expr->Type); + } + if (!IsClassPtr (Expr->Type) || !IsClassStruct (Indirect (Expr->Type))) { + Error ("Struct pointer expected"); + } + StructRef (Expr); + break; + + default: + Internal ("Invalid token in hie11: %d", CurTok.Tok); - k = primary (lval); - if (CurTok.Tok < TOK_LBRACK || CurTok.Tok > TOK_PTR_REF) { - /* Not for us */ - return k; + } } +} - while (1) { - - if (CurTok.Tok == TOK_LBRACK) { - - /* Array reference */ - k = arrayref (k, lval); - } else if (CurTok.Tok == TOK_LPAREN) { - /* Function call. Skip the opening parenthesis */ - NextToken (); - tptr = lval->Type; - if (IsTypeFunc (tptr) || IsTypeFuncPtr (tptr)) { - if (IsTypeFuncPtr (tptr)) { - /* Pointer to function. Handle transparently */ - exprhs (CF_NONE, k, lval); /* Function pointer to A/X */ - ++lval->Type; /* Skip T_PTR */ - lval->Flags |= E_MEXPR; - } - FunctionCall (lval); - lval->Flags = E_MEXPR; - lval->Type += DECODE_SIZE + 1; /* Set to result */ - } else { - Error ("Illegal function call"); - } - k = 0; +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; - } else if (CurTok.Tok == TOK_DOT) { + /* If StoreType was not given, use Expr->Type instead */ + if (StoreType == 0) { + StoreType = Expr->Type; + } - if (!IsClassStruct (lval->Type)) { - Error ("Struct expected"); - } - k = structref (0, lval); + /* Prepare the code generator flags */ + Flags = TypeOf (StoreType); + if (Expr->Test) { + /* Testing the value */ + Flags |= CF_TEST; + } - } else if (CurTok.Tok == TOK_PTR_REF) { + /* Do the store depending on the location */ + switch (ED_GetLoc (Expr)) { - tptr = lval->Type; - if (tptr[0] != T_PTR || (tptr[1] & T_STRUCT) == 0) { - Error ("Struct pointer expected"); - } - k = structref (k, lval); + case E_LOC_ABS: + /* Absolute: numeric address or const */ + g_putstatic (Flags | CF_ABSOLUTE, Expr->Val, 0); + break; - } else { - return k; - } - } -} + case E_LOC_GLOBAL: + /* Global variable */ + g_putstatic (Flags | CF_EXTERNAL, Expr->Name, Expr->Val); + break; + case E_LOC_STATIC: + case E_LOC_LITERAL: + /* Static variable or literal in the literal pool */ + g_putstatic (Flags | CF_STATIC, Expr->Name, Expr->Val); + break; + case E_LOC_REGISTER: + /* Register variable */ + g_putstatic (Flags | CF_REGVAR, Expr->Name, Expr->Val); + break; -static void store (ExprDesc* lval) -/* Store primary reg into this reference */ -{ - int f; - unsigned flags; + case E_LOC_STACK: + /* Value on the stack */ + g_putlocal (Flags, Expr->Val, 0); + break; - f = lval->Flags; - flags = TypeOf (lval->Type); - if (f & E_MGLOBAL) { - flags |= GlobalModeFlags (f); - if (lval->Test) { - /* Just testing */ - flags |= CF_TEST; - } + case E_LOC_PRIMARY: + /* The primary register (value is already there) */ + /* ### Do we need a test here if the flag is set? */ + break; - /* Generate code */ - g_putstatic (flags, lval->Name, lval->ConstVal); + case E_LOC_EXPR: + /* An expression in the primary register */ + g_putind (Flags, Expr->Val); + break; - } else if (f & E_MLOCAL) { - g_putlocal (flags, lval->ConstVal, 0); - } else if (f == E_MEOFFS) { - g_putind (flags, lval->ConstVal); - } else if (f != E_MREG) { - if (f & E_MEXPR) { - g_putind (flags, 0); - } else { - /* Store into absolute address */ - g_putstatic (flags | CF_ABSOLUTE, lval->ConstVal, 0); - } + default: + Internal ("Invalid location in Store(): 0x%04X", ED_GetLoc (Expr)); } /* Assume that each one of the stores will invalidate CC */ - lval->Test &= ~E_CC; + Expr->Test &= ~E_CC; } -static void pre_incdec (ExprDesc* lval, void (*inc) (unsigned, unsigned long)) -/* Handle --i and ++i */ +static void PreInc (ExprDesc* Expr) +/* Handle the preincrement operators */ { - int k; - unsigned flags; - unsigned long val; + unsigned Flags; + unsigned long Val; + /* Skip the operator token */ NextToken (); - if ((k = hie10 (lval)) == 0) { - Error ("Invalid lvalue"); - return; + + /* Evaluate the expression and check that it is an lvalue */ + hie10 (Expr); + if (!ED_IsLVal (Expr)) { + Error ("Invalid lvalue"); + return; } /* Get the data type */ - flags = TypeOf (lval->Type) | CF_FORCECHAR | CF_CONST; + Flags = TypeOf (Expr->Type) | CF_FORCECHAR | CF_CONST; /* Get the increment value in bytes */ - val = (lval->Type [0] == T_PTR)? PSizeOf (lval->Type) : 1; + Val = IsTypePtr (Expr->Type)? CheckedPSizeOf (Expr->Type) : 1; - /* We're currently only able to handle some adressing modes */ - if ((lval->Flags & E_MGLOBAL) == 0 && /* Global address? */ - (lval->Flags & E_MLOCAL) == 0 && /* Local address? */ - (lval->Flags & E_MCONST) == 0 && /* Constant address? */ - (lval->Flags & E_MEXPR) == 0) { /* Address in a/x? */ + /* Check the location of the data */ + switch (ED_GetLoc (Expr)) { - /* Use generic code. Push the address if needed */ - PushAddr (lval); + case E_LOC_ABS: + /* Absolute: numeric address or const */ + g_addeqstatic (Flags | CF_ABSOLUTE, Expr->Val, 0, Val); + break; - /* Fetch the value */ - exprhs (CF_NONE, k, lval); + case E_LOC_GLOBAL: + /* Global variable */ + g_addeqstatic (Flags | CF_EXTERNAL, Expr->Name, Expr->Val, Val); + break; - /* Increment value in primary */ - inc (flags, val); + case E_LOC_STATIC: + case E_LOC_LITERAL: + /* Static variable or literal in the literal pool */ + g_addeqstatic (Flags | CF_STATIC, Expr->Name, Expr->Val, Val); + break; - /* Store the result back */ - store (lval); + case E_LOC_REGISTER: + /* Register variable */ + g_addeqstatic (Flags | CF_REGVAR, Expr->Name, Expr->Val, Val); + break; - } else { + case E_LOC_STACK: + /* Value on the stack */ + g_addeqlocal (Flags, Expr->Val, Val); + break; - /* Special code for some addressing modes - use the special += ops */ - if (lval->Flags & E_MGLOBAL) { - flags |= GlobalModeFlags (lval->Flags); - if (inc == g_inc) { - g_addeqstatic (flags, lval->Name, lval->ConstVal, val); - } else { - g_subeqstatic (flags, lval->Name, lval->ConstVal, val); - } - } else if (lval->Flags & E_MLOCAL) { - /* ref to localvar */ - if (inc == g_inc) { - g_addeqlocal (flags, lval->ConstVal, val); - } else { - g_subeqlocal (flags, lval->ConstVal, val); - } - } else if (lval->Flags & E_MCONST) { - /* ref to absolute address */ - flags |= CF_ABSOLUTE; - if (inc == g_inc) { - g_addeqstatic (flags, lval->ConstVal, 0, val); - } else { - g_subeqstatic (flags, lval->ConstVal, 0, val); - } - } else if (lval->Flags & E_MEXPR) { - /* Address in a/x, check if we have an offset */ - unsigned Offs = (lval->Flags == E_MEOFFS)? lval->ConstVal : 0; - if (inc == g_inc) { - g_addeqind (flags, Offs, val); - } else { - g_subeqind (flags, Offs, val); - } - } else { - Internal ("Invalid addressing mode"); - } + 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->Val, Val); + break; + default: + Internal ("Invalid location in PreInc(): 0x%04X", ED_GetLoc (Expr)); } - /* Result is an expression */ - lval->Flags = E_MEXPR; + /* Result is an expression, no reference */ + ED_MakeRValExpr (Expr); } -static void post_incdec (ExprDesc *lval, int k, void (*inc) (unsigned, unsigned long)) -/* Handle i-- and i++ */ +static void PreDec (ExprDesc* Expr) +/* Handle the predecrement operators */ { - unsigned flags; + unsigned Flags; + unsigned long Val; + /* Skip the operator token */ NextToken (); - if (k == 0) { - Error ("Invalid lvalue"); - return; + + /* Evaluate the expression and check that it is an lvalue */ + hie10 (Expr); + if (!ED_IsLVal (Expr)) { + Error ("Invalid lvalue"); + return; } /* Get the data type */ - flags = TypeOf (lval->Type); + Flags = TypeOf (Expr->Type) | CF_FORCECHAR | CF_CONST; - /* Push the address if needed */ - PushAddr (lval); + /* Get the increment value in bytes */ + Val = IsTypePtr (Expr->Type)? CheckedPSizeOf (Expr->Type) : 1; - /* Fetch the value and save it (since it's the result of the expression) */ - exprhs (CF_NONE, 1, lval); - g_save (flags | CF_FORCECHAR); + /* Check the location of the data */ + switch (ED_GetLoc (Expr)) { - /* If we have a pointer expression, increment by the size of the type */ - if (lval->Type[0] == T_PTR) { - inc (flags | CF_CONST | CF_FORCECHAR, SizeOf (lval->Type + 1)); - } else { - inc (flags | CF_CONST | CF_FORCECHAR, 1); - } + case E_LOC_ABS: + /* Absolute: numeric address or const */ + g_subeqstatic (Flags | CF_ABSOLUTE, Expr->Val, 0, Val); + break; - /* Store the result back */ - store (lval); + case E_LOC_GLOBAL: + /* Global variable */ + g_subeqstatic (Flags | CF_EXTERNAL, Expr->Name, Expr->Val, Val); + break; - /* Restore the original value */ - g_restore (flags | CF_FORCECHAR); - lval->Flags = E_MEXPR; -} + case E_LOC_STATIC: + case E_LOC_LITERAL: + /* Static variable or literal in the literal pool */ + g_subeqstatic (Flags | CF_STATIC, Expr->Name, Expr->Val, Val); + break; + case E_LOC_REGISTER: + /* Register variable */ + g_subeqstatic (Flags | CF_REGVAR, Expr->Name, Expr->Val, Val); + break; + case E_LOC_STACK: + /* Value on the stack */ + g_subeqlocal (Flags, Expr->Val, Val); + break; -static void unaryop (int tok, ExprDesc* lval) -/* Handle unary -/+ and ~ */ -{ - int k; - unsigned flags; + case E_LOC_PRIMARY: + /* The primary register */ + g_inc (Flags, Val); + break; - NextToken (); - k = hie10 (lval); - if (k == 0 && (lval->Flags & E_MCONST) != 0) { - /* Value is constant */ - switch (tok) { - case TOK_MINUS: lval->ConstVal = -lval->ConstVal; break; - case TOK_PLUS: break; - case TOK_COMP: lval->ConstVal = ~lval->ConstVal; break; - default: Internal ("Unexpected token: %d", tok); - } - } else { - /* Value is not constant */ - exprhs (CF_NONE, k, lval); + case E_LOC_EXPR: + /* An expression in the primary register */ + g_subeqind (Flags, Expr->Val, Val); + break; - /* Get the type of the expression */ - flags = TypeOf (lval->Type); - - /* Handle the operation */ - switch (tok) { - case TOK_MINUS: g_neg (flags); break; - case TOK_PLUS: break; - case TOK_COMP: g_com (flags); break; - default: Internal ("Unexpected token: %d", tok); - } - lval->Flags = E_MEXPR; + default: + Internal ("Invalid location in PreDec(): 0x%04X", ED_GetLoc (Expr)); } -} - + /* Result is an expression, no reference */ + ED_MakeRValExpr (Expr); +} -static int typecast (ExprDesc* lval) -/* Handle an explicit cast */ -{ - int k; - type Type[MAXTYPELEN]; - - /* Skip the left paren */ - NextToken (); - /* Read the type */ - ParseType (Type); - /* Closing paren */ - ConsumeRParen (); +static void PostIncDec (ExprDesc* Expr, void (*inc) (unsigned, unsigned long)) +/* Handle i-- and i++ */ +{ + unsigned Flags; - /* Read the expression we have to cast */ - k = hie10 (lval); + NextToken (); - /* If the expression is a function, treat it as pointer-to-function */ - if (IsTypeFunc (lval->Type)) { - lval->Type = PointerTo (lval->Type); + /* The expression to increment must be an lvalue */ + if (!ED_IsLVal (Expr)) { + Error ("Invalid lvalue"); + return; } - /* Check for a constant on the right side */ - if (k == 0 && lval->Flags == E_MCONST) { + /* Get the data type */ + Flags = TypeOf (Expr->Type); - /* A cast of a constant to something else. If the new type is an int, - * be sure to handle the size extension correctly. If the new type is - * not an int, the cast is implementation specific anyway, so leave - * the value alone. - */ - if (IsClassInt (Type)) { + /* Push the address if needed */ + PushAddr (Expr); - /* Get the current and new size of the value */ - unsigned OldSize = SizeOf (lval->Type); - unsigned NewSize = SizeOf (Type); - unsigned OldBits = OldSize * 8; - unsigned NewBits = NewSize * 8; + /* Fetch the value and save it (since it's the result of the expression) */ + ExprLoad (CF_NONE, Expr); + g_save (Flags | CF_FORCECHAR); - /* Check if the new datatype will have a smaller range */ - if (NewSize < OldSize) { + /* If we have a pointer expression, increment by the size of the type */ + if (IsTypePtr (Expr->Type)) { + inc (Flags | CF_CONST | CF_FORCECHAR, CheckedSizeOf (Expr->Type + 1)); + } else { + inc (Flags | CF_CONST | CF_FORCECHAR, 1); + } - /* Cut the value to the new size */ - lval->ConstVal &= (0xFFFFFFFFUL >> (32 - NewBits)); + /* Store the result back */ + Store (Expr, 0); - /* If the new value is signed, sign extend the value */ - if (!IsSignUnsigned (Type)) { - lval->ConstVal |= ((~0L) << NewBits); - } + /* Restore the original value in the primary register */ + g_restore (Flags | CF_FORCECHAR); - } else if (NewSize > OldSize) { + /* The result is always an expression, no reference */ + ED_MakeRValExpr (Expr); +} - /* Sign extend the value if needed */ - if (!IsSignUnsigned (Type) && !IsSignUnsigned (lval->Type)) { - if (lval->ConstVal & (0x01UL << (OldBits-1))) { - lval->ConstVal |= ((~0L) << OldBits); - } - } - } - } - } else { - /* Not a constant. Be sure to ignore casts to void */ - if (!IsTypeVoid (Type)) { +static void UnaryOp (ExprDesc* Expr) +/* Handle unary -/+ and ~ */ +{ + unsigned Flags; - /* If the size does not change, leave the value alone. Otherwise, - * we have to load the value into the primary and generate code to - * cast the value in the primary register. - */ - if (SizeOf (Type) != SizeOf (lval->Type)) { + /* Remember the operator token and skip it */ + token_t Tok = CurTok.Tok; + NextToken (); - /* Load the value into the primary */ - exprhs (CF_NONE, k, lval); + /* Get the expression */ + hie10 (Expr); - /* Mark the lhs as const to avoid a manipulation of TOS */ - g_typecast (TypeOf (Type) | CF_CONST, TypeOf (lval->Type)); + /* We can only handle integer types */ + if (!IsClassInt (Expr->Type)) { + Error ("Argument must have integer type"); + ED_MakeConstAbsInt (Expr, 1); + } - /* Value is now in primary */ - lval->Flags = E_MEXPR; - k = 0; - } + /* Check for a constant expression */ + if (ED_IsConstAbs (Expr)) { + /* Value is constant */ + switch (Tok) { + case TOK_MINUS: Expr->Val = -Expr->Val; break; + case TOK_PLUS: break; + case TOK_COMP: Expr->Val = ~Expr->Val; break; + default: Internal ("Unexpected token: %d", Tok); } - } + } else { + /* Value is not constant */ + ExprLoad (CF_NONE, Expr); + + /* Get the type of the expression */ + Flags = TypeOf (Expr->Type); - /* In any case, use the new type */ - lval->Type = TypeDup (Type); + /* Handle the operation */ + switch (Tok) { + case TOK_MINUS: g_neg (Flags); break; + case TOK_PLUS: break; + case TOK_COMP: g_com (Flags); break; + default: Internal ("Unexpected token: %d", Tok); + } - /* Done */ - return k; + /* The result is a rvalue in the primary */ + ED_MakeRValExpr (Expr); + } } -static int hie10 (ExprDesc* lval) +void hie10 (ExprDesc* Expr) /* Handle ++, --, !, unary - etc. */ { - int k; - type* t; + unsigned long Size; switch (CurTok.Tok) { case TOK_INC: - pre_incdec (lval, g_inc); - return 0; + PreInc (Expr); + break; case TOK_DEC: - pre_incdec (lval, g_dec); - return 0; + PreDec (Expr); + break; case TOK_PLUS: case TOK_MINUS: case TOK_COMP: - unaryop (CurTok.Tok, lval); - return 0; + UnaryOp (Expr); + break; case TOK_BOOL_NOT: NextToken (); - if (evalexpr (CF_NONE, hie10, lval) == 0) { - /* Constant expression */ - lval->ConstVal = !lval->ConstVal; + if (evalexpr (CF_NONE, hie10, Expr) == 0) { + /* Constant expression */ + Expr->Val = !Expr->Val; } else { - g_bneg (TypeOf (lval->Type)); - lval->Test |= E_CC; /* bneg will set cc */ - lval->Flags = E_MEXPR; /* say it's an expr */ + g_bneg (TypeOf (Expr->Type)); + ED_MakeRValExpr (Expr); + Expr->Test |= E_CC; /* bneg will set cc */ } - return 0; /* expr not storable */ + break; case TOK_STAR: NextToken (); - if (evalexpr (CF_NONE, hie10, lval) != 0) { - /* Expression is not const, indirect value loaded into primary */ - lval->Flags = E_MEXPR; - lval->ConstVal = 0; /* Offset is zero now */ + if (evalexpr (CF_NONE, hie10, Expr) != 0) { + /* Expression is not const, indirect value loaded into primary */ + ED_MakeRValExpr (Expr); } - t = lval->Type; - if (IsClassPtr (t)) { - lval->Type = Indirect (t); - } else { - Error ("Illegal indirection"); - } - return 1; + /* If the expression is already a pointer to function, the + * additional dereferencing operator must be ignored. + */ + if (IsTypeFuncPtr (Expr->Type)) { + /* Expression not storable */ + ED_MakeRVal (Expr); + } else { + if (IsClassPtr (Expr->Type)) { + Expr->Type = Indirect (Expr->Type); + } else { + Error ("Illegal indirection"); + } + ED_MakeLVal (Expr); + } + break; case TOK_AND: NextToken (); - k = hie10 (lval); + hie10 (Expr); /* The & operator may be applied to any lvalue, and it may be * applied to functions, even if they're no lvalues. */ - if (k == 0 && !IsTypeFunc (lval->Type)) { - /* Allow the & operator with an array */ - if (!IsTypeArray (lval->Type)) { - Error ("Illegal address"); - } + if (ED_IsRVal (Expr) && !IsTypeFunc (Expr->Type)) { + /* Allow the & operator with an array */ + if (!IsTypeArray (Expr->Type)) { + Error ("Illegal address"); + } } else { - t = TypeAlloc (TypeLen (lval->Type) + 2); - t [0] = T_PTR; - TypeCpy (t + 1, lval->Type); - lval->Type = t; + Expr->Type = PointerTo (Expr->Type); + ED_MakeRVal (Expr); } - return 0; + break; case TOK_SIZEOF: NextToken (); - if (istypeexpr ()) { - type Type[MAXTYPELEN]; - NextToken (); - lval->ConstVal = SizeOf (ParseType (Type)); - ConsumeRParen (); + if (TypeSpecAhead ()) { + type Type[MAXTYPELEN]; + NextToken (); + Size = CheckedSizeOf (ParseType (Type)); + ConsumeRParen (); } else { - /* Remember the output queue pointer */ - CodeMark Mark = GetCodePos (); - hie10 (lval); - lval->ConstVal = SizeOf (lval->Type); - /* Remove any generated code */ - RemoveCode (Mark); + /* Remember the output queue pointer */ + CodeMark Mark = GetCodePos (); + hie10 (Expr); + Size = CheckedSizeOf (Expr->Type); + /* Remove any generated code */ + RemoveCode (Mark); } - lval->Flags = E_MCONST | E_TCONST; - lval->Type = type_uint; - lval->Test &= ~E_CC; - return 0; + ED_MakeConstAbs (Expr, Size, type_size_t); + Expr->Test &= ~E_CC; + break; default: - if (istypeexpr ()) { - /* A cast */ - return typecast (lval); - } - } + if (TypeSpecAhead ()) { - k = hie11 (lval); - switch (CurTok.Tok) { - case TOK_INC: - post_incdec (lval, k, g_inc); - return 0; + /* A typecast */ + TypeCast (Expr); - case TOK_DEC: - post_incdec (lval, k, g_dec); - return 0; + } else { + + /* An expression */ + hie11 (Expr); - default: - return k; + /* Handle post increment */ + if (CurTok.Tok == TOK_INC) { + PostIncDec (Expr, g_inc); + } else if (CurTok.Tok == TOK_DEC) { + PostIncDec (Expr, g_dec); + } + + } + break; } } -static int hie_internal (GenDesc** ops, /* List of generators */ - ExprDesc* lval, /* parent expr's lval */ - int (*hienext) (ExprDesc*), - int* UsedGen) /* next higher level */ +static void hie_internal (const GenDesc* Ops, /* List of generators */ + ExprDesc* Expr, + void (*hienext) (ExprDesc*), + int* UsedGen) /* Helper function */ { - int k; - ExprDesc lval2; + ExprDesc Expr2; CodeMark Mark1; CodeMark Mark2; - GenDesc* Gen; - token_t tok; /* The operator token */ + const GenDesc* Gen; + token_t Tok; /* The operator token */ unsigned ltype, type; int rconst; /* Operand is a constant */ - k = hienext (lval); + hienext (Expr); *UsedGen = 0; - while ((Gen = FindGen (CurTok.Tok, ops)) != 0) { + while ((Gen = FindGen (CurTok.Tok, Ops)) != 0) { /* Tell the caller that we handled it's ops */ - *UsedGen = 1; + *UsedGen = 1; /* All operators that call this function expect an int on the lhs */ - if (!IsClassInt (lval->Type)) { + if (!IsClassInt (Expr->Type)) { Error ("Integer expression expected"); } /* Remember the operator token, then skip it */ - tok = CurTok.Tok; + Tok = CurTok.Tok; NextToken (); /* Get the lhs on stack */ Mark1 = GetCodePos (); - ltype = TypeOf (lval->Type); - if (k == 0 && lval->Flags == E_MCONST) { + ltype = TypeOf (Expr->Type); + if (ED_IsConstAbs (Expr)) { /* Constant value */ Mark2 = GetCodePos (); - g_push (ltype | CF_CONST, lval->ConstVal); + g_push (ltype | CF_CONST, Expr->Val); } else { /* Value not constant */ - exprhs (CF_NONE, k, lval); + ExprLoad (CF_NONE, Expr); Mark2 = GetCodePos (); g_push (ltype, 0); } /* Get the right hand side */ - rconst = (evalexpr (CF_NONE, hienext, &lval2) == 0); + rconst = (evalexpr (CF_NONE, hienext, &Expr2) == 0); /* Check the type of the rhs */ - if (!IsClassInt (lval2.Type)) { + if (!IsClassInt (Expr2.Type)) { Error ("Integer expression expected"); } /* Check for const operands */ - if (k == 0 && lval->Flags == E_MCONST && rconst) { + if (ED_IsConstAbs (Expr) && rconst) { /* Both operands are constant, remove the generated code */ RemoveCode (Mark1); pop (ltype); /* Evaluate the result */ - lval->ConstVal = kcalc (tok, lval->ConstVal, lval2.ConstVal); + Expr->Val = kcalc (Tok, Expr->Val, Expr2.Val); /* Get the type of the result */ - lval->Type = promoteint (lval->Type, lval2.Type); + Expr->Type = promoteint (Expr->Type, Expr2.Type); } else { @@ -1764,112 +1830,108 @@ static int hie_internal (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) { + rtype |= CF_CONST; + if (Tok == TOK_DIV && Expr2.Val == 0) { Error ("Division by zero"); - } else if (tok == TOK_MOD && lval2.ConstVal == 0) { + } else if (Tok == TOK_MOD && Expr2.Val == 0) { Error ("Modulo operation with zero"); } - if ((Gen->Flags & GEN_NOPUSH) != 0) { - RemoveCode (Mark2); + if ((Gen->Flags & GEN_NOPUSH) != 0) { + RemoveCode (Mark2); pop (ltype); - ltype |= CF_REG; /* Value is in register */ - } + ltype |= CF_REG; /* Value is in register */ + } } /* Determine the type of the operation result. */ type |= g_typeadjust (ltype, rtype); - lval->Type = promoteint (lval->Type, lval2.Type); + Expr->Type = promoteint (Expr->Type, Expr2.Type); /* Generate code */ - Gen->Func (type, lval2.ConstVal); - lval->Flags = E_MEXPR; - } + Gen->Func (type, Expr2.Val); - /* We have a rvalue now */ - k = 0; + /* We have a rvalue in the primary now */ + ED_MakeRValExpr (Expr); + } } - - return k; } -static int hie_compare (GenDesc** ops, /* List of generators */ - ExprDesc* lval, /* parent expr's lval */ - int (*hienext) (ExprDesc*)) +static void hie_compare (const GenDesc* Ops, /* List of generators */ + ExprDesc* Expr, + void (*hienext) (ExprDesc*)) /* Helper function for the compare operators */ { - int k; - ExprDesc lval2; + ExprDesc Expr2; CodeMark Mark1; CodeMark Mark2; - GenDesc* Gen; - token_t tok; /* The operator token */ + const GenDesc* Gen; + token_t tok; /* The operator token */ unsigned ltype; int rconst; /* Operand is a constant */ - k = hienext (lval); + hienext (Expr); - while ((Gen = FindGen (CurTok.Tok, ops)) != 0) { + while ((Gen = FindGen (CurTok.Tok, Ops)) != 0) { - /* Remember the operator token, then skip it */ + /* Remember the operator token, then skip it */ tok = CurTok.Tok; - NextToken (); + NextToken (); - /* Get the lhs on stack */ - Mark1 = GetCodePos (); - ltype = TypeOf (lval->Type); - if (k == 0 && lval->Flags == E_MCONST) { - /* Constant value */ - Mark2 = GetCodePos (); - g_push (ltype | CF_CONST, lval->ConstVal); - } else { - /* Value not constant */ - exprhs (CF_NONE, k, lval); - Mark2 = GetCodePos (); - g_push (ltype, 0); + /* Get the lhs on stack */ + Mark1 = GetCodePos (); + ltype = TypeOf (Expr->Type); + if (ED_IsConstAbs (Expr)) { + /* Constant value */ + Mark2 = GetCodePos (); + g_push (ltype | CF_CONST, Expr->Val); + } else { + /* Value not constant */ + ExprLoad (CF_NONE, Expr); + Mark2 = GetCodePos (); + g_push (ltype, 0); } /* Get the right hand side */ - rconst = (evalexpr (CF_NONE, hienext, &lval2) == 0); + rconst = (evalexpr (CF_NONE, hienext, &Expr2) == 0); /* Make sure, the types are compatible */ - if (IsClassInt (lval->Type)) { - if (!IsClassInt (lval2.Type) && !(IsClassPtr(lval2.Type) && IsNullPtr(lval))) { + if (IsClassInt (Expr->Type)) { + if (!IsClassInt (Expr2.Type) && !(IsClassPtr(Expr2.Type) && ED_IsNullPtr(Expr))) { Error ("Incompatible types"); } - } else if (IsClassPtr (lval->Type)) { - if (IsClassPtr (lval2.Type)) { + } else if (IsClassPtr (Expr->Type)) { + if (IsClassPtr (Expr2.Type)) { /* Both pointers are allowed in comparison if they point to * the same type, or if one of them is a void pointer. */ - type* left = Indirect (lval->Type); - type* right = Indirect (lval2.Type); + type* left = Indirect (Expr->Type); + type* right = Indirect (Expr2.Type); if (TypeCmp (left, right) < TC_EQUAL && *left != T_VOID && *right != T_VOID) { /* Incomatible pointers */ Error ("Incompatible types"); } - } else if (!IsNullPtr (&lval2)) { + } else if (!ED_IsNullPtr (&Expr2)) { Error ("Incompatible types"); } } /* Check for const operands */ - if (k == 0 && lval->Flags == E_MCONST && rconst) { + if (ED_IsConstAbs (Expr) && rconst) { /* Both operands are constant, remove the generated code */ RemoveCode (Mark1); pop (ltype); /* Evaluate the result */ - lval->ConstVal = kcalc (tok, lval->ConstVal, lval2.ConstVal); + Expr->Val = kcalc (tok, Expr->Val, Expr2.Val); } else { @@ -1893,201 +1955,257 @@ static int hie_compare (GenDesc** ops, /* List of generators */ * operation as char operation. Otherwise the default * promotions are used. */ - if (IsTypeChar (lval->Type) && (IsTypeChar (lval2.Type) || rconst)) { + if (IsTypeChar (Expr->Type) && (IsTypeChar (Expr2.Type) || rconst)) { flags |= CF_CHAR; - if (IsSignUnsigned (lval->Type) || IsSignUnsigned (lval2.Type)) { + if (IsSignUnsigned (Expr->Type) || IsSignUnsigned (Expr2.Type)) { flags |= CF_UNSIGNED; } if (rconst) { flags |= CF_FORCECHAR; } } else { - unsigned rtype = TypeOf (lval2.Type) | (flags & CF_CONST); + unsigned rtype = TypeOf (Expr2.Type) | (flags & CF_CONST); flags |= g_typeadjust (ltype, rtype); } /* Generate code */ - Gen->Func (flags, lval2.ConstVal); - lval->Flags = E_MEXPR; + Gen->Func (flags, Expr2.Val); + + /* The result is an rvalue in the primary */ + ED_MakeRValExpr (Expr); } /* Result type is always int */ - lval->Type = type_int; + Expr->Type = type_int; - /* We have a rvalue now, condition codes are set */ - k = 0; - lval->Test |= E_CC; + /* Condition codes are set */ + Expr->Test |= E_CC; } - - return k; } -static int hie9 (ExprDesc *lval) +static void hie9 (ExprDesc *Expr) /* Process * and / operators. */ { - static GenDesc* hie9_ops [] = { - &GenMUL, &GenDIV, &GenMOD, 0 + static const GenDesc hie9_ops[] = { + { TOK_STAR, GEN_NOPUSH, g_mul }, + { TOK_DIV, GEN_NOPUSH, g_div }, + { TOK_MOD, GEN_NOPUSH, g_mod }, + { TOK_INVALID, 0, 0 } }; int UsedGen; - return hie_internal (hie9_ops, lval, hie10, &UsedGen); + hie_internal (hie9_ops, Expr, hie10, &UsedGen); } -static void parseadd (int k, ExprDesc* lval) -/* Parse an expression with the binary plus operator. lval contains the +static void parseadd (ExprDesc* Expr) +/* Parse an expression with the binary plus operator. Expr contains the * unprocessed left hand side of the expression and will contain the * result of the expression on return. */ { - ExprDesc lval2; - unsigned flags; /* Operation flags */ - CodeMark Mark; /* Remember code position */ - type* lhst; /* Type of left hand side */ - type* rhst; /* Type of right hand side */ + 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 */ /* Skip the PLUS token */ NextToken (); /* Get the left hand side type, initialize operation flags */ - lhst = lval->Type; + lhst = Expr->Type; flags = 0; /* Check for constness on both sides */ - if (k == 0 && (lval->Flags & E_MCONST) != 0) { + if (ED_IsConst (Expr)) { - /* The left hand side is a constant. Good. Get rhs */ - if (evalexpr (CF_NONE, hie9, &lval2) == 0) { + /* 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 */ - lval->ConstVal = lval->ConstVal + lval2.ConstVal * PSizeOf (lhst); + Expr->Val += Expr2.Val * CheckedPSizeOf (lhst); /* Result type is a pointer */ } else if (IsClassInt (lhst) && IsClassPtr (rhst)) { /* Left is int, right is pointer, must scale lhs */ - lval->ConstVal = lval->ConstVal * PSizeOf (rhst) + lval2.ConstVal; + Expr->Val = Expr->Val * CheckedPSizeOf (rhst) + Expr2.Val; /* Result type is a pointer */ - lval->Type = lval2.Type; + Expr->Type = Expr2.Type; } else if (IsClassInt (lhst) && IsClassInt (rhst)) { /* Integer addition */ - lval->ConstVal += lval2.ConstVal; - typeadjust (lval, &lval2, 1); + Expr->Val += Expr2.Val; + typeadjust (Expr, &Expr2, 1); } else { /* OOPS */ Error ("Invalid operands for binary operator `+'"); } - /* Result is constant, condition codes not set */ - lval->Test &= ~E_CC; - } else { - /* lhs is constant, rhs is not. Get the rhs type. */ - rhst = lval2.Type; + /* lhs is a constant and rhs is not constant. Load rhs into + * the primary. + */ + ExprLoad (CF_NONE, &Expr2); + + /* Beware: The check above (for lhs) lets not only pass numeric + * constants, but also constant addresses (labels), maybe even + * with an offset. We have to check for that here. + */ + + /* First, get the rhs type. */ + rhst = Expr2.Type; + + /* Setup flags */ + if (ED_IsLocAbs (Expr)) { + /* A numerical constant */ + flags |= CF_CONST; + } else { + /* Constant address label */ + flags |= GlobalModeFlags (Expr->Flags) | CF_CONSTADDR; + } /* Check for pointer arithmetic */ if (IsClassPtr (lhst) && IsClassInt (rhst)) { /* Left is pointer, right is int, must scale rhs */ - g_scale (CF_INT, PSizeOf (lhst)); + g_scale (CF_INT, CheckedPSizeOf (lhst)); /* Operate on pointers, result type is a pointer */ - flags = CF_PTR; + flags |= CF_PTR; + /* Generate the code for the add */ + if (ED_GetLoc (Expr) == E_LOC_ABS) { + /* Numeric constant */ + g_inc (flags, Expr->Val); + } else { + /* Constant address */ + g_addaddr_static (flags, Expr->Name, Expr->Val); + } } else if (IsClassInt (lhst) && IsClassPtr (rhst)) { - /* Left is int, right is pointer, must scale lhs */ - lval->ConstVal *= PSizeOf (rhst); - /* Operate on pointers, result type is a pointer */ - flags = CF_PTR; - lval->Type = lval2.Type; + + /* Left is int, right is pointer, must scale lhs. */ + unsigned ScaleFactor = CheckedPSizeOf (rhst); + + /* Operate on pointers, result type is a pointer */ + flags |= CF_PTR; + 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 (ED_IsLocAbs (Expr)) { + /* Numeric constant, scale lhs */ + Expr->Val *= ScaleFactor; + /* Generate the code for the add */ + g_inc (flags, Expr->Val); + } else if (ScaleFactor == 1) { + /* Constant address but no need to scale */ + g_addaddr_static (flags, Expr->Name, Expr->Val); + } else { + /* Constant address that must be scaled */ + g_push (TypeOf (Expr2.Type), 0); /* rhs --> stack */ + g_getimmed (flags, Expr->Name, Expr->Val); + g_scale (CF_PTR, ScaleFactor); + g_add (CF_PTR, 0); + } } else if (IsClassInt (lhst) && IsClassInt (rhst)) { /* Integer addition */ - flags = typeadjust (lval, &lval2, 1); + flags |= typeadjust (Expr, &Expr2, 1); + /* Generate the code for the add */ + if (ED_IsLocAbs (Expr)) { + /* Numeric constant */ + g_inc (flags, Expr->Val); + } else { + /* Constant address */ + g_addaddr_static (flags, Expr->Name, Expr->Val); + } } else { /* OOPS */ Error ("Invalid operands for binary operator `+'"); } - /* Generate code for the add */ - g_inc (flags | CF_CONST, lval->ConstVal); - - /* Result is in primary register */ - lval->Flags = E_MEXPR; - lval->Test &= ~E_CC; - + /* Result is a rvalue in primary register */ + ED_MakeRValExpr (Expr); } } else { /* Left hand side is not constant. Get the value onto the stack. */ - exprhs (CF_NONE, k, lval); /* --> primary register */ + ExprLoad (CF_NONE, Expr); /* --> primary register */ Mark = GetCodePos (); - g_push (TypeOf (lval->Type), 0); /* --> stack */ + g_push (TypeOf (Expr->Type), 0); /* --> stack */ /* Evaluate the rhs */ - if (evalexpr (CF_NONE, hie9, &lval2) == 0) { + if (evalexpr (CF_NONE, hie9, &Expr2) == 0) { /* 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 (lval->Type)); + pop (TypeOf (Expr->Type)); /* Check for pointer arithmetic */ if (IsClassPtr (lhst) && IsClassInt (rhst)) { /* Left is pointer, right is int, must scale rhs */ - lval2.ConstVal *= PSizeOf (lhst); + Expr2.Val *= CheckedPSizeOf (lhst); /* Operate on pointers, result type is a pointer */ flags = CF_PTR; } else if (IsClassInt (lhst) && IsClassPtr (rhst)) { /* Left is int, right is pointer, must scale lhs (ptr only) */ - g_scale (CF_INT | CF_CONST, PSizeOf (rhst)); + g_scale (CF_INT | CF_CONST, CheckedPSizeOf (rhst)); /* Operate on pointers, result type is a pointer */ flags = CF_PTR; - lval->Type = lval2.Type; + Expr->Type = Expr2.Type; } else if (IsClassInt (lhst) && IsClassInt (rhst)) { /* Integer addition */ - flags = typeadjust (lval, &lval2, 1); + flags = typeadjust (Expr, &Expr2, 1); } else { /* OOPS */ Error ("Invalid operands for binary operator `+'"); } /* Generate code for the add */ - g_inc (flags | CF_CONST, lval2.ConstVal); - - /* Result is in primary register */ - lval->Flags = E_MEXPR; - lval->Test &= ~E_CC; + g_inc (flags | CF_CONST, Expr2.Val); } else { /* 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)) { /* Left is pointer, right is int, must scale rhs */ - g_scale (CF_INT, PSizeOf (lhst)); + g_scale (CF_INT, CheckedPSizeOf (lhst)); /* Operate on pointers, result type is a pointer */ flags = CF_PTR; } else if (IsClassInt (lhst) && IsClassPtr (rhst)) { /* Left is int, right is pointer, must scale lhs */ g_tosint (TypeOf (rhst)); /* Make sure, TOS is int */ - g_swap (CF_INT); /* Swap TOS and primary */ - g_scale (CF_INT, PSizeOf (rhst)); + g_swap (CF_INT); /* Swap TOS and primary */ + g_scale (CF_INT, CheckedPSizeOf (rhst)); /* Operate on pointers, result type is a pointer */ flags = CF_PTR; - lval->Type = lval2.Type; + Expr->Type = Expr2.Type; } else if (IsClassInt (lhst) && IsClassInt (rhst)) { - /* Integer addition */ - flags = typeadjust (lval, &lval2, 0); + /* Integer addition. Note: Result is never constant. + * Problem here is that typeadjust does not know if the + * variable is an rvalue or lvalue, so if both operands + * are dereferenced constant numeric addresses, typeadjust + * thinks the operation works on constants. Removing + * CF_CONST here means handling the symptoms, however, the + * whole parser is such a mess that I fear to break anything + * when trying to apply another solution. + */ + flags = typeadjust (Expr, &Expr2, 0) & ~CF_CONST; } else { /* OOPS */ Error ("Invalid operands for binary operator `+'"); @@ -2096,29 +2214,31 @@ static void parseadd (int k, ExprDesc* lval) /* Generate code for the add */ g_add (flags, 0); - /* Result is in primary register */ - lval->Flags = E_MEXPR; - lval->Test &= ~E_CC; - } + /* Result is a rvalue in primary register */ + ED_MakeRValExpr (Expr); } + + /* Condition codes not set */ + Expr->Test &= ~E_CC; + } -static void parsesub (int k, ExprDesc* lval) -/* Parse an expression with the binary minus operator. lval contains the +static void parsesub (ExprDesc* Expr) +/* Parse an expression with the binary minus operator. Expr contains the * unprocessed left hand side of the expression and will contain the * result of the expression on return. */ { - ExprDesc lval2; + 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 */ + CodeMark Mark1; /* Save position of output queue */ + CodeMark Mark2; /* Another position in the queue */ int rscale; /* Scale factor for the result */ @@ -2126,55 +2246,55 @@ static void parsesub (int k, ExprDesc* lval) NextToken (); /* Get the left hand side type, initialize operation flags */ - lhst = lval->Type; + 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 (); - exprhs (CF_NONE, k, lval); /* --> primary register */ + ExprLoad (CF_NONE, Expr); /* --> primary register */ Mark2 = GetCodePos (); g_push (TypeOf (lhst), 0); /* --> stack */ /* Parse the right hand side */ - if (evalexpr (CF_NONE, hie9, &lval2) == 0) { + if (evalexpr (CF_NONE, hie9, &Expr2) == 0) { /* The right hand side is constant. Get the rhs type. */ - rhst = lval2.Type; + rhst = Expr2.Type; /* Check left hand side */ - if (k == 0 && (lval->Flags & E_MCONST) != 0) { + if (ED_IsConstAbs (Expr)) { /* Both sides are constant, remove generated code */ RemoveCode (Mark1); - pop (TypeOf (lhst)); /* Clean up the stack */ + pop (TypeOf (lhst)); /* Clean up the stack */ /* Check for pointer arithmetic */ if (IsClassPtr (lhst) && IsClassInt (rhst)) { /* Left is pointer, right is int, must scale rhs */ - lval->ConstVal -= lval2.ConstVal * PSizeOf (lhst); + Expr->Val -= Expr2.Val * 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_EQUAL) { + if (TypeCmp (Indirect (lhst), Indirect (rhst)) < TC_QUAL_DIFF) { Error ("Incompatible pointer types"); } else { - lval->ConstVal = (lval->ConstVal - lval2.ConstVal) / PSizeOf (lhst); + Expr->Val = (Expr->Val - Expr2.Val) / + CheckedPSizeOf (lhst); } /* Operate on pointers, result type is an integer */ - lval->Type = type_int; + Expr->Type = type_int; } else if (IsClassInt (lhst) && IsClassInt (rhst)) { /* Integer subtraction */ - typeadjust (lval, &lval2, 1); - lval->ConstVal -= lval2.ConstVal; + typeadjust (Expr, &Expr2, 1); + Expr->Val -= Expr2.Val; } else { /* OOPS */ Error ("Invalid operands for binary operator `-'"); } /* Result is constant, condition codes not set */ - /* lval->Flags = E_MCONST; ### */ - lval->Test &= ~E_CC; + Expr->Test &= ~E_CC; } else { @@ -2186,73 +2306,73 @@ static void parsesub (int k, ExprDesc* lval) if (IsClassPtr (lhst) && IsClassInt (rhst)) { /* Left is pointer, right is int, must scale rhs */ - lval2.ConstVal *= PSizeOf (lhst); + Expr2.Val *= 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_EQUAL) { + if (TypeCmp (Indirect (lhst), Indirect (rhst)) < TC_QUAL_DIFF) { Error ("Incompatible pointer types"); } else { - rscale = PSizeOf (lhst); + rscale = CheckedPSizeOf (lhst); } /* Operate on pointers, result type is an integer */ flags = CF_PTR; - lval->Type = type_int; + Expr->Type = type_int; } else if (IsClassInt (lhst) && IsClassInt (rhst)) { /* Integer subtraction */ - flags = typeadjust (lval, &lval2, 1); + flags = typeadjust (Expr, &Expr2, 1); } else { /* OOPS */ Error ("Invalid operands for binary operator `-'"); } /* Do the subtraction */ - g_dec (flags | CF_CONST, lval2.ConstVal); + g_dec (flags | CF_CONST, Expr2.Val); /* If this was a pointer subtraction, we must scale the result */ if (rscale != 1) { g_scale (flags, -rscale); } - /* Result is in primary register */ - lval->Flags = E_MEXPR; - lval->Test &= ~E_CC; + /* Result is a rvalue in the primary register */ + ED_MakeRValExpr (Expr); + Expr->Test &= ~E_CC; } } else { /* Right hand side is not constant. Get the rhs type. */ - rhst = lval2.Type; + rhst = Expr2.Type; /* Check for pointer arithmetic */ if (IsClassPtr (lhst) && IsClassInt (rhst)) { /* Left is pointer, right is int, must scale rhs */ - g_scale (CF_INT, PSizeOf (lhst)); + 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_EQUAL) { + if (TypeCmp (Indirect (lhst), Indirect (rhst)) < TC_QUAL_DIFF) { Error ("Incompatible pointer types"); } else { - rscale = PSizeOf (lhst); + rscale = CheckedPSizeOf (lhst); } /* Operate on pointers, result type is an integer */ flags = CF_PTR; - lval->Type = type_int; + 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 (lval->Flags == E_MCONST) { - lval->Flags = E_MEXPR; + if (ED_IsLocAbs (Expr)) { + ED_MakeRValExpr (Expr); } /* Adjust operand types */ - flags = typeadjust (lval, &lval2, 0); - } else { + flags = typeadjust (Expr, &Expr2, 0); + } else { /* OOPS */ Error ("Invalid operands for binary operator `-'"); } @@ -2265,190 +2385,167 @@ static void parsesub (int k, ExprDesc* lval) g_scale (flags, -rscale); } - /* Result is in primary register */ - lval->Flags = E_MEXPR; - lval->Test &= ~E_CC; + /* Result is a rvalue in the primary register */ + ED_MakeRValExpr (Expr); + Expr->Test &= ~E_CC; } } -static int hie8 (ExprDesc* lval) +static void hie8 (ExprDesc* Expr) /* Process + and - binary operators. */ { - int k = hie9 (lval); + hie9 (Expr); while (CurTok.Tok == TOK_PLUS || CurTok.Tok == TOK_MINUS) { - if (CurTok.Tok == TOK_PLUS) { - parseadd (k, lval); + parseadd (Expr); } else { - parsesub (k, lval); + parsesub (Expr); } - k = 0; } - return k; } - -static int hie7 (ExprDesc *lval) +static void hie7 (ExprDesc* Expr) /* Parse << and >>. */ { - static GenDesc* hie7_ops [] = { - &GenASL, &GenASR, 0 + static const GenDesc hie7_ops [] = { + { TOK_SHL, GEN_NOPUSH, g_asl }, + { TOK_SHR, GEN_NOPUSH, g_asr }, + { TOK_INVALID, 0, 0 } }; int UsedGen; - return hie_internal (hie7_ops, lval, hie8, &UsedGen); + hie_internal (hie7_ops, Expr, hie8, &UsedGen); } -static int hie6 (ExprDesc *lval) -/* process greater-than type comparators */ +static void hie6 (ExprDesc* Expr) +/* Handle greater-than type comparators */ { - static GenDesc* hie6_ops [] = { - &GenLT, &GenLE, &GenGE, &GenGT, 0 + static const GenDesc hie6_ops [] = { + { TOK_LT, GEN_NOPUSH, g_lt }, + { TOK_LE, GEN_NOPUSH, g_le }, + { TOK_GE, GEN_NOPUSH, g_ge }, + { TOK_GT, GEN_NOPUSH, g_gt }, + { TOK_INVALID, 0, 0 } }; - return hie_compare (hie6_ops, lval, hie7); + hie_compare (hie6_ops, Expr, hie7); } -static int hie5 (ExprDesc *lval) +static void hie5 (ExprDesc* Expr) +/* Handle == and != */ { - static GenDesc* hie5_ops[] = { - &GenEQ, &GenNE, 0 + static const GenDesc hie5_ops[] = { + { TOK_EQ, GEN_NOPUSH, g_eq }, + { TOK_NE, GEN_NOPUSH, g_ne }, + { TOK_INVALID, 0, 0 } }; - return hie_compare (hie5_ops, lval, hie6); + hie_compare (hie5_ops, Expr, hie6); } -static int hie4 (ExprDesc* lval) +static void hie4 (ExprDesc* Expr) /* Handle & (bitwise and) */ { - static GenDesc* hie4_ops [] = { - &GenAND, 0 + static const GenDesc hie4_ops[] = { + { TOK_AND, GEN_NOPUSH, g_and }, + { TOK_INVALID, 0, 0 } }; int UsedGen; - return hie_internal (hie4_ops, lval, hie5, &UsedGen); + hie_internal (hie4_ops, Expr, hie5, &UsedGen); } -static int hie3 (ExprDesc *lval) +static void hie3 (ExprDesc* Expr) /* Handle ^ (bitwise exclusive or) */ { - static GenDesc* hie3_ops [] = { - &GenXOR, 0 + static const GenDesc hie3_ops[] = { + { TOK_XOR, GEN_NOPUSH, g_xor }, + { TOK_INVALID, 0, 0 } }; int UsedGen; - return hie_internal (hie3_ops, lval, hie4, &UsedGen); + hie_internal (hie3_ops, Expr, hie4, &UsedGen); } -static int hie2 (ExprDesc *lval) +static void hie2 (ExprDesc* Expr) /* Handle | (bitwise or) */ { - static GenDesc* hie2_ops [] = { - &GenOR, 0 + static const GenDesc hie2_ops[] = { + { TOK_OR, GEN_NOPUSH, g_or }, + { TOK_INVALID, 0, 0 } }; int UsedGen; - return hie_internal (hie2_ops, lval, hie3, &UsedGen); + hie_internal (hie2_ops, Expr, hie3, &UsedGen); } -static int hieAndPP (ExprDesc* lval) +static void hieAndPP (ExprDesc* Expr) /* Process "exp && exp" in preprocessor mode (that is, when the parser is * called recursively from the preprocessor. */ { - ExprDesc lval2; + ExprDesc Expr2; - ConstSubExpr (hie2, lval); + ConstAbsIntExpr (hie2, Expr); while (CurTok.Tok == TOK_BOOL_AND) { - /* Left hand side must be an int */ - if (!IsClassInt (lval->Type)) { - Error ("Left hand side must be of integer type"); - MakeConstIntExpr (lval, 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"); - MakeConstIntExpr (&lval2, 1); - } + ConstAbsIntExpr (hie2, &Expr2); /* Combine the two */ - lval->ConstVal = (lval->ConstVal && lval2.ConstVal); + Expr->Val = (Expr->Val && Expr2.Val); } - - /* Always a rvalue */ - return 0; } -static int hieOrPP (ExprDesc *lval) +static void hieOrPP (ExprDesc *Expr) /* Process "exp || exp" in preprocessor mode (that is, when the parser is * called recursively from the preprocessor. */ { - ExprDesc lval2; + ExprDesc Expr2; - ConstSubExpr (hieAndPP, lval); + ConstAbsIntExpr (hieAndPP, Expr); while (CurTok.Tok == TOK_BOOL_OR) { - /* Left hand side must be an int */ - if (!IsClassInt (lval->Type)) { - Error ("Left hand side must be of integer type"); - MakeConstIntExpr (lval, 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"); - MakeConstIntExpr (&lval2, 1); - } + ConstAbsIntExpr (hieAndPP, &Expr2); /* Combine the two */ - lval->ConstVal = (lval->ConstVal || lval2.ConstVal); + Expr->Val = (Expr->Val || Expr2.Val); } - - /* Always a rvalue */ - return 0; } -static int hieAnd (ExprDesc* lval, unsigned TrueLab, int* BoolOp) +static void hieAnd (ExprDesc* Expr, unsigned TrueLab, int* BoolOp) /* Process "exp && exp" */ { - int k; int lab; - ExprDesc lval2; + ExprDesc Expr2; - k = hie2 (lval); + hie2 (Expr); if (CurTok.Tok == TOK_BOOL_AND) { /* Tell our caller that we're evaluating a boolean */ @@ -2458,12 +2555,12 @@ static int hieAnd (ExprDesc* lval, unsigned TrueLab, int* BoolOp) lab = GetLocalLabel (); /* If the expr hasn't set condition codes, set the force-test flag */ - if ((lval->Test & E_CC) == 0) { - lval->Test |= E_FORCETEST; + if ((Expr->Test & E_CC) == 0) { + Expr->Test |= E_FORCETEST; } /* Load the value */ - exprhs (CF_FORCECHAR, k, lval); + ExprLoad (CF_FORCECHAR, Expr); /* Generate the jump */ g_falsejump (CF_NONE, lab); @@ -2475,11 +2572,11 @@ static int hieAnd (ExprDesc* lval, unsigned TrueLab, int* BoolOp) NextToken (); /* Get rhs */ - k = hie2 (&lval2); - if ((lval2.Test & E_CC) == 0) { - lval2.Test |= E_FORCETEST; + hie2 (&Expr2); + if ((Expr2.Test & E_CC) == 0) { + Expr2.Test |= E_FORCETEST; } - exprhs (CF_FORCECHAR, k, &lval2); + ExprLoad (CF_FORCECHAR, &Expr2); /* Do short circuit evaluation */ if (CurTok.Tok == TOK_BOOL_AND) { @@ -2493,42 +2590,39 @@ static int hieAnd (ExprDesc* lval, unsigned TrueLab, int* BoolOp) /* Define the false jump label here */ g_defcodelabel (lab); - /* Define the label */ - lval->Flags = E_MEXPR; - lval->Test |= E_CC; /* Condition codes are set */ - k = 0; + /* The result is an rvalue in primary */ + ED_MakeRValExpr (Expr); + Expr->Test |= E_CC; /* Condition codes are set */ } - return k; } -static int hieOr (ExprDesc *lval) +static void hieOr (ExprDesc *Expr) /* Process "exp || exp". */ { - int k; - 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 */ TrueLab = GetLocalLabel (); /* Call the next level parser */ - k = hieAnd (lval, TrueLab, &BoolOp); + hieAnd (Expr, TrueLab, &BoolOp); /* Any boolean or's? */ if (CurTok.Tok == TOK_BOOL_OR) { /* If the expr hasn't set condition codes, set the force-test flag */ - if ((lval->Test & E_CC) == 0) { - lval->Test |= E_FORCETEST; + if ((Expr->Test & E_CC) == 0) { + Expr->Test |= E_FORCETEST; } /* Get first expr */ - exprhs (CF_FORCECHAR, k, lval); + ExprLoad (CF_FORCECHAR, Expr); /* For each expression jump to TrueLab if true. Beware: If we * had && operators, the jump is already in place! @@ -2548,19 +2642,20 @@ static int hieOr (ExprDesc *lval) /* Get a subexpr */ AndOp = 0; - k = hieAnd (&lval2, TrueLab, &AndOp); - if ((lval2.Test & E_CC) == 0) { - lval2.Test |= E_FORCETEST; + hieAnd (&Expr2, TrueLab, &AndOp); + if ((Expr2.Test & E_CC) == 0) { + Expr2.Test |= E_FORCETEST; } - exprhs (CF_FORCECHAR, k, &lval2); + ExprLoad (CF_FORCECHAR, &Expr2); /* If there is more to come, add shortcut boolean eval. */ g_truejump (CF_NONE, TrueLab); } - lval->Flags = E_MEXPR; - lval->Test |= E_CC; /* Condition codes are set */ - k = 0; + + /* The result is an rvalue in primary */ + ED_MakeRValExpr (Expr); + Expr->Test |= E_CC; /* Condition codes are set */ } /* If we really had boolean ops, generate the end sequence */ @@ -2572,45 +2667,67 @@ static int hieOr (ExprDesc *lval) g_getimmed (CF_INT | CF_CONST, 1, 0); /* Load TRUE */ g_defcodelabel (DoneLab); } - return k; } -static int hieQuest (ExprDesc *lval) -/* Parse "lvalue ? exp : exp" */ +static void hieQuest (ExprDesc* Expr) +/* Parse the ternary operator */ { - int k; - int labf; - int labt; - ExprDesc lval2; /* Expression 2 */ - ExprDesc lval3; /* Expression 3 */ - type* type2; /* Type of expression 2 */ - type* type3; /* Type of expression 3 */ - type* rtype; /* Type of result */ - CodeMark Mark1; /* Save position in output code */ - CodeMark Mark2; /* Save position in output code */ + int labf; + int labt; + 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 */ + /* Call the lower level eval routine */ + if (Preprocessing) { + hieOrPP (Expr); + } else { + hieOr (Expr); + } - k = Preprocessing? hieOrPP (lval) : hieOr (lval); + /* Check if it's a ternary expression */ if (CurTok.Tok == TOK_QUEST) { NextToken (); - if ((lval->Test & E_CC) == 0) { + if ((Expr->Test & E_CC) == 0) { /* Condition codes not set, force a test */ - lval->Test |= E_FORCETEST; + Expr->Test |= E_FORCETEST; } - exprhs (CF_NONE, k, lval); + ExprLoad (CF_NONE, Expr); labf = GetLocalLabel (); g_falsejump (CF_NONE, labf); - /* Parse second and third expression */ - expression1 (&lval2); + /* Parse second expression. Remember for later if it is a NULL pointer + * expression, then load it into the primary. + */ + ExprWithCheck (hie1, &Expr2); + Expr2IsNULL = ED_IsNullPtr (&Expr2); + if (!IsTypeVoid (Expr2.Type)) { + /* Load it into the primary */ + ExprLoad (CF_NONE, &Expr2); + ED_MakeRValExpr (&Expr2); + } labt = GetLocalLabel (); ConsumeColon (); g_jump (labt); + + /* Jump here if the first expression was false */ g_defcodelabel (labf); - expression1 (&lval3); + + /* Parse second expression. Remember for later if it is a NULL pointer + * expression, then load it into the primary. + */ + ExprWithCheck (hie1, &Expr3); + Expr3IsNULL = ED_IsNullPtr (&Expr3); + if (!IsTypeVoid (Expr3.Type)) { + /* Load it into the primary */ + ExprLoad (CF_NONE, &Expr3); + ED_MakeRValExpr (&Expr3); + } /* Check if any conversions are needed, if so, do them. * Conversion rules for ?: expression are: @@ -2621,100 +2738,109 @@ static int hieQuest (ExprDesc *lval) * - if one of the expressions is a pointer and the other is * a zero constant, the resulting type is that of the pointer * type. + * - if both expressions are void expressions, the result is of + * type void. * - all other cases are flagged by an error. */ - type2 = lval2.Type; - type3 = lval3.Type; - if (IsClassInt (type2) && IsClassInt (type3)) { + if (IsClassInt (Expr2.Type) && IsClassInt (Expr3.Type)) { /* Get common type */ - rtype = promoteint (type2, type3); + ResultType = promoteint (Expr2.Type, Expr3.Type); /* Convert the third expression to this type if needed */ - g_typecast (TypeOf (rtype), TypeOf (type3)); + 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 */ - Mark1 = GetCodePos (); /* Remember current position */ - g_jump (labf); /* Jump around code */ + g_jump (labf); /* Jump around code */ /* The jump for expr2 goes here */ g_defcodelabel (labt); /* Create the typecast code for expr2 */ - Mark2 = GetCodePos (); /* Remember position */ - g_typecast (TypeOf (rtype), TypeOf (type2)); + TypeConversion (&Expr2, ResultType); /* Jump here around the typecase code. */ g_defcodelabel (labf); - labt = 0; /* Mark other label as invalid */ + labt = 0; /* Mark other label as invalid */ - } else if (IsClassPtr (type2) && IsClassPtr (type3)) { + } else if (IsClassPtr (Expr2.Type) && IsClassPtr (Expr3.Type)) { /* Must point to same type */ - if (TypeCmp (Indirect (type2), Indirect (type3)) < TC_EQUAL) { - Error ("Incompatible pointer types"); + if (TypeCmp (Indirect (Expr2.Type), Indirect (Expr3.Type)) < TC_EQUAL) { + Error ("Incompatible pointer types"); } /* Result has the common type */ - rtype = lval2.Type; - } else if (IsClassPtr (type2) && IsNullPtr (&lval3)) { + ResultType = Expr2.Type; + } else if (IsClassPtr (Expr2.Type) && Expr3IsNULL) { /* Result type is pointer, no cast needed */ - rtype = lval2.Type; - } else if (IsNullPtr (&lval2) && IsClassPtr (type3)) { + ResultType = Expr2.Type; + } else if (Expr2IsNULL && IsClassPtr (Expr3.Type)) { /* Result type is pointer, no cast needed */ - rtype = lval3.Type; - } else { - Error ("Incompatible types"); - rtype = lval2.Type; /* Doesn't matter here */ - } + ResultType = Expr3.Type; + } else if (IsTypeVoid (Expr2.Type) && IsTypeVoid (Expr3.Type)) { + /* Result type is void */ + ResultType = Expr3.Type; + } else { + Error ("Incompatible types"); + ResultType = Expr2.Type; /* Doesn't matter here */ + } - /* If we don't have the label defined until now, do it */ - if (labt) { - g_defcodelabel (labt); - } + /* If we don't have the label defined until now, do it */ + if (labt) { + g_defcodelabel (labt); + } - /* Setup the target expression */ - lval->Flags = E_MEXPR; - lval->Type = rtype; - k = 0; + /* Setup the target expression */ + ED_MakeRValExpr (Expr); + Expr->Type = ResultType; } - return k; } -static void opeq (GenDesc* Gen, ExprDesc *lval, int k) +static void opeq (const GenDesc* Gen, ExprDesc* Expr) /* Process "op=" operators. */ { - ExprDesc lval2; + ExprDesc Expr2; unsigned flags; CodeMark Mark; int MustScale; - NextToken (); - if (k == 0) { + /* op= can only be used with lvalues */ + if (!ED_IsLVal (Expr)) { Error ("Invalid lvalue in assignment"); return; } + /* 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 (lval->Type); - MustScale = (Gen->Func == g_add || Gen->Func == g_sub) && - lval->Type [0] == T_PTR; + flags = TypeOf (Expr->Type); + MustScale = (Gen->Func == g_add || Gen->Func == g_sub) && IsTypePtr (Expr->Type); /* Get the lhs address on stack (if needed) */ - PushAddr (lval); + PushAddr (Expr); /* Fetch the lhs into the primary register if needed */ - exprhs (CF_NONE, k, lval); + ExprLoad (CF_NONE, Expr); /* Bring the lhs on stack */ Mark = GetCodePos (); g_push (flags, 0); /* Evaluate the rhs */ - if (evalexpr (CF_NONE, hie1, &lval2) == 0) { + if (evalexpr (CF_NONE, hie1, &Expr2) == 0) { /* The resulting value is a constant. If the generator has the NOPUSH * flag set, don't push the lhs. */ @@ -2724,461 +2850,324 @@ static void opeq (GenDesc* Gen, ExprDesc *lval, int k) } if (MustScale) { /* lhs is a pointer, scale rhs */ - lval2.ConstVal *= SizeOf (lval->Type+1); + Expr2.Val *= CheckedSizeOf (Expr->Type+1); } /* If the lhs is character sized, the operation may be later done * with characters. */ - if (SizeOf (lval->Type) == 1) { + if (CheckedSizeOf (Expr->Type) == SIZEOF_CHAR) { flags |= CF_FORCECHAR; } /* 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.Val); } else if (Gen->Func == g_sub) { - g_dec (flags | CF_CONST, lval2.ConstVal); + g_dec (flags | CF_CONST, Expr2.Val); } else { - Gen->Func (flags | CF_CONST, lval2.ConstVal); + Gen->Func (flags | CF_CONST, Expr2.Val); } } else { /* rhs is not constant and already in the primary register */ if (MustScale) { /* lhs is a pointer, scale rhs */ - g_scale (TypeOf (lval2.Type), SizeOf (lval->Type+1)); + g_scale (TypeOf (Expr2.Type), CheckedSizeOf (Expr->Type+1)); } /* If the lhs is character sized, the operation may be later done * with characters. */ - if (SizeOf (lval->Type) == 1) { + if (CheckedSizeOf (Expr->Type) == SIZEOF_CHAR) { flags |= CF_FORCECHAR; } /* 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 (lval); - lval->Flags = E_MEXPR; + Store (Expr, 0); + ED_MakeRValExpr (Expr); } -static void addsubeq (GenDesc* Gen, ExprDesc *lval, int k) +static void addsubeq (const GenDesc* Gen, ExprDesc *Expr) /* Process the += and -= operators */ { - ExprDesc lval2; - unsigned flags; - int MustScale; + 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); + return; + } - if (k == 0) { + /* 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 ((lval->Flags & E_MGLOBAL) == 0 && /* Global address? */ - (lval->Flags & E_MLOCAL) == 0 && /* Local address? */ - (lval->Flags & E_MCONST) == 0) { /* Constant address? */ - /* Use generic routine */ - opeq (Gen, lval, k); - return; + /* 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 = (lval->Type [0] == T_PTR); + MustScale = IsTypePtr (Expr->Type); - /* Determine the code generator flags */ - flags = TypeOf (lval->Type) | CF_FORCECHAR; + /* Initialize the code generator flags */ + lflags = 0; + rflags = 0; /* Evaluate the rhs */ - if (evalexpr (CF_NONE, hie1, &lval2) == 0) { - /* The resulting value is a constant. */ - if (MustScale) { - /* lhs is a pointer, scale rhs */ - lval2.ConstVal *= SizeOf (lval->Type+1); - } - flags |= CF_CONST; + hie1 (&Expr2); + if (ED_IsConstAbs (&Expr2)) { + /* The resulting value is a constant. Scale it. */ + if (MustScale) { + Expr2.Val *= CheckedSizeOf (Indirect (Expr->Type)); + } + rflags |= CF_CONST; + lflags |= CF_CONST; } else { - /* rhs is not constant and already in the primary register */ + /* Not constant, load into the primary */ + ExprLoad (CF_NONE, &Expr2); if (MustScale) { - /* lhs is a pointer, scale rhs */ - g_scale (TypeOf (lval2.Type), SizeOf (lval->Type+1)); - } - } - - /* Adjust the rhs to the lhs */ - g_typeadjust (flags, TypeOf (lval2.Type)); - - /* Output apropriate code */ - if (lval->Flags & E_MGLOBAL) { - /* Static variable */ - flags |= GlobalModeFlags (lval->Flags); - if (Gen->Tok == TOK_PLUS_ASSIGN) { - g_addeqstatic (flags, lval->Name, lval->ConstVal, lval2.ConstVal); - } else { - g_subeqstatic (flags, lval->Name, lval->ConstVal, lval2.ConstVal); - } - } else if (lval->Flags & E_MLOCAL) { - /* ref to localvar */ - if (Gen->Tok == TOK_PLUS_ASSIGN) { - g_addeqlocal (flags, lval->ConstVal, lval2.ConstVal); - } else { - g_subeqlocal (flags, lval->ConstVal, lval2.ConstVal); - } - } else if (lval->Flags & E_MCONST) { - /* ref to absolute address */ - flags |= CF_ABSOLUTE; - if (Gen->Tok == TOK_PLUS_ASSIGN) { - g_addeqstatic (flags, lval->ConstVal, 0, lval2.ConstVal); - } else { - g_subeqstatic (flags, lval->ConstVal, 0, lval2.ConstVal); - } - } else if (lval->Flags & E_MEXPR) { - /* Address in a/x. */ - if (Gen->Tok == TOK_PLUS_ASSIGN) { - g_addeqind (flags, lval->ConstVal, lval2.ConstVal); - } else { - g_subeqind (flags, lval->ConstVal, lval2.ConstVal); - } - } else { - Internal ("Invalid addressing mode"); - } - - /* Expression is in the primary now */ - lval->Flags = E_MEXPR; -} - - - -static void Assignment (ExprDesc* lval) -/* Parse an assignment */ -{ - int k; - ExprDesc lval2; - unsigned flags; - type* ltype = lval->Type; - - /* Check for assignment to const */ - if (IsQualConst (ltype)) { - Error ("Assignment to const"); - } - - /* cc65 does not have full support for handling structs by value. Since - * assigning structs is one of the more useful operations from this - * family, allow it here. - */ - if (IsClassStruct (ltype)) { - - /* Bring the address of the lhs into the primary and push it */ - exprhs (0, 0, lval); - g_push (CF_PTR | CF_UNSIGNED, 0); - - /* Get the expression on the right of the '=' into the primary */ - k = hie1 (&lval2); - if (k) { - /* Get the address */ - exprhs (0, 0, &lval2); - } else { - /* We need an lvalue */ - Error ("Invalid lvalue in assignment"); - } - - /* Push the address (or whatever is in ax in case of errors) */ - g_push (CF_PTR | CF_UNSIGNED, 0); - - /* Check for equality of the structs */ - if (TypeCmp (ltype, lval2.Type) < TC_EQUAL) { - Error ("Incompatible types"); - } - - /* Load the size of the struct into the primary */ - g_getimmed (CF_INT | CF_UNSIGNED | CF_CONST, SizeOf (ltype), 0); - - /* Call the memcpy function */ - g_call (CF_FIXARGC, "memcpy", 4); - - } else { - - /* Get the address on stack if needed */ - PushAddr (lval); - - /* No struct, setup flags for the load */ - flags = SizeOf (ltype) == 1? CF_FORCECHAR : CF_NONE; - - /* Get the expression on the right of the '=' into the primary */ - if (evalexpr (flags, hie1, &lval2) == 0) { - /* Constant expression. Adjust the types */ - assignadjust (ltype, &lval2); - /* Put the value into the primary register */ - lconst (flags, &lval2); - } else { - /* Expression is not constant and already in the primary */ - assignadjust (ltype, &lval2); + /* lhs is a pointer, scale rhs */ + g_scale (TypeOf (Expr2.Type), CheckedSizeOf (Indirect (Expr->Type))); } - - /* Generate a store instruction */ - store (lval); - } - /* Value is still in primary */ - lval->Flags = E_MEXPR; + /* Setup the code generator flags */ + lflags |= TypeOf (Expr->Type) | CF_FORCECHAR; + rflags |= TypeOf (Expr2.Type); + + /* Convert the type of the lhs to that of the rhs */ + g_typecast (lflags, rflags); + + /* Output apropriate code depending on the location */ + switch (ED_GetLoc (Expr)) { + + case E_LOC_ABS: + /* Absolute: numeric address or const */ + lflags |= CF_ABSOLUTE; + if (Gen->Tok == TOK_PLUS_ASSIGN) { + g_addeqstatic (lflags, Expr->Name, Expr->Val, Expr2.Val); + } else { + g_subeqstatic (lflags, Expr->Name, Expr->Val, Expr2.Val); + } + break; + + case E_LOC_GLOBAL: + /* Global variable */ + lflags |= CF_EXTERNAL; + if (Gen->Tok == TOK_PLUS_ASSIGN) { + g_addeqstatic (lflags, Expr->Name, Expr->Val, Expr2.Val); + } else { + g_subeqstatic (lflags, Expr->Name, Expr->Val, Expr2.Val); + } + break; + + case E_LOC_STATIC: + case E_LOC_LITERAL: + /* Static variable or literal in the literal pool */ + lflags |= CF_STATIC; + if (Gen->Tok == TOK_PLUS_ASSIGN) { + g_addeqstatic (lflags, Expr->Name, Expr->Val, Expr2.Val); + } else { + g_subeqstatic (lflags, Expr->Name, Expr->Val, Expr2.Val); + } + break; + + case E_LOC_REGISTER: + /* Register variable */ + lflags |= CF_REGVAR; + if (Gen->Tok == TOK_PLUS_ASSIGN) { + g_addeqstatic (lflags, Expr->Name, Expr->Val, Expr2.Val); + } else { + g_subeqstatic (lflags, Expr->Name, Expr->Val, Expr2.Val); + } + break; + + case E_LOC_STACK: + /* Value on the stack */ + if (Gen->Tok == TOK_PLUS_ASSIGN) { + g_addeqlocal (lflags, Expr->Val, Expr2.Val); + } else { + g_subeqlocal (lflags, Expr->Val, Expr2.Val); + } + break; + + default: + Internal ("Invalid location in Store(): 0x%04X", ED_GetLoc (Expr)); + } + + /* Expression is a rvalue in the primary now */ + ED_MakeRValExpr (Expr); } -int hie1 (ExprDesc* lval) +void hie1 (ExprDesc* Expr) /* Parse first level of expression hierarchy. */ { - int k; - - k = hieQuest (lval); + hieQuest (Expr); switch (CurTok.Tok) { - case TOK_RPAREN: - case TOK_SEMI: - return k; - case TOK_ASSIGN: - NextToken (); - if (k == 0) { - Error ("Invalid lvalue in assignment"); - } else { - Assignment (lval); - } + Assignment (Expr); break; case TOK_PLUS_ASSIGN: - addsubeq (&GenPASGN, lval, k); + addsubeq (&GenPASGN, Expr); break; case TOK_MINUS_ASSIGN: - addsubeq (&GenSASGN, lval, k); + addsubeq (&GenSASGN, Expr); break; case TOK_MUL_ASSIGN: - opeq (&GenMASGN, lval, k); + opeq (&GenMASGN, Expr); break; case TOK_DIV_ASSIGN: - opeq (&GenDASGN, lval, k); + opeq (&GenDASGN, Expr); break; case TOK_MOD_ASSIGN: - opeq (&GenMOASGN, lval, k); + opeq (&GenMOASGN, Expr); break; case TOK_SHL_ASSIGN: - opeq (&GenSLASGN, lval, k); + opeq (&GenSLASGN, Expr); break; case TOK_SHR_ASSIGN: - opeq (&GenSRASGN, lval, k); + opeq (&GenSRASGN, Expr); break; case TOK_AND_ASSIGN: - opeq (&GenAASGN, lval, k); + opeq (&GenAASGN, Expr); break; case TOK_XOR_ASSIGN: - opeq (&GenXOASGN, lval, k); + opeq (&GenXOASGN, Expr); break; case TOK_OR_ASSIGN: - opeq (&GenOASGN, lval, k); + opeq (&GenOASGN, Expr); break; default: - return k; + break; } - return 0; } -int hie0 (ExprDesc *lval) +void hie0 (ExprDesc *Expr) /* Parse comma operator. */ { - int k; - - k = hie1 (lval); + hie1 (Expr); while (CurTok.Tok == TOK_COMMA) { - NextToken (); - k = hie1 (lval); + NextToken (); + hie1 (Expr); } - return k; } -int evalexpr (unsigned flags, int (*f) (ExprDesc*), ExprDesc* lval) +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, exprhs 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, ExprLoad is called to bring the value into the * primary register and 1 is returned. */ { - int k; - /* Evaluate */ - k = f (lval); - if (k == 0 && lval->Flags == E_MCONST) { + ExprWithCheck (Func, Expr); + + /* Check for a constant expression */ + if (ED_IsConstAbs (Expr)) { /* Constant expression */ return 0; } else { /* Not constant, load into the primary */ - exprhs (flags, k, lval); + ExprLoad (Flags, Expr); return 1; } } -int expr (int (*func) (ExprDesc*), ExprDesc *lval) -/* 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 */ { - int k; - int savsp; - - savsp = oursp; - - k = (*func) (lval); - - /* 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); - } - } - return k; + ExprWithCheck (hie0, Expr); + ExprLoad (CF_NONE, Expr); } -void expression1 (ExprDesc* lval) -/* 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. */ { - memset (lval, 0, sizeof (*lval)); - exprhs (CF_NONE, expr (hie1, lval), lval); -} - - - -void expression (ExprDesc* lval) -/* Evaluate an expression and put it into the primary register */ -{ - memset (lval, 0, sizeof (*lval)); - exprhs (CF_NONE, expr (hie0, lval), lval); -} - - - -void constexpr (ExprDesc* lval) -/* Get a constant value */ -{ - memset (lval, 0, sizeof (*lval)); - if (expr (hie1, lval) != 0 || (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 */ - MakeConstIntExpr (lval, 1); - } -} - - - -void intexpr (ExprDesc* lval) -/* Get an integer expression */ -{ - expression (lval); - if (!IsClassInt (lval->Type)) { - Error ("Integer expression expected"); - /* To avoid any compiler errors, make the expression a valid int */ - MakeConstIntExpr (lval, 1); + ED_MakeConstAbsInt (Expr, 1); } } -void boolexpr (ExprDesc* lval) -/* Get a boolean expression */ +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. + */ { - /* Read an expression */ - expression (lval); - - /* If it's an integer, it's ok. If it's not an integer, but a pointer, - * the pointer used in a boolean context is also ok - */ - if (!IsClassInt (lval->Type) && !IsClassPtr (lval->Type)) { + ExprWithCheck (Func, Expr); + if (!ED_IsBool (Expr)) { Error ("Boolean expression expected"); /* To avoid any compiler errors, make the expression a valid int */ - MakeConstIntExpr (lval, 1); + ED_MakeConstAbsInt (Expr, 1); } } -void test (unsigned label, int cond) -/* Generate code to perform test and jump if false. */ +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. + */ { - int k; - ExprDesc lval; - - /* Eat the parenthesis */ - ConsumeLParen (); - - /* Prepare the expression, setup labels */ - memset (&lval, 0, sizeof (lval)); - - /* Generate code to eval the expr */ - k = expr (hie0, &lval); - if (k == 0 && lval.Flags == E_MCONST) { - /* Constant rvalue */ - if (cond == 0 && lval.ConstVal == 0) { - g_jump (label); - Warning ("Unreachable code"); - } else if (cond && lval.ConstVal) { - g_jump (label); - } - ConsumeRParen (); - return; - } - - /* If the expr hasn't set condition codes, set the force-test flag */ - if ((lval.Test & E_CC) == 0) { - lval.Test |= E_FORCETEST; - } - - /* Load the value into the primary register */ - exprhs (CF_FORCECHAR, k, &lval); - - /* Generate the jump */ - if (cond) { - g_truejump (CF_NONE, label); - } else { - /* Special case (putting this here is a small hack - but hey, the - * compiler itself is one big hack...): If a semicolon follows, we - * don't have a statement and may omit the jump. - */ - if (CurTok.Tok != TOK_SEMI) { - g_falsejump (CF_NONE, label); - } + 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); } - - /* Check for the closing brace */ - ConsumeRParen (); } -