X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fcc65%2Fexpr.c;h=e5e21e3ce796c9831b388aaf05413a54e6b864bc;hb=b28cf4cfd855ddf3e69eadc1a48d7582fc901e12;hp=48c284eb222fb73a71363a8b19671872bacc614d;hpb=04ee693c00802bb541934803ac947e316e33d166;p=cc65 diff --git a/src/cc65/expr.c b/src/cc65/expr.c index 48c284eb2..e5e21e3ce 100644 --- a/src/cc65/expr.c +++ b/src/cc65/expr.c @@ -8,15 +8,18 @@ #include #include -#include -#include "../common/xmalloc.h" +/* common */ +#include "check.h" +#include "debugflag.h" +#include "xmalloc.h" +/* cc65 */ #include "asmcode.h" #include "asmlabel.h" -#include "check.h" +#include "asmstmt.h" +#include "assignment.h" #include "codegen.h" -#include "datatype.h" #include "declare.h" #include "error.h" #include "funcdesc.h" @@ -28,6 +31,8 @@ #include "scanner.h" #include "stdfunc.h" #include "symtab.h" +#include "typecast.h" +#include "typecmp.h" #include "expr.h" @@ -43,8 +48,8 @@ /* Map a generator function and its attributes to a token */ typedef struct { - unsigned char Tok; /* Token to map to */ - unsigned char Flags; /* Flags for generator function */ + token_t Tok; /* Token to map to */ + unsigned Flags; /* Flags for generator function */ void (*Func) (unsigned, unsigned long); /* Generator func */ } GenDesc; @@ -82,8 +87,11 @@ static GenDesc GenOASGN = { TOK_OR_ASSIGN, GEN_NOPUSH, g_or }; -static int hie10 (struct expent* lval); -/* Handle ++, --, !, unary - etc. */ +static int hie0 (ExprDesc *lval); +/* Parse comma operator. */ + +static int expr (int (*func) (ExprDesc*), ExprDesc *lval); +/* Expression parser; func is either hie0 or hie1. */ @@ -111,12 +119,12 @@ static unsigned GlobalModeFlags (unsigned flags) -static int IsNullPtr (struct expent* lval) +static int IsNullPtr (ExprDesc* lval) /* Return true if this is the NULL pointer constant */ { - return (IsInt (lval->e_tptr) && /* Is it an int? */ - lval->e_flags == E_MCONST && /* Is it constant? */ - lval->e_const == 0); /* And is it's value zero? */ + return (IsClassInt (lval->Type) && /* Is it an int? */ + lval->Flags == E_MCONST && /* Is it constant? */ + lval->ConstVal == 0); /* And is it's value zero? */ } @@ -129,14 +137,14 @@ static type* promoteint (type* lhst, type* rhst) * - If one of the values is unsigned, the result is also unsigned. * - Otherwise the result is an int. */ - if (IsLong (lhst) || IsLong (rhst)) { - if (IsUnsigned (lhst) || IsUnsigned (rhst)) { + if (IsTypeLong (lhst) || IsTypeLong (rhst)) { + if (IsSignUnsigned (lhst) || IsSignUnsigned (rhst)) { return type_ulong; } else { return type_long; } } else { - if (IsUnsigned (lhst) || IsUnsigned (rhst)) { + if (IsSignUnsigned (lhst) || IsSignUnsigned (rhst)) { return type_uint; } else { return type_int; @@ -146,7 +154,7 @@ static type* promoteint (type* lhst, type* rhst) -static unsigned typeadjust (struct expent* lhs, struct expent* rhs, int NoPush) +static unsigned typeadjust (ExprDesc* lhs, ExprDesc* rhs, int NoPush) /* Adjust the two values for a binary operation. lhs is expected on stack or * to be constant, rhs is expected to be in the primary register or constant. * The function will put the type of the result into lhs and return the @@ -160,12 +168,12 @@ static unsigned typeadjust (struct expent* lhs, struct expent* rhs, int NoPush) unsigned flags; /* Get the type strings */ - type* lhst = lhs->e_tptr; - type* rhst = rhs->e_tptr; + type* lhst = lhs->Type; + type* rhst = rhs->Type; /* Generate type adjustment code if needed */ ltype = TypeOf (lhst); - if (lhs->e_flags == E_MCONST) { + if (lhs->Flags == E_MCONST) { ltype |= CF_CONST; } if (NoPush) { @@ -173,13 +181,13 @@ static unsigned typeadjust (struct expent* lhs, struct expent* rhs, int NoPush) ltype |= CF_REG; } rtype = TypeOf (rhst); - if (rhs->e_flags == E_MCONST) { + if (rhs->Flags == E_MCONST) { rtype |= CF_CONST; } flags = g_typeadjust (ltype, rtype); /* Set the type of the result */ - lhs->e_tptr = promoteint (lhst, rhst); + lhs->Type = promoteint (lhst, rhst); /* Return the code generator flags */ return flags; @@ -187,7 +195,7 @@ static unsigned typeadjust (struct expent* lhs, struct expent* rhs, int NoPush) -unsigned assignadjust (type* lhst, struct expent* rhs) +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 @@ -195,63 +203,78 @@ unsigned assignadjust (type* lhst, struct expent* rhs) * set to the type of the left hand side. */ { - /* Get the type of the right hand side */ - type* rhst = rhs->e_tptr; + /* 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->e_tptr = lhst; + rhs->Type = lhst; /* First, do some type checking */ - if (IsVoid (lhst) || IsVoid (rhst)) { + if (IsTypeVoid (lhst) || IsTypeVoid (rhst)) { /* If one of the sides are of type void, output a more apropriate * error message. */ - Error (ERR_ILLEGAL_TYPE); - } else if (IsInt (lhst)) { - if (IsPtr (rhst)) { + Error ("Illegal type"); + } else if (IsClassInt (lhst)) { + if (IsClassPtr (rhst)) { /* Pointer -> int conversion */ - Warning (WARN_PTR_TO_INT_CONV); - } else if (!IsInt (rhst)) { - Error (ERR_INCOMPATIBLE_TYPES); + 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. - */ + /* Convert the rhs to the type of the lhs. */ unsigned flags = TypeOf (rhst); - if (rhs->e_flags & E_MCONST) { + if (rhs->Flags == E_MCONST) { flags |= CF_CONST; } - return g_typeadjust (TypeOf (lhst) | CF_CONST, flags); + return g_typecast (TypeOf (lhst), flags); } - } else if (IsPtr (lhst)) { - if (IsPtr (rhst)) { + } 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. */ - type* left = Indirect (lhst); - type* right = Indirect (rhst); - if (!EqualTypes (left, right) && *left != T_VOID && *right != T_VOID) { - Error (ERR_INCOMPATIBLE_POINTERS); - } - } else if (IsInt (rhst)) { + 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->e_flags & E_MCONST) == 0 || rhs->e_const != 0) { - Warning (WARN_INT_TO_PTR_CONV); + if (rhs->Flags != E_MCONST || rhs->ConstVal != 0) { + Warning ("Converting integer to pointer without a cast"); } - } else if (IsFuncPtr (lhst) && IsFunc(rhst)) { + } else if (IsTypeFuncPtr (lhst) && IsTypeFunc(rhst)) { /* Assignment of function to function pointer is allowed, provided * that both functions have the same parameter list. */ - if (!EqualTypes(Indirect (lhst), rhst)) { - Error (ERR_INCOMPATIBLE_TYPES); + if (TypeCmp (Indirect (lhst), rhst) < TC_EQUAL) { + Error ("Incompatible types"); } } else { - Error (ERR_INCOMPATIBLE_TYPES); + Error ("Incompatible types"); } } else { - Error (ERR_INCOMPATIBLE_TYPES); + Error ("Incompatible types"); } /* Return an int value in all cases where the operands are not both ints */ @@ -260,16 +283,16 @@ unsigned assignadjust (type* lhst, struct expent* rhs) -void DefineData (struct expent* lval) +void DefineData (ExprDesc* Expr) /* Output a data definition for the given expression */ { - unsigned flags = lval->e_flags; + unsigned Flags = Expr->Flags; - switch (flags & E_MCTYPE) { + switch (Flags & E_MCTYPE) { case E_TCONST: /* Number */ - g_defdata (TypeOf (lval->e_tptr) | CF_CONST, lval->e_const, 0); + g_defdata (TypeOf (Expr->Type) | CF_CONST, Expr->ConstVal, 0); break; case E_TREGISTER: @@ -277,40 +300,40 @@ void DefineData (struct expent* lval) * allowed. */ if (!AllowRegVarAddr) { - Error (ERR_CANNOT_TAKE_ADDR_OF_REG); + 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->e_name, lval->e_const); + g_defdata (GlobalModeFlags (Flags), Expr->Name, Expr->ConstVal); break; case E_TLIT: /* a literal of some kind */ - g_defdata (CF_STATIC, LiteralLabel, lval->e_const); + g_defdata (CF_STATIC, LiteralPoolLabel, Expr->ConstVal); break; default: - Internal ("Unknown constant type: %04X", flags); + Internal ("Unknown constant type: %04X", Flags); } } -static void lconst (unsigned flags, struct expent* 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->e_flags & E_MCTYPE) { + switch (Expr->Flags & E_MCTYPE) { case E_TLOFFS: - g_leasp (lval->e_const); + g_leasp (Expr->ConstVal); break; case E_TCONST: /* Number constant */ - g_getimmed (flags | TypeOf (lval->e_tptr) | CF_CONST, lval->e_const, 0); + g_getimmed (Flags | TypeOf (Expr->Type) | CF_CONST, Expr->ConstVal, 0); break; case E_TREGISTER: @@ -318,25 +341,25 @@ static void lconst (unsigned flags, struct expent* lval) * allowed. */ if (!AllowRegVarAddr) { - Error (ERR_CANNOT_TAKE_ADDR_OF_REG); + 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->e_flags); - flags &= ~CF_CONST; - g_getimmed (flags, lval->e_name, lval->e_const); + Flags |= GlobalModeFlags (Expr->Flags); + Flags &= ~CF_CONST; + g_getimmed (Flags, Expr->Name, Expr->ConstVal); break; case E_TLIT: /* Literal string */ - g_getimmed (CF_STATIC, LiteralLabel, lval->e_const); + g_getimmed (CF_STATIC, LiteralPoolLabel, Expr->ConstVal); break; default: - Internal ("Unknown constant type: %04X", lval->e_flags); + Internal ("Unknown constant type: %04X", Expr->Flags); } } @@ -372,13 +395,13 @@ static int kcalc (int tok, long val1, long val2) return (val1 * val2); case TOK_DIV: if (val2 == 0) { - Error (ERR_DIV_BY_ZERO); + Error ("Division by zero"); return 0x7FFFFFFF; } return (val1 / val2); case TOK_MOD: if (val2 == 0) { - Error (ERR_MOD_BY_ZERO); + Error ("Modulo operation with zero"); return 0; } return (val1 % val2); @@ -390,9 +413,10 @@ static int kcalc (int tok, long val1, long val2) -static GenDesc* FindGen (int Tok, GenDesc** Table) +static const GenDesc* FindGen (token_t Tok, const GenDesc** Table) +/* Find a token in a generator table */ { - GenDesc* G; + const GenDesc* G; while ((G = *Table) != 0) { if (G->Tok == Tok) { return G; @@ -411,18 +435,17 @@ static int istypeexpr (void) { SymEntry* Entry; - return curtok == TOK_LPAREN && ( - (nxttok >= TOK_FIRSTTYPE && nxttok <= TOK_LASTTYPE) || - (nxttok == TOK_CONST) || - (nxttok == TOK_IDENT && - (Entry = FindSym (NextTok.Ident)) != 0 && - IsTypeDef (Entry)) - ); + 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 && + SymIsTypeDef (Entry))); } -static void PushAddr (struct expent* lval) +void PushAddr (ExprDesc* lval) /* If the expression contains an address that was somehow evaluated, * push this address on the stack. This is a helper function for all * sorts of implicit or explicit assignment functions where the lvalue @@ -430,130 +453,185 @@ static void PushAddr (struct expent* lval) */ { /* Get the address on stack if needed */ - if (lval->e_flags != E_MREG && (lval->e_flags & E_MEXPR)) { - /* Push the address (always a pointer) */ - g_push (CF_PTR, 0); + if (lval->Flags != E_MREG && (lval->Flags & E_MEXPR)) { + /* Push the address (always a pointer) */ + g_push (CF_PTR, 0); + } +} + + + +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. + */ +{ + InitExprDesc (Expr); + if (F (Expr) != 0 || Expr->Flags != E_MCONST) { + Error ("Constant expression expected"); + /* To avoid any compiler errors, make the expression a valid const */ + MakeConstIntExpr (Expr, 1); + } +} + + + +void CheckBoolExpr (ExprDesc* lval) +/* Check if the given expression is a boolean expression, output a diagnostic + * if not. + */ +{ + /* If it's an integer, it's ok. If it's not an integer, but a pointer, + * the pointer used in a boolean context is also ok + */ + if (!IsClassInt (lval->Type) && !IsClassPtr (lval->Type)) { + Error ("Boolean expression expected"); + /* To avoid any compiler errors, make the expression a valid int */ + MakeConstIntExpr (lval, 1); } } /*****************************************************************************/ -/* code */ +/* code */ /*****************************************************************************/ -void exprhs (unsigned flags, int k, struct expent *lval) +void exprhs (unsigned flags, int k, ExprDesc* lval) /* Put the result of an expression into the primary register */ { int f; - f = lval->e_flags; + f = lval->Flags; if (k) { /* Dereferenced lvalue */ - flags |= TypeOf (lval->e_tptr); - if (lval->e_test & E_FORCETEST) { + flags |= TypeOf (lval->Type); + if (lval->Test & E_FORCETEST) { flags |= CF_TEST; - lval->e_test &= ~E_FORCETEST; + lval->Test &= ~E_FORCETEST; } if (f & E_MGLOBAL) { /* ref to globalvar */ /* Generate code */ flags |= GlobalModeFlags (f); - g_getstatic (flags, lval->e_name, lval->e_const); + g_getstatic (flags, lval->Name, lval->ConstVal); } else if (f & E_MLOCAL) { /* ref to localvar */ - g_getlocal (flags, lval->e_const); + g_getlocal (flags, lval->ConstVal); } else if (f & E_MCONST) { /* ref to absolute address */ - g_getstatic (flags | CF_ABSOLUTE, lval->e_const, 0); + g_getstatic (flags | CF_ABSOLUTE, lval->ConstVal, 0); } else if (f == E_MEOFFS) { - g_getind (flags, lval->e_const); + g_getind (flags, lval->ConstVal); } else if (f != E_MREG) { g_getind (flags, 0); } } else if (f == E_MEOFFS) { /* reference not storable */ - flags |= TypeOf (lval->e_tptr); - g_inc (flags | CF_CONST, lval->e_const); + 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); + LoadConstant (flags, lval); } - if (lval->e_test & E_FORCETEST) { /* we testing this value? */ - /* debug... */ - AddCodeHint ("forcetest"); - flags |= TypeOf (lval->e_tptr); - g_test (flags); /* yes, force a test */ - lval->e_test &= ~E_FORCETEST; + /* Are we testing this value? */ + if (lval->Test & E_FORCETEST) { + /* Yes, force a test */ + flags |= TypeOf (lval->Type); + g_test (flags); + lval->Test &= ~E_FORCETEST; } } -static void callfunction (struct expent* lval) -/* Perform a function call. Called from hie11, this routine will - * either call the named function, or if the supplied ptr is zero, - * will call the contents of P. - */ -{ - struct expent lval2; - FuncDesc* Func; /* Function descriptor */ - int Ellipsis; /* True if we have an open param list */ - SymEntry* Param; /* Current formal parameter */ - unsigned ParamCount; /* Actual parameter count */ - unsigned ParamSize; /* Number of parameter bytes */ - unsigned Flags; - unsigned CFlags; - CodeMark Mark; - - /* Get a pointer to the function descriptor from the type string */ - Func = GetFuncDesc (lval->e_tptr); - - /* Initialize vars to keep gcc silent */ - Param = 0; - Mark = 0; - - /* Check if this is a function pointer. If so, save it. If not, check for - * special known library functions that may be inlined. +static unsigned FunctionParamList (FuncDesc* Func) +/* 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 + * storing into this frame. + * The function returns the size of the parameters pushed. + */ +{ + ExprDesc lval; + + /* Initialize variables */ + SymEntry* Param = 0; /* Keep gcc silent */ + unsigned ParamSize = 0; /* Size of parameters pushed */ + unsigned ParamCount = 0; /* Number of parameters pushed */ + unsigned FrameSize = 0; /* Size of parameter frame */ + unsigned FrameParams = 0; /* Number of params in frame */ + int FrameOffs = 0; /* Offset into parameter frame */ + int Ellipsis = 0; /* Function is variadic */ + + /* As an optimization, we may allocate the complete parameter frame at + * once instead of pushing each parameter as it comes. We may do that, + * if... + * + * - optimizations that increase code size are enabled (allocating the + * 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). */ - if (lval->e_flags & E_MEXPR) { - /* Function pointer is in primary register, save it */ - Mark = GetCodePos (); - g_save (CF_PTR); - } else if (InlineStdFuncs && IsStdFunc ((const char*) lval->e_name)) { - /* Inline this function */ - HandleStdFunc (lval); - return; + if (CodeSizeFactor >= 200) { + + /* Calculate the number and size of the parameters */ + FrameParams = Func->ParamCount; + FrameSize = Func->ParamSize; + if (FrameParams > 0 && (Func->Flags & FD_FASTCALL) != 0) { + /* Last parameter is not pushed */ + const SymEntry* LastParam = Func->SymTab->SymTail; + FrameSize -= CheckedSizeOf (LastParam->Type); + --FrameParams; + } + + /* Do we have more than one parameter in the frame? */ + if (FrameParams > 1) { + /* Okeydokey, setup the frame */ + FrameOffs = oursp; + g_space (FrameSize); + oursp -= FrameSize; + } else { + /* Don't use a preallocated frame */ + FrameSize = 0; + } } /* Parse the actual parameter list */ - ParamSize = 0; - ParamCount = 0; - Ellipsis = 0; - while (curtok != TOK_RPAREN) { + while (CurTok.Tok != TOK_RPAREN) { - /* Add a hint for the optimizer */ - AddCodeHint ("param:start"); + unsigned CFlags; + unsigned Flags; - /* Count arguments */ - ++ParamCount; + /* Count arguments */ + ++ParamCount; /* Fetch the pointer to the next argument, check for too many args */ if (ParamCount <= Func->ParamCount) { + /* Beware: If there are parameters with identical names, they + * cannot go into the same symbol table, which means that in this + * case of errorneous input, the number of nodes in the symbol + * table and ParamCount are NOT equal. We have to handle this case + * below to avoid segmentation violations. Since we know that this + * problem can only occur if there is more than one parameter, + * we will just use the last one. + */ if (ParamCount == 1) { - /* First argument */ - Param = Func->SymTab->SymHead; - } else { + /* First argument */ + Param = Func->SymTab->SymHead; + } else if (Param->NextSym != 0) { /* Next argument */ Param = Param->NextSym; CHECK ((Param->Flags & SC_PARAM) != 0); } } else if (!Ellipsis) { /* Too many arguments. Do we have an open param list? */ - if ((Func->Flags & FD_ELLIPSIS) == 0) { + if ((Func->Flags & FD_VARIADIC) == 0) { /* End of param list reached, no ellipsis */ - Error (ERR_TOO_MANY_FUNC_ARGS); + Error ("Too many arguments in function call"); } /* Assume an ellipsis even in case of errors to avoid an error * message for each other argument. @@ -565,11 +643,11 @@ static void callfunction (struct expent* lval) * use a special function that may optimize. */ CFlags = CF_NONE; - if (!Ellipsis && SizeOf (Param->Type) == 1) { + if (!Ellipsis && CheckedSizeOf (Param->Type) == 1) { CFlags = CF_FORCECHAR; } - Flags = 0; - if (evalexpr (CFlags, hie1, &lval2) == 0) { + Flags = CF_NONE; + if (evalexpr (CFlags, hie1, &lval) == 0) { /* A constant value */ Flags |= CF_CONST; } @@ -579,13 +657,14 @@ static void callfunction (struct expent* lval) */ if (!Ellipsis) { /* Promote the argument if needed */ - assignadjust (Param->Type, &lval2); + assignadjust (Param->Type, &lval); + /* If we have a prototype, chars may be pushed as chars */ Flags |= CF_FORCECHAR; } /* Use the type of the argument for the push */ - Flags |= TypeOf (lval2.e_tptr); + Flags |= TypeOf (lval.Type); /* If this is a fastcall function, don't push the last argument */ if (ParamCount == Func->ParamCount && (Func->Flags & FD_FASTCALL) != 0) { @@ -594,98 +673,185 @@ static void callfunction (struct expent* lval) * the primary. */ if (Flags & CF_CONST) { - exprhs (CF_FORCECHAR, 0, &lval2); + exprhs (CF_FORCECHAR, 0, &lval); } } else { - /* Push the argument, count the argument size */ - g_push (Flags, lval2.e_const); - ParamSize += sizeofarg (Flags); - } + unsigned ArgSize = sizeofarg (Flags); + if (FrameSize > 0) { + /* We have the space already allocated, store in the frame */ + CHECK (FrameSize >= ArgSize); + FrameSize -= ArgSize; + FrameOffs -= ArgSize; + /* Store */ + g_putlocal (Flags | CF_NOKEEP, FrameOffs, lval.ConstVal); + } else { + /* Push the argument */ + g_push (Flags, lval.ConstVal); + } - /* Add an optimizer hint */ - AddCodeHint ("param:end"); + /* Calculate total parameter size */ + ParamSize += ArgSize; + } /* Check for end of argument list */ - if (curtok != TOK_COMMA) { + if (CurTok.Tok != TOK_COMMA) { break; } NextToken (); } - /* We need the closing bracket here */ - ConsumeRParen (); - /* Check if we had enough parameters */ if (ParamCount < Func->ParamCount) { - Error (ERR_TOO_FEW_FUNC_ARGS); + Error ("Too few arguments in function call"); } - /* */ - if (lval->e_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); - } - g_callind (TypeOf (lval->e_tptr), ParamSize); - } else { - g_call (TypeOf (lval->e_tptr), (char*) lval->e_name, ParamSize); - } + /* The function returns the size of all parameters pushed onto the stack. + * However, if there are parameters missing (which is an error and was + * flagged by the compiler) AND a stack frame was preallocated above, + * we would loose track of the stackpointer and generate an internal error + * later. So we correct the value by the parameters that should have been + * pushed to avoid an internal compiler error. Since an error was + * generated before, no code will be output anyway. + */ + return ParamSize + FrameSize; } -void doasm (void) -/* This function parses ASM statements. The syntax of the ASM directive - * looks like the one defined for C++ (C has no ASM directive), that is, - * a string literal in parenthesis. - */ +static void FunctionCall (int k, ExprDesc* lval) +/* Perform a function call. */ { - /* Skip the ASM */ - NextToken (); + FuncDesc* Func; /* Function descriptor */ + int IsFuncPtr; /* Flag */ + 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 */ - /* Need left parenthesis */ - ConsumeLParen (); + /* Get a pointer to the function descriptor from the type string */ + Func = GetFuncDesc (lval->Type); + + /* Handle function pointers transparently */ + IsFuncPtr = IsTypeFuncPtr (lval->Type); + if (IsFuncPtr) { + + /* Check wether it's a fastcall function that has parameters */ + IsFastCall = IsFastCallFunc (lval->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 || ((lval->Flags & (E_MGLOBAL | E_MLOCAL)) == 0); + if (PtrOnStack) { - /* String literal */ - if (curtok != TOK_SCONST) { - Error (ERR_STRLIT_EXPECTED); - } else { - /* Write the string directly into the output, followed by a newline */ - AddCodeLine (GetLiteral (curval)); + /* Not a global or local variable, or a fastcall function. Load + * the pointer into the primary and mark it as an expression. + */ + exprhs (CF_NONE, k, lval); + lval->Flags |= E_MEXPR; + + /* Remember the code position */ + Mark = GetCodePos (); + + /* Push the pointer onto the stack and remember the offset */ + g_push (CF_PTR, 0); + PtrOffs = oursp; + } + + /* Check for known standard functions and inline them if requested */ + } else if (InlineStdFuncs && IsStdFunc ((const char*) lval->Name)) { + + /* Inline this function */ + HandleStdFunc (Func, lval); + return; - /* Reset the string pointer, effectivly clearing the string from the - * string table. Since we're working with one token lookahead, this - * will fail if the next token is also a string token, but that's a - * syntax error anyway, because we expect a right paren. - */ - ResetLiteralOffs (curval); } - /* Skip the string token */ - NextToken (); + /* Parse the parameter list */ + ParamSize = FunctionParamList (Func); - /* Closing paren needed */ + /* We need the closing paren here */ ConsumeRParen (); + + /* 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 */ + exprhs (CF_NONE, k, lval); + } + + /* Call the function */ + g_callind (TypeOf (lval->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); + } + + /* If we have a pointer on stack, remove it */ + if (PtrOnStack) { + g_space (- (int) sizeofarg (CF_PTR)); + pop (CF_PTR); + } + + /* Skip T_PTR */ + ++lval->Type; + + } else { + + /* Normal function */ + g_call (TypeOf (lval->Type), (const char*) lval->Name, ParamSize); + + } } -static int primary (struct expent* lval) +static int primary (ExprDesc* lval) /* This is the lowest level of the expression parser. */ { int k; - /* not a test at all, yet */ - lval->e_test = 0; + /* Initialize fields in the expression stucture */ + lval->Test = 0; /* No test */ + lval->Sym = 0; /* Symbol unknown */ /* Character and integer constants. */ - if (curtok == TOK_ICONST || curtok == TOK_CCONST) { - lval->e_flags = E_MCONST | E_TCONST; - lval->e_tptr = curtype; - lval->e_const = curval; + if (CurTok.Tok == TOK_ICONST || CurTok.Tok == TOK_CCONST) { + lval->Flags = E_MCONST | E_TCONST; + lval->Type = CurTok.Type; + lval->ConstVal = CurTok.IVal; NextToken (); return 0; } @@ -693,33 +859,40 @@ static int primary (struct expent* lval) /* Process parenthesized subexpression by calling the whole parser * recursively. */ - if (curtok == TOK_LPAREN) { + if (CurTok.Tok == TOK_LPAREN) { NextToken (); - memset (lval, 0, sizeof (*lval)); /* Remove any attributes */ + InitExprDesc (lval); /* Remove any attributes */ k = hie0 (lval); ConsumeRParen (); return k; } + /* If we run into an identifier in preprocessing mode, we assume that this + * is an undefined macro and replace it by a constant value of zero. + */ + if (Preprocessing && CurTok.Tok == TOK_IDENT) { + MakeConstIntExpr (lval, 0); + return 0; + } + /* All others may only be used if the expression evaluation is not called * recursively by the preprocessor. */ if (Preprocessing) { /* Illegal expression in PP mode */ - Error (ERR_CPP_EXPR_EXPECTED); - lval->e_flags = E_MCONST; - lval->e_tptr = type_int; + Error ("Preprocessor expression expected"); + MakeConstIntExpr (lval, 1); return 0; } /* Identifier? */ - if (curtok == TOK_IDENT) { + if (CurTok.Tok == TOK_IDENT) { SymEntry* Sym; ident Ident; /* Get a pointer to the symbol table entry */ - Sym = FindSym (CurTok.Ident); + Sym = lval->Sym = FindSym (CurTok.Ident); /* Is the symbol known? */ if (Sym) { @@ -728,62 +901,71 @@ static int primary (struct expent* lval) NextToken (); /* The expression type is the symbol type */ - lval->e_tptr = Sym->Type; + lval->Type = Sym->Type; /* Check for illegal symbol types */ - if ((Sym->Flags & SC_LABEL) == SC_LABEL) { - /* Cannot use labels in expressions */ - Error (ERR_SYMBOL_KIND); - return 1; - } else if (Sym->Flags & SC_TYPE) { + CHECK ((Sym->Flags & SC_LABEL) != SC_LABEL); + if (Sym->Flags & SC_TYPE) { /* Cannot use type symbols */ - Error (ERR_VAR_IDENT_EXPECTED); + Error ("Variable identifier expected"); /* Assume an int type to make lval valid */ - lval->e_flags = E_MLOCAL | E_TLOFFS; - lval->e_tptr = type_int; - lval->e_const = 0; + lval->Flags = E_MLOCAL | E_TLOFFS; + lval->Type = type_int; + lval->ConstVal = 0; return 0; } /* Check for legal symbol types */ - if ((Sym->Flags & SC_ENUM) == SC_ENUM) { - lval->e_flags = E_MCONST; - lval->e_const = Sym->V.EnumVal; + if ((Sym->Flags & SC_CONST) == SC_CONST) { + /* Enum or some other numeric constant */ + lval->Flags = E_MCONST | E_TCONST; + lval->ConstVal = Sym->V.ConstVal; return 0; } else if ((Sym->Flags & SC_FUNC) == SC_FUNC) { /* Function */ - lval->e_flags = E_MGLOBAL | E_MCONST | E_TGLAB; - lval->e_name = (unsigned long) Sym->Name; - lval->e_const = 0; + 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 */ - lval->e_flags = E_MLOCAL | E_TLOFFS; - lval->e_const = Sym->V.Offs; + /* 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)); + 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_REGISTER) == SC_REGISTER) { + /* Register variable, zero page based */ + lval->Flags = E_MGLOBAL | E_MCONST | E_TREGISTER; + lval->Name = Sym->V.R.RegOffs; + lval->ConstVal = 0; } else if ((Sym->Flags & SC_STATIC) == SC_STATIC) { /* Static variable */ if (Sym->Flags & (SC_EXTERN | SC_STORAGE)) { - lval->e_flags = E_MGLOBAL | E_MCONST | E_TGLAB; - lval->e_name = (unsigned long) Sym->Name; + lval->Flags = E_MGLOBAL | E_MCONST | E_TGLAB; + lval->Name = (unsigned long) Sym->Name; } else { - lval->e_flags = E_MGLOBAL | E_MCONST | E_TLLAB; - lval->e_name = Sym->V.Label; + lval->Flags = E_MGLOBAL | E_MCONST | E_TLLAB; + lval->Name = Sym->V.Label; } - lval->e_const = 0; - } else if ((Sym->Flags & SC_REGISTER) == SC_REGISTER) { - /* Register variable, zero page based */ - lval->e_flags = E_MGLOBAL | E_MCONST | E_TREGISTER; - lval->e_name = Sym->V.Offs; - lval->e_const = 0; + lval->ConstVal = 0; } else { /* Local static variable */ - lval->e_flags = E_MGLOBAL | E_MCONST | E_TLLAB; - lval->e_name = Sym->V.Offs; - lval->e_const = 0; + 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 (IsFunc (lval->e_tptr) || IsArray (lval->e_tptr)) { + if (IsTypeFunc (lval->Type) || IsTypeArray (lval->Type)) { return 0; } return 1; @@ -794,70 +976,69 @@ static int primary (struct expent* lval) NextToken (); /* IDENT is either an auto-declared function or an undefined variable. */ - if (curtok == TOK_LPAREN) { + 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 (WARN_FUNC_WITHOUT_PROTO); + Warning ("Function call without a prototype"); Sym = AddGlobalSym (Ident, GetImplicitFuncType(), SC_EXTERN | SC_REF | SC_FUNC); - lval->e_tptr = Sym->Type; - lval->e_flags = E_MGLOBAL | E_MCONST | E_TGLAB; - lval->e_name = (unsigned long) Sym->Name; - lval->e_const = 0; + 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->e_flags = E_MLOCAL | E_TLOFFS; - lval->e_tptr = type_int; - lval->e_const = 0; - Error (ERR_UNDEFINED_SYMBOL, Ident); + 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_SCONST) { - lval->e_flags = E_MCONST | E_TLIT; - lval->e_const = curval; - lval->e_tptr = GetCharArrayType (strlen (GetLiteral (curval))); + if (CurTok.Tok == TOK_SCONST) { + lval->Flags = E_MCONST | E_TLIT; + lval->ConstVal = CurTok.IVal; + lval->Type = GetCharArrayType (GetLiteralPoolOffs () - CurTok.IVal); NextToken (); return 0; } /* ASM statement? */ - if (curtok == TOK_ASM) { - doasm (); - lval->e_tptr = type_void; - lval->e_flags = E_MEXPR; - lval->e_const = 0; + if (CurTok.Tok == TOK_ASM) { + AsmStatement (); + lval->Type = type_void; + lval->Flags = E_MEXPR; + lval->ConstVal = 0; return 0; } /* __AX__ and __EAX__ pseudo values? */ - if (curtok == TOK_AX || curtok == TOK_EAX) { - lval->e_tptr = (curtok == TOK_AX)? type_uint : type_ulong; - lval->e_flags = E_MREG; - lval->e_test &= ~E_CC; - lval->e_const = 0; + 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 */ } /* Illegal primary. */ - Error (ERR_EXPR_EXPECTED); - lval->e_flags = E_MCONST; - lval->e_tptr = type_int; + Error ("Expression expected"); + MakeConstIntExpr (lval, 1); return 0; } -static int arrayref (int k, struct expent* lval) +static int arrayref (int k, ExprDesc* lval) /* Handle an array reference */ { unsigned lflags; @@ -865,7 +1046,7 @@ static int arrayref (int k, struct expent* lval) int ConstBaseAddr; int ConstSubAddr; int l; - struct expent lval2; + ExprDesc lval2; CodeMark Mark1; CodeMark Mark2; type* tptr1; @@ -876,13 +1057,13 @@ static int arrayref (int k, struct expent* lval) NextToken (); /* Get the type of left side */ - tptr1 = lval->e_tptr; + tptr1 = lval->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->e_flags & ~E_MCTYPE; + lflags = lval->Flags & ~E_MCTYPE; ConstBaseAddr = (lflags == E_MCONST) || /* Constant numeric address */ (lflags & E_MGLOBAL) != 0 || /* Static array, or ... */ lflags == E_MLOCAL; /* Local array */ @@ -904,7 +1085,7 @@ static int arrayref (int k, struct expent* lval) /* TOS now contains ptr to array elements. Get the subscript. */ l = hie0 (&lval2); - if (l == 0 && lval2.e_flags == E_MCONST) { + if (l == 0 && lval2.Flags == E_MCONST) { /* The array subscript is a constant - remove value from stack */ if (!ConstBaseAddr) { @@ -915,10 +1096,10 @@ static int arrayref (int k, struct expent* lval) exprhs (CF_NONE, k, lval); } - if (IsPtr (tptr1)) { + if (IsClassPtr (tptr1)) { /* Scale the subscript value according to element size */ - lval2.e_const *= PSizeOf (tptr1); + lval2.ConstVal *= CheckedPSizeOf (tptr1); /* Remove code for lhs load */ RemoveCode (Mark1); @@ -926,45 +1107,45 @@ static int arrayref (int k, struct expent* lval) /* Handle constant base array on stack. Be sure NOT to * handle pointers the same way, this won't work. */ - if (IsArray (tptr1) && - ((lval->e_flags & ~E_MCTYPE) == E_MCONST || - (lval->e_flags & ~E_MCTYPE) == E_MLOCAL || - (lval->e_flags & E_MGLOBAL) != 0 || - (lval->e_flags == E_MEOFFS))) { - lval->e_const += lval2.e_const; + 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; } else { /* Pointer - load into primary and remember offset */ - if ((lval->e_flags & E_MEXPR) == 0 || k != 0) { + if ((lval->Flags & E_MEXPR) == 0 || k != 0) { exprhs (CF_NONE, k, lval); } - lval->e_const = lval2.e_const; - lval->e_flags = E_MEOFFS; + lval->ConstVal = lval2.ConstVal; + lval->Flags = E_MEOFFS; } /* Result is of element type */ - lval->e_tptr = Indirect (tptr1); + lval->Type = Indirect (tptr1); /* Done */ goto end_array; - } else if ((tptr2 = lval2.e_tptr) [0] & T_POINTER) { + } else if (IsClassPtr (tptr2 = lval2.Type)) { /* Subscript is pointer, get element type */ - lval2.e_tptr = Indirect (tptr2); + lval2.Type = Indirect (tptr2); /* Scale the rhs value in the primary register */ - g_scale (TypeOf (tptr1), SizeOf (lval2.e_tptr)); + g_scale (TypeOf (tptr1), CheckedSizeOf (lval2.Type)); /* */ - lval->e_tptr = lval2.e_tptr; + lval->Type = lval2.Type; } else { - Error (ERR_CANNOT_SUBSCRIPT); + Error ("Cannot subscript"); } /* 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.e_const); + g_inc (CF_INT | CF_CONST, lval2.ConstVal); } else { @@ -972,29 +1153,29 @@ static int arrayref (int k, struct expent* lval) Mark2 = GetCodePos (); exprhs (CF_NONE, l, &lval2); - tptr2 = lval2.e_tptr; - if (IsPtr (tptr1)) { + tptr2 = lval2.Type; + if (IsClassPtr (tptr1)) { /* Get the element type */ - lval->e_tptr = Indirect (tptr1); + lval->Type = Indirect (tptr1); /* Indexing is based on int's, 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->e_tptr)); + g_scale (CF_INT, CheckedSizeOf (lval->Type)); - } else if (IsPtr (tptr2)) { + } else if (IsClassPtr (tptr2)) { /* Get the element type */ - lval2.e_tptr = Indirect (tptr2); + lval2.Type = Indirect (tptr2); /* 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. - */ + */ if (ConstBaseAddr) { g_push (CF_INT, 0); exprhs (CF_NONE, k, lval); @@ -1004,10 +1185,10 @@ static int arrayref (int k, struct expent* lval) } /* Scale it */ - g_scale (TypeOf (tptr1), SizeOf (lval2.e_tptr)); - lval->e_tptr = lval2.e_tptr; + g_scale (TypeOf (tptr1), CheckedSizeOf (lval2.Type)); + lval->Type = lval2.Type; } else { - Error (ERR_CANNOT_SUBSCRIPT); + Error ("Cannot subscript"); } /* The offset is now in the primary register. It didn't have a @@ -1028,69 +1209,69 @@ static int arrayref (int k, struct expent* lval) * subscript was not scaled, that is, if this was a byte array * or pointer. */ - rflags = lval2.e_flags & ~E_MCTYPE; + rflags = lval2.Flags & ~E_MCTYPE; ConstSubAddr = (rflags == E_MCONST) || /* Constant numeric address */ (rflags & E_MGLOBAL) != 0 || /* Static array, or ... */ - rflags == E_MLOCAL; /* Local array */ + rflags == E_MLOCAL; /* Local array */ - if (ConstSubAddr && SizeOf (lval->e_tptr) == 1) { + if (ConstSubAddr && CheckedSizeOf (lval->Type) == SIZEOF_CHAR) { type* SavedType; /* Reverse the order of evaluation */ - unsigned flags = (SizeOf (lval2.e_tptr) == 1)? CF_CHAR : CF_INT; - RemoveCode (Mark2); + unsigned flags = (CheckedSizeOf (lval2.Type) == SIZEOF_CHAR)? CF_CHAR : CF_INT; + RemoveCode (Mark2); /* Get a pointer to the array into the primary. We have changed - * e_tptr above but we need the original type to load the + * Type above but we need the original type to load the * address, so restore it temporarily. */ - SavedType = lval->e_tptr; - lval->e_tptr = tptr1; + SavedType = lval->Type; + lval->Type = tptr1; exprhs (CF_NONE, k, lval); - lval->e_tptr = SavedType; + lval->Type = SavedType; /* Add the variable */ if (rflags == E_MLOCAL) { - g_addlocal (flags, lval2.e_const); + g_addlocal (flags, lval2.ConstVal); } else { - flags |= GlobalModeFlags (lval2.e_flags); - g_addstatic (flags, lval2.e_name, lval2.e_const); + flags |= GlobalModeFlags (lval2.Flags); + g_addstatic (flags, lval2.Name, lval2.ConstVal); } } else { if (lflags == E_MCONST) { /* Constant numeric address. Just add it */ - g_inc (CF_INT | CF_UNSIGNED, lval->e_const); + g_inc (CF_INT | CF_UNSIGNED, lval->ConstVal); } else if (lflags == E_MLOCAL) { - /* Base address is a local variable address */ - if (IsArray (tptr1)) { - g_addaddr_local (CF_INT, lval->e_const); - } else { - g_addlocal (CF_PTR, lval->e_const); - } + /* Base address is a local variable address */ + if (IsTypeArray (tptr1)) { + g_addaddr_local (CF_INT, lval->ConstVal); + } else { + g_addlocal (CF_PTR, lval->ConstVal); + } } else { /* Base address is a static variable address */ unsigned flags = CF_INT; - flags |= GlobalModeFlags (lval->e_flags); - if (IsArray (tptr1)) { - g_addaddr_static (flags, lval->e_name, lval->e_const); - } else { - g_addstatic (flags, lval->e_name, lval->e_const); - } + flags |= GlobalModeFlags (lval->Flags); + if (IsTypeArray (tptr1)) { + g_addaddr_static (flags, lval->Name, lval->ConstVal); + } else { + g_addstatic (flags, lval->Name, lval->ConstVal); + } } } } } - lval->e_flags = E_MEXPR; + lval->Flags = E_MEXPR; end_array: ConsumeRBrack (); - return !IsArray (lval->e_tptr); + return !IsTypeArray (lval->Type); } -static int structref (int k, struct expent* lval) +static int structref (int k, ExprDesc* lval) /* Process struct field after . or ->. */ { ident Ident; @@ -1099,43 +1280,43 @@ static int structref (int k, struct expent* lval) /* Skip the token and check for an identifier */ NextToken (); - if (curtok != TOK_IDENT) { - Error (ERR_IDENT_EXPECTED); - lval->e_tptr = type_int; + if (CurTok.Tok != TOK_IDENT) { + Error ("Identifier expected"); + lval->Type = type_int; return 0; } /* Get the symbol table entry and check for a struct field */ strcpy (Ident, CurTok.Ident); NextToken (); - Field = FindStructField (lval->e_tptr, Ident); + Field = FindStructField (lval->Type, Ident); if (Field == 0) { - Error (ERR_STRUCT_FIELD_MISMATCH, Ident); - lval->e_tptr = type_int; + Error ("Struct/union has no field named `%s'", Ident); + lval->Type = type_int; return 0; } /* If we have constant input data, the result is also constant */ - flags = lval->e_flags & ~E_MCTYPE; + flags = lval->Flags & ~E_MCTYPE; if (flags == E_MCONST || (k == 0 && (flags == E_MLOCAL || - (flags & E_MGLOBAL) != 0 || - lval->e_flags == E_MEOFFS))) { - lval->e_const += Field->V.Offs; + (flags & E_MGLOBAL) != 0 || + lval->Flags == E_MEOFFS))) { + lval->ConstVal += Field->V.Offs; } else { if ((flags & E_MEXPR) == 0 || k != 0) { exprhs (CF_NONE, k, lval); } - lval->e_const = Field->V.Offs; - lval->e_flags = E_MEOFFS; + lval->ConstVal = Field->V.Offs; + lval->Flags = E_MEOFFS; } - lval->e_tptr = Field->Type; - return !IsArray (Field->Type); + lval->Type = Field->Type; + return !IsTypeArray (Field->Type); } -static int hie11 (struct expent *lval) +static int hie11 (ExprDesc *lval) /* Handle compound types (structs and arrays) */ { int k; @@ -1143,50 +1324,51 @@ static int hie11 (struct expent *lval) k = primary (lval); - if (curtok < TOK_LBRACK || curtok > TOK_PTR_REF) { + if (CurTok.Tok < TOK_LBRACK || CurTok.Tok > TOK_PTR_REF) { /* Not for us */ return k; } while (1) { - if (curtok == TOK_LBRACK) { + if (CurTok.Tok == TOK_LBRACK) { /* Array reference */ k = arrayref (k, lval); - } else if (curtok == TOK_LPAREN) { + } else if (CurTok.Tok == TOK_LPAREN) { /* Function call. Skip the opening parenthesis */ NextToken (); - tptr = lval->e_tptr; - if (IsFunc (tptr) || IsFuncPtr (tptr)) { - if (IsFuncPtr (tptr)) { - /* Pointer to function. Handle transparently */ - exprhs (CF_NONE, k, lval); /* Function pointer to A/X */ - ++lval->e_tptr; /* Skip T_PTR */ - lval->e_flags |= E_MEXPR; - } - callfunction (lval); - lval->e_flags = E_MEXPR; - lval->e_tptr += DECODE_SIZE + 1; /* Set to result */ + tptr = lval->Type; + if (IsTypeFunc (lval->Type) || IsTypeFuncPtr (lval->Type)) { + + /* Call the function */ + FunctionCall (k, lval); + + /* Result is in the primary register */ + lval->Flags = E_MEXPR; + + /* Set to result */ + lval->Type = GetFuncReturn (lval->Type); + } else { - Error (ERR_ILLEGAL_FUNC_CALL); + Error ("Illegal function call"); } k = 0; - } else if (curtok == TOK_DOT) { + } else if (CurTok.Tok == TOK_DOT) { - if (!IsStruct (lval->e_tptr)) { - Error (ERR_STRUCT_EXPECTED); + if (!IsClassStruct (lval->Type)) { + Error ("Struct expected"); } k = structref (0, lval); - } else if (curtok == TOK_PTR_REF) { + } else if (CurTok.Tok == TOK_PTR_REF) { - tptr = lval->e_tptr; + tptr = lval->Type; if (tptr[0] != T_PTR || (tptr[1] & T_STRUCT) == 0) { - Error (ERR_STRUCT_PTR_EXPECTED); + Error ("Struct pointer expected"); } k = structref (k, lval); @@ -1198,44 +1380,56 @@ static int hie11 (struct expent *lval) -static void store (struct expent* lval) -/* Store primary reg into this reference */ +void Store (ExprDesc* lval, const type* StoreType) +/* Store the primary register into the location denoted by lval. If StoreType + * is given, use this type when storing instead of lval->Type. If StoreType + * is NULL, use lval->Type instead. + */ { - int f; - unsigned flags; + unsigned Flags; + + unsigned f = lval->Flags; - f = lval->e_flags; - flags = TypeOf (lval->e_tptr); + /* If StoreType was not given, use lval->Type instead */ + if (StoreType == 0) { + StoreType = lval->Type; + } + + /* Get the code generator flags */ + Flags = TypeOf (StoreType); if (f & E_MGLOBAL) { - flags |= GlobalModeFlags (f); - if (lval->e_test) { - /* Just testing */ - flags |= CF_TEST; - } + Flags |= GlobalModeFlags (f); + if (lval->Test) { + /* Just testing */ + Flags |= CF_TEST; + } /* Generate code */ - g_putstatic (flags, lval->e_name, lval->e_const); + g_putstatic (Flags, lval->Name, lval->ConstVal); } else if (f & E_MLOCAL) { - g_putlocal (flags, lval->e_const); + /* Store an auto variable */ + g_putlocal (Flags, lval->ConstVal, 0); } else if (f == E_MEOFFS) { - g_putind (flags, lval->e_const); + /* Store indirect with offset */ + g_putind (Flags, lval->ConstVal); } else if (f != E_MREG) { if (f & E_MEXPR) { - g_putind (flags, 0); + /* Indirect without offset */ + g_putind (Flags, 0); } else { /* Store into absolute address */ - g_putstatic (flags | CF_ABSOLUTE, lval->e_const, 0); + g_putstatic (Flags | CF_ABSOLUTE, lval->ConstVal, 0); } } /* Assume that each one of the stores will invalidate CC */ - lval->e_test &= ~E_CC; + lval->Test &= ~E_CC; } -static void pre_incdec (struct expent* lval, void (*inc) (unsigned, unsigned long)) +static void pre_incdec (ExprDesc* lval, void (*inc) (unsigned, unsigned long)) /* Handle --i and ++i */ { int k; @@ -1244,21 +1438,21 @@ static void pre_incdec (struct expent* lval, void (*inc) (unsigned, unsigned lon NextToken (); if ((k = hie10 (lval)) == 0) { - Error (ERR_LVALUE_EXPECTED); + Error ("Invalid lvalue"); return; } /* Get the data type */ - flags = TypeOf (lval->e_tptr) | CF_FORCECHAR | CF_CONST; + flags = TypeOf (lval->Type) | CF_FORCECHAR | CF_CONST; /* Get the increment value in bytes */ - val = (lval->e_tptr [0] == T_PTR)? PSizeOf (lval->e_tptr) : 1; + val = (lval->Type [0] == T_PTR)? CheckedPSizeOf (lval->Type) : 1; /* We're currently only able to handle some adressing modes */ - if ((lval->e_flags & E_MGLOBAL) == 0 && /* Global address? */ - (lval->e_flags & E_MLOCAL) == 0 && /* Local address? */ - (lval->e_flags & E_MCONST) == 0 && /* Constant address? */ - (lval->e_flags & E_MEXPR) == 0) { /* Address in a/x? */ + 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? */ /* Use generic code. Push the address if needed */ PushAddr (lval); @@ -1270,39 +1464,40 @@ static void pre_incdec (struct expent* lval, void (*inc) (unsigned, unsigned lon inc (flags, val); /* Store the result back */ - store (lval); + Store (lval, 0); } else { /* Special code for some addressing modes - use the special += ops */ - if (lval->e_flags & E_MGLOBAL) { - flags |= GlobalModeFlags (lval->e_flags); + if (lval->Flags & E_MGLOBAL) { + flags |= GlobalModeFlags (lval->Flags); if (inc == g_inc) { - g_addeqstatic (flags, lval->e_name, lval->e_const, val); + g_addeqstatic (flags, lval->Name, lval->ConstVal, val); } else { - g_subeqstatic (flags, lval->e_name, lval->e_const, val); + g_subeqstatic (flags, lval->Name, lval->ConstVal, val); } - } else if (lval->e_flags & E_MLOCAL) { + } else if (lval->Flags & E_MLOCAL) { /* ref to localvar */ if (inc == g_inc) { - g_addeqlocal (flags, lval->e_const, val); + g_addeqlocal (flags, lval->ConstVal, val); } else { - g_subeqlocal (flags, lval->e_const, val); + g_subeqlocal (flags, lval->ConstVal, val); } - } else if (lval->e_flags & E_MCONST) { + } else if (lval->Flags & E_MCONST) { /* ref to absolute address */ flags |= CF_ABSOLUTE; if (inc == g_inc) { - g_addeqstatic (flags, lval->e_const, 0, val); + g_addeqstatic (flags, lval->ConstVal, 0, val); } else { - g_subeqstatic (flags, lval->e_const, 0, val); + g_subeqstatic (flags, lval->ConstVal, 0, val); } - } else if (lval->e_flags & E_MEXPR) { - /* Address in a/x. */ + } 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, lval->e_const, val); + g_addeqind (flags, Offs, val); } else { - g_subeqind (flags, lval->e_const, val); + g_subeqind (flags, Offs, val); } } else { Internal ("Invalid addressing mode"); @@ -1311,24 +1506,24 @@ static void pre_incdec (struct expent* lval, void (*inc) (unsigned, unsigned lon } /* Result is an expression */ - lval->e_flags = E_MEXPR; + lval->Flags = E_MEXPR; } -static void post_incdec (struct expent *lval, int k, void (*inc) (unsigned, unsigned long)) +static void post_incdec (ExprDesc* lval, int k, void (*inc) (unsigned, unsigned long)) /* Handle i-- and i++ */ { unsigned flags; NextToken (); if (k == 0) { - Error (ERR_LVALUE_EXPECTED); + Error ("Invalid lvalue"); return; } /* Get the data type */ - flags = TypeOf (lval->e_tptr); + flags = TypeOf (lval->Type); /* Push the address if needed */ PushAddr (lval); @@ -1338,23 +1533,23 @@ static void post_incdec (struct expent *lval, int k, void (*inc) (unsigned, unsi g_save (flags | CF_FORCECHAR); /* If we have a pointer expression, increment by the size of the type */ - if (lval->e_tptr[0] == T_PTR) { - inc (flags | CF_CONST | CF_FORCECHAR, SizeOf (lval->e_tptr + 1)); + if (lval->Type[0] == T_PTR) { + inc (flags | CF_CONST | CF_FORCECHAR, CheckedSizeOf (lval->Type + 1)); } else { inc (flags | CF_CONST | CF_FORCECHAR, 1); } /* Store the result back */ - store (lval); + Store (lval, 0); /* Restore the original value */ g_restore (flags | CF_FORCECHAR); - lval->e_flags = E_MEXPR; + lval->Flags = E_MEXPR; } -static void unaryop (int tok, struct expent* lval) +static void unaryop (int tok, ExprDesc* lval) /* Handle unary -/+ and ~ */ { int k; @@ -1362,12 +1557,12 @@ static void unaryop (int tok, struct expent* lval) NextToken (); k = hie10 (lval); - if (k == 0 && lval->e_flags & E_MCONST) { + if (k == 0 && (lval->Flags & E_MCONST) != 0) { /* Value is constant */ switch (tok) { - case TOK_MINUS: lval->e_const = -lval->e_const; break; + case TOK_MINUS: lval->ConstVal = -lval->ConstVal; break; case TOK_PLUS: break; - case TOK_COMP: lval->e_const = ~lval->e_const; break; + case TOK_COMP: lval->ConstVal = ~lval->ConstVal; break; default: Internal ("Unexpected token: %d", tok); } } else { @@ -1375,7 +1570,7 @@ static void unaryop (int tok, struct expent* lval) exprhs (CF_NONE, k, lval); /* Get the type of the expression */ - flags = TypeOf (lval->e_tptr); + flags = TypeOf (lval->Type); /* Handle the operation */ switch (tok) { @@ -1384,59 +1579,19 @@ static void unaryop (int tok, struct expent* lval) case TOK_COMP: g_com (flags); break; default: Internal ("Unexpected token: %d", tok); } - lval->e_flags = E_MEXPR; + lval->Flags = E_MEXPR; } } -static int typecast (struct expent* lval) -/* Handle an explicit cast */ -{ - int k; - type Type[MAXTYPELEN]; - unsigned rflags; - - /* Skip the left paren */ - NextToken (); - - /* Read the type */ - ParseType (Type); - - /* Closing paren */ - ConsumeRParen (); - - /* Read the expression we have to cast */ - k = hie10 (lval); - - /* Get the type of the expression and honor constant values */ - rflags = TypeOf (lval->e_tptr); - if (lval->e_flags & E_MCONST) { - rflags |= CF_CONST; - } - - /* Do the actual cast. Special handling for void casts */ - if (!IsVoid (Type)) { - /* Mark the lhs as const to avoid a manipulation of TOS */ - g_typecast (TypeOf (Type) | CF_CONST, rflags); - } - - /* Use the new type */ - lval->e_tptr = TypeDup (Type); - - /* Done */ - return k; -} - - - -static int hie10 (struct expent* lval) +int hie10 (ExprDesc* lval) /* Handle ++, --, !, unary - etc. */ { int k; type* t; - switch (curtok) { + switch (CurTok.Tok) { case TOK_INC: pre_incdec (lval, g_inc); @@ -1449,81 +1604,92 @@ static int hie10 (struct expent* lval) case TOK_PLUS: case TOK_MINUS: case TOK_COMP: - unaryop (curtok, lval); + unaryop (CurTok.Tok, lval); return 0; case TOK_BOOL_NOT: NextToken (); if (evalexpr (CF_NONE, hie10, lval) == 0) { - /* Constant expression */ - lval->e_const = !lval->e_const; + /* Constant expression */ + lval->ConstVal = !lval->ConstVal; } else { - g_bneg (TypeOf (lval->e_tptr)); - lval->e_test |= E_CC; /* bneg will set cc */ - lval->e_flags = E_MEXPR; /* say it's an expr */ + g_bneg (TypeOf (lval->Type)); + lval->Test |= E_CC; /* bneg will set cc */ + lval->Flags = E_MEXPR; /* say it's an expr */ } - return 0; /* expr not storable */ + return 0; /* expr not storable */ case TOK_STAR: NextToken (); if (evalexpr (CF_NONE, hie10, lval) != 0) { - /* Expression is not const, indirect value loaded into primary */ - lval->e_flags = E_MEXPR; - lval->e_const = 0; /* Offset is zero now */ + /* Expression is not const, indirect value loaded into primary */ + lval->Flags = E_MEXPR; + lval->ConstVal = 0; /* Offset is zero now */ } - t = lval->e_tptr; - if (IsPtr (t)) { - lval->e_tptr = Indirect (t); - } else { - Error (ERR_ILLEGAL_INDIRECT); - } - return 1; + /* If the expression is already a pointer to function, the + * additional dereferencing operator must be ignored. + */ + if (IsTypeFuncPtr (lval->Type)) { + /* Expression not storable */ + return 0; + } else { + if (IsClassPtr (lval->Type)) { + lval->Type = Indirect (lval->Type); + } else { + Error ("Illegal indirection"); + } + return 1; + } + break; case TOK_AND: NextToken (); k = hie10 (lval); - if (k == 0) { - /* Allow the & operator with an array */ - if (!IsArray (lval->e_tptr)) { - Error (ERR_ILLEGAL_ADDRESS); - } + /* 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"); + } } else { - t = TypeAlloc (TypeLen (lval->e_tptr) + 2); - t [0] = T_PTR; - TypeCpy (t + 1, lval->e_tptr); - lval->e_tptr = t; + t = TypeAlloc (TypeLen (lval->Type) + 2); + t [0] = T_PTR; + TypeCpy (t + 1, lval->Type); + lval->Type = t; } return 0; case TOK_SIZEOF: NextToken (); if (istypeexpr ()) { - type Type[MAXTYPELEN]; - NextToken (); - lval->e_const = SizeOf (ParseType (Type)); - ConsumeRParen (); + type Type[MAXTYPELEN]; + NextToken (); + lval->ConstVal = CheckedSizeOf (ParseType (Type)); + ConsumeRParen (); } else { - /* Remember the output queue pointer */ - CodeMark Mark = GetCodePos (); - hie10 (lval); - lval->e_const = SizeOf (lval->e_tptr); - /* Remove any generated code */ - RemoveCode (Mark); + /* Remember the output queue pointer */ + CodeMark Mark = GetCodePos (); + hie10 (lval); + lval->ConstVal = CheckedSizeOf (lval->Type); + /* Remove any generated code */ + RemoveCode (Mark); } - lval->e_flags = E_MCONST | E_TCONST; - lval->e_tptr = type_uint; - lval->e_test &= ~E_CC; + lval->Flags = E_MCONST | E_TCONST; + lval->Type = type_uint; + lval->Test &= ~E_CC; return 0; default: if (istypeexpr ()) { - /* A cast */ - return typecast (lval); + /* A cast */ + return TypeCast (lval); } } k = hie11 (lval); - switch (curtok) { + switch (CurTok.Tok) { case TOK_INC: post_incdec (lval, k, g_inc); return 0; @@ -1539,18 +1705,18 @@ static int hie10 (struct expent* lval) -static int hie_internal (GenDesc** ops, /* List of generators */ - struct expent* lval, /* parent expr's lval */ - int (*hienext) (struct expent*), - int* UsedGen) /* next higher level */ +static int hie_internal (const GenDesc** ops, /* List of generators */ + ExprDesc* lval, /* parent expr's lval */ + int (*hienext) (ExprDesc*), + int* UsedGen) /* next higher level */ /* Helper function */ { int k; - struct expent lval2; + ExprDesc lval2; 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 */ @@ -1558,27 +1724,27 @@ static int hie_internal (GenDesc** ops, /* List of generators */ k = hienext (lval); *UsedGen = 0; - while ((Gen = FindGen (curtok, ops)) != 0) { + while ((Gen = FindGen (CurTok.Tok, ops)) != 0) { /* Tell the caller that we handled it's ops */ *UsedGen = 1; /* All operators that call this function expect an int on the lhs */ - if (!IsInt (lval->e_tptr)) { - Error (ERR_INT_EXPR_EXPECTED); + if (!IsClassInt (lval->Type)) { + Error ("Integer expression expected"); } /* Remember the operator token, then skip it */ - tok = curtok; + tok = CurTok.Tok; NextToken (); /* Get the lhs on stack */ Mark1 = GetCodePos (); - ltype = TypeOf (lval->e_tptr); - if (k == 0 && lval->e_flags == E_MCONST) { + ltype = TypeOf (lval->Type); + if (k == 0 && lval->Flags == E_MCONST) { /* Constant value */ Mark2 = GetCodePos (); - g_push (ltype | CF_CONST, lval->e_const); + g_push (ltype | CF_CONST, lval->ConstVal); } else { /* Value not constant */ exprhs (CF_NONE, k, lval); @@ -1590,22 +1756,22 @@ static int hie_internal (GenDesc** ops, /* List of generators */ rconst = (evalexpr (CF_NONE, hienext, &lval2) == 0); /* Check the type of the rhs */ - if (!IsInt (lval2.e_tptr)) { - Error (ERR_INT_EXPR_EXPECTED); + if (!IsClassInt (lval2.Type)) { + Error ("Integer expression expected"); } /* Check for const operands */ - if (k == 0 && lval->e_flags == E_MCONST && rconst) { + if (k == 0 && lval->Flags == E_MCONST && rconst) { /* Both operands are constant, remove the generated code */ RemoveCode (Mark1); pop (ltype); /* Evaluate the result */ - lval->e_const = kcalc (tok, lval->e_const, lval2.e_const); + lval->ConstVal = kcalc (tok, lval->ConstVal, lval2.ConstVal); /* Get the type of the result */ - lval->e_tptr = promoteint (lval->e_tptr, lval2.e_tptr); + lval->Type = promoteint (lval->Type, lval2.Type); } else { @@ -1613,16 +1779,16 @@ 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.e_tptr); + unsigned rtype = TypeOf (lval2.Type); type = 0; if (rconst) { /* Second value is constant - check for div */ type |= CF_CONST; rtype |= CF_CONST; - if (tok == TOK_DIV && lval2.e_const == 0) { - Error (ERR_DIV_BY_ZERO); - } else if (tok == TOK_MOD && lval2.e_const == 0) { - Error (ERR_MOD_BY_ZERO); + if (tok == TOK_DIV && lval2.ConstVal == 0) { + Error ("Division by zero"); + } else if (tok == TOK_MOD && lval2.ConstVal == 0) { + Error ("Modulo operation with zero"); } if ((Gen->Flags & GEN_NOPUSH) != 0) { RemoveCode (Mark2); @@ -1633,11 +1799,11 @@ static int hie_internal (GenDesc** ops, /* List of generators */ /* Determine the type of the operation result. */ type |= g_typeadjust (ltype, rtype); - lval->e_tptr = promoteint (lval->e_tptr, lval2.e_tptr); + lval->Type = promoteint (lval->Type, lval2.Type); /* Generate code */ - Gen->Func (type, lval2.e_const); - lval->e_flags = E_MEXPR; + Gen->Func (type, lval2.ConstVal); + lval->Flags = E_MEXPR; } /* We have a rvalue now */ @@ -1649,16 +1815,16 @@ static int hie_internal (GenDesc** ops, /* List of generators */ -static int hie_compare (GenDesc** ops, /* List of generators */ - struct expent* lval, /* parent expr's lval */ - int (*hienext) (struct expent*)) +static int hie_compare (const GenDesc** ops, /* List of generators */ + ExprDesc* lval, /* parent expr's lval */ + int (*hienext) (ExprDesc*)) /* Helper function for the compare operators */ { int k; - struct expent lval2; + ExprDesc lval2; CodeMark Mark1; CodeMark Mark2; - GenDesc* Gen; + const GenDesc* Gen; token_t tok; /* The operator token */ unsigned ltype; int rconst; /* Operand is a constant */ @@ -1666,19 +1832,19 @@ static int hie_compare (GenDesc** ops, /* List of generators */ k = hienext (lval); - while ((Gen = FindGen (curtok, ops)) != 0) { + while ((Gen = FindGen (CurTok.Tok, ops)) != 0) { /* Remember the operator token, then skip it */ - tok = curtok; + tok = CurTok.Tok; NextToken (); /* Get the lhs on stack */ Mark1 = GetCodePos (); - ltype = TypeOf (lval->e_tptr); - if (k == 0 && lval->e_flags == E_MCONST) { + ltype = TypeOf (lval->Type); + if (k == 0 && lval->Flags == E_MCONST) { /* Constant value */ Mark2 = GetCodePos (); - g_push (ltype | CF_CONST, lval->e_const); + g_push (ltype | CF_CONST, lval->ConstVal); } else { /* Value not constant */ exprhs (CF_NONE, k, lval); @@ -1690,35 +1856,35 @@ static int hie_compare (GenDesc** ops, /* List of generators */ rconst = (evalexpr (CF_NONE, hienext, &lval2) == 0); /* Make sure, the types are compatible */ - if (IsInt (lval->e_tptr)) { - if (!IsInt (lval2.e_tptr) && !(IsPtr(lval2.e_tptr) && IsNullPtr(lval))) { - Error (ERR_INCOMPATIBLE_TYPES); + if (IsClassInt (lval->Type)) { + if (!IsClassInt (lval2.Type) && !(IsClassPtr(lval2.Type) && IsNullPtr(lval))) { + Error ("Incompatible types"); } - } else if (IsPtr (lval->e_tptr)) { - if (IsPtr (lval2.e_tptr)) { + } else if (IsClassPtr (lval->Type)) { + if (IsClassPtr (lval2.Type)) { /* Both pointers are allowed in comparison if they point to * the same type, or if one of them is a void pointer. */ - type* left = Indirect (lval->e_tptr); - type* right = Indirect (lval2.e_tptr); - if (!EqualTypes (left, right) && *left != T_VOID && *right != T_VOID) { + type* left = Indirect (lval->Type); + type* right = Indirect (lval2.Type); + if (TypeCmp (left, right) < TC_EQUAL && *left != T_VOID && *right != T_VOID) { /* Incomatible pointers */ - Error (ERR_INCOMPATIBLE_TYPES); + Error ("Incompatible types"); } } else if (!IsNullPtr (&lval2)) { - Error (ERR_INCOMPATIBLE_TYPES); + Error ("Incompatible types"); } } /* Check for const operands */ - if (k == 0 && lval->e_flags == E_MCONST && rconst) { + if (k == 0 && lval->Flags == E_MCONST && rconst) { /* Both operands are constant, remove the generated code */ RemoveCode (Mark1); pop (ltype); /* Evaluate the result */ - lval->e_const = kcalc (tok, lval->e_const, lval2.e_const); + lval->ConstVal = kcalc (tok, lval->ConstVal, lval2.ConstVal); } else { @@ -1742,30 +1908,30 @@ static int hie_compare (GenDesc** ops, /* List of generators */ * operation as char operation. Otherwise the default * promotions are used. */ - if (IsChar (lval->e_tptr) && (IsChar (lval2.e_tptr) || rconst)) { + if (IsTypeChar (lval->Type) && (IsTypeChar (lval2.Type) || rconst)) { flags |= CF_CHAR; - if (IsUnsigned (lval->e_tptr) || IsUnsigned (lval2.e_tptr)) { + if (IsSignUnsigned (lval->Type) || IsSignUnsigned (lval2.Type)) { flags |= CF_UNSIGNED; } if (rconst) { flags |= CF_FORCECHAR; } } else { - unsigned rtype = TypeOf (lval2.e_tptr) | (flags & CF_CONST); + unsigned rtype = TypeOf (lval2.Type) | (flags & CF_CONST); flags |= g_typeadjust (ltype, rtype); } /* Generate code */ - Gen->Func (flags, lval2.e_const); - lval->e_flags = E_MEXPR; + Gen->Func (flags, lval2.ConstVal); + lval->Flags = E_MEXPR; } /* Result type is always int */ - lval->e_tptr = type_int; + lval->Type = type_int; /* We have a rvalue now, condition codes are set */ k = 0; - lval->e_test |= E_CC; + lval->Test |= E_CC; } return k; @@ -1773,10 +1939,10 @@ static int hie_compare (GenDesc** ops, /* List of generators */ -static int hie9 (struct expent *lval) +static int hie9 (ExprDesc *lval) /* Process * and / operators. */ { - static GenDesc* hie9_ops [] = { + static const GenDesc* hie9_ops [] = { &GenMUL, &GenDIV, &GenMOD, 0 }; int UsedGen; @@ -1786,13 +1952,13 @@ static int hie9 (struct expent *lval) -static void parseadd (int k, struct expent* lval) +static void parseadd (int k, ExprDesc* lval) /* Parse an expression with the binary plus operator. lval contains the * unprocessed left hand side of the expression and will contain the * result of the expression on return. */ { - struct expent lval2; + ExprDesc lval2; unsigned flags; /* Operation flags */ CodeMark Mark; /* Remember code position */ type* lhst; /* Type of left hand side */ @@ -1803,71 +1969,126 @@ static void parseadd (int k, struct expent* lval) NextToken (); /* Get the left hand side type, initialize operation flags */ - lhst = lval->e_tptr; + lhst = lval->Type; flags = 0; /* Check for constness on both sides */ - if (k == 0 && lval->e_flags == E_MCONST) { + if (k == 0 && (lval->Flags & E_MCONST) != 0) { /* The left hand side is a constant. Good. Get rhs */ - if (evalexpr (CF_NONE, hie9, &lval2) == 0) { + k = hie9 (&lval2); + if (k == 0 && lval2.Flags == E_MCONST) { /* Right hand side is also constant. Get the rhs type */ - rhst = lval2.e_tptr; + rhst = lval2.Type; /* Both expressions are constants. Check for pointer arithmetic */ - if (IsPtr (lhst) && IsInt (rhst)) { + if (IsClassPtr (lhst) && IsClassInt (rhst)) { /* Left is pointer, right is int, must scale rhs */ - lval->e_const = lval->e_const + lval2.e_const * PSizeOf (lhst); + lval->ConstVal += lval2.ConstVal * CheckedPSizeOf (lhst); /* Result type is a pointer */ - } else if (IsInt (lhst) && IsPtr (rhst)) { + } else if (IsClassInt (lhst) && IsClassPtr (rhst)) { /* Left is int, right is pointer, must scale lhs */ - lval->e_const = lval->e_const * PSizeOf (rhst) + lval2.e_const; + lval->ConstVal = lval->ConstVal * CheckedPSizeOf (rhst) + lval2.ConstVal; /* Result type is a pointer */ - lval->e_tptr = lval2.e_tptr; - } else if (IsInt (lhst) && IsInt (rhst)) { + lval->Type = lval2.Type; + } else if (IsClassInt (lhst) && IsClassInt (rhst)) { /* Integer addition */ - lval->e_const += lval2.e_const; + lval->ConstVal += lval2.ConstVal; typeadjust (lval, &lval2, 1); } else { /* OOPS */ - Error (ERR_OP_NOT_ALLOWED); + Error ("Invalid operands for binary operator `+'"); } /* Result is constant, condition codes not set */ - lval->e_test = E_MCONST; + lval->Test &= ~E_CC; } else { - /* lhs is constant, rhs is not. Get the rhs type. */ - rhst = lval2.e_tptr; + /* lhs is a constant and rhs is not constant. Load rhs into + * the primary. + */ + exprhs (CF_NONE, k, &lval2); + + /* 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 = lval2.Type; + + /* Setup flags */ + if (lval->Flags == E_MCONST) { + /* A numerical constant */ + flags |= CF_CONST; + } else { + /* Constant address label */ + flags |= GlobalModeFlags (lval->Flags) | CF_CONSTADDR; + } /* Check for pointer arithmetic */ - if (IsPtr (lhst) && IsInt (rhst)) { + 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 (IsInt (lhst) && IsPtr (rhst)) { - /* Left is int, right is pointer, must scale lhs */ - lval->e_const *= PSizeOf (rhst); - /* Operate on pointers, result type is a pointer */ - flags = CF_PTR; - lval->e_tptr = lval2.e_tptr; - } else if (IsInt (lhst) && IsInt (rhst)) { + flags |= CF_PTR; + /* Generate the code for the add */ + if (lval->Flags == E_MCONST) { + /* Numeric constant */ + g_inc (flags, lval->ConstVal); + } else { + /* Constant address */ + g_addaddr_static (flags, lval->Name, lval->ConstVal); + } + } else if (IsClassInt (lhst) && IsClassPtr (rhst)) { + + /* Left is int, right is pointer, must scale lhs. */ + unsigned ScaleFactor = CheckedPSizeOf (rhst); + + /* Operate on pointers, result type is a pointer */ + flags |= CF_PTR; + lval->Type = lval2.Type; + + /* Since we do already have rhs in the primary, if lhs is + * not a numeric constant, and the scale factor is not one + * (no scaling), we must take the long way over the stack. + */ + if (lval->Flags == E_MCONST) { + /* Numeric constant, scale lhs */ + lval->ConstVal *= ScaleFactor; + /* Generate the code for the add */ + g_inc (flags, lval->ConstVal); + } else if (ScaleFactor == 1) { + /* Constant address but no need to scale */ + g_addaddr_static (flags, lval->Name, lval->ConstVal); + } else { + /* Constant address that must be scaled */ + g_push (TypeOf (lval2.Type), 0); /* rhs --> stack */ + g_getimmed (flags, lval->Name, lval->ConstVal); + g_scale (CF_PTR, ScaleFactor); + g_add (CF_PTR, 0); + } + } else if (IsClassInt (lhst) && IsClassInt (rhst)) { /* Integer addition */ - flags = typeadjust (lval, &lval2, 1); + flags |= typeadjust (lval, &lval2, 1); + /* Generate the code for the add */ + if (lval->Flags == E_MCONST) { + /* Numeric constant */ + g_inc (flags, lval->ConstVal); + } else { + /* Constant address */ + g_addaddr_static (flags, lval->Name, lval->ConstVal); + } } else { /* OOPS */ - Error (ERR_OP_NOT_ALLOWED); + Error ("Invalid operands for binary operator `+'"); } - /* Generate code for the add */ - g_inc (flags | CF_CONST, lval->e_const); - /* Result is in primary register */ - lval->e_flags = E_MEXPR; - lval->e_test &= ~E_CC; + lval->Flags = E_MEXPR; + lval->Test &= ~E_CC; } @@ -1876,78 +2097,86 @@ static void parseadd (int k, struct expent* lval) /* Left hand side is not constant. Get the value onto the stack. */ exprhs (CF_NONE, k, lval); /* --> primary register */ Mark = GetCodePos (); - g_push (TypeOf (lval->e_tptr), 0); /* --> stack */ + g_push (TypeOf (lval->Type), 0); /* --> stack */ /* Evaluate the rhs */ if (evalexpr (CF_NONE, hie9, &lval2) == 0) { /* Right hand side is a constant. Get the rhs type */ - rhst = lval2.e_tptr; + rhst = lval2.Type; /* Remove pushed value from stack */ RemoveCode (Mark); - pop (TypeOf (lval->e_tptr)); + pop (TypeOf (lval->Type)); /* Check for pointer arithmetic */ - if (IsPtr (lhst) && IsInt (rhst)) { + if (IsClassPtr (lhst) && IsClassInt (rhst)) { /* Left is pointer, right is int, must scale rhs */ - lval2.e_const *= PSizeOf (lhst); + lval2.ConstVal *= CheckedPSizeOf (lhst); /* Operate on pointers, result type is a pointer */ flags = CF_PTR; - } else if (IsInt (lhst) && IsPtr (rhst)) { + } 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->e_tptr = lval2.e_tptr; - } else if (IsInt (lhst) && IsInt (rhst)) { + lval->Type = lval2.Type; + } else if (IsClassInt (lhst) && IsClassInt (rhst)) { /* Integer addition */ flags = typeadjust (lval, &lval2, 1); } else { /* OOPS */ - Error (ERR_OP_NOT_ALLOWED); + Error ("Invalid operands for binary operator `+'"); } /* Generate code for the add */ - g_inc (flags | CF_CONST, lval2.e_const); + g_inc (flags | CF_CONST, lval2.ConstVal); /* Result is in primary register */ - lval->e_flags = E_MEXPR; - lval->e_test &= ~E_CC; + lval->Flags = E_MEXPR; + lval->Test &= ~E_CC; } else { /* lhs and rhs are not constant. Get the rhs type. */ - rhst = lval2.e_tptr; + rhst = lval2.Type; /* Check for pointer arithmetic */ - if (IsPtr (lhst) && IsInt (rhst)) { + 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 (IsInt (lhst) && IsPtr (rhst)) { + } 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_scale (CF_INT, CheckedPSizeOf (rhst)); /* Operate on pointers, result type is a pointer */ flags = CF_PTR; - lval->e_tptr = lval2.e_tptr; - } else if (IsInt (lhst) && IsInt (rhst)) { - /* Integer addition */ - flags = typeadjust (lval, &lval2, 0); + lval->Type = lval2.Type; + } else if (IsClassInt (lhst) && IsClassInt (rhst)) { + /* Integer addition. Note: Result is never constant. + * Problem here is that typeadjust does not know if the + * variable is an rvalue or lvalue, so if both operands + * are dereferenced constant numeric addresses, typeadjust + * thinks the operation works on constants. Removing + * CF_CONST here means handling the symptoms, however, the + * whole parser is such a mess that I fear to break anything + * when trying to apply another solution. + */ + flags = typeadjust (lval, &lval2, 0) & ~CF_CONST; } else { /* OOPS */ - Error (ERR_OP_NOT_ALLOWED); + Error ("Invalid operands for binary operator `+'"); } /* Generate code for the add */ g_add (flags, 0); /* Result is in primary register */ - lval->e_flags = E_MEXPR; - lval->e_test &= ~E_CC; + lval->Flags = E_MEXPR; + lval->Test &= ~E_CC; } @@ -1956,18 +2185,18 @@ static void parseadd (int k, struct expent* lval) -static void parsesub (int k, struct expent* lval) +static void parsesub (int k, ExprDesc* lval) /* Parse an expression with the binary minus operator. lval contains the * unprocessed left hand side of the expression and will contain the * result of the expression on return. */ { - struct expent lval2; + ExprDesc lval2; unsigned flags; /* Operation flags */ type* lhst; /* Type of left hand side */ type* rhst; /* Type of right hand side */ CodeMark Mark1; /* Save position of output queue */ - CodeMark Mark2; /* Another position in the queue */ + CodeMark Mark2; /* Another position in the queue */ int rscale; /* Scale factor for the result */ @@ -1975,7 +2204,7 @@ static void parsesub (int k, struct expent* lval) NextToken (); /* Get the left hand side type, initialize operation flags */ - lhst = lval->e_tptr; + lhst = lval->Type; flags = 0; rscale = 1; /* Scale by 1, that is, don't scale */ @@ -1989,41 +2218,42 @@ static void parsesub (int k, struct expent* lval) if (evalexpr (CF_NONE, hie9, &lval2) == 0) { /* The right hand side is constant. Get the rhs type. */ - rhst = lval2.e_tptr; + rhst = lval2.Type; /* Check left hand side */ - if (k == 0 && lval->e_flags & E_MCONST) { + if (k == 0 && (lval->Flags & E_MCONST) != 0) { /* Both sides are constant, remove generated code */ RemoveCode (Mark1); pop (TypeOf (lhst)); /* Clean up the stack */ /* Check for pointer arithmetic */ - if (IsPtr (lhst) && IsInt (rhst)) { + if (IsClassPtr (lhst) && IsClassInt (rhst)) { /* Left is pointer, right is int, must scale rhs */ - lval->e_const -= lval2.e_const * PSizeOf (lhst); + lval->ConstVal -= lval2.ConstVal * CheckedPSizeOf (lhst); /* Operate on pointers, result type is a pointer */ - } else if (IsPtr (lhst) && IsPtr (rhst)) { + } else if (IsClassPtr (lhst) && IsClassPtr (rhst)) { /* Left is pointer, right is pointer, must scale result */ - if (TypeCmp (Indirect (lhst), Indirect (rhst)) != 0) { - Error (ERR_INCOMPATIBLE_POINTERS); + if (TypeCmp (Indirect (lhst), Indirect (rhst)) < TC_QUAL_DIFF) { + Error ("Incompatible pointer types"); } else { - lval->e_const = (lval->e_const - lval2.e_const) / PSizeOf (lhst); + lval->ConstVal = (lval->ConstVal - lval2.ConstVal) / + CheckedPSizeOf (lhst); } /* Operate on pointers, result type is an integer */ - lval->e_tptr = type_int; - } else if (IsInt (lhst) && IsInt (rhst)) { + lval->Type = type_int; + } else if (IsClassInt (lhst) && IsClassInt (rhst)) { /* Integer subtraction */ typeadjust (lval, &lval2, 1); - lval->e_const -= lval2.e_const; + lval->ConstVal -= lval2.ConstVal; } else { /* OOPS */ - Error (ERR_OP_NOT_ALLOWED); + Error ("Invalid operands for binary operator `-'"); } /* Result is constant, condition codes not set */ - lval->e_flags = E_MCONST; - lval->e_test &= ~E_CC; + /* lval->Flags = E_MCONST; ### */ + lval->Test &= ~E_CC; } else { @@ -2033,31 +2263,31 @@ static void parsesub (int k, struct expent* lval) RemoveCode (Mark2); pop (TypeOf (lhst)); - if (IsPtr (lhst) && IsInt (rhst)) { + if (IsClassPtr (lhst) && IsClassInt (rhst)) { /* Left is pointer, right is int, must scale rhs */ - lval2.e_const *= PSizeOf (lhst); + lval2.ConstVal *= CheckedPSizeOf (lhst); /* Operate on pointers, result type is a pointer */ flags = CF_PTR; - } else if (IsPtr (lhst) && IsPtr (rhst)) { + } else if (IsClassPtr (lhst) && IsClassPtr (rhst)) { /* Left is pointer, right is pointer, must scale result */ - if (TypeCmp (Indirect (lhst), Indirect (rhst)) != 0) { - Error (ERR_INCOMPATIBLE_POINTERS); + 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->e_tptr = type_int; - } else if (IsInt (lhst) && IsInt (rhst)) { + lval->Type = type_int; + } else if (IsClassInt (lhst) && IsClassInt (rhst)) { /* Integer subtraction */ flags = typeadjust (lval, &lval2, 1); } else { /* OOPS */ - Error (ERR_OP_NOT_ALLOWED); + Error ("Invalid operands for binary operator `-'"); } /* Do the subtraction */ - g_dec (flags | CF_CONST, lval2.e_const); + g_dec (flags | CF_CONST, lval2.ConstVal); /* If this was a pointer subtraction, we must scale the result */ if (rscale != 1) { @@ -2065,45 +2295,45 @@ static void parsesub (int k, struct expent* lval) } /* Result is in primary register */ - lval->e_flags = E_MEXPR; - lval->e_test &= ~E_CC; + lval->Flags = E_MEXPR; + lval->Test &= ~E_CC; } } else { /* Right hand side is not constant. Get the rhs type. */ - rhst = lval2.e_tptr; + rhst = lval2.Type; /* Check for pointer arithmetic */ - if (IsPtr (lhst) && IsInt (rhst)) { + 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 (IsPtr (lhst) && IsPtr (rhst)) { + } else if (IsClassPtr (lhst) && IsClassPtr (rhst)) { /* Left is pointer, right is pointer, must scale result */ - if (TypeCmp (Indirect (lhst), Indirect (rhst)) != 0) { - Error (ERR_INCOMPATIBLE_POINTERS); + 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->e_tptr = type_int; - } else if (IsInt (lhst) && IsInt (rhst)) { + lval->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->e_flags == E_MCONST) { - lval->e_flags = E_MEXPR; + if (lval->Flags == E_MCONST) { + lval->Flags = E_MEXPR; } /* Adjust operand types */ flags = typeadjust (lval, &lval2, 0); } else { /* OOPS */ - Error (ERR_OP_NOT_ALLOWED); + Error ("Invalid operands for binary operator `-'"); } /* Generate code for the sub (the & is a hack here) */ @@ -2115,20 +2345,20 @@ static void parsesub (int k, struct expent* lval) } /* Result is in primary register */ - lval->e_flags = E_MEXPR; - lval->e_test &= ~E_CC; + lval->Flags = E_MEXPR; + lval->Test &= ~E_CC; } } -static int hie8 (struct expent* lval) +static int hie8 (ExprDesc* lval) /* Process + and - binary operators. */ { int k = hie9 (lval); - while (curtok == TOK_PLUS || curtok == TOK_MINUS) { + while (CurTok.Tok == TOK_PLUS || CurTok.Tok == TOK_MINUS) { - if (curtok == TOK_PLUS) { + if (CurTok.Tok == TOK_PLUS) { parseadd (k, lval); } else { parsesub (k, lval); @@ -2141,10 +2371,10 @@ static int hie8 (struct expent* lval) -static int hie7 (struct expent *lval) +static int hie7 (ExprDesc *lval) /* Parse << and >>. */ { - static GenDesc* hie7_ops [] = { + static const GenDesc* hie7_ops [] = { &GenASL, &GenASR, 0 }; int UsedGen; @@ -2154,10 +2384,10 @@ static int hie7 (struct expent *lval) -static int hie6 (struct expent *lval) +static int hie6 (ExprDesc *lval) /* process greater-than type comparators */ { - static GenDesc* hie6_ops [] = { + static const GenDesc* hie6_ops [] = { &GenLT, &GenLE, &GenGE, &GenGT, 0 }; return hie_compare (hie6_ops, lval, hie7); @@ -2165,9 +2395,9 @@ static int hie6 (struct expent *lval) -static int hie5 (struct expent *lval) +static int hie5 (ExprDesc *lval) { - static GenDesc* hie5_ops[] = { + static const GenDesc* hie5_ops[] = { &GenEQ, &GenNE, 0 }; return hie_compare (hie5_ops, lval, hie6); @@ -2175,10 +2405,10 @@ static int hie5 (struct expent *lval) -static int hie4 (struct expent* lval) +static int hie4 (ExprDesc* lval) /* Handle & (bitwise and) */ { - static GenDesc* hie4_ops [] = { + static const GenDesc* hie4_ops [] = { &GenAND, 0 }; int UsedGen; @@ -2188,10 +2418,10 @@ static int hie4 (struct expent* lval) -static int hie3 (struct expent *lval) +static int hie3 (ExprDesc *lval) /* Handle ^ (bitwise exclusive or) */ { - static GenDesc* hie3_ops [] = { + static const GenDesc* hie3_ops [] = { &GenXOR, 0 }; int UsedGen; @@ -2201,10 +2431,10 @@ static int hie3 (struct expent *lval) -static int hie2 (struct expent *lval) +static int hie2 (ExprDesc *lval) /* Handle | (bitwise or) */ { - static GenDesc* hie2_ops [] = { + static const GenDesc* hie2_ops [] = { &GenOR, 0 }; int UsedGen; @@ -2214,25 +2444,101 @@ static int hie2 (struct expent *lval) -static int hieAnd (struct expent* lval, unsigned TrueLab, int* BoolOp) +static int hieAndPP (ExprDesc* lval) +/* Process "exp && exp" in preprocessor mode (that is, when the parser is + * called recursively from the preprocessor. + */ +{ + ExprDesc lval2; + + ConstSubExpr (hie2, lval); + 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); + } + + /* Combine the two */ + lval->ConstVal = (lval->ConstVal && lval2.ConstVal); + } + + /* Always a rvalue */ + return 0; +} + + + +static int hieOrPP (ExprDesc *lval) +/* Process "exp || exp" in preprocessor mode (that is, when the parser is + * called recursively from the preprocessor. + */ +{ + ExprDesc lval2; + + ConstSubExpr (hieAndPP, lval); + 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); + } + + /* Combine the two */ + lval->ConstVal = (lval->ConstVal || lval2.ConstVal); + } + + /* Always a rvalue */ + return 0; +} + + + +static int hieAnd (ExprDesc* lval, unsigned TrueLab, int* BoolOp) /* Process "exp && exp" */ { int k; int lab; - struct expent lval2; + ExprDesc lval2; k = hie2 (lval); - if (curtok == TOK_BOOL_AND) { + if (CurTok.Tok == TOK_BOOL_AND) { /* Tell our caller that we're evaluating a boolean */ *BoolOp = 1; /* Get a label that we will use for false expressions */ - lab = GetLabel (); + lab = GetLocalLabel (); /* If the expr hasn't set condition codes, set the force-test flag */ - if ((lval->e_test & E_CC) == 0) { - lval->e_test |= E_FORCETEST; + if ((lval->Test & E_CC) == 0) { + lval->Test |= E_FORCETEST; } /* Load the value */ @@ -2242,20 +2548,20 @@ static int hieAnd (struct expent* lval, unsigned TrueLab, int* BoolOp) g_falsejump (CF_NONE, lab); /* Parse more boolean and's */ - while (curtok == TOK_BOOL_AND) { + while (CurTok.Tok == TOK_BOOL_AND) { /* Skip the && */ NextToken (); /* Get rhs */ k = hie2 (&lval2); - if ((lval2.e_test & E_CC) == 0) { - lval2.e_test |= E_FORCETEST; + if ((lval2.Test & E_CC) == 0) { + lval2.Test |= E_FORCETEST; } exprhs (CF_FORCECHAR, k, &lval2); /* Do short circuit evaluation */ - if (curtok == TOK_BOOL_AND) { + if (CurTok.Tok == TOK_BOOL_AND) { g_falsejump (CF_NONE, lab); } else { /* Last expression - will evaluate to true */ @@ -2264,11 +2570,11 @@ static int hieAnd (struct expent* lval, unsigned TrueLab, int* BoolOp) } /* Define the false jump label here */ - g_defloclabel (lab); + g_defcodelabel (lab); /* Define the label */ - lval->e_flags = E_MEXPR; - lval->e_test |= E_CC; /* Condition codes are set */ + lval->Flags = E_MEXPR; + lval->Test |= E_CC; /* Condition codes are set */ k = 0; } return k; @@ -2276,28 +2582,28 @@ static int hieAnd (struct expent* lval, unsigned TrueLab, int* BoolOp) -static int hieOr (struct expent *lval) +static int hieOr (ExprDesc *lval) /* Process "exp || exp". */ { int k; - struct expent lval2; + 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 */ unsigned DoneLab; /* Get a label */ - TrueLab = GetLabel (); + TrueLab = GetLocalLabel (); /* Call the next level parser */ k = hieAnd (lval, TrueLab, &BoolOp); /* Any boolean or's? */ - if (curtok == TOK_BOOL_OR) { + if (CurTok.Tok == TOK_BOOL_OR) { /* If the expr hasn't set condition codes, set the force-test flag */ - if ((lval->e_test & E_CC) == 0) { - lval->e_test |= E_FORCETEST; + if ((lval->Test & E_CC) == 0) { + lval->Test |= E_FORCETEST; } /* Get first expr */ @@ -2314,7 +2620,7 @@ static int hieOr (struct expent *lval) BoolOp = 1; /* while there's more expr */ - while (curtok == TOK_BOOL_OR) { + while (CurTok.Tok == TOK_BOOL_OR) { /* skip the || */ NextToken (); @@ -2322,77 +2628,77 @@ static int hieOr (struct expent *lval) /* Get a subexpr */ AndOp = 0; k = hieAnd (&lval2, TrueLab, &AndOp); - if ((lval2.e_test & E_CC) == 0) { - lval2.e_test |= E_FORCETEST; + if ((lval2.Test & E_CC) == 0) { + lval2.Test |= E_FORCETEST; } exprhs (CF_FORCECHAR, k, &lval2); - /* If there is more to come, add shortcut boolean eval. - * Beware: If we had && operators, the jump is already - * in place! - */ -#if 0 -/* Seems this sometimes generates wrong code */ - if (curtok == TOK_BOOL_OR && !AndOp) { - g_truejump (CF_NONE, TrueLab); - } -#else + /* If there is more to come, add shortcut boolean eval. */ g_truejump (CF_NONE, TrueLab); -#endif - } - lval->e_flags = E_MEXPR; - lval->e_test |= E_CC; /* Condition codes are set */ + + } + lval->Flags = E_MEXPR; + lval->Test |= E_CC; /* Condition codes are set */ k = 0; } /* If we really had boolean ops, generate the end sequence */ if (BoolOp) { - DoneLab = GetLabel (); + DoneLab = GetLocalLabel (); g_getimmed (CF_INT | CF_CONST, 0, 0); /* Load FALSE */ g_falsejump (CF_NONE, DoneLab); - g_defloclabel (TrueLab); + g_defcodelabel (TrueLab); g_getimmed (CF_INT | CF_CONST, 1, 0); /* Load TRUE */ - g_defloclabel (DoneLab); + g_defcodelabel (DoneLab); } return k; } -static int hieQuest (struct expent *lval) +static int hieQuest (ExprDesc *lval) /* Parse "lvalue ? exp : exp" */ { int k; int labf; int labt; - struct expent lval2; /* Expression 2 */ - struct expent lval3; /* Expression 3 */ + 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 */ - - k = hieOr (lval); - if (curtok == TOK_QUEST) { + k = Preprocessing? hieOrPP (lval) : hieOr (lval); + if (CurTok.Tok == TOK_QUEST) { NextToken (); - if ((lval->e_test & E_CC) == 0) { + if ((lval->Test & E_CC) == 0) { /* Condition codes not set, force a test */ - lval->e_test |= E_FORCETEST; + lval->Test |= E_FORCETEST; } exprhs (CF_NONE, k, lval); - labf = GetLabel (); + labf = GetLocalLabel (); g_falsejump (CF_NONE, labf); - /* Parse second and third expression */ - expression1 (&lval2); - labt = GetLabel (); + /* Parse second expression */ + k = expr (hie1, &lval2); + type2 = lval2.Type; + if (!IsTypeVoid (lval2.Type)) { + /* Load it into the primary */ + exprhs (CF_NONE, k, &lval2); + } + labt = GetLocalLabel (); ConsumeColon (); g_jump (labt); - g_defloclabel (labf); - expression1 (&lval3); + + /* Parse the third expression */ + g_defcodelabel (labf); + k = expr (hie1, &lval3); + type3 = lval3.Type; + if (!IsTypeVoid (lval3.Type)) { + /* Load it into the primary */ + exprhs (CF_NONE, k, &lval3); + } /* Check if any conversions are needed, if so, do them. * Conversion rules for ?: expression are: @@ -2403,11 +2709,11 @@ static int hieQuest (struct expent *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.e_tptr; - type3 = lval3.e_tptr; - if (IsInt (type2) && IsInt (type3)) { + if (IsClassInt (type2) && IsClassInt (type3)) { /* Get common type */ rtype = promoteint (type2, type3); @@ -2418,54 +2724,48 @@ static int hieQuest (struct expent *lval) /* Setup a new label so that the expr3 code will jump around * the type cast code for expr2. */ - labf = GetLabel (); /* Get new label */ - Mark1 = GetCodePos (); /* Remember current position */ + labf = GetLocalLabel (); /* Get new label */ g_jump (labf); /* Jump around code */ /* The jump for expr2 goes here */ - g_defloclabel (labt); + g_defcodelabel (labt); /* Create the typecast code for expr2 */ - Mark2 = GetCodePos (); /* Remember position */ g_typecast (TypeOf (rtype), TypeOf (type2)); - /* If the typecast did not produce code, remove the jump, - * otherwise output the label. - */ - if (GetCodePos() == Mark2) { - RemoveCode (Mark1); /* Remove code */ - } else { - /* We have typecast code, output label */ - g_defloclabel (labf); - labt = 0; /* Mark other label as invalid */ - } + /* Jump here around the typecase code. */ + g_defcodelabel (labf); + labt = 0; /* Mark other label as invalid */ - } else if (IsPtr (type2) && IsPtr (type3)) { + } else if (IsClassPtr (type2) && IsClassPtr (type3)) { /* Must point to same type */ - if (TypeCmp (Indirect (type2), Indirect (type3)) != 0) { - Error (ERR_INCOMPATIBLE_TYPES); + if (TypeCmp (Indirect (type2), Indirect (type3)) < TC_EQUAL) { + Error ("Incompatible pointer types"); } /* Result has the common type */ - rtype = lval2.e_tptr; - } else if (IsPtr (type2) && IsNullPtr (&lval3)) { + rtype = lval2.Type; + } else if (IsClassPtr (type2) && IsNullPtr (&lval3)) { /* Result type is pointer, no cast needed */ - rtype = lval2.e_tptr; - } else if (IsNullPtr (&lval2) && IsPtr (type3)) { + rtype = lval2.Type; + } else if (IsNullPtr (&lval2) && IsClassPtr (type3)) { /* Result type is pointer, no cast needed */ - rtype = lval3.e_tptr; + rtype = lval3.Type; + } else if (IsTypeVoid (type2) && IsTypeVoid (type3)) { + /* Result type is void */ + rtype = lval3.Type; } else { - Error (ERR_INCOMPATIBLE_TYPES); - rtype = lval2.e_tptr; /* Doesn't matter here */ + Error ("Incompatible types"); + rtype = lval2.Type; /* Doesn't matter here */ } /* If we don't have the label defined until now, do it */ if (labt) { - g_defloclabel (labt); + g_defcodelabel (labt); } /* Setup the target expression */ - lval->e_flags = E_MEXPR; - lval->e_tptr = rtype; + lval->Flags = E_MEXPR; + lval->Type = rtype; k = 0; } return k; @@ -2473,24 +2773,24 @@ static int hieQuest (struct expent *lval) -static void opeq (GenDesc* Gen, struct expent *lval, int k) +static void opeq (const GenDesc* Gen, ExprDesc *lval, int k) /* Process "op=" operators. */ { - struct expent lval2; + ExprDesc lval2; unsigned flags; CodeMark Mark; int MustScale; NextToken (); if (k == 0) { - Error (ERR_LVALUE_EXPECTED); + Error ("Invalid lvalue in assignment"); return; } /* Determine the type of the lhs */ - flags = TypeOf (lval->e_tptr); + flags = TypeOf (lval->Type); MustScale = (Gen->Func == g_add || Gen->Func == g_sub) && - lval->e_tptr [0] == T_PTR; + lval->Type [0] == T_PTR; /* Get the lhs address on stack (if needed) */ PushAddr (lval); @@ -2513,65 +2813,66 @@ static void opeq (GenDesc* Gen, struct expent *lval, int k) } if (MustScale) { /* lhs is a pointer, scale rhs */ - lval2.e_const *= SizeOf (lval->e_tptr+1); + lval2.ConstVal *= CheckedSizeOf (lval->Type+1); } /* If the lhs is character sized, the operation may be later done * with characters. */ - if (SizeOf (lval->e_tptr) == 1) { + if (CheckedSizeOf (lval->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.e_const); + g_inc (flags | CF_CONST, lval2.ConstVal); } else if (Gen->Func == g_sub) { - g_dec (flags | CF_CONST, lval2.e_const); + g_dec (flags | CF_CONST, lval2.ConstVal); } else { - Gen->Func (flags | CF_CONST, lval2.e_const); + Gen->Func (flags | CF_CONST, lval2.ConstVal); } } else { /* rhs is not constant and already in the primary register */ if (MustScale) { /* lhs is a pointer, scale rhs */ - g_scale (TypeOf (lval2.e_tptr), SizeOf (lval->e_tptr+1)); + g_scale (TypeOf (lval2.Type), CheckedSizeOf (lval->Type+1)); } /* If the lhs is character sized, the operation may be later done * with characters. */ - if (SizeOf (lval->e_tptr) == 1) { + if (CheckedSizeOf (lval->Type) == SIZEOF_CHAR) { flags |= CF_FORCECHAR; } /* Adjust the types of the operands if needed */ - Gen->Func (g_typeadjust (flags, TypeOf (lval2.e_tptr)), 0); + Gen->Func (g_typeadjust (flags, TypeOf (lval2.Type)), 0); } - store (lval); - lval->e_flags = E_MEXPR; + Store (lval, 0); + lval->Flags = E_MEXPR; } -static void addsubeq (GenDesc* Gen, struct expent *lval, int k) +static void addsubeq (const GenDesc* Gen, ExprDesc *lval, int k) /* Process the += and -= operators */ { - struct expent lval2; - unsigned flags; + ExprDesc lval2; + unsigned lflags; + unsigned rflags; int MustScale; + /* We must have an lvalue */ if (k == 0) { - Error (ERR_LVALUE_EXPECTED); + Error ("Invalid lvalue in assignment"); return; } - /* We're currently only able to handle some adressing modes */ - if ((lval->e_flags & E_MGLOBAL) == 0 && /* Global address? */ - (lval->e_flags & E_MLOCAL) == 0 && /* Local address? */ - (lval->e_flags & E_MCONST) == 0) { /* Constant address? */ + 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; @@ -2581,150 +2882,84 @@ static void addsubeq (GenDesc* Gen, struct expent *lval, int k) NextToken (); /* Check if we have a pointer expression and must scale rhs */ - MustScale = (lval->e_tptr [0] == T_PTR); + MustScale = (lval->Type [0] == T_PTR); - /* Determine the code generator flags */ - flags = TypeOf (lval->e_tptr) | 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. */ + /* The resulting value is a constant. */ if (MustScale) { - /* lhs is a pointer, scale rhs */ - lval2.e_const *= SizeOf (lval->e_tptr+1); - } - flags |= CF_CONST; + /* lhs is a pointer, scale rhs */ + lval2.ConstVal *= CheckedSizeOf (lval->Type+1); + } + rflags |= CF_CONST; + lflags |= CF_CONST; } else { - /* rhs is not constant and already in the primary register */ + /* rhs is not constant and already in the primary register */ if (MustScale) { - /* lhs is a pointer, scale rhs */ - g_scale (TypeOf (lval2.e_tptr), SizeOf (lval->e_tptr+1)); - } + /* lhs is a pointer, scale rhs */ + g_scale (TypeOf (lval2.Type), CheckedSizeOf (lval->Type+1)); + } } - /* Adjust the rhs to the lhs */ - g_typeadjust (flags, TypeOf (lval2.e_tptr)); + /* Setup the code generator flags */ + lflags |= TypeOf (lval->Type) | CF_FORCECHAR; + rflags |= TypeOf (lval2.Type); + + /* Cast the rhs to the type of the lhs */ + g_typecast (lflags, rflags); /* Output apropriate code */ - if (lval->e_flags & E_MGLOBAL) { + if (lval->Flags & E_MGLOBAL) { /* Static variable */ - flags |= GlobalModeFlags (lval->e_flags); + lflags |= GlobalModeFlags (lval->Flags); if (Gen->Tok == TOK_PLUS_ASSIGN) { - g_addeqstatic (flags, lval->e_name, lval->e_const, lval2.e_const); + g_addeqstatic (lflags, lval->Name, lval->ConstVal, lval2.ConstVal); } else { - g_subeqstatic (flags, lval->e_name, lval->e_const, lval2.e_const); + g_subeqstatic (lflags, lval->Name, lval->ConstVal, lval2.ConstVal); } - } else if (lval->e_flags & E_MLOCAL) { + } else if (lval->Flags & E_MLOCAL) { /* ref to localvar */ if (Gen->Tok == TOK_PLUS_ASSIGN) { - g_addeqlocal (flags, lval->e_const, lval2.e_const); + g_addeqlocal (lflags, lval->ConstVal, lval2.ConstVal); } else { - g_subeqlocal (flags, lval->e_const, lval2.e_const); + g_subeqlocal (lflags, lval->ConstVal, lval2.ConstVal); } - } else if (lval->e_flags & E_MCONST) { + } else if (lval->Flags & E_MCONST) { /* ref to absolute address */ - flags |= CF_ABSOLUTE; + lflags |= CF_ABSOLUTE; if (Gen->Tok == TOK_PLUS_ASSIGN) { - g_addeqstatic (flags, lval->e_const, 0, lval2.e_const); + g_addeqstatic (lflags, lval->ConstVal, 0, lval2.ConstVal); } else { - g_subeqstatic (flags, lval->e_const, 0, lval2.e_const); + g_subeqstatic (lflags, lval->ConstVal, 0, lval2.ConstVal); } - } else if (lval->e_flags & E_MEXPR) { + } else if (lval->Flags & E_MEXPR) { /* Address in a/x. */ if (Gen->Tok == TOK_PLUS_ASSIGN) { - g_addeqind (flags, lval->e_const, lval2.e_const); + g_addeqind (lflags, lval->ConstVal, lval2.ConstVal); } else { - g_subeqind (flags, lval->e_const, lval2.e_const); + g_subeqind (lflags, lval->ConstVal, lval2.ConstVal); } } else { Internal ("Invalid addressing mode"); } /* Expression is in the primary now */ - lval->e_flags = E_MEXPR; + lval->Flags = E_MEXPR; } -static void Assignment (struct expent* lval) -/* Parse an assignment */ -{ - int k; - struct expent lval2; - unsigned flags; - type* ltype = lval->e_tptr; - - /* cc65 does not have full support for handling structs by value. Since - * assigning structs is one of the more useful operations from this - * familiy, allow it here. - */ - if (IsStruct (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 (ERR_LVALUE_EXPECTED); - } - - /* 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 (!EqualTypes (ltype, lval2.e_tptr)) { - Error (ERR_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); - } - - /* Generate a store instruction */ - store (lval); - - } - - /* Value is still in primary */ - lval->e_flags = E_MEXPR; -} - - - -int hie1 (struct expent* lval) +int hie1 (ExprDesc* lval) /* Parse first level of expression hierarchy. */ { int k; k = hieQuest (lval); - switch (curtok) { + switch (CurTok.Tok) { case TOK_RPAREN: case TOK_SEMI: @@ -2733,7 +2968,7 @@ int hie1 (struct expent* lval) case TOK_ASSIGN: NextToken (); if (k == 0) { - Error (ERR_LVALUE_EXPECTED); + Error ("Invalid lvalue in assignment"); } else { Assignment (lval); } @@ -2787,22 +3022,22 @@ int hie1 (struct expent* lval) -int hie0 (struct expent *lval) +static int hie0 (ExprDesc *lval) /* Parse comma operator. */ { int k; k = hie1 (lval); - while (curtok == TOK_COMMA) { + while (CurTok.Tok == TOK_COMMA) { NextToken (); - k = hie1 (lval); + k = hie1 (lval); } return k; } -int evalexpr (unsigned flags, int (*f) (struct expent*), struct expent* lval) +int evalexpr (unsigned flags, int (*f) (ExprDesc*), ExprDesc* lval) /* 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 @@ -2813,11 +3048,11 @@ int evalexpr (unsigned flags, int (*f) (struct expent*), struct expent* lval) /* Evaluate */ k = f (lval); - if (k == 0 && lval->e_flags == E_MCONST) { - /* Constant expression */ - return 0; + if (k == 0 && lval->Flags == E_MCONST) { + /* Constant expression */ + return 0; } else { - /* Not constant, load into the primary */ + /* Not constant, load into the primary */ exprhs (flags, k, lval); return 1; } @@ -2825,7 +3060,7 @@ int evalexpr (unsigned flags, int (*f) (struct expent*), struct expent* lval) -int expr (int (*func) (), struct expent *lval) +static int expr (int (*func) (ExprDesc*), ExprDesc *lval) /* Expression parser; func is either hie0 or hie1. */ { int k; @@ -2848,129 +3083,127 @@ int expr (int (*func) (), struct expent *lval) -void expression1 (struct expent* lval) +void expression1 (ExprDesc* lval) /* Evaluate an expression on level 1 (no comma operator) and put it into * the primary register */ { - memset (lval, 0, sizeof (*lval)); + InitExprDesc (lval); exprhs (CF_NONE, expr (hie1, lval), lval); } -void expression (struct expent* lval) +void expression (ExprDesc* lval) /* Evaluate an expression and put it into the primary register */ { - memset (lval, 0, sizeof (*lval)); + InitExprDesc (lval); exprhs (CF_NONE, expr (hie0, lval), lval); } -void constexpr (struct expent* lval) +void ConstExpr (ExprDesc* lval) /* Get a constant value */ { - memset (lval, 0, sizeof (*lval)); - if (expr (hie1, lval) != 0 || (lval->e_flags & E_MCONST) == 0) { - Error (ERR_CONST_EXPR_EXPECTED); + InitExprDesc (lval); + if (expr (hie1, lval) != 0 || (lval->Flags & E_MCONST) == 0) { + Error ("Constant expression expected"); /* To avoid any compiler errors, make the expression a valid const */ - lval->e_flags = E_MCONST; - lval->e_tptr = type_int; - lval->e_const = 0; + MakeConstIntExpr (lval, 1); } } -void intexpr (struct expent* lval) -/* Get an integer expression */ +void ConstIntExpr (ExprDesc* Val) +/* Get a constant int value */ { - expression (lval); - if (!IsInt (lval->e_tptr)) { - Error (ERR_INT_EXPR_EXPECTED); - /* To avoid any compiler errors, make the expression a valid int */ - lval->e_flags = E_MCONST; - lval->e_tptr = type_int; - lval->e_const = 0; + InitExprDesc (Val); + if (expr (hie1, Val) != 0 || + (Val->Flags & E_MCONST) == 0 || + !IsClassInt (Val->Type)) { + Error ("Constant integer expression expected"); + /* To avoid any compiler errors, make the expression a valid const */ + MakeConstIntExpr (Val, 1); } } -void boolexpr (struct expent* lval) -/* Get a boolean expression */ +void intexpr (ExprDesc* lval) +/* Get an integer expression */ { - /* Read an expression */ expression (lval); - - /* If it's an integer, it's ok. If it's not an integer, but a pointer, - * the pointer used in a boolean context is also ok (Ootherwise check if it's a pointer - * expression. - */ - if (!IsInt (lval->e_tptr) && !IsPtr (lval->e_tptr)) { - Error (ERR_INT_EXPR_EXPECTED); - /* To avoid any compiler errors, make the expression a valid int */ - lval->e_flags = E_MCONST; - lval->e_tptr = type_int; - lval->e_const = 0; + if (!IsClassInt (lval->Type)) { + Error ("Integer expression expected"); + /* To avoid any compiler errors, make the expression a valid int */ + MakeConstIntExpr (lval, 1); } } -void test (unsigned label, int cond) -/* Generate code to perform test and jump if false. */ +void Test (unsigned Label, int Invert) +/* Evaluate a boolean test expression and jump depending on the result of + * the test and on Invert. + */ { int k; - struct expent lval; + ExprDesc lval; - /* Eat the parenthesis */ - ConsumeLParen (); + /* Evaluate the expression */ + k = expr (hie0, InitExprDesc (&lval)); + + /* Check for a boolean expression */ + CheckBoolExpr (&lval); - /* Prepare the expression, setup labels */ - memset (&lval, 0, sizeof (lval)); - lval.e_test = E_TEST; + /* Check for a constant expression */ + if (k == 0 && lval.Flags == E_MCONST) { - /* Generate code to eval the expr */ - k = expr (hie0, &lval); - if (k == 0 && lval.e_flags == E_MCONST) { /* Constant rvalue */ - if (cond == 0 && lval.e_const == 0) { - g_jump (label); - Warning (WARN_UNREACHABLE_CODE); - } else if (cond && lval.e_const) { - g_jump (label); + if (!Invert && lval.ConstVal == 0) { + g_jump (Label); + Warning ("Unreachable code"); + } else if (Invert && lval.ConstVal != 0) { + g_jump (Label); } - ConsumeRParen (); - return; - } - /* If the expr hasn't set condition codes, set the force-test flag */ - if ((lval.e_test & E_CC) == 0) { - lval.e_test |= E_FORCETEST; - } + } else { - /* Load the value into the primary register */ - exprhs (CF_FORCECHAR, k, &lval); + /* If the expr hasn't set condition codes, set the force-test flag */ + if ((lval.Test & E_CC) == 0) { + lval.Test |= E_FORCETEST; + } - /* Check for the closing brace */ - ConsumeRParen (); + /* 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_SEMI) { - g_falsejump (CF_NONE, label); - } + /* Generate the jump */ + if (Invert) { + g_truejump (CF_NONE, Label); + } else { + g_falsejump (CF_NONE, Label); + } } } +void TestInParens (unsigned Label, int Invert) +/* Evaluate a boolean test expression in parenthesis and jump depending on + * the result of the test * and on Invert. + */ +{ + /* Eat the parenthesis */ + ConsumeLParen (); + + /* Do the test */ + Test (Label, Invert); + + /* Check for the closing brace */ + ConsumeRParen (); +} + +