X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fcc65%2Fexpr.c;h=343ecdfed4eb048acab1813cef404fc9205623d1;hb=77bfcc1ff0a88e0430f077d22b6fad07c7d0c86b;hp=e7c69579960f83c31878b0a1c20f350812031be8;hpb=8752f0b2c19fb307232ebdbb0d6a00971292a6d7;p=cc65 diff --git a/src/cc65/expr.c b/src/cc65/expr.c index e7c695799..343ecdfed 100644 --- a/src/cc65/expr.c +++ b/src/cc65/expr.c @@ -29,7 +29,9 @@ #include "macrotab.h" #include "preproc.h" #include "scanner.h" +#include "shiftexpr.h" #include "stackptr.h" +#include "standard.h" #include "stdfunc.h" #include "symtab.h" #include "typecmp.h" @@ -69,37 +71,33 @@ static GenDesc GenOASGN = { TOK_OR_ASSIGN, GEN_NOPUSH, g_or }; /*****************************************************************************/ -/* Function forwards */ +/* Helper functions */ /*****************************************************************************/ -void hie0 (ExprDesc *lval); -/* Parse comma operator. */ - - - -/*****************************************************************************/ -/* Helper functions */ -/*****************************************************************************/ - - - -static unsigned GlobalModeFlags (unsigned Flags) -/* Return the addressing mode flags for the variable with the given flags */ +static unsigned GlobalModeFlags (const ExprDesc* Expr) +/* Return the addressing mode flags for the given expression */ { - switch (Flags & E_MASK_LOC) { + switch (ED_GetLoc (Expr)) { + case E_LOC_ABS: return CF_ABSOLUTE; case E_LOC_GLOBAL: return CF_EXTERNAL; case E_LOC_STATIC: return CF_STATIC; case E_LOC_REGISTER: return CF_REGVAR; + case E_LOC_STACK: return CF_NONE; + case E_LOC_PRIMARY: return CF_NONE; + case E_LOC_EXPR: return CF_NONE; + case E_LOC_LITERAL: return CF_STATIC; /* Same as static */ default: - Internal ("GlobalModeFlags: Invalid flags value: %u", Flags); + Internal ("GlobalModeFlags: Invalid location flags value: 0x%04X", Expr->Flags); + /* NOTREACHED */ + return 0; } } -void ExprWithCheck (void (*Func) (ExprDesc*), ExprDesc *Expr) +void ExprWithCheck (void (*Func) (ExprDesc*), ExprDesc* Expr) /* Call an expression function with checks. */ { /* Remember the stack pointer */ @@ -123,7 +121,21 @@ void ExprWithCheck (void (*Func) (ExprDesc*), ExprDesc *Expr) -static type* promoteint (type* lhst, type* rhst) +void MarkedExprWithCheck (void (*Func) (ExprDesc*), ExprDesc* Expr) +/* Call an expression function with checks and record start and end of the + * generated code. + */ +{ + CodeMark Start, End; + GetCodePos (&Start); + ExprWithCheck (Func, Expr); + GetCodePos (&End); + ED_SetCodeRange (Expr, &Start, &End); +} + + + +static Type* promoteint (Type* lhst, Type* rhst) /* In an expression with two ints, return the type of the result */ { /* Rules for integer types: @@ -135,7 +147,7 @@ static type* promoteint (type* lhst, type* rhst) if (IsSignUnsigned (lhst) || IsSignUnsigned (rhst)) { return type_ulong; } else { - return type_long; + return type_long; } } else { if (IsSignUnsigned (lhst) || IsSignUnsigned (rhst)) { @@ -162,8 +174,8 @@ static unsigned typeadjust (ExprDesc* lhs, ExprDesc* rhs, int NoPush) unsigned flags; /* Get the type strings */ - type* lhst = lhs->Type; - type* rhst = rhs->Type; + Type* lhst = lhs->Type; + Type* rhst = rhs->Type; /* Generate type adjustment code if needed */ ltype = TypeOf (lhst); @@ -189,92 +201,6 @@ static unsigned typeadjust (ExprDesc* lhs, ExprDesc* rhs, int NoPush) -void DefineData (ExprDesc* Expr) -/* Output a data definition for the given expression */ -{ - switch (ED_GetLoc (Expr)) { - - case E_LOC_ABS: - /* Absolute: numeric address or const */ - g_defdata (TypeOf (Expr->Type) | CF_CONST, Expr->IVal, 0); - break; - - case E_LOC_GLOBAL: - /* Global variable */ - g_defdata (CF_EXTERNAL, Expr->Name, Expr->IVal); - break; - - case E_LOC_STATIC: - case E_LOC_LITERAL: - /* Static variable or literal in the literal pool */ - g_defdata (CF_STATIC, Expr->Name, Expr->IVal); - break; - - case E_LOC_REGISTER: - /* Register variable. Taking the address is usually not - * allowed. - */ - if (IS_Get (&AllowRegVarAddr) == 0) { - Error ("Cannot take the address of a register variable"); - } - g_defdata (CF_REGVAR, Expr->Name, Expr->IVal); - break; - - default: - Internal ("Unknown constant type: 0x%04X", ED_GetLoc (Expr)); - } -} - - - -static int kcalc (token_t tok, long val1, long val2) -/* Calculate an operation with left and right operand constant. */ -{ - switch (tok) { - case TOK_EQ: - return (val1 == val2); - case TOK_NE: - return (val1 != val2); - case TOK_LT: - return (val1 < val2); - case TOK_LE: - return (val1 <= val2); - case TOK_GE: - return (val1 >= val2); - case TOK_GT: - return (val1 > val2); - case TOK_OR: - return (val1 | val2); - case TOK_XOR: - return (val1 ^ val2); - case TOK_AND: - return (val1 & val2); - case TOK_SHR: - return (val1 >> val2); - case TOK_SHL: - return (val1 << val2); - case TOK_STAR: - return (val1 * val2); - case TOK_DIV: - if (val2 == 0) { - Error ("Division by zero"); - return 0x7FFFFFFF; - } - return (val1 / val2); - case TOK_MOD: - if (val2 == 0) { - Error ("Modulo operation with zero"); - return 0; - } - return (val1 % val2); - default: - Internal ("kcalc: got token 0x%X\n", tok); - return 0; - } -} - - - static const GenDesc* FindGen (token_t Tok, const GenDesc* Table) /* Find a token in a generator table */ { @@ -330,12 +256,12 @@ void PushAddr (const ExprDesc* Expr) /*****************************************************************************/ -/* code */ +/* code */ /*****************************************************************************/ -static unsigned FunctionParamList (FuncDesc* Func) +static unsigned FunctionParamList (FuncDesc* Func, int IsFastcall) /* Parse a function parameter list and pass the parameters to the called * function. Depending on several criteria this may be done by just pushing * each parameter separately, or creating the parameter frame once and then @@ -367,18 +293,18 @@ static unsigned FunctionParamList (FuncDesc* Func) * (instead of pushing) is enabled. * */ - if (CodeSizeFactor >= 200) { + if (IS_Get (&CodeSizeFactor) >= 200) { /* Calculate the number and size of the parameters */ FrameParams = Func->ParamCount; FrameSize = Func->ParamSize; - if (FrameParams > 0 && (Func->Flags & FD_FASTCALL) != 0) { + if (FrameParams > 0 && IsFastcall) { /* Last parameter is not pushed */ FrameSize -= CheckedSizeOf (Func->LastParam->Type); --FrameParams; } - /* Do we have more than one parameter in the frame? */ + /* Do we have more than one parameter in the frame? */ if (FrameParams > 1) { /* Okeydokey, setup the frame */ FrameOffs = StackPtr; @@ -421,7 +347,7 @@ static unsigned FunctionParamList (FuncDesc* Func) if ((Func->Flags & FD_VARIADIC) == 0) { /* End of param list reached, no ellipsis */ Error ("Too many arguments in function call"); - } + } /* Assume an ellipsis even in case of errors to avoid an error * message for each other argument. */ @@ -436,12 +362,21 @@ static unsigned FunctionParamList (FuncDesc* Func) */ Flags = CF_NONE; if (!Ellipsis) { + /* Convert the argument to the parameter type if needed */ TypeConversion (&Expr, Param->Type); /* If we have a prototype, chars may be pushed as chars */ Flags |= CF_FORCECHAR; - } + + } else { + + /* No prototype available. Convert array to "pointer to first + * element", and function to "pointer to function". + */ + Expr.Type = PtrConversion (Expr.Type); + + } /* Load the value into the primary if it is not already there */ LoadExpr (Flags, &Expr); @@ -450,7 +385,7 @@ static unsigned FunctionParamList (FuncDesc* Func) Flags |= TypeOf (Expr.Type); /* If this is a fastcall function, don't push the last argument */ - if (ParamCount != Func->ParamCount || (Func->Flags & FD_FASTCALL) == 0) { + if (ParamCount != Func->ParamCount || !IsFastcall) { unsigned ArgSize = sizeofarg (Flags); if (FrameSize > 0) { /* We have the space already allocated, store in the frame. @@ -506,11 +441,10 @@ static void FunctionCall (ExprDesc* Expr) { 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 */ + CodeMark Mark; int PtrOffs = 0; /* Offset of function pointer on stack */ - int IsFastCall = 0; /* True if it's a fast call function */ + int IsFastcall = 0; /* True if it's a fast call function */ int PtrOnStack = 0; /* True if a pointer copy is on stack */ /* Skip the left paren */ @@ -524,7 +458,7 @@ static void FunctionCall (ExprDesc* Expr) if (IsFuncPtr) { /* Check wether it's a fastcall function that has parameters */ - IsFastCall = IsFastCallFunc (Expr->Type + 1) && (Func->ParamCount > 0); + IsFastcall = IsQualFastcall (Expr->Type + 1) && (Func->ParamCount > 0); /* Things may be difficult, depending on where the function pointer * resides. If the function pointer is an expression of some sort @@ -534,7 +468,7 @@ static void FunctionCall (ExprDesc* Expr) * For fastcall functions we do also need to place a copy of the * pointer on stack, since we cannot use a/x. */ - PtrOnStack = IsFastCall || !ED_IsConst (Expr); + PtrOnStack = IsFastcall || !ED_IsConst (Expr); if (PtrOnStack) { /* Not a global or local variable, or a fastcall function. Load @@ -544,24 +478,36 @@ static void FunctionCall (ExprDesc* Expr) ED_MakeRValExpr (Expr); /* Remember the code position */ - Mark = GetCodePos (); + GetCodePos (&Mark); /* Push the pointer onto the stack and remember the offset */ g_push (CF_PTR, 0); PtrOffs = StackPtr; } - /* Check for known standard functions and inline them */ - } else if ((StdFunc = FindStdFunc ((const char*) Expr->Name)) >= 0) { + } else { + /* Check function attributes */ + if (Expr->Sym && SymHasAttr (Expr->Sym, atNoReturn)) { + /* For now, handle as if a return statement was encountered */ + F_ReturnFound (CurrentFunc); + } - /* Inline this function */ - HandleStdFunc (StdFunc, Func, Expr); - return; + /* Check for known standard functions and inline them */ + if (Expr->Name != 0) { + int StdFunc = FindStdFunc ((const char*) Expr->Name); + if (StdFunc >= 0) { + /* Inline this function */ + HandleStdFunc (StdFunc, Func, Expr); + return; + } + } + /* If we didn't inline the function, get fastcall info */ + IsFastcall = IsQualFastcall (Expr->Type); } /* Parse the parameter list */ - ParamSize = FunctionParamList (Func); + ParamSize = FunctionParamList (Func, IsFastcall); /* We need the closing paren here */ ConsumeRParen (); @@ -572,7 +518,7 @@ static void FunctionCall (ExprDesc* Expr) /* If the function is not a fastcall function, load the pointer to * the function into the primary. */ - if (!IsFastCall) { + if (!IsFastcall) { /* Not a fastcall function - we may use the primary */ if (PtrOnStack) { @@ -581,11 +527,10 @@ static void FunctionCall (ExprDesc* Expr) * stack pointer. */ if (ParamSize == 0) { - RemoveCode (Mark); - pop (CF_PTR); + RemoveCode (&Mark); PtrOnStack = 0; } else { - /* Load from the saved copy */ + /* Load from the saved copy */ g_getlocal (CF_PTR, PtrOffs); } } else { @@ -608,7 +553,7 @@ static void FunctionCall (ExprDesc* Expr) /* If we have a pointer on stack, remove it */ if (PtrOnStack) { - g_space (- (int) sizeofarg (CF_PTR)); + g_drop (SIZEOF_PTR); pop (CF_PTR); } @@ -669,6 +614,7 @@ static void Primary (ExprDesc* E) * is an undefined macro and replace it by a constant value of zero. */ if (Preprocessing && CurTok.Tok == TOK_IDENT) { + NextToken (); ED_MakeConstAbsInt (E, 0); return; } @@ -773,11 +719,17 @@ static void Primary (ExprDesc* E) /* IDENT is either an auto-declared function or an undefined variable. */ if (CurTok.Tok == TOK_LPAREN) { - /* Declare a function returning int. For that purpose, prepare a - * function signature for a function having an empty param list - * and returning int. + /* C99 doesn't allow calls to undefined functions, so + * generate an error and otherwise a warning. Declare a + * function returning int. For that purpose, prepare a + * function signature for a function having an empty param + * list and returning int. */ - Warning ("Function call without a prototype"); + if (IS_Get (&Standard) >= STD_C99) { + Error ("Call to undefined function `%s'", Ident); + } else { + Warning ("Call to undefined function `%s'", Ident); + } Sym = AddGlobalSym (Ident, GetImplicitFuncType(), SC_EXTERN | SC_REF | SC_FUNC); E->Type = Sym->Type; E->Flags = E_LOC_GLOBAL | E_RTYPE_RVAL; @@ -794,11 +746,13 @@ static void Primary (ExprDesc* E) break; case TOK_SCONST: + case TOK_WCSCONST: /* String literal */ - E->Type = GetCharArrayType (GetLiteralPoolOffs () - CurTok.IVal); + E->LVal = UseLiteral (CurTok.SVal); + E->Type = GetCharArrayType (GetLiteralSize (CurTok.SVal)); E->Flags = E_LOC_LITERAL | E_RTYPE_RVAL; - E->IVal = CurTok.IVal; - E->Name = LiteralPoolLabel; + E->IVal = 0; + E->Name = GetLiteralLabel (CurTok.SVal); NextToken (); break; @@ -831,8 +785,11 @@ static void Primary (ExprDesc* E) break; default: - /* Illegal primary. */ + /* Illegal primary. Be sure to skip the token to avoid endless + * error loops. + */ Error ("Expression expected"); + NextToken (); ED_MakeConstAbsInt (E, 1); break; } @@ -841,14 +798,15 @@ static void Primary (ExprDesc* E) static void ArrayRef (ExprDesc* Expr) -/* Handle an array reference */ +/* Handle an array reference. This function needs a rewrite. */ { int ConstBaseAddr; - ExprDesc SubScript; + ExprDesc Subscript; CodeMark Mark1; CodeMark Mark2; - type* ElementType; - type* tptr1; + TypeCode Qualifiers; + Type* ElementType; + Type* tptr1; /* Skip the bracket */ @@ -861,11 +819,11 @@ static void ArrayRef (ExprDesc* Expr) * address. This is true for most arrays and will produce a lot better * code. Check if this is a const base address. */ - ConstBaseAddr = (ED_IsLocConst (Expr) || ED_IsLocStack (Expr)); + ConstBaseAddr = ED_IsRVal (Expr) && + (ED_IsLocConst (Expr) || ED_IsLocStack (Expr)); /* If we have a constant base, we delay the address fetch */ - Mark1 = GetCodePos (); - Mark2 = 0; /* Silence gcc */ + GetCodePos (&Mark1); if (!ConstBaseAddr) { /* Get a pointer to the array into the primary */ LoadExpr (CF_NONE, Expr); @@ -874,12 +832,12 @@ static void ArrayRef (ExprDesc* Expr) * bit, even if this value is greater, since we cannot handle * other than 16bit stuff when doing indexing. */ - Mark2 = GetCodePos (); + GetCodePos (&Mark2); g_push (CF_PTR, 0); } /* TOS now contains ptr to array elements. Get the subscript. */ - ExprWithCheck (hie0, &SubScript); + MarkedExprWithCheck (hie0, &Subscript); /* Check the types of array and subscript. We can either have a * pointer/array to the left, in which case the subscript must be of an @@ -888,42 +846,61 @@ static void ArrayRef (ExprDesc* Expr) * Since we do the necessary checking here, we can rely later on the * correct types. */ + Qualifiers = T_QUAL_NONE; if (IsClassPtr (Expr->Type)) { - if (!IsClassInt (SubScript.Type)) { + if (!IsClassInt (Subscript.Type)) { Error ("Array subscript is not an integer"); /* To avoid any compiler errors, make the expression a valid int */ - ED_MakeConstAbsInt (&SubScript, 0); + ED_MakeConstAbsInt (&Subscript, 0); + } + if (IsTypeArray (Expr->Type)) { + Qualifiers = GetQualifier (Expr->Type); } ElementType = Indirect (Expr->Type); } else if (IsClassInt (Expr->Type)) { - if (!IsClassPtr (SubScript.Type)) { + if (!IsClassPtr (Subscript.Type)) { Error ("Subscripted value is neither array nor pointer"); /* To avoid compiler errors, make the subscript a char[] at * address 0. */ - ED_MakeConstAbs (&SubScript, 0, GetCharArrayType (1)); + ED_MakeConstAbs (&Subscript, 0, GetCharArrayType (1)); + } else if (IsTypeArray (Subscript.Type)) { + Qualifiers = GetQualifier (Subscript.Type); } - ElementType = Indirect (SubScript.Type); + ElementType = Indirect (Subscript.Type); } else { Error ("Cannot subscript"); /* To avoid compiler errors, fake both the array and the subscript, so * we can just proceed. */ ED_MakeConstAbs (Expr, 0, GetCharArrayType (1)); - ED_MakeConstAbsInt (&SubScript, 0); + ED_MakeConstAbsInt (&Subscript, 0); ElementType = Indirect (Expr->Type); } + /* The element type has the combined qualifiers from itself and the array, + * it is a member of (if any). + */ + if (GetQualifier (ElementType) != (GetQualifier (ElementType) | Qualifiers)) { + ElementType = TypeDup (ElementType); + ElementType->C |= Qualifiers; + } + + /* If the subscript is a bit-field, load it and make it an rvalue */ + if (ED_IsBitField (&Subscript)) { + LoadExpr (CF_NONE, &Subscript); + ED_MakeRValExpr (&Subscript); + } + /* Check if the subscript is constant absolute value */ - if (ED_IsConstAbs (&SubScript)) { + if (ED_IsConstAbs (&Subscript) && ED_CodeRangeIsEmpty (&Subscript)) { /* The array subscript is a numeric constant. If we had pushed the * array base address onto the stack before, we can remove this value, * since we can generate expression+offset. */ if (!ConstBaseAddr) { - RemoveCode (Mark2); - pop (CF_PTR); + RemoveCode (&Mark2); } else { /* Get an array pointer into the primary */ LoadExpr (CF_NONE, Expr); @@ -934,10 +911,10 @@ static void ArrayRef (ExprDesc* Expr) /* Lhs is pointer/array. Scale the subscript value according to * the element size. */ - SubScript.IVal *= CheckedSizeOf (ElementType); + Subscript.IVal *= CheckedSizeOf (ElementType); /* Remove the address load code */ - RemoveCode (Mark1); + RemoveCode (&Mark1); /* 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 @@ -946,20 +923,20 @@ static void ArrayRef (ExprDesc* Expr) if (IsTypeArray (Expr->Type)) { /* Adjust the offset */ - Expr->IVal += SubScript.IVal; + Expr->IVal += Subscript.IVal; } else { /* It's a pointer, so we do have to load it into the primary * first (if it's not already there). */ - if (ConstBaseAddr) { + if (ConstBaseAddr || ED_IsLVal (Expr)) { LoadExpr (CF_NONE, Expr); ED_MakeRValExpr (Expr); } /* Use the offset */ - Expr->IVal = SubScript.IVal; + Expr->IVal = Subscript.IVal; } } else { @@ -971,15 +948,15 @@ static void ArrayRef (ExprDesc* Expr) * we will ignore the true type of the subscript here and * use always an int. #### Use offset but beware of LoadExpr! */ - g_inc (CF_INT | CF_CONST, SubScript.IVal); + g_inc (CF_INT | CF_CONST, Subscript.IVal); } } else { /* Array subscript is not constant. Load it into the primary */ - Mark2 = GetCodePos (); - LoadExpr (CF_NONE, &SubScript); + GetCodePos (&Mark2); + LoadExpr (CF_NONE, &Subscript); /* Do scaling */ if (IsClassPtr (Expr->Type)) { @@ -1017,7 +994,7 @@ static void ArrayRef (ExprDesc* Expr) * constant, we call special functions to add the address to the * offset value. */ - if (!ConstBaseAddr) { + if (!ConstBaseAddr) { /* The array base address is on stack and the subscript is in the * primary. Add both. @@ -1031,49 +1008,52 @@ static void ArrayRef (ExprDesc* Expr) * often a better idea to reverse again the order of the * evaluation. This will generate better code if the subscript is * a byte sized variable. But beware: This is only possible if the - * subscript was not scaled, that is, if this was a byte array - * or pointer. - */ - if ((ED_IsLocConst (&SubScript) || ED_IsLocStack (&SubScript)) && + * subscript was not scaled, that is, if this was a byte array + * or pointer. + */ + if ((ED_IsLocConst (&Subscript) || ED_IsLocStack (&Subscript)) && CheckedSizeOf (ElementType) == SIZEOF_CHAR) { unsigned Flags; - /* Reverse the order of evaluation */ - if (CheckedSizeOf (SubScript.Type) == SIZEOF_CHAR) { + /* Reverse the order of evaluation */ + if (CheckedSizeOf (Subscript.Type) == SIZEOF_CHAR) { Flags = CF_CHAR; } else { Flags = CF_INT; } - RemoveCode (Mark2); + RemoveCode (&Mark2); - /* Get a pointer to the array into the primary. */ - LoadExpr (CF_NONE, Expr); + /* Get a pointer to the array into the primary. */ + LoadExpr (CF_NONE, Expr); - /* Add the variable */ - if (ED_IsLocStack (&SubScript)) { - g_addlocal (Flags, SubScript.IVal); - } else { - Flags |= GlobalModeFlags (SubScript.Flags); - g_addstatic (Flags, SubScript.Name, SubScript.IVal); - } - } else { - if (ED_IsLocAbs (Expr)) { - /* Constant numeric address. Just add it */ - g_inc (CF_INT, Expr->IVal); - } else if (ED_IsLocStack (Expr)) { - /* Base address is a local variable address */ - if (IsTypeArray (Expr->Type)) { - g_addaddr_local (CF_INT, Expr->IVal); + /* Add the variable */ + if (ED_IsLocStack (&Subscript)) { + g_addlocal (Flags, Subscript.IVal); + } else { + Flags |= GlobalModeFlags (&Subscript); + g_addstatic (Flags, Subscript.Name, Subscript.IVal); + } + } else { + + if (ED_IsLocAbs (Expr)) { + /* Constant numeric address. Just add it */ + g_inc (CF_INT, Expr->IVal); + } else if (ED_IsLocStack (Expr)) { + /* Base address is a local variable address */ + if (IsTypeArray (Expr->Type)) { + g_addaddr_local (CF_INT, Expr->IVal); } else { - g_addlocal (CF_PTR, Expr->IVal); + g_addlocal (CF_PTR, Expr->IVal); } } else { /* Base address is a static variable address */ - unsigned Flags = CF_INT | GlobalModeFlags (Expr->Flags); - if (IsTypeArray (Expr->Type)) { + unsigned Flags = CF_INT | GlobalModeFlags (Expr); + if (ED_IsRVal (Expr)) { + /* Add the address of the location */ g_addaddr_static (Flags, Expr->Name, Expr->IVal); } else { + /* Add the contents of the location */ g_addstatic (Flags, Expr->Name, Expr->IVal); } } @@ -1112,12 +1092,14 @@ static void StructRef (ExprDesc* Expr) { ident Ident; SymEntry* Field; + TypeCode Q; /* Skip the token and check for an identifier */ NextToken (); if (CurTok.Tok != TOK_IDENT) { Error ("Identifier expected"); - Expr->Type = type_int; + /* Make the expression an integer at address zero */ + ED_MakeConstAbs (Expr, 0, type_int); return; } @@ -1127,7 +1109,8 @@ static void StructRef (ExprDesc* Expr) Field = FindStructField (Expr->Type, Ident); if (Field == 0) { Error ("Struct/union has no field named `%s'", Ident); - Expr->Type = type_int; + /* Make the expression an integer at address zero */ + ED_MakeConstAbs (Expr, 0, type_int); return; } @@ -1146,8 +1129,18 @@ static void StructRef (ExprDesc* Expr) /* Set the struct field offset */ Expr->IVal += Field->V.Offs; - /* The type is now the type of the field */ - Expr->Type = Field->Type; + /* The type is the type of the field plus any qualifiers from the struct */ + if (IsClassStruct (Expr->Type)) { + Q = GetQualifier (Expr->Type); + } else { + Q = GetQualifier (Indirect (Expr->Type)); + } + if (GetQualifier (Field->Type) == (GetQualifier (Field->Type) | Q)) { + Expr->Type = Field->Type; + } else { + Expr->Type = TypeDup (Field->Type); + Expr->Type->C |= Q; + } /* An struct member is actually a variable. So the rules for variables * with respect to the reference type apply: If it's an array, it is @@ -1159,6 +1152,11 @@ static void StructRef (ExprDesc* Expr) } else { ED_MakeLVal (Expr); } + + /* Make the expression a bit field if necessary */ + if (SymIsBitField (Field)) { + ED_MakeBitField (Expr, Field->V.B.BitOffs, Field->V.B.BitWidth); + } } @@ -1166,6 +1164,9 @@ static void StructRef (ExprDesc* Expr) static void hie11 (ExprDesc *Expr) /* Handle compound types (structs and arrays) */ { + /* Name value used in invalid function calls */ + static const char IllegalFunc[] = "illegal_function_call"; + /* Evaluate the lhs */ Primary (Expr); @@ -1187,10 +1188,10 @@ static void hie11 (ExprDesc *Expr) Error ("Illegal function call"); /* Force the type to be a implicitly defined function, one * returning an int and taking any number of arguments. - * Since we don't have a name, place it at absolute address - * zero. + * Since we don't have a name, invent one. */ ED_MakeConstAbs (Expr, 0, GetImplicitFuncType ()); + Expr->Name = (long) IllegalFunc; } /* Call the function */ FunctionCall (Expr); @@ -1223,7 +1224,7 @@ static void hie11 (ExprDesc *Expr) -void Store (ExprDesc* Expr, const type* StoreType) +void Store (ExprDesc* Expr, const Type* StoreType) /* Store the primary register into the location denoted by Expr. If StoreType * is given, use this type when storing instead of Expr->Type. If StoreType * is NULL, use Expr->Type instead. @@ -1237,30 +1238,30 @@ void Store (ExprDesc* Expr, const type* StoreType) } /* Prepare the code generator flags */ - Flags = TypeOf (StoreType); + Flags = TypeOf (StoreType) | GlobalModeFlags (Expr); /* Do the store depending on the location */ switch (ED_GetLoc (Expr)) { case E_LOC_ABS: /* Absolute: numeric address or const */ - g_putstatic (Flags | CF_ABSOLUTE, Expr->IVal, 0); + g_putstatic (Flags, Expr->IVal, 0); break; case E_LOC_GLOBAL: /* Global variable */ - g_putstatic (Flags | CF_EXTERNAL, Expr->Name, Expr->IVal); + g_putstatic (Flags, Expr->Name, Expr->IVal); break; case E_LOC_STATIC: case E_LOC_LITERAL: /* Static variable or literal in the literal pool */ - g_putstatic (Flags | CF_STATIC, Expr->Name, Expr->IVal); + g_putstatic (Flags, Expr->Name, Expr->IVal); break; case E_LOC_REGISTER: /* Register variable */ - g_putstatic (Flags | CF_REGVAR, Expr->Name, Expr->IVal); + g_putstatic (Flags, Expr->Name, Expr->IVal); break; case E_LOC_STACK: @@ -1270,7 +1271,6 @@ void Store (ExprDesc* Expr, const type* StoreType) case E_LOC_PRIMARY: /* The primary register (value is already there) */ - /* ### Do we need a test here if the flag is set? */ break; case E_LOC_EXPR: @@ -1304,8 +1304,13 @@ static void PreInc (ExprDesc* Expr) return; } + /* We cannot modify const values */ + if (IsQualConst (Expr->Type)) { + Error ("Increment of read-only variable"); + } + /* Get the data type */ - Flags = TypeOf (Expr->Type) | CF_FORCECHAR | CF_CONST; + Flags = TypeOf (Expr->Type) | GlobalModeFlags (Expr) | CF_FORCECHAR | CF_CONST; /* Get the increment value in bytes */ Val = IsTypePtr (Expr->Type)? CheckedPSizeOf (Expr->Type) : 1; @@ -1315,23 +1320,23 @@ static void PreInc (ExprDesc* Expr) case E_LOC_ABS: /* Absolute: numeric address or const */ - g_addeqstatic (Flags | CF_ABSOLUTE, Expr->IVal, 0, Val); + g_addeqstatic (Flags, Expr->IVal, 0, Val); break; case E_LOC_GLOBAL: /* Global variable */ - g_addeqstatic (Flags | CF_EXTERNAL, Expr->Name, Expr->IVal, Val); + g_addeqstatic (Flags, Expr->Name, Expr->IVal, Val); break; case E_LOC_STATIC: case E_LOC_LITERAL: /* Static variable or literal in the literal pool */ - g_addeqstatic (Flags | CF_STATIC, Expr->Name, Expr->IVal, Val); + g_addeqstatic (Flags, Expr->Name, Expr->IVal, Val); break; case E_LOC_REGISTER: /* Register variable */ - g_addeqstatic (Flags | CF_REGVAR, Expr->Name, Expr->IVal, Val); + g_addeqstatic (Flags, Expr->Name, Expr->IVal, Val); break; case E_LOC_STACK: @@ -1375,8 +1380,13 @@ static void PreDec (ExprDesc* Expr) return; } + /* We cannot modify const values */ + if (IsQualConst (Expr->Type)) { + Error ("Decrement of read-only variable"); + } + /* Get the data type */ - Flags = TypeOf (Expr->Type) | CF_FORCECHAR | CF_CONST; + Flags = TypeOf (Expr->Type) | GlobalModeFlags (Expr) | CF_FORCECHAR | CF_CONST; /* Get the increment value in bytes */ Val = IsTypePtr (Expr->Type)? CheckedPSizeOf (Expr->Type) : 1; @@ -1386,23 +1396,23 @@ static void PreDec (ExprDesc* Expr) case E_LOC_ABS: /* Absolute: numeric address or const */ - g_subeqstatic (Flags | CF_ABSOLUTE, Expr->IVal, 0, Val); + g_subeqstatic (Flags, Expr->IVal, 0, Val); break; case E_LOC_GLOBAL: /* Global variable */ - g_subeqstatic (Flags | CF_EXTERNAL, Expr->Name, Expr->IVal, Val); + g_subeqstatic (Flags, Expr->Name, Expr->IVal, Val); break; case E_LOC_STATIC: case E_LOC_LITERAL: /* Static variable or literal in the literal pool */ - g_subeqstatic (Flags | CF_STATIC, Expr->Name, Expr->IVal, Val); + g_subeqstatic (Flags, Expr->Name, Expr->IVal, Val); break; case E_LOC_REGISTER: /* Register variable */ - g_subeqstatic (Flags | CF_REGVAR, Expr->Name, Expr->IVal, Val); + g_subeqstatic (Flags, Expr->Name, Expr->IVal, Val); break; case E_LOC_STACK: @@ -1430,8 +1440,55 @@ static void PreDec (ExprDesc* Expr) -static void PostIncDec (ExprDesc* Expr, void (*inc) (unsigned, unsigned long)) -/* Handle i-- and i++ */ +static void PostInc (ExprDesc* Expr) +/* Handle the postincrement operator */ +{ + unsigned Flags; + + NextToken (); + + /* The expression to increment must be an lvalue */ + if (!ED_IsLVal (Expr)) { + Error ("Invalid lvalue"); + return; + } + + /* We cannot modify const values */ + if (IsQualConst (Expr->Type)) { + Error ("Increment of read-only variable"); + } + + /* Get the data type */ + Flags = TypeOf (Expr->Type); + + /* Push the address if needed */ + PushAddr (Expr); + + /* Fetch the value and save it (since it's the result of the expression) */ + LoadExpr (CF_NONE, Expr); + g_save (Flags | CF_FORCECHAR); + + /* If we have a pointer expression, increment by the size of the type */ + if (IsTypePtr (Expr->Type)) { + g_inc (Flags | CF_CONST | CF_FORCECHAR, CheckedSizeOf (Expr->Type + 1)); + } else { + g_inc (Flags | CF_CONST | CF_FORCECHAR, 1); + } + + /* Store the result back */ + Store (Expr, 0); + + /* Restore the original value in the primary register */ + g_restore (Flags | CF_FORCECHAR); + + /* The result is always an expression, no reference */ + ED_MakeRValExpr (Expr); +} + + + +static void PostDec (ExprDesc* Expr) +/* Handle the postdecrement operator */ { unsigned Flags; @@ -1443,6 +1500,11 @@ static void PostIncDec (ExprDesc* Expr, void (*inc) (unsigned, unsigned long)) return; } + /* We cannot modify const values */ + if (IsQualConst (Expr->Type)) { + Error ("Decrement of read-only variable"); + } + /* Get the data type */ Flags = TypeOf (Expr->Type); @@ -1455,9 +1517,9 @@ static void PostIncDec (ExprDesc* Expr, void (*inc) (unsigned, unsigned long)) /* If we have a pointer expression, increment by the size of the type */ if (IsTypePtr (Expr->Type)) { - inc (Flags | CF_CONST | CF_FORCECHAR, CheckedSizeOf (Expr->Type + 1)); + g_dec (Flags | CF_CONST | CF_FORCECHAR, CheckedSizeOf (Expr->Type + 1)); } else { - inc (Flags | CF_CONST | CF_FORCECHAR, 1); + g_dec (Flags | CF_CONST | CF_FORCECHAR, 1); } /* Store the result back */ @@ -1565,9 +1627,12 @@ void hie10 (ExprDesc* Expr) ED_MakeRValExpr (Expr); } /* If the expression is already a pointer to function, the - * additional dereferencing operator must be ignored. + * additional dereferencing operator must be ignored. A function + * itself is represented as "pointer to function", so any number + * of dereference operators is legal, since the result will + * always be converted to "pointer to function". */ - if (IsTypeFuncPtr (Expr->Type)) { + if (IsTypeFuncPtr (Expr->Type) || IsTypeFunc (Expr->Type)) { /* Expression not storable */ ED_MakeRVal (Expr); } else { @@ -1576,6 +1641,7 @@ void hie10 (ExprDesc* Expr) } else { Error ("Illegal indirection"); } + /* The * operator yields an lvalue */ ED_MakeLVal (Expr); } break; @@ -1586,13 +1652,16 @@ void hie10 (ExprDesc* Expr) /* The & operator may be applied to any lvalue, and it may be * applied to functions, even if they're no lvalues. */ - if (ED_IsRVal (Expr) && !IsTypeFunc (Expr->Type)) { - /* Allow the & operator with an array */ - if (!IsTypeArray (Expr->Type)) { - Error ("Illegal address"); - } - } else { + if (ED_IsRVal (Expr) && !IsTypeFunc (Expr->Type) && !IsTypeArray (Expr->Type)) { + Error ("Illegal address"); + } else { + if (ED_IsBitField (Expr)) { + Error ("Cannot take address of bit-field"); + /* Do it anyway, just to avoid further warnings */ + Expr->Flags &= ~E_BITFIELD; + } Expr->Type = PointerTo (Expr->Type); + /* The & operator yields an rvalue */ ED_MakeRVal (Expr); } break; @@ -1600,17 +1669,18 @@ void hie10 (ExprDesc* Expr) case TOK_SIZEOF: NextToken (); if (TypeSpecAhead ()) { - type Type[MAXTYPELEN]; + Type T[MAXTYPELEN]; NextToken (); - Size = CheckedSizeOf (ParseType (Type)); + Size = CheckedSizeOf (ParseType (T)); ConsumeRParen (); } else { /* Remember the output queue pointer */ - CodeMark Mark = GetCodePos (); + CodeMark Mark; + GetCodePos (&Mark); hie10 (Expr); Size = CheckedSizeOf (Expr->Type); /* Remove any generated code */ - RemoveCode (Mark); + RemoveCode (&Mark); } ED_MakeConstAbs (Expr, Size, type_size_t); ED_MarkAsUntested (Expr); @@ -1628,10 +1698,10 @@ void hie10 (ExprDesc* Expr) hie11 (Expr); /* Handle post increment */ - if (CurTok.Tok == TOK_INC) { - PostIncDec (Expr, g_inc); - } else if (CurTok.Tok == TOK_DEC) { - PostIncDec (Expr, g_dec); + switch (CurTok.Tok) { + case TOK_INC: PostInc (Expr); break; + case TOK_DEC: PostDec (Expr); break; + default: break; } } @@ -1667,6 +1737,8 @@ static void hie_internal (const GenDesc* Ops, /* List of generators */ /* All operators that call this function expect an int on the lhs */ if (!IsClassInt (Expr->Type)) { Error ("Integer expression expected"); + /* To avoid further errors, make Expr a valid int expression */ + ED_MakeConstAbsInt (Expr, 1); } /* Remember the operator token, then skip it */ @@ -1674,21 +1746,28 @@ static void hie_internal (const GenDesc* Ops, /* List of generators */ NextToken (); /* Get the lhs on stack */ - Mark1 = GetCodePos (); + GetCodePos (&Mark1); ltype = TypeOf (Expr->Type); if (ED_IsConstAbs (Expr)) { /* Constant value */ - Mark2 = GetCodePos (); + GetCodePos (&Mark2); g_push (ltype | CF_CONST, Expr->IVal); } else { /* Value not constant */ LoadExpr (CF_NONE, Expr); - Mark2 = GetCodePos (); + GetCodePos (&Mark2); g_push (ltype, 0); } /* Get the right hand side */ - rconst = (evalexpr (CF_NONE, hienext, &Expr2) == 0); + MarkedExprWithCheck (hienext, &Expr2); + + /* Check for a constant expression */ + rconst = (ED_IsConstAbs (&Expr2) && ED_CodeRangeIsEmpty (&Expr2)); + if (!rconst) { + /* Not constant, load into the primary */ + LoadExpr (CF_NONE, &Expr2); + } /* Check the type of the rhs */ if (!IsClassInt (Expr2.Type)) { @@ -1699,15 +1778,88 @@ static void hie_internal (const GenDesc* Ops, /* List of generators */ if (ED_IsConstAbs (Expr) && rconst) { /* Both operands are constant, remove the generated code */ - RemoveCode (Mark1); - pop (ltype); - - /* Evaluate the result */ - Expr->IVal = kcalc (Tok, Expr->IVal, Expr2.IVal); + RemoveCode (&Mark1); /* Get the type of the result */ Expr->Type = promoteint (Expr->Type, Expr2.Type); + /* Handle the op differently for signed and unsigned types */ + if (IsSignSigned (Expr->Type)) { + + /* Evaluate the result for signed operands */ + signed long Val1 = Expr->IVal; + signed long Val2 = Expr2.IVal; + switch (Tok) { + case TOK_OR: + Expr->IVal = (Val1 | Val2); + break; + case TOK_XOR: + Expr->IVal = (Val1 ^ Val2); + break; + case TOK_AND: + Expr->IVal = (Val1 & Val2); + break; + case TOK_STAR: + Expr->IVal = (Val1 * Val2); + break; + case TOK_DIV: + if (Val2 == 0) { + Error ("Division by zero"); + Expr->IVal = 0x7FFFFFFF; + } else { + Expr->IVal = (Val1 / Val2); + } + break; + case TOK_MOD: + if (Val2 == 0) { + Error ("Modulo operation with zero"); + Expr->IVal = 0; + } else { + Expr->IVal = (Val1 % Val2); + } + break; + default: + Internal ("hie_internal: got token 0x%X\n", Tok); + } + } else { + + /* Evaluate the result for unsigned operands */ + unsigned long Val1 = Expr->IVal; + unsigned long Val2 = Expr2.IVal; + switch (Tok) { + case TOK_OR: + Expr->IVal = (Val1 | Val2); + break; + case TOK_XOR: + Expr->IVal = (Val1 ^ Val2); + break; + case TOK_AND: + Expr->IVal = (Val1 & Val2); + break; + case TOK_STAR: + Expr->IVal = (Val1 * Val2); + break; + case TOK_DIV: + if (Val2 == 0) { + Error ("Division by zero"); + Expr->IVal = 0xFFFFFFFF; + } else { + Expr->IVal = (Val1 / Val2); + } + break; + case TOK_MOD: + if (Val2 == 0) { + Error ("Modulo operation with zero"); + Expr->IVal = 0; + } else { + Expr->IVal = (Val1 % Val2); + } + break; + default: + Internal ("hie_internal: got token 0x%X\n", Tok); + } + } + } else { /* If the right hand side is constant, and the generator function @@ -1726,8 +1878,7 @@ static void hie_internal (const GenDesc* Ops, /* List of generators */ Error ("Modulo operation with zero"); } if ((Gen->Flags & GEN_NOPUSH) != 0) { - RemoveCode (Mark2); - pop (ltype); + RemoveCode (&Mark2); ltype |= CF_REG; /* Value is in register */ } } @@ -1756,7 +1907,7 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */ CodeMark Mark1; CodeMark Mark2; const GenDesc* Gen; - token_t tok; /* The operator token */ + token_t Tok; /* The operator token */ unsigned ltype; int rconst; /* Operand is a constant */ @@ -1766,56 +1917,99 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */ while ((Gen = FindGen (CurTok.Tok, Ops)) != 0) { /* Remember the operator token, then skip it */ - tok = CurTok.Tok; + Tok = CurTok.Tok; NextToken (); /* Get the lhs on stack */ - Mark1 = GetCodePos (); + GetCodePos (&Mark1); ltype = TypeOf (Expr->Type); if (ED_IsConstAbs (Expr)) { /* Constant value */ - Mark2 = GetCodePos (); + GetCodePos (&Mark2); g_push (ltype | CF_CONST, Expr->IVal); } else { /* Value not constant */ LoadExpr (CF_NONE, Expr); - Mark2 = GetCodePos (); + GetCodePos (&Mark2); g_push (ltype, 0); } /* Get the right hand side */ - rconst = (evalexpr (CF_NONE, hienext, &Expr2) == 0); + MarkedExprWithCheck (hienext, &Expr2); + + /* Check for a constant expression */ + rconst = (ED_IsConstAbs (&Expr2) && ED_CodeRangeIsEmpty (&Expr2)); + if (!rconst) { + /* Not constant, load into the primary */ + LoadExpr (CF_NONE, &Expr2); + } /* Make sure, the types are compatible */ if (IsClassInt (Expr->Type)) { if (!IsClassInt (Expr2.Type) && !(IsClassPtr(Expr2.Type) && ED_IsNullPtr(Expr))) { - Error ("Incompatible types"); + Error ("Incompatible types"); } } else if (IsClassPtr (Expr->Type)) { if (IsClassPtr (Expr2.Type)) { - /* Both pointers are allowed in comparison if they point to - * the same type, or if one of them is a void pointer. + /* Both pointers are allowed in comparison if they point to + * the same type, or if one of them is a void pointer. */ - type* left = Indirect (Expr->Type); - type* right = Indirect (Expr2.Type); - if (TypeCmp (left, right) < TC_EQUAL && *left != T_VOID && *right != T_VOID) { - /* Incomatible pointers */ - Error ("Incompatible types"); - } + Type* left = Indirect (Expr->Type); + Type* right = Indirect (Expr2.Type); + if (TypeCmp (left, right) < TC_EQUAL && left->C != T_VOID && right->C != T_VOID) { + /* Incomatible pointers */ + Error ("Incompatible types"); + } } else if (!ED_IsNullPtr (&Expr2)) { - Error ("Incompatible types"); + Error ("Incompatible types"); } } /* Check for const operands */ if (ED_IsConstAbs (Expr) && rconst) { - /* Both operands are constant, remove the generated code */ - RemoveCode (Mark1); - pop (ltype); + /* If the result is constant, this is suspicious when not in + * preprocessor mode. + */ + if (!Preprocessing) { + Warning ("Result of comparison is constant"); + } + + /* Both operands are constant, remove the generated code */ + RemoveCode (&Mark1); + + /* Determine if this is a signed or unsigned compare */ + if (IsClassInt (Expr->Type) && IsSignSigned (Expr->Type) && + IsClassInt (Expr2.Type) && IsSignSigned (Expr2.Type)) { + + /* Evaluate the result for signed operands */ + signed long Val1 = Expr->IVal; + signed long Val2 = Expr2.IVal; + switch (Tok) { + case TOK_EQ: Expr->IVal = (Val1 == Val2); break; + case TOK_NE: Expr->IVal = (Val1 != Val2); break; + case TOK_LT: Expr->IVal = (Val1 < Val2); break; + case TOK_LE: Expr->IVal = (Val1 <= Val2); break; + case TOK_GE: Expr->IVal = (Val1 >= Val2); break; + case TOK_GT: Expr->IVal = (Val1 > Val2); break; + default: Internal ("hie_compare: got token 0x%X\n", Tok); + } - /* Evaluate the result */ - Expr->IVal = kcalc (tok, Expr->IVal, Expr2.IVal); + } else { + + /* Evaluate the result for unsigned operands */ + unsigned long Val1 = Expr->IVal; + unsigned long Val2 = Expr2.IVal; + switch (Tok) { + case TOK_EQ: Expr->IVal = (Val1 == Val2); break; + case TOK_NE: Expr->IVal = (Val1 != Val2); break; + case TOK_LT: Expr->IVal = (Val1 < Val2); break; + case TOK_LE: Expr->IVal = (Val1 <= Val2); break; + case TOK_GE: Expr->IVal = (Val1 >= Val2); break; + case TOK_GT: Expr->IVal = (Val1 > Val2); break; + default: Internal ("hie_compare: got token 0x%X\n", Tok); + } + } } else { @@ -1827,8 +2021,7 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */ if (rconst) { flags |= CF_CONST; if ((Gen->Flags & GEN_NOPUSH) != 0) { - RemoveCode (Mark2); - pop (ltype); + RemoveCode (&Mark2); ltype |= CF_REG; /* Value is in register */ } } @@ -1894,8 +2087,8 @@ static void parseadd (ExprDesc* Expr) ExprDesc Expr2; unsigned flags; /* Operation flags */ CodeMark Mark; /* Remember code position */ - type* lhst; /* Type of left hand side */ - type* rhst; /* Type of right hand side */ + Type* lhst; /* Type of left hand side */ + Type* rhst; /* Type of right hand side */ /* Skip the PLUS token */ @@ -1917,24 +2110,24 @@ static void parseadd (ExprDesc* Expr) /* Both expressions are constants. Check for pointer arithmetic */ if (IsClassPtr (lhst) && IsClassInt (rhst)) { - /* Left is pointer, right is int, must scale rhs */ + /* Left is pointer, right is int, must scale rhs */ Expr->IVal += Expr2.IVal * CheckedPSizeOf (lhst); - /* Result type is a pointer */ + /* Result type is a pointer */ } else if (IsClassInt (lhst) && IsClassPtr (rhst)) { - /* Left is int, right is pointer, must scale lhs */ + /* Left is int, right is pointer, must scale lhs */ Expr->IVal = Expr->IVal * CheckedPSizeOf (rhst) + Expr2.IVal; - /* Result type is a pointer */ - Expr->Type = Expr2.Type; + /* Result type is a pointer */ + Expr->Type = Expr2.Type; } else if (IsClassInt (lhst) && IsClassInt (rhst)) { - /* Integer addition */ - Expr->IVal += Expr2.IVal; - typeadjust (Expr, &Expr2, 1); + /* Integer addition */ + Expr->IVal += Expr2.IVal; + typeadjust (Expr, &Expr2, 1); } else { /* OOPS */ - Error ("Invalid operands for binary operator `+'"); + Error ("Invalid operands for binary operator `+'"); } - } else { + } else { /* lhs is a constant and rhs is not constant. Load rhs into * the primary. @@ -1955,7 +2148,7 @@ static void parseadd (ExprDesc* Expr) flags |= CF_CONST; } else { /* Constant address label */ - flags |= GlobalModeFlags (Expr->Flags) | CF_CONSTADDR; + flags |= GlobalModeFlags (Expr) | CF_CONSTADDR; } /* Check for pointer arithmetic */ @@ -1987,7 +2180,7 @@ static void parseadd (ExprDesc* Expr) */ if (ED_IsLocAbs (Expr)) { /* Numeric constant, scale lhs */ - Expr->IVal *= ScaleFactor; + Expr->IVal *= ScaleFactor; /* Generate the code for the add */ g_inc (flags, Expr->IVal); } else if (ScaleFactor == 1) { @@ -2014,6 +2207,7 @@ static void parseadd (ExprDesc* Expr) } else { /* OOPS */ Error ("Invalid operands for binary operator `+'"); + flags = CF_INT; } /* Result is a rvalue in primary register */ @@ -2024,18 +2218,20 @@ static void parseadd (ExprDesc* Expr) /* Left hand side is not constant. Get the value onto the stack. */ LoadExpr (CF_NONE, Expr); /* --> primary register */ - Mark = GetCodePos (); + GetCodePos (&Mark); g_push (TypeOf (Expr->Type), 0); /* --> stack */ /* Evaluate the rhs */ - if (evalexpr (CF_NONE, hie9, &Expr2) == 0) { + MarkedExprWithCheck (hie9, &Expr2); + + /* Check for a constant rhs expression */ + if (ED_IsConstAbs (&Expr2) && ED_CodeRangeIsEmpty (&Expr2)) { /* Right hand side is a constant. Get the rhs type */ rhst = Expr2.Type; /* Remove pushed value from stack */ - RemoveCode (Mark); - pop (TypeOf (Expr->Type)); + RemoveCode (&Mark); /* Check for pointer arithmetic */ if (IsClassPtr (lhst) && IsClassInt (rhst)) { @@ -2055,6 +2251,7 @@ static void parseadd (ExprDesc* Expr) } else { /* OOPS */ Error ("Invalid operands for binary operator `+'"); + flags = CF_INT; } /* Generate code for the add */ @@ -2062,6 +2259,9 @@ static void parseadd (ExprDesc* Expr) } else { + /* Not constant, load into the primary */ + LoadExpr (CF_NONE, &Expr2); + /* lhs and rhs are not constant. Get the rhs type. */ rhst = Expr2.Type; @@ -2092,7 +2292,8 @@ static void parseadd (ExprDesc* Expr) flags = typeadjust (Expr, &Expr2, 0) & ~CF_CONST; } else { /* OOPS */ - Error ("Invalid operands for binary operator `+'"); + Error ("Invalid operands for binary operator `+'"); + flags = CF_INT; } /* Generate code for the add */ @@ -2118,12 +2319,12 @@ static void parsesub (ExprDesc* Expr) */ { ExprDesc Expr2; - unsigned flags; /* Operation flags */ - type* lhst; /* Type of left hand side */ - type* rhst; /* Type of right hand side */ - CodeMark Mark1; /* Save position of output queue */ + unsigned flags; /* Operation flags */ + Type* lhst; /* Type of left hand side */ + Type* rhst; /* Type of right hand side */ + CodeMark Mark1; /* Save position of output queue */ CodeMark Mark2; /* Another position in the queue */ - int rscale; /* Scale factor for the result */ + int rscale; /* Scale factor for the result */ /* Skip the MINUS token */ @@ -2131,17 +2332,19 @@ static void parsesub (ExprDesc* Expr) /* Get the left hand side type, initialize operation flags */ lhst = Expr->Type; - flags = 0; rscale = 1; /* Scale by 1, that is, don't scale */ /* Remember the output queue position, then bring the value onto the stack */ - Mark1 = GetCodePos (); + GetCodePos (&Mark1); LoadExpr (CF_NONE, Expr); /* --> primary register */ - Mark2 = GetCodePos (); + GetCodePos (&Mark2); g_push (TypeOf (lhst), 0); /* --> stack */ /* Parse the right hand side */ - if (evalexpr (CF_NONE, hie9, &Expr2) == 0) { + MarkedExprWithCheck (hie9, &Expr2); + + /* Check for a constant rhs expression */ + if (ED_IsConstAbs (&Expr2) && ED_CodeRangeIsEmpty (&Expr2)) { /* The right hand side is constant. Get the rhs type. */ rhst = Expr2.Type; @@ -2150,8 +2353,7 @@ static void parsesub (ExprDesc* Expr) if (ED_IsConstAbs (Expr)) { /* Both sides are constant, remove generated code */ - RemoveCode (Mark1); - pop (TypeOf (lhst)); /* Clean up the stack */ + RemoveCode (&Mark1); /* Check for pointer arithmetic */ if (IsClassPtr (lhst) && IsClassInt (rhst)) { @@ -2185,8 +2387,7 @@ static void parsesub (ExprDesc* Expr) /* Left hand side is not constant, right hand side is. * Remove pushed value from stack. */ - RemoveCode (Mark2); - pop (TypeOf (lhst)); + RemoveCode (&Mark2); if (IsClassPtr (lhst) && IsClassInt (rhst)) { /* Left is pointer, right is int, must scale rhs */ @@ -2200,7 +2401,7 @@ static void parsesub (ExprDesc* Expr) } else { rscale = CheckedPSizeOf (lhst); } - /* Operate on pointers, result type is an integer */ + /* Operate on pointers, result type is an integer */ flags = CF_PTR; Expr->Type = type_int; } else if (IsClassInt (lhst) && IsClassInt (rhst)) { @@ -2209,56 +2410,61 @@ static void parsesub (ExprDesc* Expr) } else { /* OOPS */ Error ("Invalid operands for binary operator `-'"); + flags = CF_INT; } /* Do the subtraction */ g_dec (flags | CF_CONST, Expr2.IVal); - /* If this was a pointer subtraction, we must scale the result */ - if (rscale != 1) { - g_scale (flags, -rscale); - } + /* If this was a pointer subtraction, we must scale the result */ + if (rscale != 1) { + g_scale (flags, -rscale); + } - /* Result is a rvalue in the primary register */ - ED_MakeRValExpr (Expr); - ED_MarkAsUntested (Expr); + /* Result is a rvalue in the primary register */ + ED_MakeRValExpr (Expr); + ED_MarkAsUntested (Expr); - } + } } else { - /* Right hand side is not constant. Get the rhs type. */ - rhst = Expr2.Type; + /* Not constant, load into the primary */ + LoadExpr (CF_NONE, &Expr2); + + /* Right hand side is not constant. Get the rhs type. */ + rhst = Expr2.Type; /* Check for pointer arithmetic */ - if (IsClassPtr (lhst) && IsClassInt (rhst)) { + if (IsClassPtr (lhst) && IsClassInt (rhst)) { /* Left is pointer, right is int, must scale rhs */ - g_scale (CF_INT, CheckedPSizeOf (lhst)); - /* Operate on pointers, result type is a pointer */ - flags = CF_PTR; - } else if (IsClassPtr (lhst) && IsClassPtr (rhst)) { - /* Left is pointer, right is pointer, must scale result */ - if (TypeCmp (Indirect (lhst), Indirect (rhst)) < TC_QUAL_DIFF) { - Error ("Incompatible pointer types"); - } else { - rscale = CheckedPSizeOf (lhst); - } - /* Operate on pointers, result type is an integer */ - flags = CF_PTR; - Expr->Type = type_int; + g_scale (CF_INT, CheckedPSizeOf (lhst)); + /* Operate on pointers, result type is a pointer */ + flags = CF_PTR; + } else if (IsClassPtr (lhst) && IsClassPtr (rhst)) { + /* Left is pointer, right is pointer, must scale result */ + if (TypeCmp (Indirect (lhst), Indirect (rhst)) < TC_QUAL_DIFF) { + Error ("Incompatible pointer types"); + } else { + rscale = CheckedPSizeOf (lhst); + } + /* Operate on pointers, result type is an integer */ + flags = CF_PTR; + Expr->Type = type_int; } else if (IsClassInt (lhst) && IsClassInt (rhst)) { /* Integer subtraction. If the left hand side descriptor says that * the lhs is const, we have to remove this mark, since this is no * longer true, lhs is on stack instead. */ if (ED_IsLocAbs (Expr)) { - ED_MakeRValExpr (Expr); + ED_MakeRValExpr (Expr); } /* Adjust operand types */ flags = typeadjust (Expr, &Expr2, 0); } else { /* OOPS */ Error ("Invalid operands for binary operator `-'"); + flags = CF_INT; } /* Generate code for the sub (the & is a hack here) */ @@ -2277,7 +2483,7 @@ static void parsesub (ExprDesc* Expr) -static void hie8 (ExprDesc* Expr) +void hie8 (ExprDesc* Expr) /* Process + and - binary operators. */ { hie9 (Expr); @@ -2292,21 +2498,6 @@ static void hie8 (ExprDesc* Expr) -static void hie7 (ExprDesc* Expr) -/* Parse << and >>. */ -{ - static const GenDesc hie7_ops [] = { - { TOK_SHL, GEN_NOPUSH, g_asl }, - { TOK_SHR, GEN_NOPUSH, g_asr }, - { TOK_INVALID, 0, 0 } - }; - int UsedGen; - - hie_internal (hie7_ops, Expr, hie8, &UsedGen); -} - - - static void hie6 (ExprDesc* Expr) /* Handle greater-than type comparators */ { @@ -2317,7 +2508,7 @@ static void hie6 (ExprDesc* Expr) { TOK_GT, GEN_NOPUSH, g_gt }, { TOK_INVALID, 0, 0 } }; - hie_compare (hie6_ops, Expr, hie7); + hie_compare (hie6_ops, Expr, ShiftExpr); } @@ -2426,7 +2617,7 @@ static void hieOrPP (ExprDesc *Expr) static void hieAnd (ExprDesc* Expr, unsigned TrueLab, int* BoolOp) /* Process "exp && exp" */ { - int lab; + int FalseLab; ExprDesc Expr2; hie2 (Expr); @@ -2436,7 +2627,7 @@ static void hieAnd (ExprDesc* Expr, unsigned TrueLab, int* BoolOp) *BoolOp = 1; /* Get a label that we will use for false expressions */ - lab = GetLocalLabel (); + FalseLab = GetLocalLabel (); /* If the expr hasn't set condition codes, set the force-test flag */ if (!ED_IsTested (Expr)) { @@ -2447,7 +2638,7 @@ static void hieAnd (ExprDesc* Expr, unsigned TrueLab, int* BoolOp) LoadExpr (CF_FORCECHAR, Expr); /* Generate the jump */ - g_falsejump (CF_NONE, lab); + g_falsejump (CF_NONE, FalseLab); /* Parse more boolean and's */ while (CurTok.Tok == TOK_BOOL_AND) { @@ -2464,7 +2655,7 @@ static void hieAnd (ExprDesc* Expr, unsigned TrueLab, int* BoolOp) /* Do short circuit evaluation */ if (CurTok.Tok == TOK_BOOL_AND) { - g_falsejump (CF_NONE, lab); + g_falsejump (CF_NONE, FalseLab); } else { /* Last expression - will evaluate to true */ g_truejump (CF_NONE, TrueLab); @@ -2472,7 +2663,7 @@ static void hieAnd (ExprDesc* Expr, unsigned TrueLab, int* BoolOp) } /* Define the false jump label here */ - g_defcodelabel (lab); + g_defcodelabel (FalseLab); /* The result is an rvalue in primary */ ED_MakeRValExpr (Expr); @@ -2558,13 +2749,14 @@ static void hieOr (ExprDesc *Expr) static void hieQuest (ExprDesc* Expr) /* Parse the ternary operator */ { - int labf; - int labt; + int FalseLab; + int TrueLab; + CodeMark TrueCodeEnd; ExprDesc Expr2; /* Expression 2 */ ExprDesc Expr3; /* Expression 3 */ int Expr2IsNULL; /* Expression 2 is a NULL pointer */ int Expr3IsNULL; /* Expression 3 is a NULL pointer */ - type* ResultType; /* Type of result */ + Type* ResultType; /* Type of result */ /* Call the lower level eval routine */ @@ -2582,8 +2774,8 @@ static void hieQuest (ExprDesc* Expr) ED_MarkForTest (Expr); } LoadExpr (CF_NONE, Expr); - labf = GetLocalLabel (); - g_falsejump (CF_NONE, labf); + FalseLab = GetLocalLabel (); + g_falsejump (CF_NONE, FalseLab); /* Parse second expression. Remember for later if it is a NULL pointer * expression, then load it into the primary. @@ -2594,15 +2786,21 @@ static void hieQuest (ExprDesc* Expr) /* Load it into the primary */ LoadExpr (CF_NONE, &Expr2); ED_MakeRValExpr (&Expr2); + Expr2.Type = PtrConversion (Expr2.Type); } - labt = GetLocalLabel (); + + /* Remember the current code position */ + GetCodePos (&TrueCodeEnd); + + /* Jump around the evaluation of the third expression */ + TrueLab = GetLocalLabel (); ConsumeColon (); - g_jump (labt); + g_jump (TrueLab); /* Jump here if the first expression was false */ - g_defcodelabel (labf); + g_defcodelabel (FalseLab); - /* Parse second expression. Remember for later if it is a NULL pointer + /* Parse third expression. Remember for later if it is a NULL pointer * expression, then load it into the primary. */ ExprWithCheck (hie1, &Expr3); @@ -2611,6 +2809,7 @@ static void hieQuest (ExprDesc* Expr) /* Load it into the primary */ LoadExpr (CF_NONE, &Expr3); ED_MakeRValExpr (&Expr3); + Expr3.Type = PtrConversion (Expr3.Type); } /* Check if any conversions are needed, if so, do them. @@ -2628,27 +2827,27 @@ static void hieQuest (ExprDesc* Expr) */ if (IsClassInt (Expr2.Type) && IsClassInt (Expr3.Type)) { + CodeMark CvtCodeStart; + CodeMark CvtCodeEnd; + + /* Get common type */ ResultType = promoteint (Expr2.Type, Expr3.Type); /* Convert the third expression to this type if needed */ TypeConversion (&Expr3, ResultType); - /* Setup a new label so that the expr3 code will jump around - * the type cast code for expr2. - */ - labf = GetLocalLabel (); /* Get new label */ - g_jump (labf); /* Jump around code */ - - /* The jump for expr2 goes here */ - g_defcodelabel (labt); - - /* Create the typecast code for expr2 */ + /* Emit conversion code for the second expression, but remember + * where it starts end ends. + */ + GetCodePos (&CvtCodeStart); TypeConversion (&Expr2, ResultType); + GetCodePos (&CvtCodeEnd); - /* Jump here around the typecase code. */ - g_defcodelabel (labf); - labt = 0; /* Mark other label as invalid */ + /* If we had conversion code, move it to the right place */ + if (!CodeRangeIsEmpty (&CvtCodeStart, &CvtCodeEnd)) { + MoveCode (&CvtCodeStart, &CvtCodeEnd, &TrueCodeEnd); + } } else if (IsClassPtr (Expr2.Type) && IsClassPtr (Expr3.Type)) { /* Must point to same type */ @@ -2671,10 +2870,8 @@ static void hieQuest (ExprDesc* Expr) ResultType = Expr2.Type; /* Doesn't matter here */ } - /* If we don't have the label defined until now, do it */ - if (labt) { - g_defcodelabel (labt); - } + /* Define the final label */ + g_defcodelabel (TrueLab); /* Setup the target expression */ ED_MakeRValExpr (Expr); @@ -2684,7 +2881,7 @@ static void hieQuest (ExprDesc* Expr) -static void opeq (const GenDesc* Gen, ExprDesc* Expr) +static void opeq (const GenDesc* Gen, ExprDesc* Expr, const char* Op) /* Process "op=" operators. */ { ExprDesc Expr2; @@ -2698,6 +2895,11 @@ static void opeq (const GenDesc* Gen, ExprDesc* Expr) return; } + /* The left side must not be const qualified */ + if (IsQualConst (Expr->Type)) { + Error ("Assignment to const"); + } + /* There must be an integer or pointer on the left side */ if (!IsClassInt (Expr->Type) && !IsTypePtr (Expr->Type)) { Error ("Invalid left operand type"); @@ -2720,17 +2922,27 @@ static void opeq (const GenDesc* Gen, ExprDesc* Expr) LoadExpr (CF_NONE, Expr); /* Bring the lhs on stack */ - Mark = GetCodePos (); + GetCodePos (&Mark); g_push (flags, 0); /* Evaluate the rhs */ - if (evalexpr (CF_NONE, hie1, &Expr2) == 0) { - /* The resulting value is a constant. If the generator has the NOPUSH - * flag set, don't push the lhs. - */ - if (Gen->Flags & GEN_NOPUSH) { - RemoveCode (Mark); - pop (flags); + MarkedExprWithCheck (hie1, &Expr2); + + /* The rhs must be an integer (or a float, but we don't support that yet */ + if (!IsClassInt (Expr2.Type)) { + Error ("Invalid right operand for binary operator `%s'", Op); + /* Continue. Wrong code will be generated, but the compiler won't + * break, so this is the best error recovery. + */ + } + + /* Check for a constant expression */ + if (ED_IsConstAbs (&Expr2) && ED_CodeRangeIsEmpty (&Expr2)) { + /* The resulting value is a constant. If the generator has the NOPUSH + * flag set, don't push the lhs. + */ + if (Gen->Flags & GEN_NOPUSH) { + RemoveCode (&Mark); } if (MustScale) { /* lhs is a pointer, scale rhs */ @@ -2750,10 +2962,20 @@ static void opeq (const GenDesc* Gen, ExprDesc* Expr) } else if (Gen->Func == g_sub) { g_dec (flags | CF_CONST, Expr2.IVal); } else { + if (Expr2.IVal == 0) { + /* Check for div by zero/mod by zero */ + if (Gen->Func == g_div) { + Error ("Division by zero"); + } else if (Gen->Func == g_mod) { + Error ("Modulo operation with zero"); + } + } Gen->Func (flags | CF_CONST, Expr2.IVal); } } else { - /* rhs is not constant and already in the primary register */ + + /* rhs is not constant. Load into the primary */ + LoadExpr (CF_NONE, &Expr2); if (MustScale) { /* lhs is a pointer, scale rhs */ g_scale (TypeOf (Expr2.Type), CheckedSizeOf (Expr->Type+1)); @@ -2775,7 +2997,7 @@ static void opeq (const GenDesc* Gen, ExprDesc* Expr) -static void addsubeq (const GenDesc* Gen, ExprDesc *Expr) +static void addsubeq (const GenDesc* Gen, ExprDesc *Expr, const char* Op) /* Process the += and -= operators */ { ExprDesc Expr2; @@ -2787,7 +3009,7 @@ static void addsubeq (const GenDesc* Gen, ExprDesc *Expr) /* We're currently only able to handle some adressing modes */ if (ED_GetLoc (Expr) == E_LOC_EXPR || ED_GetLoc (Expr) == E_LOC_PRIMARY) { /* Use generic routine */ - opeq (Gen, Expr); + opeq (Gen, Expr, Op); return; } @@ -2797,6 +3019,11 @@ static void addsubeq (const GenDesc* Gen, ExprDesc *Expr) return; } + /* The left side must not be const qualified */ + if (IsQualConst (Expr->Type)) { + Error ("Assignment to const"); + } + /* There must be an integer or pointer on the left side */ if (!IsClassInt (Expr->Type) && !IsTypePtr (Expr->Type)) { Error ("Invalid left operand type"); @@ -2815,8 +3042,16 @@ static void addsubeq (const GenDesc* Gen, ExprDesc *Expr) lflags = 0; rflags = 0; - /* Evaluate the rhs */ + /* Evaluate the rhs. We expect an integer here, since float is not + * supported + */ hie1 (&Expr2); + if (!IsClassInt (Expr2.Type)) { + Error ("Invalid right operand for binary operator `%s'", Op); + /* Continue. Wrong code will be generated, but the compiler won't + * break, so this is the best error recovery. + */ + } if (ED_IsConstAbs (&Expr2)) { /* The resulting value is a constant. Scale it. */ if (MustScale) { @@ -2834,8 +3069,8 @@ static void addsubeq (const GenDesc* Gen, ExprDesc *Expr) } /* Setup the code generator flags */ - lflags |= TypeOf (Expr->Type) | CF_FORCECHAR; - rflags |= TypeOf (Expr2.Type); + lflags |= TypeOf (Expr->Type) | GlobalModeFlags (Expr) | CF_FORCECHAR; + rflags |= TypeOf (Expr2.Type) | CF_FORCECHAR; /* Convert the type of the lhs to that of the rhs */ g_typecast (lflags, rflags); @@ -2845,7 +3080,6 @@ static void addsubeq (const GenDesc* Gen, ExprDesc *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->IVal, Expr2.IVal); } else { @@ -2855,7 +3089,6 @@ static void addsubeq (const GenDesc* Gen, ExprDesc *Expr) case E_LOC_GLOBAL: /* Global variable */ - lflags |= CF_EXTERNAL; if (Gen->Tok == TOK_PLUS_ASSIGN) { g_addeqstatic (lflags, Expr->Name, Expr->IVal, Expr2.IVal); } else { @@ -2866,7 +3099,6 @@ static void addsubeq (const GenDesc* Gen, ExprDesc *Expr) case E_LOC_STATIC: case E_LOC_LITERAL: /* Static variable or literal in the literal pool */ - lflags |= CF_STATIC; if (Gen->Tok == TOK_PLUS_ASSIGN) { g_addeqstatic (lflags, Expr->Name, Expr->IVal, Expr2.IVal); } else { @@ -2876,7 +3108,6 @@ static void addsubeq (const GenDesc* Gen, ExprDesc *Expr) case E_LOC_REGISTER: /* Register variable */ - lflags |= CF_REGVAR; if (Gen->Tok == TOK_PLUS_ASSIGN) { g_addeqstatic (lflags, Expr->Name, Expr->IVal, Expr2.IVal); } else { @@ -2914,43 +3145,43 @@ void hie1 (ExprDesc* Expr) break; case TOK_PLUS_ASSIGN: - addsubeq (&GenPASGN, Expr); + addsubeq (&GenPASGN, Expr, "+="); break; case TOK_MINUS_ASSIGN: - addsubeq (&GenSASGN, Expr); + addsubeq (&GenSASGN, Expr, "-="); break; case TOK_MUL_ASSIGN: - opeq (&GenMASGN, Expr); + opeq (&GenMASGN, Expr, "*="); break; case TOK_DIV_ASSIGN: - opeq (&GenDASGN, Expr); + opeq (&GenDASGN, Expr, "/="); break; case TOK_MOD_ASSIGN: - opeq (&GenMOASGN, Expr); + opeq (&GenMOASGN, Expr, "%="); break; case TOK_SHL_ASSIGN: - opeq (&GenSLASGN, Expr); + opeq (&GenSLASGN, Expr, "<<="); break; case TOK_SHR_ASSIGN: - opeq (&GenSRASGN, Expr); + opeq (&GenSRASGN, Expr, ">>="); break; case TOK_AND_ASSIGN: - opeq (&GenAASGN, Expr); + opeq (&GenAASGN, Expr, "&="); break; case TOK_XOR_ASSIGN: - opeq (&GenXOASGN, Expr); + opeq (&GenXOASGN, Expr, "^="); break; case TOK_OR_ASSIGN: - opeq (&GenOASGN, Expr); + opeq (&GenOASGN, Expr, "|="); break; default: