2004-05-26 16:15:28 +00:00
|
|
|
/* expr.c
|
2000-05-28 13:40:48 +00:00
|
|
|
*
|
|
|
|
* Ullrich von Bassewitz, 21.06.1998
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
2000-08-01 15:04:35 +00:00
|
|
|
/* common */
|
|
|
|
#include "check.h"
|
2003-01-04 16:59:51 +00:00
|
|
|
#include "debugflag.h"
|
2000-08-01 15:04:35 +00:00
|
|
|
#include "xmalloc.h"
|
2000-06-14 21:01:37 +00:00
|
|
|
|
2000-08-01 15:04:35 +00:00
|
|
|
/* cc65 */
|
2000-05-28 13:40:48 +00:00
|
|
|
#include "asmcode.h"
|
|
|
|
#include "asmlabel.h"
|
2001-09-09 09:33:06 +00:00
|
|
|
#include "asmstmt.h"
|
2002-11-01 21:27:31 +00:00
|
|
|
#include "assignment.h"
|
2000-05-28 13:40:48 +00:00
|
|
|
#include "codegen.h"
|
|
|
|
#include "declare.h"
|
|
|
|
#include "error.h"
|
|
|
|
#include "funcdesc.h"
|
|
|
|
#include "function.h"
|
|
|
|
#include "global.h"
|
|
|
|
#include "litpool.h"
|
2004-06-09 14:12:57 +00:00
|
|
|
#include "loadexpr.h"
|
2000-05-28 13:40:48 +00:00
|
|
|
#include "macrotab.h"
|
|
|
|
#include "preproc.h"
|
|
|
|
#include "scanner.h"
|
2004-06-29 20:44:01 +00:00
|
|
|
#include "shiftexpr.h"
|
2004-06-05 11:35:53 +00:00
|
|
|
#include "stackptr.h"
|
2008-07-31 18:30:33 +00:00
|
|
|
#include "standard.h"
|
2000-05-28 13:40:48 +00:00
|
|
|
#include "stdfunc.h"
|
|
|
|
#include "symtab.h"
|
2000-08-14 22:18:26 +00:00
|
|
|
#include "typecmp.h"
|
2003-08-11 20:18:30 +00:00
|
|
|
#include "typeconv.h"
|
2000-05-28 13:40:48 +00:00
|
|
|
#include "expr.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
/* Data */
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Generator attributes */
|
|
|
|
#define GEN_NOPUSH 0x01 /* Don't push lhs */
|
|
|
|
|
|
|
|
/* Map a generator function and its attributes to a token */
|
|
|
|
typedef struct {
|
2001-08-03 06:45:30 +00:00
|
|
|
token_t Tok; /* Token to map to */
|
|
|
|
unsigned Flags; /* Flags for generator function */
|
2000-05-28 13:40:48 +00:00
|
|
|
void (*Func) (unsigned, unsigned long); /* Generator func */
|
|
|
|
} GenDesc;
|
|
|
|
|
|
|
|
/* Descriptors for the operations */
|
2000-06-12 18:31:40 +00:00
|
|
|
static GenDesc GenPASGN = { TOK_PLUS_ASSIGN, GEN_NOPUSH, g_add };
|
|
|
|
static GenDesc GenSASGN = { TOK_MINUS_ASSIGN, GEN_NOPUSH, g_sub };
|
|
|
|
static GenDesc GenMASGN = { TOK_MUL_ASSIGN, GEN_NOPUSH, g_mul };
|
|
|
|
static GenDesc GenDASGN = { TOK_DIV_ASSIGN, GEN_NOPUSH, g_div };
|
|
|
|
static GenDesc GenMOASGN = { TOK_MOD_ASSIGN, GEN_NOPUSH, g_mod };
|
|
|
|
static GenDesc GenSLASGN = { TOK_SHL_ASSIGN, GEN_NOPUSH, g_asl };
|
|
|
|
static GenDesc GenSRASGN = { TOK_SHR_ASSIGN, GEN_NOPUSH, g_asr };
|
|
|
|
static GenDesc GenAASGN = { TOK_AND_ASSIGN, GEN_NOPUSH, g_and };
|
|
|
|
static GenDesc GenXOASGN = { TOK_XOR_ASSIGN, GEN_NOPUSH, g_xor };
|
|
|
|
static GenDesc GenOASGN = { TOK_OR_ASSIGN, GEN_NOPUSH, g_or };
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
2006-05-29 20:38:44 +00:00
|
|
|
/* Helper functions */
|
2000-05-28 13:40:48 +00:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
2008-08-05 21:11:26 +00:00
|
|
|
static unsigned GlobalModeFlags (const ExprDesc* Expr)
|
|
|
|
/* Return the addressing mode flags for the given expression */
|
2000-05-28 13:40:48 +00:00
|
|
|
{
|
2008-08-05 21:11:26 +00:00
|
|
|
switch (ED_GetLoc (Expr)) {
|
2004-05-31 15:27:33 +00:00
|
|
|
case E_LOC_GLOBAL: return CF_EXTERNAL;
|
|
|
|
case E_LOC_STATIC: return CF_STATIC;
|
|
|
|
case E_LOC_REGISTER: return CF_REGVAR;
|
|
|
|
default:
|
2008-08-05 21:11:26 +00:00
|
|
|
Internal ("GlobalModeFlags: Invalid location flags value: 0x%04X", Expr->Flags);
|
2004-07-17 22:16:02 +00:00
|
|
|
/* NOTREACHED */
|
|
|
|
return 0;
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-06-29 20:44:01 +00:00
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-06-05 11:35:53 +00:00
|
|
|
void ExprWithCheck (void (*Func) (ExprDesc*), ExprDesc *Expr)
|
2004-05-31 15:27:33 +00:00
|
|
|
/* Call an expression function with checks. */
|
2000-05-28 13:40:48 +00:00
|
|
|
{
|
2004-05-31 15:27:33 +00:00
|
|
|
/* Remember the stack pointer */
|
|
|
|
int OldSP = StackPtr;
|
|
|
|
|
|
|
|
/* Call the expression function */
|
|
|
|
(*Func) (Expr);
|
|
|
|
|
|
|
|
/* Do some checks if code generation is still constistent */
|
|
|
|
if (StackPtr != OldSP) {
|
|
|
|
if (Debug) {
|
|
|
|
fprintf (stderr,
|
|
|
|
"Code generation messed up!\n"
|
|
|
|
"StackPtr is %d, should be %d",
|
|
|
|
StackPtr, OldSP);
|
|
|
|
} else {
|
|
|
|
Internal ("StackPtr is %d, should be %d\n", StackPtr, OldSP);
|
|
|
|
}
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2006-02-19 12:29:37 +00:00
|
|
|
static Type* promoteint (Type* lhst, Type* rhst)
|
2000-05-28 13:40:48 +00:00
|
|
|
/* In an expression with two ints, return the type of the result */
|
|
|
|
{
|
|
|
|
/* Rules for integer types:
|
|
|
|
* - If one of the values is a long, the result is long.
|
|
|
|
* - If one of the values is unsigned, the result is also unsigned.
|
|
|
|
* - Otherwise the result is an int.
|
|
|
|
*/
|
2000-08-01 18:45:08 +00:00
|
|
|
if (IsTypeLong (lhst) || IsTypeLong (rhst)) {
|
2000-08-14 22:18:26 +00:00
|
|
|
if (IsSignUnsigned (lhst) || IsSignUnsigned (rhst)) {
|
2000-05-28 13:40:48 +00:00
|
|
|
return type_ulong;
|
|
|
|
} else {
|
2006-05-29 20:38:44 +00:00
|
|
|
return type_long;
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
} else {
|
2000-08-14 22:18:26 +00:00
|
|
|
if (IsSignUnsigned (lhst) || IsSignUnsigned (rhst)) {
|
2000-05-28 13:40:48 +00:00
|
|
|
return type_uint;
|
|
|
|
} else {
|
|
|
|
return type_int;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2001-07-17 21:24:19 +00:00
|
|
|
static unsigned typeadjust (ExprDesc* lhs, ExprDesc* rhs, int NoPush)
|
2000-05-28 13:40:48 +00:00
|
|
|
/* 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
|
|
|
|
* code generator flags for the operation.
|
|
|
|
* If NoPush is given, it is assumed that the operation does not expect the lhs
|
|
|
|
* to be on stack, and that lhs is in a register instead.
|
|
|
|
* Beware: The function does only accept int types.
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
unsigned ltype, rtype;
|
|
|
|
unsigned flags;
|
|
|
|
|
|
|
|
/* Get the type strings */
|
2006-02-19 12:29:37 +00:00
|
|
|
Type* lhst = lhs->Type;
|
|
|
|
Type* rhst = rhs->Type;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Generate type adjustment code if needed */
|
|
|
|
ltype = TypeOf (lhst);
|
2004-05-31 15:27:33 +00:00
|
|
|
if (ED_IsLocAbs (lhs)) {
|
2000-05-28 13:40:48 +00:00
|
|
|
ltype |= CF_CONST;
|
|
|
|
}
|
|
|
|
if (NoPush) {
|
|
|
|
/* Value is in primary register*/
|
|
|
|
ltype |= CF_REG;
|
|
|
|
}
|
|
|
|
rtype = TypeOf (rhst);
|
2004-05-31 15:27:33 +00:00
|
|
|
if (ED_IsLocAbs (rhs)) {
|
2000-05-28 13:40:48 +00:00
|
|
|
rtype |= CF_CONST;
|
|
|
|
}
|
|
|
|
flags = g_typeadjust (ltype, rtype);
|
|
|
|
|
2002-12-12 17:40:58 +00:00
|
|
|
/* Set the type of the result */
|
2001-07-17 21:29:21 +00:00
|
|
|
lhs->Type = promoteint (lhst, rhst);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Return the code generator flags */
|
|
|
|
return flags;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
static const GenDesc* FindGen (token_t Tok, const GenDesc* Table)
|
2002-04-06 14:51:27 +00:00
|
|
|
/* Find a token in a generator table */
|
2000-05-28 13:40:48 +00:00
|
|
|
{
|
2004-05-25 20:59:38 +00:00
|
|
|
while (Table->Tok != TOK_INVALID) {
|
|
|
|
if (Table->Tok == Tok) {
|
|
|
|
return Table;
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
++Table;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2004-05-26 16:15:28 +00:00
|
|
|
static int TypeSpecAhead (void)
|
|
|
|
/* Return true if some sort of type is waiting (helper for cast and sizeof()
|
|
|
|
* in hie10).
|
2000-05-28 13:40:48 +00:00
|
|
|
*/
|
|
|
|
{
|
|
|
|
SymEntry* Entry;
|
|
|
|
|
2004-05-26 16:15:28 +00:00
|
|
|
/* There's a type waiting if:
|
|
|
|
*
|
2004-05-31 15:27:33 +00:00
|
|
|
* We have an opening paren, and
|
|
|
|
* a. the next token is a type, or
|
|
|
|
* b. the next token is a type qualifier, or
|
|
|
|
* c. the next token is a typedef'd type
|
2004-05-26 16:15:28 +00:00
|
|
|
*/
|
2001-05-22 09:32:24 +00:00
|
|
|
return CurTok.Tok == TOK_LPAREN && (
|
2004-05-26 16:15:28 +00:00
|
|
|
TokIsType (&NextTok) ||
|
|
|
|
TokIsTypeQual (&NextTok) ||
|
|
|
|
(NextTok.Tok == TOK_IDENT &&
|
|
|
|
(Entry = FindSym (NextTok.Ident)) != 0 &&
|
2002-11-24 23:31:54 +00:00
|
|
|
SymIsTypeDef (Entry)));
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2004-05-31 15:27:33 +00:00
|
|
|
void PushAddr (const ExprDesc* Expr)
|
2000-05-28 13:40:48 +00:00
|
|
|
/* 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
|
|
|
|
* must be saved if it's not constant, before evaluating the rhs.
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
/* Get the address on stack if needed */
|
2004-05-31 15:27:33 +00:00
|
|
|
if (ED_IsLocExpr (Expr)) {
|
2002-11-01 21:27:31 +00:00
|
|
|
/* Push the address (always a pointer) */
|
|
|
|
g_push (CF_PTR, 0);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
2001-09-08 13:59:32 +00:00
|
|
|
/* code */
|
2000-05-28 13:40:48 +00:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
2001-03-24 13:00:16 +00:00
|
|
|
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.
|
2003-03-04 10:46:27 +00:00
|
|
|
*/
|
2000-05-28 13:40:48 +00:00
|
|
|
{
|
2003-08-27 19:40:40 +00:00
|
|
|
ExprDesc Expr;
|
2001-03-24 13:00:16 +00:00
|
|
|
|
|
|
|
/* 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).
|
2004-05-25 20:59:38 +00:00
|
|
|
*
|
|
|
|
* The FrameSize variable will contain a value > 0 if storing into a frame
|
|
|
|
* (instead of pushing) is enabled.
|
|
|
|
*
|
2000-05-28 13:40:48 +00:00
|
|
|
*/
|
2004-06-15 20:29:49 +00:00
|
|
|
if (IS_Get (&CodeSizeFactor) >= 200) {
|
2001-03-24 13:00:16 +00:00
|
|
|
|
|
|
|
/* 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 */
|
2003-08-10 17:05:18 +00:00
|
|
|
FrameSize -= CheckedSizeOf (Func->LastParam->Type);
|
2001-03-24 13:00:16 +00:00
|
|
|
--FrameParams;
|
|
|
|
}
|
|
|
|
|
2006-05-29 20:38:44 +00:00
|
|
|
/* Do we have more than one parameter in the frame? */
|
2001-03-24 13:00:16 +00:00
|
|
|
if (FrameParams > 1) {
|
|
|
|
/* Okeydokey, setup the frame */
|
2004-05-31 15:27:33 +00:00
|
|
|
FrameOffs = StackPtr;
|
2001-03-24 13:00:16 +00:00
|
|
|
g_space (FrameSize);
|
2004-05-31 15:27:33 +00:00
|
|
|
StackPtr -= FrameSize;
|
2001-03-24 13:00:16 +00:00
|
|
|
} else {
|
|
|
|
/* Don't use a preallocated frame */
|
|
|
|
FrameSize = 0;
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Parse the actual parameter list */
|
2001-05-22 09:32:24 +00:00
|
|
|
while (CurTok.Tok != TOK_RPAREN) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2001-03-24 13:00:16 +00:00
|
|
|
unsigned Flags;
|
|
|
|
|
|
|
|
/* Count arguments */
|
|
|
|
++ParamCount;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Fetch the pointer to the next argument, check for too many args */
|
|
|
|
if (ParamCount <= Func->ParamCount) {
|
2001-03-22 20:54:52 +00:00
|
|
|
/* 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.
|
|
|
|
*/
|
2000-05-28 13:40:48 +00:00
|
|
|
if (ParamCount == 1) {
|
2001-03-22 20:54:52 +00:00
|
|
|
/* First argument */
|
|
|
|
Param = Func->SymTab->SymHead;
|
|
|
|
} else if (Param->NextSym != 0) {
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Next argument */
|
|
|
|
Param = Param->NextSym;
|
|
|
|
CHECK ((Param->Flags & SC_PARAM) != 0);
|
|
|
|
}
|
|
|
|
} else if (!Ellipsis) {
|
|
|
|
/* Too many arguments. Do we have an open param list? */
|
2001-03-24 13:00:16 +00:00
|
|
|
if ((Func->Flags & FD_VARIADIC) == 0) {
|
2000-05-28 13:40:48 +00:00
|
|
|
/* End of param list reached, no ellipsis */
|
2000-11-02 21:22:33 +00:00
|
|
|
Error ("Too many arguments in function call");
|
2006-05-29 20:38:44 +00:00
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Assume an ellipsis even in case of errors to avoid an error
|
|
|
|
* message for each other argument.
|
|
|
|
*/
|
|
|
|
Ellipsis = 1;
|
|
|
|
}
|
|
|
|
|
2003-08-27 19:40:40 +00:00
|
|
|
/* Evaluate the parameter expression */
|
2004-05-31 15:27:33 +00:00
|
|
|
hie1 (&Expr);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* If we don't have an argument spec, accept anything, otherwise
|
|
|
|
* convert the actual argument to the type needed.
|
2003-08-29 09:16:28 +00:00
|
|
|
*/
|
2003-08-27 19:40:40 +00:00
|
|
|
Flags = CF_NONE;
|
2000-05-28 13:40:48 +00:00
|
|
|
if (!Ellipsis) {
|
2004-08-02 16:39:55 +00:00
|
|
|
|
2003-08-11 20:18:30 +00:00
|
|
|
/* Convert the argument to the parameter type if needed */
|
2004-05-25 20:59:38 +00:00
|
|
|
TypeConversion (&Expr, Param->Type);
|
2000-08-14 22:18:26 +00:00
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
/* If we have a prototype, chars may be pushed as chars */
|
|
|
|
Flags |= CF_FORCECHAR;
|
2004-08-02 16:39:55 +00:00
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
/* No prototype available. Convert array to "pointer to first
|
|
|
|
* element", and function to "pointer to function".
|
|
|
|
*/
|
2004-08-02 17:19:52 +00:00
|
|
|
Expr.Type = PtrConversion (Expr.Type);
|
2004-08-02 16:39:55 +00:00
|
|
|
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2003-08-27 19:40:40 +00:00
|
|
|
/* Load the value into the primary if it is not already there */
|
2004-06-09 14:12:57 +00:00
|
|
|
LoadExpr (Flags, &Expr);
|
2003-08-27 19:40:40 +00:00
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Use the type of the argument for the push */
|
2003-08-27 19:40:40 +00:00
|
|
|
Flags |= TypeOf (Expr.Type);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* If this is a fastcall function, don't push the last argument */
|
2003-08-27 19:40:40 +00:00
|
|
|
if (ParamCount != Func->ParamCount || (Func->Flags & FD_FASTCALL) == 0) {
|
2001-03-24 13:00:16 +00:00
|
|
|
unsigned ArgSize = sizeofarg (Flags);
|
|
|
|
if (FrameSize > 0) {
|
2003-08-17 15:20:18 +00:00
|
|
|
/* We have the space already allocated, store in the frame.
|
|
|
|
* Because of invalid type conversions (that have produced an
|
|
|
|
* error before), we can end up here with a non aligned stack
|
2003-08-19 20:31:10 +00:00
|
|
|
* frame. Since no output will be generated anyway, handle
|
2003-08-17 15:20:18 +00:00
|
|
|
* these cases gracefully instead of doing a CHECK.
|
|
|
|
*/
|
|
|
|
if (FrameSize >= ArgSize) {
|
|
|
|
FrameSize -= ArgSize;
|
|
|
|
} else {
|
|
|
|
FrameSize = 0;
|
|
|
|
}
|
2001-04-04 20:20:48 +00:00
|
|
|
FrameOffs -= ArgSize;
|
|
|
|
/* Store */
|
2004-06-06 14:48:59 +00:00
|
|
|
g_putlocal (Flags | CF_NOKEEP, FrameOffs, Expr.IVal);
|
2001-03-24 13:00:16 +00:00
|
|
|
} else {
|
|
|
|
/* Push the argument */
|
2004-06-06 14:48:59 +00:00
|
|
|
g_push (Flags, Expr.IVal);
|
2003-08-29 09:16:28 +00:00
|
|
|
}
|
2001-03-24 13:00:16 +00:00
|
|
|
|
|
|
|
/* Calculate total parameter size */
|
|
|
|
ParamSize += ArgSize;
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Check for end of argument list */
|
2001-05-22 09:32:24 +00:00
|
|
|
if (CurTok.Tok != TOK_COMMA) {
|
2000-05-28 13:40:48 +00:00
|
|
|
break;
|
|
|
|
}
|
2000-06-12 18:31:40 +00:00
|
|
|
NextToken ();
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if we had enough parameters */
|
|
|
|
if (ParamCount < Func->ParamCount) {
|
2000-11-02 21:22:33 +00:00
|
|
|
Error ("Too few arguments in function call");
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
2001-04-04 20:20:48 +00:00
|
|
|
/* The function returns the size of all parameters pushed onto the stack.
|
2001-04-19 06:49:08 +00:00
|
|
|
* However, if there are parameters missing (which is an error and was
|
2001-04-04 20:20:48 +00:00
|
|
|
* 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
|
2001-04-19 06:49:08 +00:00
|
|
|
* pushed to avoid an internal compiler error. Since an error was
|
2001-04-04 20:20:48 +00:00
|
|
|
* generated before, no code will be output anyway.
|
|
|
|
*/
|
|
|
|
return ParamSize + FrameSize;
|
2001-03-24 13:00:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
static void FunctionCall (ExprDesc* Expr)
|
2001-09-24 22:36:35 +00:00
|
|
|
/* Perform a function call. */
|
2001-03-24 13:00:16 +00:00
|
|
|
{
|
2001-09-24 22:36:35 +00:00
|
|
|
FuncDesc* Func; /* Function descriptor */
|
|
|
|
int IsFuncPtr; /* Flag */
|
|
|
|
unsigned ParamSize; /* Number of parameter bytes */
|
2004-07-06 11:30:08 +00:00
|
|
|
CodeMark Mark;
|
2001-09-24 22:36:35 +00:00
|
|
|
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 */
|
2001-03-24 13:00:16 +00:00
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
/* Skip the left paren */
|
|
|
|
NextToken ();
|
|
|
|
|
2001-03-24 13:00:16 +00:00
|
|
|
/* Get a pointer to the function descriptor from the type string */
|
2004-05-25 20:59:38 +00:00
|
|
|
Func = GetFuncDesc (Expr->Type);
|
2001-03-24 13:00:16 +00:00
|
|
|
|
2001-09-24 22:36:35 +00:00
|
|
|
/* Handle function pointers transparently */
|
2004-05-25 20:59:38 +00:00
|
|
|
IsFuncPtr = IsTypeFuncPtr (Expr->Type);
|
2001-09-24 22:36:35 +00:00
|
|
|
if (IsFuncPtr) {
|
2001-03-24 13:00:16 +00:00
|
|
|
|
2002-05-26 11:08:17 +00:00
|
|
|
/* Check wether it's a fastcall function that has parameters */
|
2004-05-25 20:59:38 +00:00
|
|
|
IsFastCall = IsFastCallFunc (Expr->Type + 1) && (Func->ParamCount > 0);
|
2001-09-24 22:36:35 +00:00
|
|
|
|
|
|
|
/* 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.
|
|
|
|
*/
|
2004-05-31 15:27:33 +00:00
|
|
|
PtrOnStack = IsFastCall || !ED_IsConst (Expr);
|
2001-09-24 22:36:35 +00:00
|
|
|
if (PtrOnStack) {
|
|
|
|
|
|
|
|
/* Not a global or local variable, or a fastcall function. Load
|
|
|
|
* the pointer into the primary and mark it as an expression.
|
|
|
|
*/
|
2004-06-09 14:12:57 +00:00
|
|
|
LoadExpr (CF_NONE, Expr);
|
2004-05-31 15:27:33 +00:00
|
|
|
ED_MakeRValExpr (Expr);
|
2001-09-24 22:36:35 +00:00
|
|
|
|
|
|
|
/* Remember the code position */
|
2004-07-06 11:30:08 +00:00
|
|
|
GetCodePos (&Mark);
|
2001-09-24 22:36:35 +00:00
|
|
|
|
|
|
|
/* Push the pointer onto the stack and remember the offset */
|
|
|
|
g_push (CF_PTR, 0);
|
2004-05-31 15:27:33 +00:00
|
|
|
PtrOffs = StackPtr;
|
2001-09-24 22:36:35 +00:00
|
|
|
}
|
|
|
|
|
2004-06-04 14:37:50 +00:00
|
|
|
/* Check for known standard functions and inline them */
|
2004-07-11 13:47:57 +00:00
|
|
|
} else if (Expr->Name != 0) {
|
|
|
|
int StdFunc = FindStdFunc ((const char*) Expr->Name);
|
|
|
|
if (StdFunc >= 0) {
|
|
|
|
/* Inline this function */
|
|
|
|
HandleStdFunc (StdFunc, Func, Expr);
|
|
|
|
return;
|
|
|
|
}
|
2001-03-24 13:00:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Parse the parameter list */
|
|
|
|
ParamSize = FunctionParamList (Func);
|
|
|
|
|
2001-09-24 22:36:35 +00:00
|
|
|
/* We need the closing paren here */
|
2001-03-24 13:00:16 +00:00
|
|
|
ConsumeRParen ();
|
|
|
|
|
2001-09-24 22:36:35 +00:00
|
|
|
/* Special handling for function pointers */
|
|
|
|
if (IsFuncPtr) {
|
|
|
|
|
|
|
|
/* If the function is not a fastcall function, load the pointer to
|
|
|
|
* the function into the primary.
|
|
|
|
*/
|
2001-09-25 10:30:48 +00:00
|
|
|
if (!IsFastCall) {
|
2001-09-24 22:36:35 +00:00
|
|
|
|
|
|
|
/* Not a fastcall function - we may use the primary */
|
|
|
|
if (PtrOnStack) {
|
2001-09-25 10:30:48 +00:00
|
|
|
/* 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) {
|
2004-07-06 11:30:08 +00:00
|
|
|
RemoveCode (&Mark);
|
2001-09-25 10:30:48 +00:00
|
|
|
PtrOnStack = 0;
|
|
|
|
} else {
|
2006-05-29 20:38:44 +00:00
|
|
|
/* Load from the saved copy */
|
2001-09-25 10:30:48 +00:00
|
|
|
g_getlocal (CF_PTR, PtrOffs);
|
|
|
|
}
|
2001-09-24 22:36:35 +00:00
|
|
|
} else {
|
|
|
|
/* Load from original location */
|
2004-06-09 14:12:57 +00:00
|
|
|
LoadExpr (CF_NONE, Expr);
|
2001-09-24 22:36:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Call the function */
|
2004-05-25 20:59:38 +00:00
|
|
|
g_callind (TypeOf (Expr->Type+1), ParamSize, PtrOffs);
|
2001-09-24 22:36:35 +00:00
|
|
|
|
|
|
|
} 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.
|
|
|
|
*/
|
2001-09-25 10:30:48 +00:00
|
|
|
g_callind (CF_LOCAL, ParamSize, PtrOffs);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
2001-09-24 22:36:35 +00:00
|
|
|
|
2001-09-25 10:30:48 +00:00
|
|
|
/* If we have a pointer on stack, remove it */
|
|
|
|
if (PtrOnStack) {
|
|
|
|
g_space (- (int) sizeofarg (CF_PTR));
|
|
|
|
pop (CF_PTR);
|
|
|
|
}
|
2001-09-30 21:56:45 +00:00
|
|
|
|
2001-09-25 10:30:48 +00:00
|
|
|
/* Skip T_PTR */
|
2004-05-25 20:59:38 +00:00
|
|
|
++Expr->Type;
|
2001-09-24 22:36:35 +00:00
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
} else {
|
2001-09-24 22:36:35 +00:00
|
|
|
|
|
|
|
/* Normal function */
|
2004-05-25 20:59:38 +00:00
|
|
|
g_call (TypeOf (Expr->Type), (const char*) Expr->Name, ParamSize);
|
2001-09-24 22:36:35 +00:00
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
2004-05-31 15:27:33 +00:00
|
|
|
|
|
|
|
/* The function result is an rvalue in the primary register */
|
|
|
|
ED_MakeRValExpr (Expr);
|
|
|
|
Expr->Type = GetFuncReturn (Expr->Type);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
static void Primary (ExprDesc* E)
|
2000-05-28 13:40:48 +00:00
|
|
|
/* This is the lowest level of the expression parser. */
|
|
|
|
{
|
2004-05-25 20:59:38 +00:00
|
|
|
SymEntry* Sym;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2002-03-18 20:04:03 +00:00
|
|
|
/* Initialize fields in the expression stucture */
|
2004-05-31 15:27:33 +00:00
|
|
|
ED_Init (E);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Character and integer constants. */
|
2001-05-22 09:32:24 +00:00
|
|
|
if (CurTok.Tok == TOK_ICONST || CurTok.Tok == TOK_CCONST) {
|
2004-06-06 15:59:44 +00:00
|
|
|
E->IVal = CurTok.IVal;
|
2004-05-31 15:27:33 +00:00
|
|
|
E->Flags = E_LOC_ABS | E_RTYPE_RVAL;
|
2004-05-25 20:59:38 +00:00
|
|
|
E->Type = CurTok.Type;
|
2000-06-12 18:31:40 +00:00
|
|
|
NextToken ();
|
2004-05-25 20:59:38 +00:00
|
|
|
return;
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
2004-06-06 15:59:44 +00:00
|
|
|
/* Floating point constant */
|
|
|
|
if (CurTok.Tok == TOK_FCONST) {
|
|
|
|
E->FVal = CurTok.FVal;
|
|
|
|
E->Flags = E_LOC_ABS | E_RTYPE_RVAL;
|
|
|
|
E->Type = CurTok.Type;
|
|
|
|
NextToken ();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Process parenthesized subexpression by calling the whole parser
|
|
|
|
* recursively.
|
|
|
|
*/
|
2001-05-22 09:32:24 +00:00
|
|
|
if (CurTok.Tok == TOK_LPAREN) {
|
2004-06-06 15:59:44 +00:00
|
|
|
NextToken ();
|
2004-05-31 15:27:33 +00:00
|
|
|
hie0 (E);
|
2000-05-28 13:40:48 +00:00
|
|
|
ConsumeRParen ();
|
2004-06-06 15:59:44 +00:00
|
|
|
return;
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
2002-07-26 19:27:55 +00:00
|
|
|
/* 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) {
|
2006-05-29 20:38:44 +00:00
|
|
|
NextToken ();
|
2004-05-31 15:27:33 +00:00
|
|
|
ED_MakeConstAbsInt (E, 0);
|
2004-05-25 20:59:38 +00:00
|
|
|
return;
|
2002-07-26 19:27:55 +00:00
|
|
|
}
|
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
/* All others may only be used if the expression evaluation is not called
|
|
|
|
* recursively by the preprocessor.
|
|
|
|
*/
|
|
|
|
if (Preprocessing) {
|
|
|
|
/* Illegal expression in PP mode */
|
2000-11-02 21:22:33 +00:00
|
|
|
Error ("Preprocessor expression expected");
|
2004-05-31 15:27:33 +00:00
|
|
|
ED_MakeConstAbsInt (E, 1);
|
2004-05-25 20:59:38 +00:00
|
|
|
return;
|
2006-02-17 20:19:35 +00:00
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
switch (CurTok.Tok) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
case TOK_IDENT:
|
|
|
|
/* Identifier. Get a pointer to the symbol table entry */
|
|
|
|
Sym = E->Sym = FindSym (CurTok.Ident);
|
|
|
|
|
|
|
|
/* Is the symbol known? */
|
|
|
|
if (Sym) {
|
|
|
|
|
|
|
|
/* We found the symbol - skip the name token */
|
|
|
|
NextToken ();
|
|
|
|
|
|
|
|
/* Check for illegal symbol types */
|
|
|
|
CHECK ((Sym->Flags & SC_LABEL) != SC_LABEL);
|
|
|
|
if (Sym->Flags & SC_TYPE) {
|
|
|
|
/* Cannot use type symbols */
|
|
|
|
Error ("Variable identifier expected");
|
|
|
|
/* Assume an int type to make E valid */
|
2004-05-31 15:27:33 +00:00
|
|
|
E->Flags = E_LOC_STACK | E_RTYPE_LVAL;
|
2004-05-25 20:59:38 +00:00
|
|
|
E->Type = type_int;
|
|
|
|
return;
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
/* Mark the symbol as referenced */
|
|
|
|
Sym->Flags |= SC_REF;
|
|
|
|
|
2004-05-31 15:27:33 +00:00
|
|
|
/* The expression type is the symbol type */
|
|
|
|
E->Type = Sym->Type;
|
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
/* Check for legal symbol types */
|
|
|
|
if ((Sym->Flags & SC_CONST) == SC_CONST) {
|
|
|
|
/* Enum or some other numeric constant */
|
2004-05-31 15:27:33 +00:00
|
|
|
E->Flags = E_LOC_ABS | E_RTYPE_RVAL;
|
2004-06-06 14:48:59 +00:00
|
|
|
E->IVal = Sym->V.ConstVal;
|
2004-05-25 20:59:38 +00:00
|
|
|
} else if ((Sym->Flags & SC_FUNC) == SC_FUNC) {
|
|
|
|
/* Function */
|
2004-05-31 15:27:33 +00:00
|
|
|
E->Flags = E_LOC_GLOBAL | E_RTYPE_LVAL;
|
2004-05-25 20:59:38 +00:00
|
|
|
E->Name = (unsigned long) Sym->Name;
|
|
|
|
} else if ((Sym->Flags & SC_AUTO) == SC_AUTO) {
|
|
|
|
/* Local variable. If this is a parameter for a variadic
|
|
|
|
* function, we have to add some address calculations, and the
|
|
|
|
* address is not const.
|
|
|
|
*/
|
|
|
|
if ((Sym->Flags & SC_PARAM) == SC_PARAM && F_IsVariadic (CurrentFunc)) {
|
|
|
|
/* Variadic parameter */
|
|
|
|
g_leavariadic (Sym->V.Offs - F_GetParamSize (CurrentFunc));
|
2004-05-31 15:27:33 +00:00
|
|
|
E->Flags = E_LOC_EXPR | E_RTYPE_LVAL;
|
2004-05-25 20:59:38 +00:00
|
|
|
} else {
|
|
|
|
/* Normal parameter */
|
2004-05-31 15:27:33 +00:00
|
|
|
E->Flags = E_LOC_STACK | E_RTYPE_LVAL;
|
2004-06-06 14:48:59 +00:00
|
|
|
E->IVal = Sym->V.Offs;
|
2004-05-25 20:59:38 +00:00
|
|
|
}
|
|
|
|
} else if ((Sym->Flags & SC_REGISTER) == SC_REGISTER) {
|
|
|
|
/* Register variable, zero page based */
|
2004-05-31 15:27:33 +00:00
|
|
|
E->Flags = E_LOC_REGISTER | E_RTYPE_LVAL;
|
2004-05-25 20:59:38 +00:00
|
|
|
E->Name = Sym->V.R.RegOffs;
|
|
|
|
} else if ((Sym->Flags & SC_STATIC) == SC_STATIC) {
|
|
|
|
/* Static variable */
|
|
|
|
if (Sym->Flags & (SC_EXTERN | SC_STORAGE)) {
|
2004-05-31 15:27:33 +00:00
|
|
|
E->Flags = E_LOC_GLOBAL | E_RTYPE_LVAL;
|
2004-05-25 20:59:38 +00:00
|
|
|
E->Name = (unsigned long) Sym->Name;
|
|
|
|
} else {
|
2004-05-31 15:27:33 +00:00
|
|
|
E->Flags = E_LOC_STATIC | E_RTYPE_LVAL;
|
2004-05-25 20:59:38 +00:00
|
|
|
E->Name = Sym->V.Label;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* Local static variable */
|
2004-05-31 15:27:33 +00:00
|
|
|
E->Flags = E_LOC_STATIC | E_RTYPE_LVAL;
|
2004-05-25 20:59:38 +00:00
|
|
|
E->Name = Sym->V.Offs;
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-31 15:27:33 +00:00
|
|
|
/* We've made all variables lvalues above. However, this is
|
|
|
|
* not always correct: An array is actually the address of its
|
|
|
|
* first element, which is a rvalue, and a function is a
|
|
|
|
* rvalue, too, because we cannot store anything in a function.
|
|
|
|
* So fix the flags depending on the type.
|
2004-05-25 20:59:38 +00:00
|
|
|
*/
|
2004-05-31 15:27:33 +00:00
|
|
|
if (IsTypeArray (E->Type) || IsTypeFunc (E->Type)) {
|
|
|
|
ED_MakeRVal (E);
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
} else {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
/* We did not find the symbol. Remember the name, then skip it */
|
|
|
|
ident Ident;
|
|
|
|
strcpy (Ident, CurTok.Ident);
|
|
|
|
NextToken ();
|
|
|
|
|
2005-08-31 21:49:12 +00:00
|
|
|
/* IDENT is either an auto-declared function or an undefined variable. */
|
2004-05-25 20:59:38 +00:00
|
|
|
if (CurTok.Tok == TOK_LPAREN) {
|
2008-07-31 18:30:33 +00:00
|
|
|
/* C99 doesn't allow calls to undefined functions, so
|
|
|
|
* generate an error and otherwise a warning. Declare a
|
|
|
|
* function returning int. For that purpose, prepare a
|
2008-08-03 20:09:03 +00:00
|
|
|
* function signature for a function having an empty param
|
|
|
|
* list and returning int.
|
2004-05-25 20:59:38 +00:00
|
|
|
*/
|
2008-07-31 18:30:33 +00:00
|
|
|
if (IS_Get (&Standard) >= STD_C99) {
|
|
|
|
Error ("Call to undefined function `%s'", Ident);
|
|
|
|
} else {
|
|
|
|
Warning ("Call to undefined function `%s'", Ident);
|
|
|
|
}
|
2004-05-25 20:59:38 +00:00
|
|
|
Sym = AddGlobalSym (Ident, GetImplicitFuncType(), SC_EXTERN | SC_REF | SC_FUNC);
|
|
|
|
E->Type = Sym->Type;
|
2004-05-31 15:27:33 +00:00
|
|
|
E->Flags = E_LOC_GLOBAL | E_RTYPE_RVAL;
|
2004-05-25 20:59:38 +00:00
|
|
|
E->Name = (unsigned long) Sym->Name;
|
|
|
|
} else {
|
|
|
|
/* Undeclared Variable */
|
|
|
|
Sym = AddLocalSym (Ident, type_int, SC_AUTO | SC_REF, 0);
|
2004-05-31 15:27:33 +00:00
|
|
|
E->Flags = E_LOC_STACK | E_RTYPE_LVAL;
|
2004-05-25 20:59:38 +00:00
|
|
|
E->Type = type_int;
|
|
|
|
Error ("Undefined symbol: `%s'", Ident);
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
}
|
|
|
|
break;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
case TOK_SCONST:
|
|
|
|
/* String literal */
|
|
|
|
E->Type = GetCharArrayType (GetLiteralPoolOffs () - CurTok.IVal);
|
2004-05-31 19:51:13 +00:00
|
|
|
E->Flags = E_LOC_LITERAL | E_RTYPE_RVAL;
|
2004-06-06 14:48:59 +00:00
|
|
|
E->IVal = CurTok.IVal;
|
2004-05-31 19:51:13 +00:00
|
|
|
E->Name = LiteralPoolLabel;
|
2004-05-25 20:59:38 +00:00
|
|
|
NextToken ();
|
|
|
|
break;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
case TOK_ASM:
|
|
|
|
/* ASM statement */
|
|
|
|
AsmStatement ();
|
2004-05-31 15:27:33 +00:00
|
|
|
E->Flags = E_LOC_EXPR | E_RTYPE_RVAL;
|
2004-05-25 20:59:38 +00:00
|
|
|
E->Type = type_void;
|
|
|
|
break;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-31 15:27:33 +00:00
|
|
|
case TOK_A:
|
|
|
|
/* Register pseudo variable */
|
|
|
|
E->Type = type_uchar;
|
|
|
|
E->Flags = E_LOC_PRIMARY | E_RTYPE_LVAL;
|
|
|
|
NextToken ();
|
|
|
|
break;
|
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
case TOK_AX:
|
2004-05-31 15:27:33 +00:00
|
|
|
/* Register pseudo variable */
|
|
|
|
E->Type = type_uint;
|
|
|
|
E->Flags = E_LOC_PRIMARY | E_RTYPE_LVAL;
|
|
|
|
NextToken ();
|
|
|
|
break;
|
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
case TOK_EAX:
|
2004-05-31 15:27:33 +00:00
|
|
|
/* Register pseudo variable */
|
|
|
|
E->Type = type_ulong;
|
|
|
|
E->Flags = E_LOC_PRIMARY | E_RTYPE_LVAL;
|
2004-05-25 20:59:38 +00:00
|
|
|
NextToken ();
|
|
|
|
break;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
default:
|
|
|
|
/* Illegal primary. */
|
|
|
|
Error ("Expression expected");
|
2004-05-31 15:27:33 +00:00
|
|
|
ED_MakeConstAbsInt (E, 1);
|
2004-05-25 20:59:38 +00:00
|
|
|
break;
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
static void ArrayRef (ExprDesc* Expr)
|
2005-01-09 21:17:19 +00:00
|
|
|
/* Handle an array reference. This function needs a rewrite. */
|
2000-05-28 13:40:48 +00:00
|
|
|
{
|
2004-05-31 15:27:33 +00:00
|
|
|
int ConstBaseAddr;
|
|
|
|
ExprDesc SubScript;
|
|
|
|
CodeMark Mark1;
|
|
|
|
CodeMark Mark2;
|
2006-02-19 12:29:37 +00:00
|
|
|
Type* ElementType;
|
|
|
|
Type* tptr1;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
|
|
|
|
/* Skip the bracket */
|
2000-06-12 18:31:40 +00:00
|
|
|
NextToken ();
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Get the type of left side */
|
2004-05-25 20:59:38 +00:00
|
|
|
tptr1 = Expr->Type;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* 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.
|
|
|
|
*/
|
2005-07-17 09:49:34 +00:00
|
|
|
ConstBaseAddr = ED_IsRVal (Expr) &&
|
2005-05-11 13:54:22 +00:00
|
|
|
(ED_IsLocConst (Expr) || ED_IsLocStack (Expr));
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* If we have a constant base, we delay the address fetch */
|
2004-07-06 11:30:08 +00:00
|
|
|
GetCodePos (&Mark1);
|
2000-05-28 13:40:48 +00:00
|
|
|
if (!ConstBaseAddr) {
|
|
|
|
/* Get a pointer to the array into the primary */
|
2004-06-09 14:12:57 +00:00
|
|
|
LoadExpr (CF_NONE, Expr);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Get the array pointer on stack. Do not push more than 16
|
|
|
|
* bit, even if this value is greater, since we cannot handle
|
|
|
|
* other than 16bit stuff when doing indexing.
|
|
|
|
*/
|
2004-07-06 11:30:08 +00:00
|
|
|
GetCodePos (&Mark2);
|
2000-05-28 13:40:48 +00:00
|
|
|
g_push (CF_PTR, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* TOS now contains ptr to array elements. Get the subscript. */
|
2004-05-31 15:27:33 +00:00
|
|
|
ExprWithCheck (hie0, &SubScript);
|
|
|
|
|
|
|
|
/* Check the types of array and subscript. We can either have a
|
|
|
|
* pointer/array to the left, in which case the subscript must be of an
|
|
|
|
* integer type, or we have an integer to the left, in which case the
|
|
|
|
* subscript must be a pointer/array.
|
|
|
|
* Since we do the necessary checking here, we can rely later on the
|
|
|
|
* correct types.
|
|
|
|
*/
|
|
|
|
if (IsClassPtr (Expr->Type)) {
|
|
|
|
if (!IsClassInt (SubScript.Type)) {
|
|
|
|
Error ("Array subscript is not an integer");
|
|
|
|
/* To avoid any compiler errors, make the expression a valid int */
|
|
|
|
ED_MakeConstAbsInt (&SubScript, 0);
|
|
|
|
}
|
|
|
|
ElementType = Indirect (Expr->Type);
|
|
|
|
} else if (IsClassInt (Expr->Type)) {
|
|
|
|
if (!IsClassPtr (SubScript.Type)) {
|
|
|
|
Error ("Subscripted value is neither array nor pointer");
|
|
|
|
/* To avoid compiler errors, make the subscript a char[] at
|
|
|
|
* address 0.
|
|
|
|
*/
|
|
|
|
ED_MakeConstAbs (&SubScript, 0, GetCharArrayType (1));
|
|
|
|
}
|
|
|
|
ElementType = Indirect (SubScript.Type);
|
|
|
|
} else {
|
|
|
|
Error ("Cannot subscript");
|
|
|
|
/* To avoid compiler errors, fake both the array and the subscript, so
|
|
|
|
* we can just proceed.
|
|
|
|
*/
|
|
|
|
ED_MakeConstAbs (Expr, 0, GetCharArrayType (1));
|
|
|
|
ED_MakeConstAbsInt (&SubScript, 0);
|
|
|
|
ElementType = Indirect (Expr->Type);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if the subscript is constant absolute value */
|
|
|
|
if (ED_IsConstAbs (&SubScript)) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-31 15:27:33 +00:00
|
|
|
/* The array subscript is a numeric constant. If we had pushed the
|
|
|
|
* array base address onto the stack before, we can remove this value,
|
|
|
|
* since we can generate expression+offset.
|
|
|
|
*/
|
2000-05-28 13:40:48 +00:00
|
|
|
if (!ConstBaseAddr) {
|
2004-07-06 11:30:08 +00:00
|
|
|
RemoveCode (&Mark2);
|
2000-05-28 13:40:48 +00:00
|
|
|
} else {
|
|
|
|
/* Get an array pointer into the primary */
|
2004-06-09 14:12:57 +00:00
|
|
|
LoadExpr (CF_NONE, Expr);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
2004-05-31 15:27:33 +00:00
|
|
|
if (IsClassPtr (Expr->Type)) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-31 15:27:33 +00:00
|
|
|
/* Lhs is pointer/array. Scale the subscript value according to
|
|
|
|
* the element size.
|
|
|
|
*/
|
2004-06-06 14:48:59 +00:00
|
|
|
SubScript.IVal *= CheckedSizeOf (ElementType);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-31 15:27:33 +00:00
|
|
|
/* Remove the address load code */
|
2004-07-06 11:30:08 +00:00
|
|
|
RemoveCode (&Mark1);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-31 15:27:33 +00:00
|
|
|
/* In case of an array, we can adjust the offset of the expression
|
|
|
|
* already in Expr. If the base address was a constant, we can even
|
|
|
|
* remove the code that loaded the address into the primary.
|
|
|
|
*/
|
|
|
|
if (IsTypeArray (Expr->Type)) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-31 15:27:33 +00:00
|
|
|
/* Adjust the offset */
|
2004-06-06 14:48:59 +00:00
|
|
|
Expr->IVal += SubScript.IVal;
|
2004-05-31 15:27:33 +00:00
|
|
|
|
|
|
|
} else {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-31 15:27:33 +00:00
|
|
|
/* It's a pointer, so we do have to load it into the primary
|
|
|
|
* first (if it's not already there).
|
|
|
|
*/
|
2005-01-09 21:17:19 +00:00
|
|
|
if (ConstBaseAddr || ED_IsLVal (Expr)) {
|
2004-06-09 14:12:57 +00:00
|
|
|
LoadExpr (CF_NONE, Expr);
|
2004-05-31 15:27:33 +00:00
|
|
|
ED_MakeRValExpr (Expr);
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-31 15:27:33 +00:00
|
|
|
/* Use the offset */
|
2004-06-06 14:48:59 +00:00
|
|
|
Expr->IVal = SubScript.IVal;
|
2004-05-31 15:27:33 +00:00
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-31 15:27:33 +00:00
|
|
|
} else {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-31 15:27:33 +00:00
|
|
|
/* Scale the rhs value according to the element type */
|
|
|
|
g_scale (TypeOf (tptr1), CheckedSizeOf (ElementType));
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-31 15:27:33 +00:00
|
|
|
/* Add the subscript. Since arrays are indexed by integers,
|
|
|
|
* we will ignore the true type of the subscript here and
|
2004-06-09 14:12:57 +00:00
|
|
|
* use always an int. #### Use offset but beware of LoadExpr!
|
2004-05-31 15:27:33 +00:00
|
|
|
*/
|
2004-06-06 14:48:59 +00:00
|
|
|
g_inc (CF_INT | CF_CONST, SubScript.IVal);
|
2004-05-31 15:27:33 +00:00
|
|
|
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
/* Array subscript is not constant. Load it into the primary */
|
2004-07-06 11:30:08 +00:00
|
|
|
GetCodePos (&Mark2);
|
2004-06-09 14:12:57 +00:00
|
|
|
LoadExpr (CF_NONE, &SubScript);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-31 15:27:33 +00:00
|
|
|
/* Do scaling */
|
|
|
|
if (IsClassPtr (Expr->Type)) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-31 15:27:33 +00:00
|
|
|
/* Indexing is based on unsigneds, so we will just use the integer
|
2000-05-28 13:40:48 +00:00
|
|
|
* portion of the index (which is in (e)ax, so there's no further
|
|
|
|
* action required).
|
|
|
|
*/
|
2004-06-02 21:33:35 +00:00
|
|
|
g_scale (CF_INT, CheckedSizeOf (ElementType));
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-31 15:27:33 +00:00
|
|
|
} else {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-31 15:27:33 +00:00
|
|
|
/* Get the int value on top. If we come here, we're sure, both
|
|
|
|
* values are 16 bit (the first one was truncated if necessary
|
|
|
|
* and the second one is a pointer). Note: If ConstBaseAddr is
|
|
|
|
* true, we don't have a value on stack, so to "swap" both, just
|
|
|
|
* push the subscript.
|
2000-10-10 20:40:36 +00:00
|
|
|
*/
|
2000-05-28 13:40:48 +00:00
|
|
|
if (ConstBaseAddr) {
|
2004-05-31 15:27:33 +00:00
|
|
|
g_push (CF_INT, 0);
|
2004-06-09 14:12:57 +00:00
|
|
|
LoadExpr (CF_NONE, Expr);
|
2004-05-31 15:27:33 +00:00
|
|
|
ConstBaseAddr = 0;
|
2000-05-28 13:40:48 +00:00
|
|
|
} else {
|
|
|
|
g_swap (CF_INT);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Scale it */
|
2004-05-31 15:27:33 +00:00
|
|
|
g_scale (TypeOf (tptr1), CheckedSizeOf (ElementType));
|
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
2004-05-31 15:27:33 +00:00
|
|
|
/* The offset is now in the primary register. It we didn't have a
|
2000-05-28 13:40:48 +00:00
|
|
|
* constant base address for the lhs, the lhs address is already
|
|
|
|
* on stack, and we must add the offset. If the base address was
|
|
|
|
* constant, we call special functions to add the address to the
|
|
|
|
* offset value.
|
|
|
|
*/
|
2008-08-05 19:47:57 +00:00
|
|
|
if (!ConstBaseAddr) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-31 15:27:33 +00:00
|
|
|
/* The array base address is on stack and the subscript is in the
|
|
|
|
* primary. Add both.
|
|
|
|
*/
|
2004-06-02 21:33:35 +00:00
|
|
|
g_add (CF_INT, 0);
|
2004-05-31 15:27:33 +00:00
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
/* The subscript is in the primary, and the array base address is
|
|
|
|
* in Expr. If the subscript has itself a constant address, it is
|
|
|
|
* often a better idea to reverse again the order of the
|
|
|
|
* evaluation. This will generate better code if the subscript is
|
|
|
|
* a byte sized variable. But beware: This is only possible if the
|
2008-08-05 19:47:57 +00:00
|
|
|
* subscript was not scaled, that is, if this was a byte array
|
|
|
|
* or pointer.
|
|
|
|
*/
|
2004-05-31 15:27:33 +00:00
|
|
|
if ((ED_IsLocConst (&SubScript) || ED_IsLocStack (&SubScript)) &&
|
|
|
|
CheckedSizeOf (ElementType) == SIZEOF_CHAR) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-31 15:27:33 +00:00
|
|
|
unsigned Flags;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2008-08-05 19:47:57 +00:00
|
|
|
/* Reverse the order of evaluation */
|
2004-05-31 15:27:33 +00:00
|
|
|
if (CheckedSizeOf (SubScript.Type) == SIZEOF_CHAR) {
|
|
|
|
Flags = CF_CHAR;
|
|
|
|
} else {
|
|
|
|
Flags = CF_INT;
|
|
|
|
}
|
2004-07-06 11:30:08 +00:00
|
|
|
RemoveCode (&Mark2);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2008-08-05 19:47:57 +00:00
|
|
|
/* Get a pointer to the array into the primary. */
|
|
|
|
LoadExpr (CF_NONE, Expr);
|
|
|
|
|
|
|
|
/* Add the variable */
|
|
|
|
if (ED_IsLocStack (&SubScript)) {
|
|
|
|
g_addlocal (Flags, SubScript.IVal);
|
|
|
|
} else {
|
2008-08-05 21:11:26 +00:00
|
|
|
Flags |= GlobalModeFlags (&SubScript);
|
2008-08-05 19:47:57 +00:00
|
|
|
g_addstatic (Flags, SubScript.Name, SubScript.IVal);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
|
|
|
|
if (ED_IsLocAbs (Expr)) {
|
|
|
|
/* Constant numeric address. Just add it */
|
|
|
|
g_inc (CF_INT, Expr->IVal);
|
|
|
|
} else if (ED_IsLocStack (Expr)) {
|
|
|
|
/* Base address is a local variable address */
|
|
|
|
if (IsTypeArray (Expr->Type)) {
|
|
|
|
g_addaddr_local (CF_INT, Expr->IVal);
|
2002-12-12 17:40:58 +00:00
|
|
|
} else {
|
2008-08-05 19:47:57 +00:00
|
|
|
g_addlocal (CF_PTR, Expr->IVal);
|
2002-12-12 17:40:58 +00:00
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
} else {
|
|
|
|
/* Base address is a static variable address */
|
2008-08-05 21:11:26 +00:00
|
|
|
unsigned Flags = CF_INT | GlobalModeFlags (Expr);
|
2008-08-05 19:47:57 +00:00
|
|
|
if (ED_IsRVal (Expr)) {
|
|
|
|
/* Add the address of the location */
|
2004-06-06 14:48:59 +00:00
|
|
|
g_addaddr_static (Flags, Expr->Name, Expr->IVal);
|
2002-12-12 17:40:58 +00:00
|
|
|
} else {
|
2008-08-05 19:47:57 +00:00
|
|
|
/* Add the contents of the location */
|
2004-06-06 14:48:59 +00:00
|
|
|
g_addstatic (Flags, Expr->Name, Expr->IVal);
|
2002-12-12 17:40:58 +00:00
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
}
|
2004-05-31 15:27:33 +00:00
|
|
|
|
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
2004-05-31 15:27:33 +00:00
|
|
|
|
|
|
|
/* The result is an expression in the primary */
|
|
|
|
ED_MakeRValExpr (Expr);
|
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
2004-05-31 15:27:33 +00:00
|
|
|
|
|
|
|
/* Result is of element type */
|
|
|
|
Expr->Type = ElementType;
|
|
|
|
|
|
|
|
/* An array element is actually a variable. So the rules for variables
|
|
|
|
* with respect to the reference type apply: If it's an array, it is
|
|
|
|
* a rvalue, otherwise it's an lvalue. (A function would also be a rvalue,
|
|
|
|
* but an array cannot contain functions).
|
|
|
|
*/
|
|
|
|
if (IsTypeArray (Expr->Type)) {
|
|
|
|
ED_MakeRVal (Expr);
|
|
|
|
} else {
|
|
|
|
ED_MakeLVal (Expr);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Consume the closing bracket */
|
2000-05-28 13:40:48 +00:00
|
|
|
ConsumeRBrack ();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
static void StructRef (ExprDesc* Expr)
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Process struct field after . or ->. */
|
|
|
|
{
|
|
|
|
ident Ident;
|
|
|
|
SymEntry* Field;
|
|
|
|
|
|
|
|
/* Skip the token and check for an identifier */
|
2000-06-12 18:31:40 +00:00
|
|
|
NextToken ();
|
2001-05-22 09:32:24 +00:00
|
|
|
if (CurTok.Tok != TOK_IDENT) {
|
2000-11-02 21:22:33 +00:00
|
|
|
Error ("Identifier expected");
|
2004-05-25 20:59:38 +00:00
|
|
|
Expr->Type = type_int;
|
|
|
|
return;
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Get the symbol table entry and check for a struct field */
|
|
|
|
strcpy (Ident, CurTok.Ident);
|
2000-06-12 18:31:40 +00:00
|
|
|
NextToken ();
|
2004-05-25 20:59:38 +00:00
|
|
|
Field = FindStructField (Expr->Type, Ident);
|
2000-05-28 13:40:48 +00:00
|
|
|
if (Field == 0) {
|
2000-11-02 21:22:33 +00:00
|
|
|
Error ("Struct/union has no field named `%s'", Ident);
|
2004-05-25 20:59:38 +00:00
|
|
|
Expr->Type = type_int;
|
|
|
|
return;
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
2004-06-03 12:08:49 +00:00
|
|
|
/* If we have a struct pointer that is an lvalue and not already in the
|
2004-06-03 11:10:30 +00:00
|
|
|
* primary, load it now.
|
2004-05-31 15:27:33 +00:00
|
|
|
*/
|
2004-06-03 11:10:30 +00:00
|
|
|
if (ED_IsLVal (Expr) && IsTypePtr (Expr->Type)) {
|
2004-05-31 15:27:33 +00:00
|
|
|
|
|
|
|
/* Load into the primary */
|
2004-06-09 14:12:57 +00:00
|
|
|
LoadExpr (CF_NONE, Expr);
|
2004-05-31 15:27:33 +00:00
|
|
|
|
|
|
|
/* Make it an lvalue expression */
|
|
|
|
ED_MakeLValExpr (Expr);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
2004-05-31 15:27:33 +00:00
|
|
|
|
|
|
|
/* Set the struct field offset */
|
2004-06-06 14:48:59 +00:00
|
|
|
Expr->IVal += Field->V.Offs;
|
2004-05-31 15:27:33 +00:00
|
|
|
|
|
|
|
/* The type is now the type of the field */
|
2004-05-25 20:59:38 +00:00
|
|
|
Expr->Type = Field->Type;
|
2004-05-31 15:27:33 +00:00
|
|
|
|
|
|
|
/* An struct member is actually a variable. So the rules for variables
|
|
|
|
* with respect to the reference type apply: If it's an array, it is
|
|
|
|
* a rvalue, otherwise it's an lvalue. (A function would also be a rvalue,
|
|
|
|
* but a struct field cannot be a function).
|
|
|
|
*/
|
|
|
|
if (IsTypeArray (Expr->Type)) {
|
|
|
|
ED_MakeRVal (Expr);
|
|
|
|
} else {
|
|
|
|
ED_MakeLVal (Expr);
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
static void hie11 (ExprDesc *Expr)
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Handle compound types (structs and arrays) */
|
|
|
|
{
|
2005-07-17 09:49:34 +00:00
|
|
|
/* Name value used in invalid function calls */
|
|
|
|
static const char IllegalFunc[] = "illegal_function_call";
|
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
/* Evaluate the lhs */
|
|
|
|
Primary (Expr);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
/* Check for a rhs */
|
|
|
|
while (CurTok.Tok == TOK_LBRACK || CurTok.Tok == TOK_LPAREN ||
|
|
|
|
CurTok.Tok == TOK_DOT || CurTok.Tok == TOK_PTR_REF) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
switch (CurTok.Tok) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
case TOK_LBRACK:
|
|
|
|
/* Array reference */
|
|
|
|
ArrayRef (Expr);
|
|
|
|
break;
|
2001-09-24 22:36:35 +00:00
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
case TOK_LPAREN:
|
|
|
|
/* Function call. */
|
2004-05-31 15:27:33 +00:00
|
|
|
if (!IsTypeFunc (Expr->Type) && !IsTypeFuncPtr (Expr->Type)) {
|
|
|
|
/* Not a function */
|
2004-05-25 20:59:38 +00:00
|
|
|
Error ("Illegal function call");
|
2004-05-31 15:27:33 +00:00
|
|
|
/* Force the type to be a implicitly defined function, one
|
|
|
|
* returning an int and taking any number of arguments.
|
2005-07-17 09:49:34 +00:00
|
|
|
* Since we don't have a name, invent one.
|
2004-05-31 15:27:33 +00:00
|
|
|
*/
|
|
|
|
ED_MakeConstAbs (Expr, 0, GetImplicitFuncType ());
|
2005-07-17 09:49:34 +00:00
|
|
|
Expr->Name = (long) IllegalFunc;
|
2004-05-25 20:59:38 +00:00
|
|
|
}
|
2004-05-31 15:27:33 +00:00
|
|
|
/* Call the function */
|
|
|
|
FunctionCall (Expr);
|
2004-05-25 20:59:38 +00:00
|
|
|
break;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
case TOK_DOT:
|
|
|
|
if (!IsClassStruct (Expr->Type)) {
|
|
|
|
Error ("Struct expected");
|
|
|
|
}
|
|
|
|
StructRef (Expr);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TOK_PTR_REF:
|
|
|
|
/* If we have an array, convert it to pointer to first element */
|
|
|
|
if (IsTypeArray (Expr->Type)) {
|
|
|
|
Expr->Type = ArrayToPtr (Expr->Type);
|
|
|
|
}
|
|
|
|
if (!IsClassPtr (Expr->Type) || !IsClassStruct (Indirect (Expr->Type))) {
|
|
|
|
Error ("Struct pointer expected");
|
|
|
|
}
|
|
|
|
StructRef (Expr);
|
|
|
|
break;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
default:
|
|
|
|
Internal ("Invalid token in hie11: %d", CurTok.Tok);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2006-02-19 12:29:37 +00:00
|
|
|
void Store (ExprDesc* Expr, const Type* StoreType)
|
2004-05-26 16:15:28 +00:00
|
|
|
/* Store the primary register into the location denoted by Expr. If StoreType
|
|
|
|
* is given, use this type when storing instead of Expr->Type. If StoreType
|
|
|
|
* is NULL, use Expr->Type instead.
|
2002-11-01 21:27:31 +00:00
|
|
|
*/
|
2000-05-28 13:40:48 +00:00
|
|
|
{
|
2002-11-01 21:27:31 +00:00
|
|
|
unsigned Flags;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-26 16:15:28 +00:00
|
|
|
/* If StoreType was not given, use Expr->Type instead */
|
2002-11-01 21:27:31 +00:00
|
|
|
if (StoreType == 0) {
|
2004-05-26 16:15:28 +00:00
|
|
|
StoreType = Expr->Type;
|
2002-11-01 21:27:31 +00:00
|
|
|
}
|
|
|
|
|
2004-05-31 15:27:33 +00:00
|
|
|
/* Prepare the code generator flags */
|
2002-11-01 21:27:31 +00:00
|
|
|
Flags = TypeOf (StoreType);
|
2004-05-31 15:27:33 +00:00
|
|
|
|
|
|
|
/* Do the store depending on the location */
|
|
|
|
switch (ED_GetLoc (Expr)) {
|
|
|
|
|
|
|
|
case E_LOC_ABS:
|
|
|
|
/* Absolute: numeric address or const */
|
2004-06-06 14:48:59 +00:00
|
|
|
g_putstatic (Flags | CF_ABSOLUTE, Expr->IVal, 0);
|
2004-05-31 15:27:33 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case E_LOC_GLOBAL:
|
|
|
|
/* Global variable */
|
2004-06-06 14:48:59 +00:00
|
|
|
g_putstatic (Flags | CF_EXTERNAL, Expr->Name, Expr->IVal);
|
2004-05-31 15:27:33 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case E_LOC_STATIC:
|
2004-05-31 19:51:13 +00:00
|
|
|
case E_LOC_LITERAL:
|
|
|
|
/* Static variable or literal in the literal pool */
|
2004-06-06 14:48:59 +00:00
|
|
|
g_putstatic (Flags | CF_STATIC, Expr->Name, Expr->IVal);
|
2006-05-29 20:38:44 +00:00
|
|
|
break;
|
2004-05-31 15:27:33 +00:00
|
|
|
|
|
|
|
case E_LOC_REGISTER:
|
|
|
|
/* Register variable */
|
2004-06-06 14:48:59 +00:00
|
|
|
g_putstatic (Flags | CF_REGVAR, Expr->Name, Expr->IVal);
|
2004-05-31 15:27:33 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case E_LOC_STACK:
|
|
|
|
/* Value on the stack */
|
2004-06-06 14:48:59 +00:00
|
|
|
g_putlocal (Flags, Expr->IVal, 0);
|
2004-05-31 15:27:33 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case E_LOC_PRIMARY:
|
|
|
|
/* The primary register (value is already there) */
|
|
|
|
/* ### Do we need a test here if the flag is set? */
|
|
|
|
break;
|
|
|
|
|
|
|
|
case E_LOC_EXPR:
|
|
|
|
/* An expression in the primary register */
|
2004-06-06 14:48:59 +00:00
|
|
|
g_putind (Flags, Expr->IVal);
|
2004-05-31 15:27:33 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
Internal ("Invalid location in Store(): 0x%04X", ED_GetLoc (Expr));
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Assume that each one of the stores will invalidate CC */
|
2004-06-05 20:29:47 +00:00
|
|
|
ED_MarkAsUntested (Expr);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2004-05-31 15:27:33 +00:00
|
|
|
static void PreInc (ExprDesc* Expr)
|
|
|
|
/* Handle the preincrement operators */
|
2000-05-28 13:40:48 +00:00
|
|
|
{
|
2004-05-31 15:27:33 +00:00
|
|
|
unsigned Flags;
|
|
|
|
unsigned long Val;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
/* Skip the operator token */
|
2000-06-12 18:31:40 +00:00
|
|
|
NextToken ();
|
2004-05-25 20:59:38 +00:00
|
|
|
|
|
|
|
/* Evaluate the expression and check that it is an lvalue */
|
|
|
|
hie10 (Expr);
|
2004-05-31 15:27:33 +00:00
|
|
|
if (!ED_IsLVal (Expr)) {
|
|
|
|
Error ("Invalid lvalue");
|
|
|
|
return;
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Get the data type */
|
2004-05-31 15:27:33 +00:00
|
|
|
Flags = TypeOf (Expr->Type) | CF_FORCECHAR | CF_CONST;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Get the increment value in bytes */
|
2004-05-31 15:27:33 +00:00
|
|
|
Val = IsTypePtr (Expr->Type)? CheckedPSizeOf (Expr->Type) : 1;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-31 15:27:33 +00:00
|
|
|
/* Check the location of the data */
|
|
|
|
switch (ED_GetLoc (Expr)) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-31 15:27:33 +00:00
|
|
|
case E_LOC_ABS:
|
|
|
|
/* Absolute: numeric address or const */
|
2004-06-06 14:48:59 +00:00
|
|
|
g_addeqstatic (Flags | CF_ABSOLUTE, Expr->IVal, 0, Val);
|
2004-05-31 15:27:33 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case E_LOC_GLOBAL:
|
|
|
|
/* Global variable */
|
2004-06-06 14:48:59 +00:00
|
|
|
g_addeqstatic (Flags | CF_EXTERNAL, Expr->Name, Expr->IVal, Val);
|
2004-05-31 15:27:33 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case E_LOC_STATIC:
|
2004-05-31 19:51:13 +00:00
|
|
|
case E_LOC_LITERAL:
|
|
|
|
/* Static variable or literal in the literal pool */
|
2004-06-06 14:48:59 +00:00
|
|
|
g_addeqstatic (Flags | CF_STATIC, Expr->Name, Expr->IVal, Val);
|
2004-05-31 15:27:33 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case E_LOC_REGISTER:
|
|
|
|
/* Register variable */
|
2004-06-06 14:48:59 +00:00
|
|
|
g_addeqstatic (Flags | CF_REGVAR, Expr->Name, Expr->IVal, Val);
|
2004-05-31 15:27:33 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case E_LOC_STACK:
|
|
|
|
/* Value on the stack */
|
2004-06-06 14:48:59 +00:00
|
|
|
g_addeqlocal (Flags, Expr->IVal, Val);
|
2004-05-31 15:27:33 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case E_LOC_PRIMARY:
|
|
|
|
/* The primary register */
|
|
|
|
g_inc (Flags, Val);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case E_LOC_EXPR:
|
|
|
|
/* An expression in the primary register */
|
2004-06-06 14:48:59 +00:00
|
|
|
g_addeqind (Flags, Expr->IVal, Val);
|
2004-05-31 15:27:33 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
Internal ("Invalid location in PreInc(): 0x%04X", ED_GetLoc (Expr));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Result is an expression, no reference */
|
|
|
|
ED_MakeRValExpr (Expr);
|
|
|
|
}
|
|
|
|
|
2004-06-06 15:59:44 +00:00
|
|
|
|
2004-05-31 15:27:33 +00:00
|
|
|
|
|
|
|
static void PreDec (ExprDesc* Expr)
|
|
|
|
/* Handle the predecrement operators */
|
|
|
|
{
|
|
|
|
unsigned Flags;
|
|
|
|
unsigned long Val;
|
|
|
|
|
|
|
|
/* Skip the operator token */
|
|
|
|
NextToken ();
|
|
|
|
|
|
|
|
/* Evaluate the expression and check that it is an lvalue */
|
|
|
|
hie10 (Expr);
|
|
|
|
if (!ED_IsLVal (Expr)) {
|
|
|
|
Error ("Invalid lvalue");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get the data type */
|
|
|
|
Flags = TypeOf (Expr->Type) | CF_FORCECHAR | CF_CONST;
|
|
|
|
|
|
|
|
/* Get the increment value in bytes */
|
|
|
|
Val = IsTypePtr (Expr->Type)? CheckedPSizeOf (Expr->Type) : 1;
|
|
|
|
|
|
|
|
/* Check the location of the data */
|
|
|
|
switch (ED_GetLoc (Expr)) {
|
|
|
|
|
|
|
|
case E_LOC_ABS:
|
|
|
|
/* Absolute: numeric address or const */
|
2004-06-06 14:48:59 +00:00
|
|
|
g_subeqstatic (Flags | CF_ABSOLUTE, Expr->IVal, 0, Val);
|
2004-05-31 15:27:33 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case E_LOC_GLOBAL:
|
|
|
|
/* Global variable */
|
2004-06-06 14:48:59 +00:00
|
|
|
g_subeqstatic (Flags | CF_EXTERNAL, Expr->Name, Expr->IVal, Val);
|
2004-05-31 15:27:33 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case E_LOC_STATIC:
|
2004-05-31 19:51:13 +00:00
|
|
|
case E_LOC_LITERAL:
|
|
|
|
/* Static variable or literal in the literal pool */
|
2004-06-06 14:48:59 +00:00
|
|
|
g_subeqstatic (Flags | CF_STATIC, Expr->Name, Expr->IVal, Val);
|
2004-05-31 15:27:33 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case E_LOC_REGISTER:
|
|
|
|
/* Register variable */
|
2004-06-06 14:48:59 +00:00
|
|
|
g_subeqstatic (Flags | CF_REGVAR, Expr->Name, Expr->IVal, Val);
|
2004-05-31 15:27:33 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case E_LOC_STACK:
|
|
|
|
/* Value on the stack */
|
2004-06-06 14:48:59 +00:00
|
|
|
g_subeqlocal (Flags, Expr->IVal, Val);
|
2004-05-31 15:27:33 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case E_LOC_PRIMARY:
|
|
|
|
/* The primary register */
|
|
|
|
g_inc (Flags, Val);
|
|
|
|
break;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-31 15:27:33 +00:00
|
|
|
case E_LOC_EXPR:
|
|
|
|
/* An expression in the primary register */
|
2004-06-06 14:48:59 +00:00
|
|
|
g_subeqind (Flags, Expr->IVal, Val);
|
2004-05-31 15:27:33 +00:00
|
|
|
break;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-31 15:27:33 +00:00
|
|
|
default:
|
|
|
|
Internal ("Invalid location in PreDec(): 0x%04X", ED_GetLoc (Expr));
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
/* Result is an expression, no reference */
|
2004-05-31 15:27:33 +00:00
|
|
|
ED_MakeRValExpr (Expr);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-06 15:59:44 +00:00
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
static void PostIncDec (ExprDesc* Expr, void (*inc) (unsigned, unsigned long))
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Handle i-- and i++ */
|
|
|
|
{
|
2004-05-31 15:27:33 +00:00
|
|
|
unsigned Flags;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2000-06-12 18:31:40 +00:00
|
|
|
NextToken ();
|
2004-05-25 20:59:38 +00:00
|
|
|
|
|
|
|
/* The expression to increment must be an lvalue */
|
2004-05-31 15:27:33 +00:00
|
|
|
if (!ED_IsLVal (Expr)) {
|
2000-11-02 21:22:33 +00:00
|
|
|
Error ("Invalid lvalue");
|
2000-05-28 13:40:48 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get the data type */
|
2004-05-31 15:27:33 +00:00
|
|
|
Flags = TypeOf (Expr->Type);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Push the address if needed */
|
2004-05-25 20:59:38 +00:00
|
|
|
PushAddr (Expr);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Fetch the value and save it (since it's the result of the expression) */
|
2004-06-09 14:12:57 +00:00
|
|
|
LoadExpr (CF_NONE, Expr);
|
2004-05-31 15:27:33 +00:00
|
|
|
g_save (Flags | CF_FORCECHAR);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* If we have a pointer expression, increment by the size of the type */
|
2004-05-31 15:27:33 +00:00
|
|
|
if (IsTypePtr (Expr->Type)) {
|
|
|
|
inc (Flags | CF_CONST | CF_FORCECHAR, CheckedSizeOf (Expr->Type + 1));
|
2000-05-28 13:40:48 +00:00
|
|
|
} else {
|
2004-05-31 15:27:33 +00:00
|
|
|
inc (Flags | CF_CONST | CF_FORCECHAR, 1);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Store the result back */
|
2004-05-25 20:59:38 +00:00
|
|
|
Store (Expr, 0);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
/* Restore the original value in the primary register */
|
2004-05-31 15:27:33 +00:00
|
|
|
g_restore (Flags | CF_FORCECHAR);
|
2004-05-25 20:59:38 +00:00
|
|
|
|
|
|
|
/* The result is always an expression, no reference */
|
2004-05-31 15:27:33 +00:00
|
|
|
ED_MakeRValExpr (Expr);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
static void UnaryOp (ExprDesc* Expr)
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Handle unary -/+ and ~ */
|
|
|
|
{
|
2004-05-31 15:27:33 +00:00
|
|
|
unsigned Flags;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
/* Remember the operator token and skip it */
|
|
|
|
token_t Tok = CurTok.Tok;
|
2000-06-12 18:31:40 +00:00
|
|
|
NextToken ();
|
2004-05-25 20:59:38 +00:00
|
|
|
|
|
|
|
/* Get the expression */
|
|
|
|
hie10 (Expr);
|
|
|
|
|
2004-05-31 15:27:33 +00:00
|
|
|
/* We can only handle integer types */
|
|
|
|
if (!IsClassInt (Expr->Type)) {
|
|
|
|
Error ("Argument must have integer type");
|
|
|
|
ED_MakeConstAbsInt (Expr, 1);
|
|
|
|
}
|
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
/* Check for a constant expression */
|
2004-05-31 15:27:33 +00:00
|
|
|
if (ED_IsConstAbs (Expr)) {
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Value is constant */
|
2004-05-25 20:59:38 +00:00
|
|
|
switch (Tok) {
|
2004-06-06 14:48:59 +00:00
|
|
|
case TOK_MINUS: Expr->IVal = -Expr->IVal; break;
|
|
|
|
case TOK_PLUS: break;
|
|
|
|
case TOK_COMP: Expr->IVal = ~Expr->IVal; break;
|
2004-05-25 20:59:38 +00:00
|
|
|
default: Internal ("Unexpected token: %d", Tok);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* Value is not constant */
|
2004-06-09 14:12:57 +00:00
|
|
|
LoadExpr (CF_NONE, Expr);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Get the type of the expression */
|
2004-05-31 15:27:33 +00:00
|
|
|
Flags = TypeOf (Expr->Type);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Handle the operation */
|
2004-05-25 20:59:38 +00:00
|
|
|
switch (Tok) {
|
2004-05-31 15:27:33 +00:00
|
|
|
case TOK_MINUS: g_neg (Flags); break;
|
2000-06-12 18:31:40 +00:00
|
|
|
case TOK_PLUS: break;
|
2004-05-31 15:27:33 +00:00
|
|
|
case TOK_COMP: g_com (Flags); break;
|
|
|
|
default: Internal ("Unexpected token: %d", Tok);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
2004-05-25 20:59:38 +00:00
|
|
|
|
|
|
|
/* The result is a rvalue in the primary */
|
2004-05-31 15:27:33 +00:00
|
|
|
ED_MakeRValExpr (Expr);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
void hie10 (ExprDesc* Expr)
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Handle ++, --, !, unary - etc. */
|
|
|
|
{
|
2004-05-31 15:27:33 +00:00
|
|
|
unsigned long Size;
|
|
|
|
|
2001-05-22 09:32:24 +00:00
|
|
|
switch (CurTok.Tok) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2000-06-12 18:31:40 +00:00
|
|
|
case TOK_INC:
|
2004-05-31 15:27:33 +00:00
|
|
|
PreInc (Expr);
|
2004-05-25 20:59:38 +00:00
|
|
|
break;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2000-06-12 18:31:40 +00:00
|
|
|
case TOK_DEC:
|
2004-05-31 15:27:33 +00:00
|
|
|
PreDec (Expr);
|
2004-05-25 20:59:38 +00:00
|
|
|
break;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2000-06-12 18:31:40 +00:00
|
|
|
case TOK_PLUS:
|
|
|
|
case TOK_MINUS:
|
|
|
|
case TOK_COMP:
|
2004-05-25 20:59:38 +00:00
|
|
|
UnaryOp (Expr);
|
|
|
|
break;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2000-06-12 18:31:40 +00:00
|
|
|
case TOK_BOOL_NOT:
|
|
|
|
NextToken ();
|
2004-05-25 20:59:38 +00:00
|
|
|
if (evalexpr (CF_NONE, hie10, Expr) == 0) {
|
2002-12-29 21:23:28 +00:00
|
|
|
/* Constant expression */
|
2004-06-06 14:48:59 +00:00
|
|
|
Expr->IVal = !Expr->IVal;
|
2000-05-28 13:40:48 +00:00
|
|
|
} else {
|
2004-05-25 20:59:38 +00:00
|
|
|
g_bneg (TypeOf (Expr->Type));
|
2004-05-31 15:27:33 +00:00
|
|
|
ED_MakeRValExpr (Expr);
|
2004-06-05 20:29:47 +00:00
|
|
|
ED_TestDone (Expr); /* bneg will set cc */
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
2004-05-25 20:59:38 +00:00
|
|
|
break;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2000-06-12 18:31:40 +00:00
|
|
|
case TOK_STAR:
|
|
|
|
NextToken ();
|
2004-06-03 12:08:49 +00:00
|
|
|
ExprWithCheck (hie10, Expr);
|
2004-06-03 12:09:24 +00:00
|
|
|
if (ED_IsLVal (Expr) || !(ED_IsLocConst (Expr) || ED_IsLocStack (Expr))) {
|
2004-06-03 12:08:49 +00:00
|
|
|
/* Not a const, load it into the primary and make it a
|
|
|
|
* calculated value.
|
|
|
|
*/
|
2004-06-09 14:12:57 +00:00
|
|
|
LoadExpr (CF_NONE, Expr);
|
2004-06-03 12:08:49 +00:00
|
|
|
ED_MakeRValExpr (Expr);
|
|
|
|
}
|
2002-12-29 21:23:28 +00:00
|
|
|
/* If the expression is already a pointer to function, the
|
|
|
|
* additional dereferencing operator must be ignored.
|
|
|
|
*/
|
2004-05-25 20:59:38 +00:00
|
|
|
if (IsTypeFuncPtr (Expr->Type)) {
|
2002-12-29 21:23:28 +00:00
|
|
|
/* Expression not storable */
|
2004-05-25 20:59:38 +00:00
|
|
|
ED_MakeRVal (Expr);
|
2002-12-29 21:23:28 +00:00
|
|
|
} else {
|
2004-05-25 20:59:38 +00:00
|
|
|
if (IsClassPtr (Expr->Type)) {
|
|
|
|
Expr->Type = Indirect (Expr->Type);
|
2002-12-29 21:23:28 +00:00
|
|
|
} else {
|
|
|
|
Error ("Illegal indirection");
|
|
|
|
}
|
2004-05-25 20:59:38 +00:00
|
|
|
ED_MakeLVal (Expr);
|
2002-12-29 21:23:28 +00:00
|
|
|
}
|
|
|
|
break;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2000-06-12 18:31:40 +00:00
|
|
|
case TOK_AND:
|
|
|
|
NextToken ();
|
2004-06-03 12:08:49 +00:00
|
|
|
ExprWithCheck (hie10, Expr);
|
2000-11-24 10:46:04 +00:00
|
|
|
/* The & operator may be applied to any lvalue, and it may be
|
|
|
|
* applied to functions, even if they're no lvalues.
|
|
|
|
*/
|
2007-03-18 19:15:35 +00:00
|
|
|
if (ED_IsRVal (Expr) && !IsTypeFunc (Expr->Type) && !IsTypeArray (Expr->Type)) {
|
|
|
|
Error ("Illegal address");
|
2000-05-28 13:40:48 +00:00
|
|
|
} else {
|
2004-05-25 20:59:38 +00:00
|
|
|
Expr->Type = PointerTo (Expr->Type);
|
|
|
|
ED_MakeRVal (Expr);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
2004-05-25 20:59:38 +00:00
|
|
|
break;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2000-06-12 18:31:40 +00:00
|
|
|
case TOK_SIZEOF:
|
|
|
|
NextToken ();
|
2004-05-26 16:15:28 +00:00
|
|
|
if (TypeSpecAhead ()) {
|
2006-02-19 12:29:37 +00:00
|
|
|
Type T[MAXTYPELEN];
|
2002-12-29 21:23:28 +00:00
|
|
|
NextToken ();
|
2006-02-19 12:29:37 +00:00
|
|
|
Size = CheckedSizeOf (ParseType (T));
|
2002-12-29 21:23:28 +00:00
|
|
|
ConsumeRParen ();
|
2000-05-28 13:40:48 +00:00
|
|
|
} else {
|
2002-12-29 21:23:28 +00:00
|
|
|
/* Remember the output queue pointer */
|
2004-07-06 11:30:08 +00:00
|
|
|
CodeMark Mark;
|
|
|
|
GetCodePos (&Mark);
|
2004-05-25 20:59:38 +00:00
|
|
|
hie10 (Expr);
|
2004-05-31 15:27:33 +00:00
|
|
|
Size = CheckedSizeOf (Expr->Type);
|
2002-12-29 21:23:28 +00:00
|
|
|
/* Remove any generated code */
|
2004-07-06 11:30:08 +00:00
|
|
|
RemoveCode (&Mark);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
2004-05-31 15:27:33 +00:00
|
|
|
ED_MakeConstAbs (Expr, Size, type_size_t);
|
2004-06-05 20:29:47 +00:00
|
|
|
ED_MarkAsUntested (Expr);
|
2004-05-25 20:59:38 +00:00
|
|
|
break;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
default:
|
2004-05-26 16:15:28 +00:00
|
|
|
if (TypeSpecAhead ()) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
/* A typecast */
|
|
|
|
TypeCast (Expr);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
} else {
|
|
|
|
|
|
|
|
/* An expression */
|
|
|
|
hie11 (Expr);
|
|
|
|
|
|
|
|
/* Handle post increment */
|
|
|
|
if (CurTok.Tok == TOK_INC) {
|
|
|
|
PostIncDec (Expr, g_inc);
|
|
|
|
} else if (CurTok.Tok == TOK_DEC) {
|
|
|
|
PostIncDec (Expr, g_dec);
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
}
|
|
|
|
break;
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
static void hie_internal (const GenDesc* Ops, /* List of generators */
|
2004-05-26 16:15:28 +00:00
|
|
|
ExprDesc* Expr,
|
2004-05-25 20:59:38 +00:00
|
|
|
void (*hienext) (ExprDesc*),
|
2004-05-26 16:15:28 +00:00
|
|
|
int* UsedGen)
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Helper function */
|
|
|
|
{
|
2004-05-31 15:27:33 +00:00
|
|
|
ExprDesc Expr2;
|
2000-05-28 13:40:48 +00:00
|
|
|
CodeMark Mark1;
|
|
|
|
CodeMark Mark2;
|
2002-04-06 14:51:27 +00:00
|
|
|
const GenDesc* Gen;
|
2004-05-31 15:27:33 +00:00
|
|
|
token_t Tok; /* The operator token */
|
2000-05-28 13:40:48 +00:00
|
|
|
unsigned ltype, type;
|
|
|
|
int rconst; /* Operand is a constant */
|
|
|
|
|
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
hienext (Expr);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
*UsedGen = 0;
|
2004-05-25 20:59:38 +00:00
|
|
|
while ((Gen = FindGen (CurTok.Tok, Ops)) != 0) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Tell the caller that we handled it's ops */
|
2004-05-25 20:59:38 +00:00
|
|
|
*UsedGen = 1;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* All operators that call this function expect an int on the lhs */
|
2004-05-25 20:59:38 +00:00
|
|
|
if (!IsClassInt (Expr->Type)) {
|
2000-11-02 21:22:33 +00:00
|
|
|
Error ("Integer expression expected");
|
2006-02-17 20:19:35 +00:00
|
|
|
/* To avoid further errors, make Expr a valid int expression */
|
|
|
|
ED_MakeConstAbsInt (Expr, 1);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Remember the operator token, then skip it */
|
2004-05-25 20:59:38 +00:00
|
|
|
Tok = CurTok.Tok;
|
2000-06-12 18:31:40 +00:00
|
|
|
NextToken ();
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Get the lhs on stack */
|
2004-07-06 11:30:08 +00:00
|
|
|
GetCodePos (&Mark1);
|
2004-05-25 20:59:38 +00:00
|
|
|
ltype = TypeOf (Expr->Type);
|
2004-05-31 15:27:33 +00:00
|
|
|
if (ED_IsConstAbs (Expr)) {
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Constant value */
|
2004-07-06 11:30:08 +00:00
|
|
|
GetCodePos (&Mark2);
|
2004-06-06 14:48:59 +00:00
|
|
|
g_push (ltype | CF_CONST, Expr->IVal);
|
2000-05-28 13:40:48 +00:00
|
|
|
} else {
|
|
|
|
/* Value not constant */
|
2004-06-09 14:12:57 +00:00
|
|
|
LoadExpr (CF_NONE, Expr);
|
2004-07-06 11:30:08 +00:00
|
|
|
GetCodePos (&Mark2);
|
2000-05-28 13:40:48 +00:00
|
|
|
g_push (ltype, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get the right hand side */
|
2004-05-31 15:27:33 +00:00
|
|
|
rconst = (evalexpr (CF_NONE, hienext, &Expr2) == 0);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Check the type of the rhs */
|
2005-08-31 21:49:12 +00:00
|
|
|
if (!IsClassInt (Expr2.Type)) {
|
2000-11-02 21:22:33 +00:00
|
|
|
Error ("Integer expression expected");
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Check for const operands */
|
2004-05-31 15:27:33 +00:00
|
|
|
if (ED_IsConstAbs (Expr) && rconst) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Both operands are constant, remove the generated code */
|
2004-07-06 11:30:08 +00:00
|
|
|
RemoveCode (&Mark1);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Get the type of the result */
|
2004-05-31 15:27:33 +00:00
|
|
|
Expr->Type = promoteint (Expr->Type, Expr2.Type);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2007-08-26 18:53:46 +00:00
|
|
|
/* Handle the op differently for signed and unsigned types */
|
|
|
|
if (IsSignSigned (Expr->Type)) {
|
|
|
|
|
|
|
|
/* Evaluate the result for signed operands */
|
|
|
|
signed long Val1 = Expr->IVal;
|
|
|
|
signed long Val2 = Expr2.IVal;
|
|
|
|
switch (Tok) {
|
|
|
|
case TOK_OR:
|
|
|
|
Expr->IVal = (Val1 | Val2);
|
|
|
|
break;
|
|
|
|
case TOK_XOR:
|
|
|
|
Expr->IVal = (Val1 ^ Val2);
|
|
|
|
break;
|
|
|
|
case TOK_AND:
|
|
|
|
Expr->IVal = (Val1 & Val2);
|
|
|
|
break;
|
|
|
|
case TOK_STAR:
|
|
|
|
Expr->IVal = (Val1 * Val2);
|
|
|
|
break;
|
|
|
|
case TOK_DIV:
|
|
|
|
if (Val2 == 0) {
|
|
|
|
Error ("Division by zero");
|
|
|
|
Expr->IVal = 0x7FFFFFFF;
|
|
|
|
} else {
|
|
|
|
Expr->IVal = (Val1 / Val2);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case TOK_MOD:
|
|
|
|
if (Val2 == 0) {
|
|
|
|
Error ("Modulo operation with zero");
|
|
|
|
Expr->IVal = 0;
|
|
|
|
} else {
|
|
|
|
Expr->IVal = (Val1 % Val2);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
Internal ("hie_internal: got token 0x%X\n", Tok);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
|
|
|
|
/* Evaluate the result for unsigned operands */
|
|
|
|
unsigned long Val1 = Expr->IVal;
|
|
|
|
unsigned long Val2 = Expr2.IVal;
|
|
|
|
switch (Tok) {
|
|
|
|
case TOK_OR:
|
|
|
|
Expr->IVal = (Val1 | Val2);
|
|
|
|
break;
|
|
|
|
case TOK_XOR:
|
|
|
|
Expr->IVal = (Val1 ^ Val2);
|
|
|
|
break;
|
|
|
|
case TOK_AND:
|
|
|
|
Expr->IVal = (Val1 & Val2);
|
|
|
|
break;
|
|
|
|
case TOK_STAR:
|
|
|
|
Expr->IVal = (Val1 * Val2);
|
|
|
|
break;
|
|
|
|
case TOK_DIV:
|
|
|
|
if (Val2 == 0) {
|
|
|
|
Error ("Division by zero");
|
|
|
|
Expr->IVal = 0xFFFFFFFF;
|
|
|
|
} else {
|
|
|
|
Expr->IVal = (Val1 / Val2);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case TOK_MOD:
|
|
|
|
if (Val2 == 0) {
|
|
|
|
Error ("Modulo operation with zero");
|
|
|
|
Expr->IVal = 0;
|
|
|
|
} else {
|
|
|
|
Expr->IVal = (Val1 % Val2);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
Internal ("hie_internal: got token 0x%X\n", Tok);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
} else {
|
|
|
|
|
|
|
|
/* If the right hand side is constant, and the generator function
|
|
|
|
* expects the lhs in the primary, remove the push of the primary
|
|
|
|
* now.
|
|
|
|
*/
|
2004-05-31 15:27:33 +00:00
|
|
|
unsigned rtype = TypeOf (Expr2.Type);
|
2000-05-28 13:40:48 +00:00
|
|
|
type = 0;
|
|
|
|
if (rconst) {
|
|
|
|
/* Second value is constant - check for div */
|
|
|
|
type |= CF_CONST;
|
2004-05-25 20:59:38 +00:00
|
|
|
rtype |= CF_CONST;
|
2004-06-06 14:48:59 +00:00
|
|
|
if (Tok == TOK_DIV && Expr2.IVal == 0) {
|
2000-11-02 21:22:33 +00:00
|
|
|
Error ("Division by zero");
|
2004-06-06 14:48:59 +00:00
|
|
|
} else if (Tok == TOK_MOD && Expr2.IVal == 0) {
|
2000-11-02 21:22:33 +00:00
|
|
|
Error ("Modulo operation with zero");
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
2004-05-25 20:59:38 +00:00
|
|
|
if ((Gen->Flags & GEN_NOPUSH) != 0) {
|
2004-07-06 11:30:08 +00:00
|
|
|
RemoveCode (&Mark2);
|
2004-05-25 20:59:38 +00:00
|
|
|
ltype |= CF_REG; /* Value is in register */
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Determine the type of the operation result. */
|
|
|
|
type |= g_typeadjust (ltype, rtype);
|
2004-05-31 15:27:33 +00:00
|
|
|
Expr->Type = promoteint (Expr->Type, Expr2.Type);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Generate code */
|
2004-06-06 14:48:59 +00:00
|
|
|
Gen->Func (type, Expr2.IVal);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
/* We have a rvalue in the primary now */
|
2004-05-31 15:27:33 +00:00
|
|
|
ED_MakeRValExpr (Expr);
|
2004-05-25 20:59:38 +00:00
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
static void hie_compare (const GenDesc* Ops, /* List of generators */
|
2004-05-26 16:15:28 +00:00
|
|
|
ExprDesc* Expr,
|
2004-05-25 20:59:38 +00:00
|
|
|
void (*hienext) (ExprDesc*))
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Helper function for the compare operators */
|
|
|
|
{
|
2004-05-31 15:27:33 +00:00
|
|
|
ExprDesc Expr2;
|
2000-05-28 13:40:48 +00:00
|
|
|
CodeMark Mark1;
|
|
|
|
CodeMark Mark2;
|
2002-04-06 14:51:27 +00:00
|
|
|
const GenDesc* Gen;
|
2007-08-26 18:53:46 +00:00
|
|
|
token_t Tok; /* The operator token */
|
2000-05-28 13:40:48 +00:00
|
|
|
unsigned ltype;
|
|
|
|
int rconst; /* Operand is a constant */
|
|
|
|
|
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
hienext (Expr);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
while ((Gen = FindGen (CurTok.Tok, Ops)) != 0) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
/* Remember the operator token, then skip it */
|
2007-08-26 18:53:46 +00:00
|
|
|
Tok = CurTok.Tok;
|
2004-05-25 20:59:38 +00:00
|
|
|
NextToken ();
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
/* Get the lhs on stack */
|
2004-07-06 11:30:08 +00:00
|
|
|
GetCodePos (&Mark1);
|
2004-05-25 20:59:38 +00:00
|
|
|
ltype = TypeOf (Expr->Type);
|
2004-05-31 15:27:33 +00:00
|
|
|
if (ED_IsConstAbs (Expr)) {
|
2004-05-25 20:59:38 +00:00
|
|
|
/* Constant value */
|
2004-07-06 11:30:08 +00:00
|
|
|
GetCodePos (&Mark2);
|
2004-06-06 14:48:59 +00:00
|
|
|
g_push (ltype | CF_CONST, Expr->IVal);
|
2004-05-25 20:59:38 +00:00
|
|
|
} else {
|
|
|
|
/* Value not constant */
|
2004-06-09 14:12:57 +00:00
|
|
|
LoadExpr (CF_NONE, Expr);
|
2004-07-06 11:30:08 +00:00
|
|
|
GetCodePos (&Mark2);
|
2004-05-25 20:59:38 +00:00
|
|
|
g_push (ltype, 0);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Get the right hand side */
|
2004-05-31 15:27:33 +00:00
|
|
|
rconst = (evalexpr (CF_NONE, hienext, &Expr2) == 0);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Make sure, the types are compatible */
|
2004-05-25 20:59:38 +00:00
|
|
|
if (IsClassInt (Expr->Type)) {
|
2004-05-31 15:27:33 +00:00
|
|
|
if (!IsClassInt (Expr2.Type) && !(IsClassPtr(Expr2.Type) && ED_IsNullPtr(Expr))) {
|
2000-11-02 21:22:33 +00:00
|
|
|
Error ("Incompatible types");
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
2004-05-25 20:59:38 +00:00
|
|
|
} else if (IsClassPtr (Expr->Type)) {
|
2004-05-31 15:27:33 +00:00
|
|
|
if (IsClassPtr (Expr2.Type)) {
|
2005-08-31 21:49:12 +00:00
|
|
|
/* Both pointers are allowed in comparison if they point to
|
2000-05-28 13:40:48 +00:00
|
|
|
* the same type, or if one of them is a void pointer.
|
|
|
|
*/
|
2006-02-19 12:29:37 +00:00
|
|
|
Type* left = Indirect (Expr->Type);
|
|
|
|
Type* right = Indirect (Expr2.Type);
|
|
|
|
if (TypeCmp (left, right) < TC_EQUAL && left->C != T_VOID && right->C != T_VOID) {
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Incomatible pointers */
|
2007-08-26 18:53:46 +00:00
|
|
|
Error ("Incompatible types");
|
|
|
|
}
|
2004-05-31 15:27:33 +00:00
|
|
|
} else if (!ED_IsNullPtr (&Expr2)) {
|
2007-08-26 18:53:46 +00:00
|
|
|
Error ("Incompatible types");
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check for const operands */
|
2004-05-31 15:27:33 +00:00
|
|
|
if (ED_IsConstAbs (Expr) && rconst) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2007-08-26 18:53:46 +00:00
|
|
|
/* Both operands are constant, remove the generated code */
|
|
|
|
RemoveCode (&Mark1);
|
|
|
|
|
|
|
|
/* Determine if this is a signed or unsigned compare */
|
|
|
|
if (IsClassInt (Expr->Type) && IsSignSigned (Expr->Type) &&
|
|
|
|
IsClassInt (Expr2.Type) && IsSignSigned (Expr2.Type)) {
|
|
|
|
|
|
|
|
/* Evaluate the result for signed operands */
|
|
|
|
signed long Val1 = Expr->IVal;
|
|
|
|
signed long Val2 = Expr2.IVal;
|
|
|
|
switch (Tok) {
|
|
|
|
case TOK_EQ: Expr->IVal = (Val1 == Val2); break;
|
|
|
|
case TOK_NE: Expr->IVal = (Val1 != Val2); break;
|
|
|
|
case TOK_LT: Expr->IVal = (Val1 < Val2); break;
|
|
|
|
case TOK_LE: Expr->IVal = (Val1 <= Val2); break;
|
|
|
|
case TOK_GE: Expr->IVal = (Val1 >= Val2); break;
|
|
|
|
case TOK_GT: Expr->IVal = (Val1 > Val2); break;
|
|
|
|
default: Internal ("hie_compare: got token 0x%X\n", Tok);
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2007-08-26 18:53:46 +00:00
|
|
|
/* Evaluate the result for unsigned operands */
|
|
|
|
unsigned long Val1 = Expr->IVal;
|
|
|
|
unsigned long Val2 = Expr2.IVal;
|
|
|
|
switch (Tok) {
|
|
|
|
case TOK_EQ: Expr->IVal = (Val1 == Val2); break;
|
|
|
|
case TOK_NE: Expr->IVal = (Val1 != Val2); break;
|
|
|
|
case TOK_LT: Expr->IVal = (Val1 < Val2); break;
|
|
|
|
case TOK_LE: Expr->IVal = (Val1 <= Val2); break;
|
|
|
|
case TOK_GE: Expr->IVal = (Val1 >= Val2); break;
|
|
|
|
case TOK_GT: Expr->IVal = (Val1 > Val2); break;
|
|
|
|
default: Internal ("hie_compare: got token 0x%X\n", Tok);
|
|
|
|
}
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
/* If the right hand side is constant, and the generator function
|
|
|
|
* expects the lhs in the primary, remove the push of the primary
|
|
|
|
* now.
|
|
|
|
*/
|
|
|
|
unsigned flags = 0;
|
|
|
|
if (rconst) {
|
|
|
|
flags |= CF_CONST;
|
|
|
|
if ((Gen->Flags & GEN_NOPUSH) != 0) {
|
2004-07-06 11:30:08 +00:00
|
|
|
RemoveCode (&Mark2);
|
2000-05-28 13:40:48 +00:00
|
|
|
ltype |= CF_REG; /* Value is in register */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Determine the type of the operation result. If the left
|
|
|
|
* operand is of type char and the right is a constant, or
|
|
|
|
* if both operands are of type char, we will encode the
|
|
|
|
* operation as char operation. Otherwise the default
|
|
|
|
* promotions are used.
|
|
|
|
*/
|
2004-05-31 15:27:33 +00:00
|
|
|
if (IsTypeChar (Expr->Type) && (IsTypeChar (Expr2.Type) || rconst)) {
|
2000-05-28 13:40:48 +00:00
|
|
|
flags |= CF_CHAR;
|
2004-05-31 15:27:33 +00:00
|
|
|
if (IsSignUnsigned (Expr->Type) || IsSignUnsigned (Expr2.Type)) {
|
2000-05-28 13:40:48 +00:00
|
|
|
flags |= CF_UNSIGNED;
|
|
|
|
}
|
|
|
|
if (rconst) {
|
2005-08-31 21:49:12 +00:00
|
|
|
flags |= CF_FORCECHAR;
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
} else {
|
2004-05-31 15:27:33 +00:00
|
|
|
unsigned rtype = TypeOf (Expr2.Type) | (flags & CF_CONST);
|
2000-05-28 13:40:48 +00:00
|
|
|
flags |= g_typeadjust (ltype, rtype);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Generate code */
|
2004-06-06 14:48:59 +00:00
|
|
|
Gen->Func (flags, Expr2.IVal);
|
2004-05-31 15:27:33 +00:00
|
|
|
|
|
|
|
/* The result is an rvalue in the primary */
|
|
|
|
ED_MakeRValExpr (Expr);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Result type is always int */
|
2004-05-25 20:59:38 +00:00
|
|
|
Expr->Type = type_int;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
/* Condition codes are set */
|
2004-06-05 20:29:47 +00:00
|
|
|
ED_TestDone (Expr);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2005-08-31 21:49:12 +00:00
|
|
|
static void hie9 (ExprDesc *Expr)
|
|
|
|
/* Process * and / operators. */
|
2000-05-28 13:40:48 +00:00
|
|
|
{
|
2004-05-25 20:59:38 +00:00
|
|
|
static const GenDesc hie9_ops[] = {
|
|
|
|
{ TOK_STAR, GEN_NOPUSH, g_mul },
|
|
|
|
{ TOK_DIV, GEN_NOPUSH, g_div },
|
|
|
|
{ TOK_MOD, GEN_NOPUSH, g_mod },
|
|
|
|
{ TOK_INVALID, 0, 0 }
|
2000-05-28 13:40:48 +00:00
|
|
|
};
|
|
|
|
int UsedGen;
|
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
hie_internal (hie9_ops, Expr, hie10, &UsedGen);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
static void parseadd (ExprDesc* Expr)
|
|
|
|
/* Parse an expression with the binary plus operator. Expr contains the
|
2000-05-28 13:40:48 +00:00
|
|
|
* unprocessed left hand side of the expression and will contain the
|
|
|
|
* result of the expression on return.
|
|
|
|
*/
|
|
|
|
{
|
2004-05-31 15:27:33 +00:00
|
|
|
ExprDesc Expr2;
|
2004-05-25 20:59:38 +00:00
|
|
|
unsigned flags; /* Operation flags */
|
|
|
|
CodeMark Mark; /* Remember code position */
|
2006-02-19 12:29:37 +00:00
|
|
|
Type* lhst; /* Type of left hand side */
|
|
|
|
Type* rhst; /* Type of right hand side */
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
|
|
|
|
/* Skip the PLUS token */
|
2000-06-12 18:31:40 +00:00
|
|
|
NextToken ();
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Get the left hand side type, initialize operation flags */
|
2004-05-25 20:59:38 +00:00
|
|
|
lhst = Expr->Type;
|
2000-05-28 13:40:48 +00:00
|
|
|
flags = 0;
|
|
|
|
|
|
|
|
/* Check for constness on both sides */
|
2004-05-31 15:27:33 +00:00
|
|
|
if (ED_IsConst (Expr)) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-31 15:27:33 +00:00
|
|
|
/* The left hand side is a constant of some sort. Good. Get rhs */
|
|
|
|
hie9 (&Expr2);
|
|
|
|
if (ED_IsConstAbs (&Expr2)) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-31 15:27:33 +00:00
|
|
|
/* Right hand side is a constant numeric value. Get the rhs type */
|
|
|
|
rhst = Expr2.Type;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Both expressions are constants. Check for pointer arithmetic */
|
2000-08-01 18:45:08 +00:00
|
|
|
if (IsClassPtr (lhst) && IsClassInt (rhst)) {
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Left is pointer, right is int, must scale rhs */
|
2004-06-06 14:48:59 +00:00
|
|
|
Expr->IVal += Expr2.IVal * CheckedPSizeOf (lhst);
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Result type is a pointer */
|
2000-08-01 18:45:08 +00:00
|
|
|
} else if (IsClassInt (lhst) && IsClassPtr (rhst)) {
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Left is int, right is pointer, must scale lhs */
|
2004-06-06 14:48:59 +00:00
|
|
|
Expr->IVal = Expr->IVal * CheckedPSizeOf (rhst) + Expr2.IVal;
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Result type is a pointer */
|
2004-05-31 15:27:33 +00:00
|
|
|
Expr->Type = Expr2.Type;
|
2000-08-01 18:45:08 +00:00
|
|
|
} else if (IsClassInt (lhst) && IsClassInt (rhst)) {
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Integer addition */
|
2004-06-06 14:48:59 +00:00
|
|
|
Expr->IVal += Expr2.IVal;
|
2004-05-31 15:27:33 +00:00
|
|
|
typeadjust (Expr, &Expr2, 1);
|
2000-05-28 13:40:48 +00:00
|
|
|
} else {
|
|
|
|
/* OOPS */
|
2000-11-02 21:22:33 +00:00
|
|
|
Error ("Invalid operands for binary operator `+'");
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
2007-02-03 18:11:37 +00:00
|
|
|
} else {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2001-11-07 10:32:51 +00:00
|
|
|
/* lhs is a constant and rhs is not constant. Load rhs into
|
|
|
|
* the primary.
|
|
|
|
*/
|
2004-06-09 14:12:57 +00:00
|
|
|
LoadExpr (CF_NONE, &Expr2);
|
2001-11-07 10:32:51 +00:00
|
|
|
|
|
|
|
/* 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. */
|
2004-05-31 15:27:33 +00:00
|
|
|
rhst = Expr2.Type;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2001-11-07 10:32:51 +00:00
|
|
|
/* Setup flags */
|
2004-05-31 15:27:33 +00:00
|
|
|
if (ED_IsLocAbs (Expr)) {
|
2001-11-07 10:32:51 +00:00
|
|
|
/* A numerical constant */
|
|
|
|
flags |= CF_CONST;
|
|
|
|
} else {
|
|
|
|
/* Constant address label */
|
2008-08-05 21:11:26 +00:00
|
|
|
flags |= GlobalModeFlags (Expr) | CF_CONSTADDR;
|
2001-11-07 10:32:51 +00:00
|
|
|
}
|
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Check for pointer arithmetic */
|
2000-08-01 18:45:08 +00:00
|
|
|
if (IsClassPtr (lhst) && IsClassInt (rhst)) {
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Left is pointer, right is int, must scale rhs */
|
2002-03-10 20:44:58 +00:00
|
|
|
g_scale (CF_INT, CheckedPSizeOf (lhst));
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Operate on pointers, result type is a pointer */
|
2001-11-07 10:32:51 +00:00
|
|
|
flags |= CF_PTR;
|
2003-02-02 21:05:39 +00:00
|
|
|
/* Generate the code for the add */
|
2004-05-31 15:27:33 +00:00
|
|
|
if (ED_GetLoc (Expr) == E_LOC_ABS) {
|
2003-02-02 21:05:39 +00:00
|
|
|
/* Numeric constant */
|
2004-06-06 14:48:59 +00:00
|
|
|
g_inc (flags, Expr->IVal);
|
2003-02-02 21:05:39 +00:00
|
|
|
} else {
|
|
|
|
/* Constant address */
|
2004-06-06 14:48:59 +00:00
|
|
|
g_addaddr_static (flags, Expr->Name, Expr->IVal);
|
2003-02-02 21:05:39 +00:00
|
|
|
}
|
2000-08-01 18:45:08 +00:00
|
|
|
} else if (IsClassInt (lhst) && IsClassPtr (rhst)) {
|
2001-11-07 10:32:51 +00:00
|
|
|
|
|
|
|
/* Left is int, right is pointer, must scale lhs. */
|
2003-02-02 21:05:39 +00:00
|
|
|
unsigned ScaleFactor = CheckedPSizeOf (rhst);
|
2001-11-07 10:32:51 +00:00
|
|
|
|
|
|
|
/* Operate on pointers, result type is a pointer */
|
2003-02-02 21:05:39 +00:00
|
|
|
flags |= CF_PTR;
|
2004-05-31 15:27:33 +00:00
|
|
|
Expr->Type = Expr2.Type;
|
2003-02-02 21:05:39 +00:00
|
|
|
|
|
|
|
/* 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.
|
|
|
|
*/
|
2004-05-31 15:27:33 +00:00
|
|
|
if (ED_IsLocAbs (Expr)) {
|
2003-02-02 21:05:39 +00:00
|
|
|
/* Numeric constant, scale lhs */
|
2004-06-06 14:48:59 +00:00
|
|
|
Expr->IVal *= ScaleFactor;
|
2003-02-02 21:05:39 +00:00
|
|
|
/* Generate the code for the add */
|
2004-06-06 14:48:59 +00:00
|
|
|
g_inc (flags, Expr->IVal);
|
2003-02-02 21:05:39 +00:00
|
|
|
} else if (ScaleFactor == 1) {
|
|
|
|
/* Constant address but no need to scale */
|
2004-06-06 14:48:59 +00:00
|
|
|
g_addaddr_static (flags, Expr->Name, Expr->IVal);
|
2003-02-02 21:05:39 +00:00
|
|
|
} else {
|
|
|
|
/* Constant address that must be scaled */
|
2004-05-31 15:27:33 +00:00
|
|
|
g_push (TypeOf (Expr2.Type), 0); /* rhs --> stack */
|
2004-06-06 14:48:59 +00:00
|
|
|
g_getimmed (flags, Expr->Name, Expr->IVal);
|
2005-08-31 21:49:12 +00:00
|
|
|
g_scale (CF_PTR, ScaleFactor);
|
2003-02-02 21:05:39 +00:00
|
|
|
g_add (CF_PTR, 0);
|
|
|
|
}
|
2000-08-01 18:45:08 +00:00
|
|
|
} else if (IsClassInt (lhst) && IsClassInt (rhst)) {
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Integer addition */
|
2004-05-31 15:27:33 +00:00
|
|
|
flags |= typeadjust (Expr, &Expr2, 1);
|
2003-02-02 21:05:39 +00:00
|
|
|
/* Generate the code for the add */
|
2004-05-31 15:27:33 +00:00
|
|
|
if (ED_IsLocAbs (Expr)) {
|
2003-02-02 21:05:39 +00:00
|
|
|
/* Numeric constant */
|
2004-06-06 14:48:59 +00:00
|
|
|
g_inc (flags, Expr->IVal);
|
2003-02-02 21:05:39 +00:00
|
|
|
} else {
|
|
|
|
/* Constant address */
|
2004-06-06 14:48:59 +00:00
|
|
|
g_addaddr_static (flags, Expr->Name, Expr->IVal);
|
2003-02-02 21:05:39 +00:00
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
} else {
|
|
|
|
/* OOPS */
|
2000-11-02 21:22:33 +00:00
|
|
|
Error ("Invalid operands for binary operator `+'");
|
2007-02-03 18:11:37 +00:00
|
|
|
flags = CF_INT;
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
/* Result is a rvalue in primary register */
|
2004-05-31 15:27:33 +00:00
|
|
|
ED_MakeRValExpr (Expr);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
/* Left hand side is not constant. Get the value onto the stack. */
|
2004-06-09 14:12:57 +00:00
|
|
|
LoadExpr (CF_NONE, Expr); /* --> primary register */
|
2004-07-06 11:30:08 +00:00
|
|
|
GetCodePos (&Mark);
|
2004-05-25 20:59:38 +00:00
|
|
|
g_push (TypeOf (Expr->Type), 0); /* --> stack */
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Evaluate the rhs */
|
2004-05-31 15:27:33 +00:00
|
|
|
if (evalexpr (CF_NONE, hie9, &Expr2) == 0) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Right hand side is a constant. Get the rhs type */
|
2004-05-31 15:27:33 +00:00
|
|
|
rhst = Expr2.Type;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Remove pushed value from stack */
|
2004-07-06 11:30:08 +00:00
|
|
|
RemoveCode (&Mark);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Check for pointer arithmetic */
|
2000-08-01 18:45:08 +00:00
|
|
|
if (IsClassPtr (lhst) && IsClassInt (rhst)) {
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Left is pointer, right is int, must scale rhs */
|
2004-06-06 14:48:59 +00:00
|
|
|
Expr2.IVal *= CheckedPSizeOf (lhst);
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Operate on pointers, result type is a pointer */
|
|
|
|
flags = CF_PTR;
|
2000-08-01 18:45:08 +00:00
|
|
|
} else if (IsClassInt (lhst) && IsClassPtr (rhst)) {
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Left is int, right is pointer, must scale lhs (ptr only) */
|
2002-03-10 20:44:58 +00:00
|
|
|
g_scale (CF_INT | CF_CONST, CheckedPSizeOf (rhst));
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Operate on pointers, result type is a pointer */
|
|
|
|
flags = CF_PTR;
|
2004-05-31 15:27:33 +00:00
|
|
|
Expr->Type = Expr2.Type;
|
2000-08-01 18:45:08 +00:00
|
|
|
} else if (IsClassInt (lhst) && IsClassInt (rhst)) {
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Integer addition */
|
2004-05-31 15:27:33 +00:00
|
|
|
flags = typeadjust (Expr, &Expr2, 1);
|
2000-05-28 13:40:48 +00:00
|
|
|
} else {
|
|
|
|
/* OOPS */
|
2000-11-02 21:22:33 +00:00
|
|
|
Error ("Invalid operands for binary operator `+'");
|
2007-02-03 18:11:37 +00:00
|
|
|
flags = CF_INT;
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Generate code for the add */
|
2004-06-06 14:48:59 +00:00
|
|
|
g_inc (flags | CF_CONST, Expr2.IVal);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
/* lhs and rhs are not constant. Get the rhs type. */
|
2004-05-31 15:27:33 +00:00
|
|
|
rhst = Expr2.Type;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Check for pointer arithmetic */
|
2000-08-01 18:45:08 +00:00
|
|
|
if (IsClassPtr (lhst) && IsClassInt (rhst)) {
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Left is pointer, right is int, must scale rhs */
|
2002-03-10 20:44:58 +00:00
|
|
|
g_scale (CF_INT, CheckedPSizeOf (lhst));
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Operate on pointers, result type is a pointer */
|
|
|
|
flags = CF_PTR;
|
2000-08-01 18:45:08 +00:00
|
|
|
} else if (IsClassInt (lhst) && IsClassPtr (rhst)) {
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Left is int, right is pointer, must scale lhs */
|
|
|
|
g_tosint (TypeOf (rhst)); /* Make sure, TOS is int */
|
2004-05-25 20:59:38 +00:00
|
|
|
g_swap (CF_INT); /* Swap TOS and primary */
|
2002-03-10 20:44:58 +00:00
|
|
|
g_scale (CF_INT, CheckedPSizeOf (rhst));
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Operate on pointers, result type is a pointer */
|
|
|
|
flags = CF_PTR;
|
2004-05-31 15:27:33 +00:00
|
|
|
Expr->Type = Expr2.Type;
|
2000-08-01 18:45:08 +00:00
|
|
|
} else if (IsClassInt (lhst) && IsClassInt (rhst)) {
|
2003-02-02 21:05:39 +00:00
|
|
|
/* 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.
|
|
|
|
*/
|
2004-05-31 15:27:33 +00:00
|
|
|
flags = typeadjust (Expr, &Expr2, 0) & ~CF_CONST;
|
2000-05-28 13:40:48 +00:00
|
|
|
} else {
|
|
|
|
/* OOPS */
|
2000-11-02 21:22:33 +00:00
|
|
|
Error ("Invalid operands for binary operator `+'");
|
2007-02-03 18:11:37 +00:00
|
|
|
flags = CF_INT;
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Generate code for the add */
|
|
|
|
g_add (flags, 0);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
/* Result is a rvalue in primary register */
|
2004-05-31 15:27:33 +00:00
|
|
|
ED_MakeRValExpr (Expr);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
2004-05-25 20:59:38 +00:00
|
|
|
|
|
|
|
/* Condition codes not set */
|
2004-06-05 20:29:47 +00:00
|
|
|
ED_MarkAsUntested (Expr);
|
2004-05-25 20:59:38 +00:00
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
static void parsesub (ExprDesc* Expr)
|
|
|
|
/* Parse an expression with the binary minus operator. Expr contains the
|
2000-05-28 13:40:48 +00:00
|
|
|
* unprocessed left hand side of the expression and will contain the
|
|
|
|
* result of the expression on return.
|
|
|
|
*/
|
|
|
|
{
|
2004-05-31 15:27:33 +00:00
|
|
|
ExprDesc Expr2;
|
2007-02-03 18:11:37 +00:00
|
|
|
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 */
|
2004-05-25 20:59:38 +00:00
|
|
|
CodeMark Mark2; /* Another position in the queue */
|
2007-02-03 18:11:37 +00:00
|
|
|
int rscale; /* Scale factor for the result */
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
|
|
|
|
/* Skip the MINUS token */
|
2000-06-12 18:31:40 +00:00
|
|
|
NextToken ();
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Get the left hand side type, initialize operation flags */
|
2004-05-25 20:59:38 +00:00
|
|
|
lhst = Expr->Type;
|
2000-05-28 13:40:48 +00:00
|
|
|
rscale = 1; /* Scale by 1, that is, don't scale */
|
|
|
|
|
|
|
|
/* Remember the output queue position, then bring the value onto the stack */
|
2004-07-06 11:30:08 +00:00
|
|
|
GetCodePos (&Mark1);
|
2004-06-09 14:12:57 +00:00
|
|
|
LoadExpr (CF_NONE, Expr); /* --> primary register */
|
2004-07-06 11:30:08 +00:00
|
|
|
GetCodePos (&Mark2);
|
2000-05-28 13:40:48 +00:00
|
|
|
g_push (TypeOf (lhst), 0); /* --> stack */
|
|
|
|
|
|
|
|
/* Parse the right hand side */
|
2004-05-31 15:27:33 +00:00
|
|
|
if (evalexpr (CF_NONE, hie9, &Expr2) == 0) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* The right hand side is constant. Get the rhs type. */
|
2004-05-31 15:27:33 +00:00
|
|
|
rhst = Expr2.Type;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Check left hand side */
|
2004-05-31 15:27:33 +00:00
|
|
|
if (ED_IsConstAbs (Expr)) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Both sides are constant, remove generated code */
|
2004-07-06 11:30:08 +00:00
|
|
|
RemoveCode (&Mark1);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Check for pointer arithmetic */
|
2000-08-01 18:45:08 +00:00
|
|
|
if (IsClassPtr (lhst) && IsClassInt (rhst)) {
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Left is pointer, right is int, must scale rhs */
|
2004-06-06 14:48:59 +00:00
|
|
|
Expr->IVal -= Expr2.IVal * CheckedPSizeOf (lhst);
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Operate on pointers, result type is a pointer */
|
2000-08-01 18:45:08 +00:00
|
|
|
} else if (IsClassPtr (lhst) && IsClassPtr (rhst)) {
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Left is pointer, right is pointer, must scale result */
|
2002-03-06 06:38:48 +00:00
|
|
|
if (TypeCmp (Indirect (lhst), Indirect (rhst)) < TC_QUAL_DIFF) {
|
2000-11-02 21:22:33 +00:00
|
|
|
Error ("Incompatible pointer types");
|
2000-05-28 13:40:48 +00:00
|
|
|
} else {
|
2004-06-06 14:48:59 +00:00
|
|
|
Expr->IVal = (Expr->IVal - Expr2.IVal) /
|
2002-03-10 20:44:58 +00:00
|
|
|
CheckedPSizeOf (lhst);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
/* Operate on pointers, result type is an integer */
|
2004-05-25 20:59:38 +00:00
|
|
|
Expr->Type = type_int;
|
2000-08-01 18:45:08 +00:00
|
|
|
} else if (IsClassInt (lhst) && IsClassInt (rhst)) {
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Integer subtraction */
|
2004-05-31 15:27:33 +00:00
|
|
|
typeadjust (Expr, &Expr2, 1);
|
2004-06-06 14:48:59 +00:00
|
|
|
Expr->IVal -= Expr2.IVal;
|
2000-05-28 13:40:48 +00:00
|
|
|
} else {
|
|
|
|
/* OOPS */
|
2000-11-02 21:22:33 +00:00
|
|
|
Error ("Invalid operands for binary operator `-'");
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Result is constant, condition codes not set */
|
2004-06-05 20:29:47 +00:00
|
|
|
ED_MarkAsUntested (Expr);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
/* Left hand side is not constant, right hand side is.
|
|
|
|
* Remove pushed value from stack.
|
|
|
|
*/
|
2004-07-06 11:30:08 +00:00
|
|
|
RemoveCode (&Mark2);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2000-08-01 18:45:08 +00:00
|
|
|
if (IsClassPtr (lhst) && IsClassInt (rhst)) {
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Left is pointer, right is int, must scale rhs */
|
2004-06-06 14:48:59 +00:00
|
|
|
Expr2.IVal *= CheckedPSizeOf (lhst);
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Operate on pointers, result type is a pointer */
|
|
|
|
flags = CF_PTR;
|
2000-08-01 18:45:08 +00:00
|
|
|
} else if (IsClassPtr (lhst) && IsClassPtr (rhst)) {
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Left is pointer, right is pointer, must scale result */
|
2002-03-06 06:38:48 +00:00
|
|
|
if (TypeCmp (Indirect (lhst), Indirect (rhst)) < TC_QUAL_DIFF) {
|
2000-11-02 21:22:33 +00:00
|
|
|
Error ("Incompatible pointer types");
|
2000-05-28 13:40:48 +00:00
|
|
|
} else {
|
2002-03-10 20:44:58 +00:00
|
|
|
rscale = CheckedPSizeOf (lhst);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
/* Operate on pointers, result type is an integer */
|
|
|
|
flags = CF_PTR;
|
2004-05-25 20:59:38 +00:00
|
|
|
Expr->Type = type_int;
|
2000-08-01 18:45:08 +00:00
|
|
|
} else if (IsClassInt (lhst) && IsClassInt (rhst)) {
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Integer subtraction */
|
2004-05-31 15:27:33 +00:00
|
|
|
flags = typeadjust (Expr, &Expr2, 1);
|
2000-05-28 13:40:48 +00:00
|
|
|
} else {
|
|
|
|
/* OOPS */
|
2000-11-02 21:22:33 +00:00
|
|
|
Error ("Invalid operands for binary operator `-'");
|
2007-02-03 18:11:37 +00:00
|
|
|
flags = CF_INT;
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Do the subtraction */
|
2004-06-06 14:48:59 +00:00
|
|
|
g_dec (flags | CF_CONST, Expr2.IVal);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* If this was a pointer subtraction, we must scale the result */
|
|
|
|
if (rscale != 1) {
|
|
|
|
g_scale (flags, -rscale);
|
|
|
|
}
|
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
/* Result is a rvalue in the primary register */
|
2004-05-31 15:27:33 +00:00
|
|
|
ED_MakeRValExpr (Expr);
|
2004-06-05 20:29:47 +00:00
|
|
|
ED_MarkAsUntested (Expr);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
/* Right hand side is not constant. Get the rhs type. */
|
2004-05-31 15:27:33 +00:00
|
|
|
rhst = Expr2.Type;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Check for pointer arithmetic */
|
2000-08-01 18:45:08 +00:00
|
|
|
if (IsClassPtr (lhst) && IsClassInt (rhst)) {
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Left is pointer, right is int, must scale rhs */
|
2002-03-10 20:44:58 +00:00
|
|
|
g_scale (CF_INT, CheckedPSizeOf (lhst));
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Operate on pointers, result type is a pointer */
|
|
|
|
flags = CF_PTR;
|
2000-08-01 18:45:08 +00:00
|
|
|
} else if (IsClassPtr (lhst) && IsClassPtr (rhst)) {
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Left is pointer, right is pointer, must scale result */
|
2002-03-06 06:38:48 +00:00
|
|
|
if (TypeCmp (Indirect (lhst), Indirect (rhst)) < TC_QUAL_DIFF) {
|
2000-11-02 21:22:33 +00:00
|
|
|
Error ("Incompatible pointer types");
|
2000-05-28 13:40:48 +00:00
|
|
|
} else {
|
2002-03-10 20:44:58 +00:00
|
|
|
rscale = CheckedPSizeOf (lhst);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
/* Operate on pointers, result type is an integer */
|
|
|
|
flags = CF_PTR;
|
2004-05-25 20:59:38 +00:00
|
|
|
Expr->Type = type_int;
|
2000-08-01 18:45:08 +00:00
|
|
|
} else if (IsClassInt (lhst) && IsClassInt (rhst)) {
|
2000-05-28 13:40:48 +00:00
|
|
|
/* 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.
|
2005-08-31 21:49:12 +00:00
|
|
|
*/
|
2004-05-31 15:27:33 +00:00
|
|
|
if (ED_IsLocAbs (Expr)) {
|
|
|
|
ED_MakeRValExpr (Expr);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
/* Adjust operand types */
|
2004-05-31 15:27:33 +00:00
|
|
|
flags = typeadjust (Expr, &Expr2, 0);
|
2004-05-25 20:59:38 +00:00
|
|
|
} else {
|
2000-05-28 13:40:48 +00:00
|
|
|
/* OOPS */
|
2000-11-02 21:22:33 +00:00
|
|
|
Error ("Invalid operands for binary operator `-'");
|
2007-02-03 18:11:37 +00:00
|
|
|
flags = CF_INT;
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Generate code for the sub (the & is a hack here) */
|
|
|
|
g_sub (flags & ~CF_CONST, 0);
|
|
|
|
|
|
|
|
/* If this was a pointer subtraction, we must scale the result */
|
|
|
|
if (rscale != 1) {
|
|
|
|
g_scale (flags, -rscale);
|
|
|
|
}
|
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
/* Result is a rvalue in the primary register */
|
2004-05-31 15:27:33 +00:00
|
|
|
ED_MakeRValExpr (Expr);
|
2004-06-05 20:29:47 +00:00
|
|
|
ED_MarkAsUntested (Expr);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2004-06-29 20:26:27 +00:00
|
|
|
void hie8 (ExprDesc* Expr)
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Process + and - binary operators. */
|
|
|
|
{
|
2004-05-25 20:59:38 +00:00
|
|
|
hie9 (Expr);
|
2001-05-22 09:32:24 +00:00
|
|
|
while (CurTok.Tok == TOK_PLUS || CurTok.Tok == TOK_MINUS) {
|
|
|
|
if (CurTok.Tok == TOK_PLUS) {
|
2004-05-25 20:59:38 +00:00
|
|
|
parseadd (Expr);
|
2000-05-28 13:40:48 +00:00
|
|
|
} else {
|
2004-05-25 20:59:38 +00:00
|
|
|
parsesub (Expr);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
static void hie6 (ExprDesc* Expr)
|
|
|
|
/* Handle greater-than type comparators */
|
2000-05-28 13:40:48 +00:00
|
|
|
{
|
2004-05-25 20:59:38 +00:00
|
|
|
static const GenDesc hie6_ops [] = {
|
|
|
|
{ TOK_LT, GEN_NOPUSH, g_lt },
|
|
|
|
{ TOK_LE, GEN_NOPUSH, g_le },
|
|
|
|
{ TOK_GE, GEN_NOPUSH, g_ge },
|
|
|
|
{ TOK_GT, GEN_NOPUSH, g_gt },
|
|
|
|
{ TOK_INVALID, 0, 0 }
|
2000-05-28 13:40:48 +00:00
|
|
|
};
|
2004-06-29 20:44:01 +00:00
|
|
|
hie_compare (hie6_ops, Expr, ShiftExpr);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
static void hie5 (ExprDesc* Expr)
|
|
|
|
/* Handle == and != */
|
2000-05-28 13:40:48 +00:00
|
|
|
{
|
2004-05-25 20:59:38 +00:00
|
|
|
static const GenDesc hie5_ops[] = {
|
|
|
|
{ TOK_EQ, GEN_NOPUSH, g_eq },
|
|
|
|
{ TOK_NE, GEN_NOPUSH, g_ne },
|
|
|
|
{ TOK_INVALID, 0, 0 }
|
2000-05-28 13:40:48 +00:00
|
|
|
};
|
2004-05-25 20:59:38 +00:00
|
|
|
hie_compare (hie5_ops, Expr, hie6);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
static void hie4 (ExprDesc* Expr)
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Handle & (bitwise and) */
|
|
|
|
{
|
2004-05-25 20:59:38 +00:00
|
|
|
static const GenDesc hie4_ops[] = {
|
|
|
|
{ TOK_AND, GEN_NOPUSH, g_and },
|
|
|
|
{ TOK_INVALID, 0, 0 }
|
2000-05-28 13:40:48 +00:00
|
|
|
};
|
|
|
|
int UsedGen;
|
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
hie_internal (hie4_ops, Expr, hie5, &UsedGen);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
static void hie3 (ExprDesc* Expr)
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Handle ^ (bitwise exclusive or) */
|
|
|
|
{
|
2004-05-25 20:59:38 +00:00
|
|
|
static const GenDesc hie3_ops[] = {
|
|
|
|
{ TOK_XOR, GEN_NOPUSH, g_xor },
|
|
|
|
{ TOK_INVALID, 0, 0 }
|
2000-05-28 13:40:48 +00:00
|
|
|
};
|
|
|
|
int UsedGen;
|
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
hie_internal (hie3_ops, Expr, hie4, &UsedGen);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
static void hie2 (ExprDesc* Expr)
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Handle | (bitwise or) */
|
|
|
|
{
|
2004-05-25 20:59:38 +00:00
|
|
|
static const GenDesc hie2_ops[] = {
|
|
|
|
{ TOK_OR, GEN_NOPUSH, g_or },
|
|
|
|
{ TOK_INVALID, 0, 0 }
|
2000-05-28 13:40:48 +00:00
|
|
|
};
|
|
|
|
int UsedGen;
|
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
hie_internal (hie2_ops, Expr, hie3, &UsedGen);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
static void hieAndPP (ExprDesc* Expr)
|
2001-09-08 13:59:32 +00:00
|
|
|
/* Process "exp && exp" in preprocessor mode (that is, when the parser is
|
|
|
|
* called recursively from the preprocessor.
|
|
|
|
*/
|
|
|
|
{
|
2004-05-31 15:27:33 +00:00
|
|
|
ExprDesc Expr2;
|
2001-09-08 13:59:32 +00:00
|
|
|
|
2004-05-31 15:27:33 +00:00
|
|
|
ConstAbsIntExpr (hie2, Expr);
|
2001-09-08 13:59:32 +00:00
|
|
|
while (CurTok.Tok == TOK_BOOL_AND) {
|
|
|
|
|
|
|
|
/* Skip the && */
|
|
|
|
NextToken ();
|
|
|
|
|
|
|
|
/* Get rhs */
|
2004-05-31 15:27:33 +00:00
|
|
|
ConstAbsIntExpr (hie2, &Expr2);
|
2001-09-08 13:59:32 +00:00
|
|
|
|
|
|
|
/* Combine the two */
|
2004-06-06 14:48:59 +00:00
|
|
|
Expr->IVal = (Expr->IVal && Expr2.IVal);
|
2001-09-08 13:59:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
static void hieOrPP (ExprDesc *Expr)
|
2001-09-08 13:59:32 +00:00
|
|
|
/* Process "exp || exp" in preprocessor mode (that is, when the parser is
|
|
|
|
* called recursively from the preprocessor.
|
|
|
|
*/
|
|
|
|
{
|
2004-05-31 15:27:33 +00:00
|
|
|
ExprDesc Expr2;
|
2001-09-08 13:59:32 +00:00
|
|
|
|
2004-05-31 15:27:33 +00:00
|
|
|
ConstAbsIntExpr (hieAndPP, Expr);
|
2001-09-08 13:59:32 +00:00
|
|
|
while (CurTok.Tok == TOK_BOOL_OR) {
|
|
|
|
|
|
|
|
/* Skip the && */
|
|
|
|
NextToken ();
|
|
|
|
|
|
|
|
/* Get rhs */
|
2004-05-31 15:27:33 +00:00
|
|
|
ConstAbsIntExpr (hieAndPP, &Expr2);
|
2005-08-31 21:49:12 +00:00
|
|
|
|
2001-09-08 13:59:32 +00:00
|
|
|
/* Combine the two */
|
2004-06-06 14:48:59 +00:00
|
|
|
Expr->IVal = (Expr->IVal || Expr2.IVal);
|
2001-09-08 13:59:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
static void hieAnd (ExprDesc* Expr, unsigned TrueLab, int* BoolOp)
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Process "exp && exp" */
|
|
|
|
{
|
|
|
|
int lab;
|
2004-05-31 15:27:33 +00:00
|
|
|
ExprDesc Expr2;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
hie2 (Expr);
|
2001-05-22 09:32:24 +00:00
|
|
|
if (CurTok.Tok == TOK_BOOL_AND) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Tell our caller that we're evaluating a boolean */
|
|
|
|
*BoolOp = 1;
|
|
|
|
|
|
|
|
/* Get a label that we will use for false expressions */
|
2001-04-19 06:49:08 +00:00
|
|
|
lab = GetLocalLabel ();
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* If the expr hasn't set condition codes, set the force-test flag */
|
2004-06-05 20:29:47 +00:00
|
|
|
if (!ED_IsTested (Expr)) {
|
|
|
|
ED_MarkForTest (Expr);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Load the value */
|
2004-06-09 14:12:57 +00:00
|
|
|
LoadExpr (CF_FORCECHAR, Expr);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Generate the jump */
|
|
|
|
g_falsejump (CF_NONE, lab);
|
|
|
|
|
|
|
|
/* Parse more boolean and's */
|
2001-05-22 09:32:24 +00:00
|
|
|
while (CurTok.Tok == TOK_BOOL_AND) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Skip the && */
|
2000-06-12 18:31:40 +00:00
|
|
|
NextToken ();
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Get rhs */
|
2004-05-31 15:27:33 +00:00
|
|
|
hie2 (&Expr2);
|
2004-06-05 20:29:47 +00:00
|
|
|
if (!ED_IsTested (&Expr2)) {
|
|
|
|
ED_MarkForTest (&Expr2);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
2004-06-09 14:12:57 +00:00
|
|
|
LoadExpr (CF_FORCECHAR, &Expr2);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Do short circuit evaluation */
|
2001-05-22 09:32:24 +00:00
|
|
|
if (CurTok.Tok == TOK_BOOL_AND) {
|
2000-05-28 13:40:48 +00:00
|
|
|
g_falsejump (CF_NONE, lab);
|
|
|
|
} else {
|
|
|
|
/* Last expression - will evaluate to true */
|
|
|
|
g_truejump (CF_NONE, TrueLab);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Define the false jump label here */
|
2001-05-03 20:16:41 +00:00
|
|
|
g_defcodelabel (lab);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
/* The result is an rvalue in primary */
|
2004-05-31 15:27:33 +00:00
|
|
|
ED_MakeRValExpr (Expr);
|
2004-06-05 20:29:47 +00:00
|
|
|
ED_TestDone (Expr); /* Condition codes are set */
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
static void hieOr (ExprDesc *Expr)
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Process "exp || exp". */
|
|
|
|
{
|
2004-05-31 15:27:33 +00:00
|
|
|
ExprDesc Expr2;
|
|
|
|
int BoolOp = 0; /* Did we have a boolean op? */
|
|
|
|
int AndOp; /* Did we have a && operation? */
|
|
|
|
unsigned TrueLab; /* Jump to this label if true */
|
2000-05-28 13:40:48 +00:00
|
|
|
unsigned DoneLab;
|
|
|
|
|
|
|
|
/* Get a label */
|
2001-04-19 06:49:08 +00:00
|
|
|
TrueLab = GetLocalLabel ();
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Call the next level parser */
|
2004-05-25 20:59:38 +00:00
|
|
|
hieAnd (Expr, TrueLab, &BoolOp);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Any boolean or's? */
|
2001-05-22 09:32:24 +00:00
|
|
|
if (CurTok.Tok == TOK_BOOL_OR) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* If the expr hasn't set condition codes, set the force-test flag */
|
2004-06-05 20:29:47 +00:00
|
|
|
if (!ED_IsTested (Expr)) {
|
|
|
|
ED_MarkForTest (Expr);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Get first expr */
|
2004-06-09 14:12:57 +00:00
|
|
|
LoadExpr (CF_FORCECHAR, Expr);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* For each expression jump to TrueLab if true. Beware: If we
|
|
|
|
* had && operators, the jump is already in place!
|
|
|
|
*/
|
|
|
|
if (!BoolOp) {
|
|
|
|
g_truejump (CF_NONE, TrueLab);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Remember that we had a boolean op */
|
|
|
|
BoolOp = 1;
|
|
|
|
|
|
|
|
/* while there's more expr */
|
2001-05-22 09:32:24 +00:00
|
|
|
while (CurTok.Tok == TOK_BOOL_OR) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* skip the || */
|
2000-06-12 18:31:40 +00:00
|
|
|
NextToken ();
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Get a subexpr */
|
|
|
|
AndOp = 0;
|
2004-05-31 15:27:33 +00:00
|
|
|
hieAnd (&Expr2, TrueLab, &AndOp);
|
2004-06-05 20:29:47 +00:00
|
|
|
if (!ED_IsTested (&Expr2)) {
|
|
|
|
ED_MarkForTest (&Expr2);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
2004-06-09 14:12:57 +00:00
|
|
|
LoadExpr (CF_FORCECHAR, &Expr2);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2001-09-08 13:59:32 +00:00
|
|
|
/* If there is more to come, add shortcut boolean eval. */
|
2000-05-28 13:40:48 +00:00
|
|
|
g_truejump (CF_NONE, TrueLab);
|
2001-09-08 13:59:32 +00:00
|
|
|
|
|
|
|
}
|
2004-05-25 20:59:38 +00:00
|
|
|
|
|
|
|
/* The result is an rvalue in primary */
|
2004-05-31 15:27:33 +00:00
|
|
|
ED_MakeRValExpr (Expr);
|
2004-06-05 20:29:47 +00:00
|
|
|
ED_TestDone (Expr); /* Condition codes are set */
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* If we really had boolean ops, generate the end sequence */
|
|
|
|
if (BoolOp) {
|
2001-04-19 06:49:08 +00:00
|
|
|
DoneLab = GetLocalLabel ();
|
2000-05-28 13:40:48 +00:00
|
|
|
g_getimmed (CF_INT | CF_CONST, 0, 0); /* Load FALSE */
|
|
|
|
g_falsejump (CF_NONE, DoneLab);
|
2001-05-03 20:16:41 +00:00
|
|
|
g_defcodelabel (TrueLab);
|
2000-05-28 13:40:48 +00:00
|
|
|
g_getimmed (CF_INT | CF_CONST, 1, 0); /* Load TRUE */
|
2001-05-03 20:16:41 +00:00
|
|
|
g_defcodelabel (DoneLab);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
static void hieQuest (ExprDesc* Expr)
|
2003-08-20 08:32:07 +00:00
|
|
|
/* Parse the ternary operator */
|
2000-05-28 13:40:48 +00:00
|
|
|
{
|
2003-08-20 08:32:07 +00:00
|
|
|
int labf;
|
|
|
|
int labt;
|
|
|
|
ExprDesc Expr2; /* Expression 2 */
|
|
|
|
ExprDesc Expr3; /* Expression 3 */
|
|
|
|
int Expr2IsNULL; /* Expression 2 is a NULL pointer */
|
|
|
|
int Expr3IsNULL; /* Expression 3 is a NULL pointer */
|
2006-02-19 12:29:37 +00:00
|
|
|
Type* ResultType; /* Type of result */
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
/* Call the lower level eval routine */
|
|
|
|
if (Preprocessing) {
|
|
|
|
hieOrPP (Expr);
|
|
|
|
} else {
|
|
|
|
hieOr (Expr);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if it's a ternary expression */
|
2001-05-22 09:32:24 +00:00
|
|
|
if (CurTok.Tok == TOK_QUEST) {
|
2000-06-12 18:31:40 +00:00
|
|
|
NextToken ();
|
2004-06-05 20:29:47 +00:00
|
|
|
if (!ED_IsTested (Expr)) {
|
|
|
|
/* Condition codes not set, request a test */
|
|
|
|
ED_MarkForTest (Expr);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
2004-06-09 14:12:57 +00:00
|
|
|
LoadExpr (CF_NONE, Expr);
|
2001-04-19 06:49:08 +00:00
|
|
|
labf = GetLocalLabel ();
|
2000-05-28 13:40:48 +00:00
|
|
|
g_falsejump (CF_NONE, labf);
|
|
|
|
|
2003-08-20 08:32:07 +00:00
|
|
|
/* Parse second expression. Remember for later if it is a NULL pointer
|
|
|
|
* expression, then load it into the primary.
|
|
|
|
*/
|
2004-05-31 15:27:33 +00:00
|
|
|
ExprWithCheck (hie1, &Expr2);
|
|
|
|
Expr2IsNULL = ED_IsNullPtr (&Expr2);
|
2003-08-20 08:32:07 +00:00
|
|
|
if (!IsTypeVoid (Expr2.Type)) {
|
2002-09-18 20:14:51 +00:00
|
|
|
/* Load it into the primary */
|
2004-06-09 14:12:57 +00:00
|
|
|
LoadExpr (CF_NONE, &Expr2);
|
2004-05-31 15:27:33 +00:00
|
|
|
ED_MakeRValExpr (&Expr2);
|
2002-09-18 20:14:51 +00:00
|
|
|
}
|
2001-04-19 06:49:08 +00:00
|
|
|
labt = GetLocalLabel ();
|
2000-05-28 13:40:48 +00:00
|
|
|
ConsumeColon ();
|
|
|
|
g_jump (labt);
|
2002-09-18 20:14:51 +00:00
|
|
|
|
2003-08-20 08:32:07 +00:00
|
|
|
/* Jump here if the first expression was false */
|
2001-05-03 20:16:41 +00:00
|
|
|
g_defcodelabel (labf);
|
2003-08-20 08:32:07 +00:00
|
|
|
|
|
|
|
/* Parse second expression. Remember for later if it is a NULL pointer
|
|
|
|
* expression, then load it into the primary.
|
|
|
|
*/
|
2004-05-31 15:27:33 +00:00
|
|
|
ExprWithCheck (hie1, &Expr3);
|
|
|
|
Expr3IsNULL = ED_IsNullPtr (&Expr3);
|
2003-08-20 08:32:07 +00:00
|
|
|
if (!IsTypeVoid (Expr3.Type)) {
|
2002-09-18 20:14:51 +00:00
|
|
|
/* Load it into the primary */
|
2004-06-09 14:12:57 +00:00
|
|
|
LoadExpr (CF_NONE, &Expr3);
|
2004-05-31 15:27:33 +00:00
|
|
|
ED_MakeRValExpr (&Expr3);
|
2002-09-18 20:14:51 +00:00
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Check if any conversions are needed, if so, do them.
|
|
|
|
* Conversion rules for ?: expression are:
|
|
|
|
* - if both expressions are int expressions, default promotion
|
|
|
|
* rules for ints apply.
|
|
|
|
* - if both expressions are pointers of the same type, the
|
|
|
|
* result of the expression is of this type.
|
|
|
|
* - if one of the expressions is a pointer and the other is
|
|
|
|
* a zero constant, the resulting type is that of the pointer
|
|
|
|
* type.
|
2002-09-18 20:14:51 +00:00
|
|
|
* - if both expressions are void expressions, the result is of
|
|
|
|
* type void.
|
2000-05-28 13:40:48 +00:00
|
|
|
* - all other cases are flagged by an error.
|
|
|
|
*/
|
2003-08-20 08:32:07 +00:00
|
|
|
if (IsClassInt (Expr2.Type) && IsClassInt (Expr3.Type)) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Get common type */
|
2003-08-20 08:32:07 +00:00
|
|
|
ResultType = promoteint (Expr2.Type, Expr3.Type);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Convert the third expression to this type if needed */
|
2004-05-25 20:59:38 +00:00
|
|
|
TypeConversion (&Expr3, ResultType);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Setup a new label so that the expr3 code will jump around
|
|
|
|
* the type cast code for expr2.
|
|
|
|
*/
|
2001-04-19 06:49:08 +00:00
|
|
|
labf = GetLocalLabel (); /* Get new label */
|
2003-08-19 20:31:10 +00:00
|
|
|
g_jump (labf); /* Jump around code */
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* The jump for expr2 goes here */
|
2001-05-03 20:16:41 +00:00
|
|
|
g_defcodelabel (labt);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Create the typecast code for expr2 */
|
2004-05-25 20:59:38 +00:00
|
|
|
TypeConversion (&Expr2, ResultType);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2001-05-07 22:07:59 +00:00
|
|
|
/* Jump here around the typecase code. */
|
|
|
|
g_defcodelabel (labf);
|
2003-08-19 20:31:10 +00:00
|
|
|
labt = 0; /* Mark other label as invalid */
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2003-08-20 08:32:07 +00:00
|
|
|
} else if (IsClassPtr (Expr2.Type) && IsClassPtr (Expr3.Type)) {
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Must point to same type */
|
2003-08-20 08:32:07 +00:00
|
|
|
if (TypeCmp (Indirect (Expr2.Type), Indirect (Expr3.Type)) < TC_EQUAL) {
|
2003-08-19 20:31:10 +00:00
|
|
|
Error ("Incompatible pointer types");
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
/* Result has the common type */
|
2003-08-20 08:32:07 +00:00
|
|
|
ResultType = Expr2.Type;
|
|
|
|
} else if (IsClassPtr (Expr2.Type) && Expr3IsNULL) {
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Result type is pointer, no cast needed */
|
2003-08-20 08:32:07 +00:00
|
|
|
ResultType = Expr2.Type;
|
|
|
|
} else if (Expr2IsNULL && IsClassPtr (Expr3.Type)) {
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Result type is pointer, no cast needed */
|
2003-08-20 08:32:07 +00:00
|
|
|
ResultType = Expr3.Type;
|
|
|
|
} else if (IsTypeVoid (Expr2.Type) && IsTypeVoid (Expr3.Type)) {
|
2002-09-18 20:14:51 +00:00
|
|
|
/* Result type is void */
|
2003-08-20 08:32:07 +00:00
|
|
|
ResultType = Expr3.Type;
|
2003-08-19 20:31:10 +00:00
|
|
|
} else {
|
|
|
|
Error ("Incompatible types");
|
2003-08-20 08:32:07 +00:00
|
|
|
ResultType = Expr2.Type; /* Doesn't matter here */
|
2003-08-19 20:31:10 +00:00
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2003-08-19 20:31:10 +00:00
|
|
|
/* If we don't have the label defined until now, do it */
|
|
|
|
if (labt) {
|
|
|
|
g_defcodelabel (labt);
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2003-08-19 20:31:10 +00:00
|
|
|
/* Setup the target expression */
|
2004-05-31 15:27:33 +00:00
|
|
|
ED_MakeRValExpr (Expr);
|
2004-05-25 20:59:38 +00:00
|
|
|
Expr->Type = ResultType;
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
static void opeq (const GenDesc* Gen, ExprDesc* Expr)
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Process "op=" operators. */
|
|
|
|
{
|
2004-05-31 15:27:33 +00:00
|
|
|
ExprDesc Expr2;
|
2000-05-28 13:40:48 +00:00
|
|
|
unsigned flags;
|
|
|
|
CodeMark Mark;
|
|
|
|
int MustScale;
|
|
|
|
|
2004-05-31 15:27:33 +00:00
|
|
|
/* op= can only be used with lvalues */
|
|
|
|
if (!ED_IsLVal (Expr)) {
|
2000-11-02 21:22:33 +00:00
|
|
|
Error ("Invalid lvalue in assignment");
|
2000-05-28 13:40:48 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2004-05-31 15:27:33 +00:00
|
|
|
/* There must be an integer or pointer on the left side */
|
|
|
|
if (!IsClassInt (Expr->Type) && !IsTypePtr (Expr->Type)) {
|
|
|
|
Error ("Invalid left operand type");
|
|
|
|
/* Continue. Wrong code will be generated, but the compiler won't
|
|
|
|
* break, so this is the best error recovery.
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Skip the operator token */
|
|
|
|
NextToken ();
|
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Determine the type of the lhs */
|
2004-05-25 20:59:38 +00:00
|
|
|
flags = TypeOf (Expr->Type);
|
2004-05-31 15:27:33 +00:00
|
|
|
MustScale = (Gen->Func == g_add || Gen->Func == g_sub) && IsTypePtr (Expr->Type);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Get the lhs address on stack (if needed) */
|
2004-05-25 20:59:38 +00:00
|
|
|
PushAddr (Expr);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Fetch the lhs into the primary register if needed */
|
2004-06-09 14:12:57 +00:00
|
|
|
LoadExpr (CF_NONE, Expr);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Bring the lhs on stack */
|
2004-07-06 11:30:08 +00:00
|
|
|
GetCodePos (&Mark);
|
2000-05-28 13:40:48 +00:00
|
|
|
g_push (flags, 0);
|
|
|
|
|
|
|
|
/* Evaluate the rhs */
|
2004-05-31 15:27:33 +00:00
|
|
|
if (evalexpr (CF_NONE, hie1, &Expr2) == 0) {
|
2004-07-06 11:30:08 +00:00
|
|
|
/* The resulting value is a constant. If the generator has the NOPUSH
|
|
|
|
* flag set, don't push the lhs.
|
|
|
|
*/
|
|
|
|
if (Gen->Flags & GEN_NOPUSH) {
|
|
|
|
RemoveCode (&Mark);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
if (MustScale) {
|
|
|
|
/* lhs is a pointer, scale rhs */
|
2004-06-06 14:48:59 +00:00
|
|
|
Expr2.IVal *= CheckedSizeOf (Expr->Type+1);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* If the lhs is character sized, the operation may be later done
|
|
|
|
* with characters.
|
|
|
|
*/
|
2004-05-25 20:59:38 +00:00
|
|
|
if (CheckedSizeOf (Expr->Type) == SIZEOF_CHAR) {
|
2000-05-28 13:40:48 +00:00
|
|
|
flags |= CF_FORCECHAR;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Special handling for add and sub - some sort of a hack, but short code */
|
|
|
|
if (Gen->Func == g_add) {
|
2004-06-06 14:48:59 +00:00
|
|
|
g_inc (flags | CF_CONST, Expr2.IVal);
|
2000-05-28 13:40:48 +00:00
|
|
|
} else if (Gen->Func == g_sub) {
|
2004-06-06 14:48:59 +00:00
|
|
|
g_dec (flags | CF_CONST, Expr2.IVal);
|
2000-05-28 13:40:48 +00:00
|
|
|
} else {
|
2004-06-06 14:48:59 +00:00
|
|
|
Gen->Func (flags | CF_CONST, Expr2.IVal);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* rhs is not constant and already in the primary register */
|
|
|
|
if (MustScale) {
|
|
|
|
/* lhs is a pointer, scale rhs */
|
2004-05-31 15:27:33 +00:00
|
|
|
g_scale (TypeOf (Expr2.Type), CheckedSizeOf (Expr->Type+1));
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* If the lhs is character sized, the operation may be later done
|
|
|
|
* with characters.
|
|
|
|
*/
|
2004-05-25 20:59:38 +00:00
|
|
|
if (CheckedSizeOf (Expr->Type) == SIZEOF_CHAR) {
|
2000-05-28 13:40:48 +00:00
|
|
|
flags |= CF_FORCECHAR;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Adjust the types of the operands if needed */
|
2004-05-31 15:27:33 +00:00
|
|
|
Gen->Func (g_typeadjust (flags, TypeOf (Expr2.Type)), 0);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
2004-05-25 20:59:38 +00:00
|
|
|
Store (Expr, 0);
|
2004-05-31 15:27:33 +00:00
|
|
|
ED_MakeRValExpr (Expr);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
static void addsubeq (const GenDesc* Gen, ExprDesc *Expr)
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Process the += and -= operators */
|
|
|
|
{
|
2004-05-31 15:27:33 +00:00
|
|
|
ExprDesc Expr2;
|
2001-10-11 09:52:02 +00:00
|
|
|
unsigned lflags;
|
|
|
|
unsigned rflags;
|
2003-08-19 20:31:10 +00:00
|
|
|
int MustScale;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
|
2004-05-31 15:27:33 +00:00
|
|
|
/* We're currently only able to handle some adressing modes */
|
|
|
|
if (ED_GetLoc (Expr) == E_LOC_EXPR || ED_GetLoc (Expr) == E_LOC_PRIMARY) {
|
|
|
|
/* Use generic routine */
|
|
|
|
opeq (Gen, Expr);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2001-10-11 09:52:02 +00:00
|
|
|
/* We must have an lvalue */
|
2004-05-25 20:59:38 +00:00
|
|
|
if (ED_IsRVal (Expr)) {
|
2000-11-02 21:22:33 +00:00
|
|
|
Error ("Invalid lvalue in assignment");
|
2000-05-28 13:40:48 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2004-05-31 15:27:33 +00:00
|
|
|
/* There must be an integer or pointer on the left side */
|
|
|
|
if (!IsClassInt (Expr->Type) && !IsTypePtr (Expr->Type)) {
|
|
|
|
Error ("Invalid left operand type");
|
|
|
|
/* Continue. Wrong code will be generated, but the compiler won't
|
|
|
|
* break, so this is the best error recovery.
|
|
|
|
*/
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Skip the operator */
|
2000-06-12 18:31:40 +00:00
|
|
|
NextToken ();
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Check if we have a pointer expression and must scale rhs */
|
2004-05-31 15:27:33 +00:00
|
|
|
MustScale = IsTypePtr (Expr->Type);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2001-10-11 09:52:02 +00:00
|
|
|
/* Initialize the code generator flags */
|
|
|
|
lflags = 0;
|
|
|
|
rflags = 0;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Evaluate the rhs */
|
2004-05-31 15:27:33 +00:00
|
|
|
hie1 (&Expr2);
|
|
|
|
if (ED_IsConstAbs (&Expr2)) {
|
|
|
|
/* The resulting value is a constant. Scale it. */
|
|
|
|
if (MustScale) {
|
2004-06-06 14:48:59 +00:00
|
|
|
Expr2.IVal *= CheckedSizeOf (Indirect (Expr->Type));
|
2004-05-31 15:27:33 +00:00
|
|
|
}
|
2001-10-11 09:52:02 +00:00
|
|
|
rflags |= CF_CONST;
|
2003-08-19 20:31:10 +00:00
|
|
|
lflags |= CF_CONST;
|
2000-05-28 13:40:48 +00:00
|
|
|
} else {
|
2003-08-19 20:31:10 +00:00
|
|
|
/* Not constant, load into the primary */
|
2004-06-09 14:12:57 +00:00
|
|
|
LoadExpr (CF_NONE, &Expr2);
|
2000-05-28 13:40:48 +00:00
|
|
|
if (MustScale) {
|
2001-10-11 09:52:02 +00:00
|
|
|
/* lhs is a pointer, scale rhs */
|
2004-05-31 15:27:33 +00:00
|
|
|
g_scale (TypeOf (Expr2.Type), CheckedSizeOf (Indirect (Expr->Type)));
|
2001-10-11 09:52:02 +00:00
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
2001-10-11 09:52:02 +00:00
|
|
|
/* Setup the code generator flags */
|
2004-05-25 20:59:38 +00:00
|
|
|
lflags |= TypeOf (Expr->Type) | CF_FORCECHAR;
|
2004-05-31 15:27:33 +00:00
|
|
|
rflags |= TypeOf (Expr2.Type);
|
2001-10-11 09:52:02 +00:00
|
|
|
|
2003-08-19 20:31:10 +00:00
|
|
|
/* Convert the type of the lhs to that of the rhs */
|
2003-08-20 08:32:07 +00:00
|
|
|
g_typecast (lflags, rflags);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2004-05-31 15:27:33 +00:00
|
|
|
/* Output apropriate code depending on the location */
|
|
|
|
switch (ED_GetLoc (Expr)) {
|
|
|
|
|
|
|
|
case E_LOC_ABS:
|
|
|
|
/* Absolute: numeric address or const */
|
|
|
|
lflags |= CF_ABSOLUTE;
|
|
|
|
if (Gen->Tok == TOK_PLUS_ASSIGN) {
|
2004-06-06 14:48:59 +00:00
|
|
|
g_addeqstatic (lflags, Expr->Name, Expr->IVal, Expr2.IVal);
|
2004-05-31 15:27:33 +00:00
|
|
|
} else {
|
2004-06-06 14:48:59 +00:00
|
|
|
g_subeqstatic (lflags, Expr->Name, Expr->IVal, Expr2.IVal);
|
2004-05-31 15:27:33 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case E_LOC_GLOBAL:
|
|
|
|
/* Global variable */
|
|
|
|
lflags |= CF_EXTERNAL;
|
|
|
|
if (Gen->Tok == TOK_PLUS_ASSIGN) {
|
2004-06-06 14:48:59 +00:00
|
|
|
g_addeqstatic (lflags, Expr->Name, Expr->IVal, Expr2.IVal);
|
2004-05-31 15:27:33 +00:00
|
|
|
} else {
|
2004-06-06 14:48:59 +00:00
|
|
|
g_subeqstatic (lflags, Expr->Name, Expr->IVal, Expr2.IVal);
|
2004-05-31 15:27:33 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case E_LOC_STATIC:
|
2004-05-31 19:51:13 +00:00
|
|
|
case E_LOC_LITERAL:
|
|
|
|
/* Static variable or literal in the literal pool */
|
2004-05-31 15:27:33 +00:00
|
|
|
lflags |= CF_STATIC;
|
|
|
|
if (Gen->Tok == TOK_PLUS_ASSIGN) {
|
2004-06-06 14:48:59 +00:00
|
|
|
g_addeqstatic (lflags, Expr->Name, Expr->IVal, Expr2.IVal);
|
2004-05-31 15:27:33 +00:00
|
|
|
} else {
|
2004-06-06 14:48:59 +00:00
|
|
|
g_subeqstatic (lflags, Expr->Name, Expr->IVal, Expr2.IVal);
|
2004-05-31 15:27:33 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case E_LOC_REGISTER:
|
|
|
|
/* Register variable */
|
|
|
|
lflags |= CF_REGVAR;
|
|
|
|
if (Gen->Tok == TOK_PLUS_ASSIGN) {
|
2004-06-06 14:48:59 +00:00
|
|
|
g_addeqstatic (lflags, Expr->Name, Expr->IVal, Expr2.IVal);
|
2004-05-31 15:27:33 +00:00
|
|
|
} else {
|
2004-06-06 14:48:59 +00:00
|
|
|
g_subeqstatic (lflags, Expr->Name, Expr->IVal, Expr2.IVal);
|
2004-05-31 15:27:33 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case E_LOC_STACK:
|
|
|
|
/* Value on the stack */
|
|
|
|
if (Gen->Tok == TOK_PLUS_ASSIGN) {
|
2004-06-06 14:48:59 +00:00
|
|
|
g_addeqlocal (lflags, Expr->IVal, Expr2.IVal);
|
2004-05-31 15:27:33 +00:00
|
|
|
} else {
|
2004-06-06 14:48:59 +00:00
|
|
|
g_subeqlocal (lflags, Expr->IVal, Expr2.IVal);
|
2004-05-31 15:27:33 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
Internal ("Invalid location in Store(): 0x%04X", ED_GetLoc (Expr));
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
/* Expression is a rvalue in the primary now */
|
2004-05-31 15:27:33 +00:00
|
|
|
ED_MakeRValExpr (Expr);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
void hie1 (ExprDesc* Expr)
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Parse first level of expression hierarchy. */
|
|
|
|
{
|
2004-05-25 20:59:38 +00:00
|
|
|
hieQuest (Expr);
|
2001-05-22 09:32:24 +00:00
|
|
|
switch (CurTok.Tok) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2000-06-12 18:31:40 +00:00
|
|
|
case TOK_ASSIGN:
|
2004-05-25 20:59:38 +00:00
|
|
|
Assignment (Expr);
|
2000-05-28 13:40:48 +00:00
|
|
|
break;
|
|
|
|
|
2000-06-12 18:31:40 +00:00
|
|
|
case TOK_PLUS_ASSIGN:
|
2004-05-25 20:59:38 +00:00
|
|
|
addsubeq (&GenPASGN, Expr);
|
2000-05-28 13:40:48 +00:00
|
|
|
break;
|
|
|
|
|
2000-06-12 18:31:40 +00:00
|
|
|
case TOK_MINUS_ASSIGN:
|
2004-05-25 20:59:38 +00:00
|
|
|
addsubeq (&GenSASGN, Expr);
|
2000-05-28 13:40:48 +00:00
|
|
|
break;
|
|
|
|
|
2000-06-12 18:31:40 +00:00
|
|
|
case TOK_MUL_ASSIGN:
|
2004-05-25 20:59:38 +00:00
|
|
|
opeq (&GenMASGN, Expr);
|
2000-05-28 13:40:48 +00:00
|
|
|
break;
|
|
|
|
|
2000-06-12 18:31:40 +00:00
|
|
|
case TOK_DIV_ASSIGN:
|
2004-05-25 20:59:38 +00:00
|
|
|
opeq (&GenDASGN, Expr);
|
2000-05-28 13:40:48 +00:00
|
|
|
break;
|
|
|
|
|
2000-06-12 18:31:40 +00:00
|
|
|
case TOK_MOD_ASSIGN:
|
2004-05-25 20:59:38 +00:00
|
|
|
opeq (&GenMOASGN, Expr);
|
2000-05-28 13:40:48 +00:00
|
|
|
break;
|
|
|
|
|
2000-06-12 18:31:40 +00:00
|
|
|
case TOK_SHL_ASSIGN:
|
2004-05-25 20:59:38 +00:00
|
|
|
opeq (&GenSLASGN, Expr);
|
2000-05-28 13:40:48 +00:00
|
|
|
break;
|
|
|
|
|
2000-06-12 18:31:40 +00:00
|
|
|
case TOK_SHR_ASSIGN:
|
2004-05-25 20:59:38 +00:00
|
|
|
opeq (&GenSRASGN, Expr);
|
2000-05-28 13:40:48 +00:00
|
|
|
break;
|
|
|
|
|
2000-06-12 18:31:40 +00:00
|
|
|
case TOK_AND_ASSIGN:
|
2004-05-25 20:59:38 +00:00
|
|
|
opeq (&GenAASGN, Expr);
|
2000-05-28 13:40:48 +00:00
|
|
|
break;
|
|
|
|
|
2000-06-12 18:31:40 +00:00
|
|
|
case TOK_XOR_ASSIGN:
|
2004-05-25 20:59:38 +00:00
|
|
|
opeq (&GenXOASGN, Expr);
|
2000-05-28 13:40:48 +00:00
|
|
|
break;
|
|
|
|
|
2000-06-12 18:31:40 +00:00
|
|
|
case TOK_OR_ASSIGN:
|
2004-05-25 20:59:38 +00:00
|
|
|
opeq (&GenOASGN, Expr);
|
2000-05-28 13:40:48 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2004-05-25 20:59:38 +00:00
|
|
|
break;
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
void hie0 (ExprDesc *Expr)
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Parse comma operator. */
|
|
|
|
{
|
2004-05-25 20:59:38 +00:00
|
|
|
hie1 (Expr);
|
2001-05-22 09:32:24 +00:00
|
|
|
while (CurTok.Tok == TOK_COMMA) {
|
2004-05-25 20:59:38 +00:00
|
|
|
NextToken ();
|
|
|
|
hie1 (Expr);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2004-05-25 20:59:38 +00:00
|
|
|
int evalexpr (unsigned Flags, void (*Func) (ExprDesc*), ExprDesc* Expr)
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Will evaluate an expression via the given function. If the result is a
|
2004-05-26 16:15:28 +00:00
|
|
|
* constant, 0 is returned and the value is put in the Expr struct. If the
|
2004-06-09 14:12:57 +00:00
|
|
|
* result is not constant, LoadExpr is called to bring the value into the
|
2000-05-28 13:40:48 +00:00
|
|
|
* primary register and 1 is returned.
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
/* Evaluate */
|
2004-05-31 15:27:33 +00:00
|
|
|
ExprWithCheck (Func, Expr);
|
2004-05-25 20:59:38 +00:00
|
|
|
|
|
|
|
/* Check for a constant expression */
|
2004-05-31 15:27:33 +00:00
|
|
|
if (ED_IsConstAbs (Expr)) {
|
2000-10-10 20:40:36 +00:00
|
|
|
/* Constant expression */
|
|
|
|
return 0;
|
2000-05-28 13:40:48 +00:00
|
|
|
} else {
|
2000-10-10 20:40:36 +00:00
|
|
|
/* Not constant, load into the primary */
|
2004-06-09 14:12:57 +00:00
|
|
|
LoadExpr (Flags, Expr);
|
2000-05-28 13:40:48 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2004-05-31 15:27:33 +00:00
|
|
|
void Expression0 (ExprDesc* Expr)
|
|
|
|
/* Evaluate an expression via hie0 and put the result into the primary register */
|
2000-05-28 13:40:48 +00:00
|
|
|
{
|
2004-05-31 15:27:33 +00:00
|
|
|
ExprWithCheck (hie0, Expr);
|
2004-06-09 14:12:57 +00:00
|
|
|
LoadExpr (CF_NONE, Expr);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2004-05-31 15:27:33 +00:00
|
|
|
void ConstExpr (void (*Func) (ExprDesc*), ExprDesc* Expr)
|
|
|
|
/* Will evaluate an expression via the given function. If the result is not
|
|
|
|
* a constant of some sort, a diagnostic will be printed, and the value is
|
|
|
|
* replaced by a constant one to make sure there are no internal errors that
|
|
|
|
* result from this input error.
|
|
|
|
*/
|
2000-05-28 13:40:48 +00:00
|
|
|
{
|
2004-05-31 15:27:33 +00:00
|
|
|
ExprWithCheck (Func, Expr);
|
|
|
|
if (!ED_IsConst (Expr)) {
|
2000-11-02 21:22:33 +00:00
|
|
|
Error ("Constant expression expected");
|
2000-05-28 13:40:48 +00:00
|
|
|
/* To avoid any compiler errors, make the expression a valid const */
|
2004-05-31 15:27:33 +00:00
|
|
|
ED_MakeConstAbsInt (Expr, 1);
|
2002-02-18 08:40:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2004-05-31 15:27:33 +00:00
|
|
|
void BoolExpr (void (*Func) (ExprDesc*), ExprDesc* Expr)
|
|
|
|
/* Will evaluate an expression via the given function. If the result is not
|
|
|
|
* something that may be evaluated in a boolean context, a diagnostic will be
|
|
|
|
* printed, and the value is replaced by a constant one to make sure there
|
|
|
|
* are no internal errors that result from this input error.
|
|
|
|
*/
|
2002-02-18 08:40:11 +00:00
|
|
|
{
|
2004-05-31 15:27:33 +00:00
|
|
|
ExprWithCheck (Func, Expr);
|
|
|
|
if (!ED_IsBool (Expr)) {
|
|
|
|
Error ("Boolean expression expected");
|
|
|
|
/* To avoid any compiler errors, make the expression a valid int */
|
|
|
|
ED_MakeConstAbsInt (Expr, 1);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2004-05-31 15:27:33 +00:00
|
|
|
void ConstAbsIntExpr (void (*Func) (ExprDesc*), ExprDesc* Expr)
|
|
|
|
/* Will evaluate an expression via the given function. If the result is not
|
|
|
|
* a constant numeric integer value, a diagnostic will be printed, and the
|
|
|
|
* value is replaced by a constant one to make sure there are no internal
|
|
|
|
* errors that result from this input error.
|
|
|
|
*/
|
2000-05-28 13:40:48 +00:00
|
|
|
{
|
2004-05-31 15:27:33 +00:00
|
|
|
ExprWithCheck (Func, Expr);
|
|
|
|
if (!ED_IsConstAbsInt (Expr)) {
|
|
|
|
Error ("Constant integer expression expected");
|
|
|
|
/* To avoid any compiler errors, make the expression a valid const */
|
|
|
|
ED_MakeConstAbsInt (Expr, 1);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|