Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

5441 lines
143 KiB

/*** DEBEVAL.C - Expression evaluator main routines
*
*
*/
// Return values from Logical ().
#define DL_DEBERR 1 // Error occurred, DebErr is set
#define DL_SUCCESS 2 // Evaluation successful
#define DL_CONTINUE 3 // Inconclusive, continue evaluation
// Actions to be taken by EvalUtil().
#define EU_LOAD 0x0001 // Load node values
#define EU_TYPE 0x0002 // Do implicit type coercion
LOCAL uint NEAR PASCAL Logical (op_t, bool_t);
LOCAL bool_t NEAR FASTCALL CalcThisExpr (CV_typ_t, OFFSET, OFFSET, CV_typ_t);
LOCAL bool_t NEAR PASCAL DerefVBPtr (CV_typ_t);
LOCAL bool_t NEAR FASTCALL Eval (bnode_t);
LOCAL bool_t NEAR FASTCALL EvalAddrOf (bnode_t);
LOCAL bool_t NEAR FASTCALL AddrOf (bnode_t);
LOCAL bool_t NEAR FASTCALL EvalArray (bnode_t);
LOCAL bool_t NEAR FASTCALL EvalAssign (bnode_t);
LOCAL bool_t NEAR FASTCALL EvalBang (bnode_t);
LOCAL bool_t NEAR FASTCALL EvalBasePtr (bnode_t);
LOCAL bool_t NEAR FASTCALL EvalBinary (bnode_t);
LOCAL bool_t NEAR FASTCALL EvalBScope (bnode_t);
LOCAL bool_t NEAR FASTCALL EvalByteOps (bnode_t);
LOCAL bool_t NEAR FASTCALL EvalCast (bnode_t);
LOCAL bool_t NEAR FASTCALL CastST (bnode_t);
LOCAL bool_t NEAR FASTCALL EvalCastBin (bnode_t);
LOCAL bool_t NEAR FASTCALL EvalContext (bnode_t);
LOCAL bool_t NEAR FASTCALL EvalDMember (bnode_t);
LOCAL bool_t NEAR FASTCALL EvalDot (bnode_t);
LOCAL bool_t NEAR FASTCALL EvalError (register bnode_t);
LOCAL bool_t NEAR FASTCALL EvalFetch (bnode_t);
LOCAL bool_t NEAR FASTCALL EvalFunction (bnode_t);
LOCAL bool_t NEAR FASTCALL EvalFuncIdent (bnode_t);
LOCAL bool_t NEAR FASTCALL EvalLChild (bnode_t);
LOCAL bool_t NEAR FASTCALL EvalLogical (bnode_t);
LOCAL bool_t NEAR FASTCALL EvalRChild (bnode_t);
LOCAL bool_t NEAR FASTCALL EvalPlusMinus (bnode_t);
LOCAL bool_t NEAR FASTCALL EvalPMember (bnode_t);
LOCAL bool_t NEAR FASTCALL EvalPostIncDec (bnode_t);
LOCAL bool_t NEAR FASTCALL EvalPreIncDec (bnode_t);
LOCAL bool_t NEAR FASTCALL EvalPointsTo (bnode_t);
LOCAL bool_t NEAR FASTCALL EvalPushNode (bnode_t);
LOCAL bool_t NEAR FASTCALL EvalRelat (bnode_t);
LOCAL bool_t NEAR FASTCALL EvalSegOp (bnode_t);
LOCAL bool_t NEAR FASTCALL EvalThisInit (bnode_t);
LOCAL bool_t NEAR FASTCALL EvalThisConst (bnode_t);
LOCAL bool_t NEAR FASTCALL EvalThisExpr (bnode_t);
LOCAL bool_t NEAR FASTCALL EvalUnary (bnode_t);
LOCAL bool_t NEAR FASTCALL EvalUScope (bnode_t);
LOCAL bool_t NEAR FASTCALL Arith (op_t);
LOCAL bool_t NEAR FASTCALL Assign (op_t);
LOCAL bool_t NEAR FASTCALL EvalUtil (op_t, peval_t, peval_t, ushort);
LOCAL bool_t NEAR FASTCALL FetchOp (peval_t pv);
LOCAL bool_t NEAR FASTCALL InitConst (long);
LOCAL bool_t NEAR FASTCALL PlusMinus (op_t);
LOCAL bool_t NEAR FASTCALL PrePost (op_t);
LOCAL bool_t NEAR FASTCALL Relational (op_t);
LOCAL bool_t NEAR FASTCALL SBitField (void);
LOCAL bool_t NEAR FASTCALL StructEval (bnode_t);
LOCAL bool_t NEAR FASTCALL StructElem (bnode_t);
LOCAL bool_t NEAR PASCAL ThisOffset (peval_t);
LOCAL bool_t NEAR FASTCALL Unary (op_t);
LOCAL bool_t NEAR PASCAL PushArgs (pnode_t, SHREG FAR *, UOFFSET FAR*);
LOCAL bool_t NEAR PASCAL PushOffset (UOFFSET, SHREG FAR *, UOFFSET FAR *, uint);
LOCAL bool_t NEAR PASCAL PushString (peval_t, SHREG FAR *, CV_typ_t);
LOCAL bool_t NEAR PASCAL PushRef (peval_t, SHREG FAR *, CV_typ_t);
LOCAL bool_t NEAR PASCAL PushUserValue (peval_t, pargd_t, SHREG FAR *, UOFFSET FAR *);
LOCAL bool_t NEAR PASCAL StoreC (peval_t);
LOCAL bool_t NEAR PASCAL StoreP (void);
LOCAL bool_t NEAR PASCAL StoreF (void);
LOCAL bool_t NEAR PASCAL StorePPC (peval_t);
LOCAL bool_t NEAR PASCAL StoreMips (peval_t);
LOCAL bool_t NEAR PASCAL StoreAlpha (peval_t);
LOCAL bool_t NEAR PASCAL VFuncAddress (peval_t, ulong);
eval_t ThisAddress;
const peval_t pvThis = &ThisAddress;
// Bind dispatch table
#ifdef WIN32
LOCAL bool_t (NEAR FASTCALL *pEval[]) (bnode_t) = {
#else
LOCAL bool_t (NEAR FASTCALL *_based(_segname("_CODE"))pEval[]) (bnode_t) = {
#endif
#define OPCNT(name, val)
#define OPCDAT(opc)
#define OPDAT(op, opfprec, opgprec, opclass, opbind, opeval, opwalk) opeval,
#include "debops.h"
#undef OPDAT
#undef OPCDAT
#undef OPCNT
};
LOCAL bool_t NEAR FASTCALL EvalError (register bnode_t bn)
{
Unreferenced(bn);
pExState->err_num = ERR_INTERNAL;
return (FALSE);
}
LOCAL bool_t NEAR FASTCALL Eval (bnode_t bn)
{
return ((*pEval[NODE_OP(pnodeOfbnode(bn))])(bn));
}
LOCAL bool_t NEAR FASTCALL EvalLChild (bnode_t bn)
{
register bnode_t bnL = NODE_LCHILD (pnodeOfbnode(bn));
return ((*pEval[NODE_OP(pnodeOfbnode(bnL))])(bnL));
}
LOCAL bool_t NEAR FASTCALL EvalRChild (bnode_t bn)
{
register bnode_t bnR = NODE_RCHILD (pnodeOfbnode(bn));
return ((*pEval[NODE_OP(pnodeOfbnode(bnR))])(bnR));
}
/*** DoEval - Evaluate parse tree
*
* SYNOPSIS
* error = DoEval ()
*
* ENTRY
* none
*
* RETURNS
* True if tree evaluated without error.
*
* DESCRIPTION
* The parser will call this routine to evaluate the parse tree
*
* NOTES
*/
EESTATUS PASCAL DoEval (PHTM phTM, PFRAME pFrame, EEDSP style)
{
EESTATUS retval = EEGENERAL;
bool_t evalstate;
// lock the expression state structure, save the formatting style
// and frame
DASSERT (*phTM != 0);
if (*phTM == 0) {
return (EECATASTROPHIC);
}
DASSERT(pExState == NULL );
pExState = MHMemLock (*phTM);
pExState->style = style;
pExState->frame = *pFrame;
pCxt = &pExState->cxt;
//DASSERT (pExState->state.parse_ok == TRUE);
//DASSERT (pExState->state.bind_ok == TRUE);
//DASSERT (pExState->hSTree != 0);
if ((pExState->state.parse_ok == TRUE)
&& (pExState->state.bind_ok == TRUE)) {
pTree = MHMemLock (pExState->hETree);
DASSERT (hEStack != 0);
pEStack = MHMemLock (hEStack);
StackMax = 0;
StackCkPoint = 0;
StackOffset = 0;
pExState->err_num = 0;
ST = NULL;
STP = NULL;
pExStr = MHMemLock (pExState->hExStr);
// zero out type of ThisAddress so that users can check to see if
// ThisAddress has been correctly initialized
bnCxt = 0;
EVAL_TYP (pvThis) = 0;
Evaluating = TRUE;
evalstate = Eval ((bnode_t)pTree->start_node);
Evaluating = FALSE;
bnCxt = 0;
MHMemUnLock (pExState->hExStr);
// If the input consisted of a single identifier (i.e., no
// operators involved), then the resulting value may still
// be an identifier. Look it up in the symbols.
if (evalstate == TRUE) {
pExState->result = *ST;
pExState->state.eval_ok = TRUE;
retval = EENOERROR;
}
else {
retval = EEGENERAL;
}
MHMemUnLock (hEStack);
MHMemUnLock (pExState->hETree);
} else {
if(!pExState->err_num) {
pExState->err_num = ERR_NOTEVALUATABLE;
}
}
MHMemUnLock (*phTM);
pExState = NULL;
return (retval);
}
LOCAL bool_t NEAR FASTCALL EvalPushNode (bnode_t bn)
{
bool_t Ok;
Ok = PushStack(&pnodeOfbnode(bn)->v[0]);
if ( Ok && EVAL_IS_CURPC( ST ) ) {
//
// Get current PC
//
SYGetAddr( &(EVAL_PTR( ST )), adrPC);
EVAL_IS_ADDR( ST ) = TRUE;
EVAL_IS_BPREL( ST ) = FALSE;
EVAL_IS_REGREL( ST ) = FALSE;
EVAL_IS_TLSREL( ST ) = FALSE;
}
return Ok;
}
/** EvalUnary - perform a unary arithmetic operation
*
* fSuccess = EvalUnary (bn)
*
* Entry bn = based pointer to node
*
* Returns TRUE if no error during evaluation
* FALSE if error during evaluation
*
* DESCRIPTION
* Evaluates the result of an arithmetic operation. The unary operators
* dealt with here are:
*
* ~ - +
*
* Pointer arithmetic is NOT handled; all operands must be of
* arithmetic type.
*/
LOCAL bool_t NEAR FASTCALL EvalUnary (bnode_t bn)
{
if (EvalLChild (bn)) {
return (Unary (NODE_OP (pnodeOfbnode(bn))));
}
return (FALSE);
}
/*** EvalBasePtr - Perform a based pointer access (:>)
*
* fSuccess = EvalBasePtr (bnRight)
*
* Entry bnRight = based pointer to right operand node
*
* Exit
*
* Returns TRUE if successful
* FALSE if error
*/
LOCAL bool_t NEAR FASTCALL EvalBasePtr (bnode_t bn)
{
return (EvalSegOp (bn));
}
/** EvalBinary - evaluate a binary arithmetic operation
*
* fSuccess = EvalBinary (bn)
*
* Entry bn = based pointer to node
*
* Returns TRUE if no error during evaluation
* FALSE if error during evaluation
*
*/
LOCAL bool_t NEAR FASTCALL EvalBinary (bnode_t bn)
{
if (EvalLChild (bn) && EvalRChild (bn)) {
return (Arith (NODE_OP (pnodeOfbnode(bn))));
}
return (FALSE);
}
LOCAL bool_t NEAR FASTCALL EvalCastBin (bnode_t bn)
{
bool_t f = FALSE;
if ( EvalLChild(bn) && EvalRChild (bn)) {
switch( (NODE_OP (pnodeOfbnode(bn)) ) ) {
case OP_caststar:
f = (FetchOp(ST));
break;
case OP_castplus:
f = Unary(OP_uplus);
break;
case OP_castminus:
f = Unary(OP_negate);
break;
case OP_castamp:
f = AddrOf( NODE_RCHILD(pnodeOfbnode(bn)) );
break;
}
if ( f ) {
f = CastST( bn );
*STP = *ST;
PopStack ();
}
}
return f;
}
/*** EvalPlusMinus - Evaluate binary plus or minus
*
* fSuccess = EvalPlusMinus (bn)
*
* Entry bn = based pointer to tree node
*
* Exit ST = STP +- ST
*
* Returns TRUE if Eval successful
* FALSE if Eval error
*
*
*/
LOCAL bool_t NEAR FASTCALL EvalPlusMinus (bnode_t bn)
{
if (EvalLChild (bn) && EvalRChild (bn)) {
return (PlusMinus (NODE_OP (pnodeOfbnode(bn))));
}
return (FALSE);
}
/*** EvalDot - Perform the dot ('.') operation
*
* fSuccess = EvalDot (bn)
*
* Entry bn = based pointer to tree node
*
* Exit NODE_STYPE (bn) = type of stack top
*
* Returns TRUE if Eval successful
* FALSE if Eval error
*
* Exit pExState->err_num = error ordinal if Eval error
*
*/
LOCAL bool_t NEAR FASTCALL EvalDot (bnode_t bn)
{
if (!EvalLChild (bn)) {
return (FALSE);
}
if (EVAL_STATE (ST) == EV_rvalue) {
return (StructElem (bn));
}
else {
return (StructEval (bn));
}
}
/** EvalLogical - Handle '&&' and '||' operators
*
* wStatus = EvalLogical (bn)
*
* Entry op = Operand (OP_andand or OP_oror)
* REval = FALSE if right hand not evaluated
* ST = left hand value
* REval = TRUE if right hand evaluated
* STP = left hand value
* ST = right hand value
*
* Returns wStatus = evaluation status
* (REval = TRUE)
* DL_DEBERR Evaluation failed, DebErr is set
* DL_SUCCESS Evaluation succeeded, result in ST
*
* (REVAL == FALSE)
* DL_DEBERR Evaluation failed,
* DL_SUCCESS Evaluation succeeded, result in ST
* DL_CONTINUE Evaluation inconclusive, must evaluate right node
*
* DESCRIPTION
* If (REval = TRUE), checks that both operands (STP and ST) are of scalar
* type and evaluates the result (0 or 1).
*
* If (REval == FALSE), checks that the left operand (ST) is of scalar
* type and determines whether evaluation of the right operand is
* necessary.
*
*/
LOCAL bool_t NEAR FASTCALL EvalLogical (bnode_t bn)
{
uint wStatus;
if (!EvalLChild (bn)) {
return (FALSE);
}
wStatus = Logical (NODE_OP (pnodeOfbnode(bn)), FALSE);
if (wStatus == DL_DEBERR) {
return(FALSE);
}
else if (wStatus == DL_SUCCESS) {
// Do not evaluate rhs
return (TRUE);
}
//DASSERT (wStatus == DL_CONTINUE);
if (!EvalRChild (bn)) {
return (FALSE);
}
return (Logical (NODE_OP (pnodeOfbnode(bn)), TRUE) == DL_SUCCESS);
}
/** Logical - Handle '&&' and '||' operators
*
* wStatus = Logical (op, REval)
*
* Entry op = Operand (OP_andand or OP_oror)
* REval = FALSE if right hand not evaluated
* ST = left hand value
* REval = TRUE if right hand evaluated
* STP = left hand value
* ST = right hand value
*
* Returns wStatus = evaluation status
* (REval = TRUE)
* DL_DEBERR Evaluation failed, DebErr is set
* DL_SUCCESS Evaluation succeeded, result in ST
*
* (REVAL == FALSE)
* DL_DEBERR Evaluation failed,
* DL_SUCCESS Evaluation succeeded, result in ST
* DL_CONTINUE Evaluation inconclusive, must evaluate right node
*
* DESCRIPTION
* If (REval = TRUE), checks that both operands (STP and ST) are of scalar
* type and evaluates the result (0 or 1).
*
* If (REval == FALSE), checks that the left operand (ST) is of scalar
* type and determines whether evaluation of the right operand is
* necessary.
*
*/
LOCAL uint NEAR PASCAL Logical (op_t op, bool_t REval)
{
int result;
bool_t fIsZeroL;
bool_t fIsZeroR;
// Evaluate the result. We push a constant node with value of
// zero so we can compare against it (i.e., expr1 && expr2 is
// equivalent to (expr1 != 0) && (expr2 != 0)).
// Evaluate whether the left node is zero.
if (REval == FALSE) {
if (!PushStack (ST) || !InitConst (0)) {
pExState->err_num = ERR_NOMEMORY;
return (FALSE);
}
if (!Relational (OP_eqeq))
return (DL_DEBERR);
//DASSERT (EVAL_TYP (ST) == T_SHORT);
fIsZeroL = (EVAL_SHORT (ST) == 1);
// remove left hand comparison
PopStack ();
result = (op == OP_oror);
EVAL_STATE (ST) = EV_rvalue;
EVAL_SHORT (ST) = (short) result;
SetNodeType (ST, T_SHORT);
if (
((op == OP_andand) && (!fIsZeroL))
||
((op == OP_oror) && (fIsZeroL))
) {
return(DL_CONTINUE);
}
else {
return (DL_SUCCESS);
}
}
else {
if (!PushStack (ST) || !InitConst (0)) {
pExState->err_num = ERR_NOMEMORY;
return (FALSE);
}
if (!Relational (OP_eqeq))
return (DL_DEBERR);
//DASSERT (EVAL_TYP(ST) == T_SHORT);
fIsZeroR = (EVAL_SHORT (ST) == 1);
PopStack ();
fIsZeroL = (EVAL_SHORT (STP) == 1);
// Finally, determine whether or not we have a result, and if so,
// what the result is:
if (
((op == OP_andand) && ((!fIsZeroL) && (!fIsZeroR)))
||
((op == OP_oror) && ((!fIsZeroL) || (!fIsZeroR)))
)
result = 1;
else
result = 0;
}
EVAL_STATE (STP) = EV_rvalue;
EVAL_SHORT (STP) = (short) result;
SetNodeType (STP, T_SHORT);
PopStack ();
return (DL_SUCCESS);
}
/*** EvalContext - evaluate the context operator
*
* fSuccess = EvalContext (bn)
*
*
* Exit ST = address node
* pExState->err_num = error number if error
*
* Returns TRUE if successful
* FALSE if error
*
* The stack top value (ST) is set to the address of the
* stack top operand
*/
LOCAL bool_t NEAR FASTCALL EvalContext (bnode_t bn)
{
PCXT oldCxt;
bool_t error;
bnode_t oldbnCxt;
FRAME oldFrame;
// Set the new context for evaluation of the remainder of this
// part of the tree
oldCxt = pCxt;
oldbnCxt = bnCxt;
pCxt = SHpCXTFrompCXF ((PCXF)&pnodeOfbnode(bn)->v[0]);
oldFrame = pExState->frame;
pExState->frame = *SHpFrameFrompCXF ((PCXF)&pnodeOfbnode(bn)->v[0]);
if ((pExState->frame.BP.seg == 0) && (pExState->frame.BP.off == 0)) {
// we did not have a valid frame at bind time
pExState->frame = oldFrame;
}
error = EvalLChild (bn);
if (error == TRUE) {
// if there was not an error and if the result of the
// expression is bp relative, then we must load the value
// before returning to the original context
if ((EVAL_STATE (ST) == EV_lvalue) &&
(EVAL_IS_BPREL (ST) || EVAL_IS_REGREL (ST) ||
EVAL_IS_TLSREL (ST))) {
if (EVAL_IS_REF (ST)) {
if (!EvalUtil (OP_fetch, ST, NULL, EU_LOAD)) {
// unable to load value
pExState->err_num = ERR_NOTEVALUATABLE;
pExState->frame = oldFrame;
return (FALSE);
}
EVAL_IS_REF (ST) = FALSE;
EVAL_STATE (ST) = EV_lvalue;
EVAL_SYM_OFF (ST) = EVAL_PTR_OFF (ST);
EVAL_SYM_SEG (ST) = EVAL_PTR_SEG (ST);
SetNodeType (ST, PTR_UTYPE (ST));
}
if (EVAL_IS_ENUM (ST)) {
SetNodeType (ST, ENUM_UTYPE (ST));
}
if (!EvalUtil (OP_fetch, ST, NULL, EU_LOAD)) {
// unable to load value
pExState->err_num = ERR_NOTEVALUATABLE;
pExState->frame = oldFrame;
return (FALSE);
}
}
}
pExState->frame = oldFrame;
if ((bnCxt = oldbnCxt) != 0) {
// the old context was pointing into the expression tree.
// since the expression tree could have been reallocated,
// we must recompute the context pointer
pCxt = SHpCXTFrompCXF ((PCXF)&(pnodeOfbnode(bnCxt))->v[0]);
}
else {
// the context pointer is pointing into the expression state structure
pCxt = oldCxt;
}
return (error);
}
/*** EvalAddrOf - Perform the address-of ('&') operation
*
* fSuccess = EvalAddrOf (bn)
*
* Entry
*
* Exit ST = address node
* pExState->err_num = error number if error
*
* Returns TRUE if successful
* FALSE if error
*
* The stack top value (ST) is set to the address of the
* stack top operand
*/
LOCAL bool_t NEAR FASTCALL EvalAddrOf (bnode_t bn)
{
if (!EvalLChild (bn)) {
return (FALSE);
}
return AddrOf( bn );
}
LOCAL bool_t NEAR FASTCALL AddrOf (bnode_t bn)
{
CV_typ_t type;
if (EVAL_STATE (ST) == EV_type) {
pExState->err_num = ERR_NOTEVALUATABLE;
return (FALSE);
}
// The operand must be an lvalue and cannot be a register variable
DASSERT (EVAL_STATE (ST) == EV_lvalue);
DASSERT (!(EVAL_IS_REG (ST)));
DASSERT (NODE_STYPE (pnodeOfbnode(bn)) != 0);
if ((type = NODE_STYPE (pnodeOfbnode(bn))) == 0) {
// unable to find proper pointer type
return (FALSE);
}
else {
/*
* If the address is a reference -- then all that changes
* is the type, the value of the reference is the pointer
* value. Otherwise the address of the pointer becomes
* the value of the pointer to the pointer.
*/
if (!EVAL_IS_REF(ST)) {
ResolveAddr(ST);
EVAL_STATE(ST) = EV_rvalue;
EVAL_PTR (ST) = EVAL_SYM (ST);
if (ADDR_IS_LI (EVAL_PTR (ST))) {
SHFixupAddr (&EVAL_PTR (ST));
}
}
return (SetNodeType (ST, type));
}
}
/*** EvalFetch - Perform the fetch ('*') operation
*
* fSuccess = EvalFetch (bn)
*
* Entry ST = pointer to address value
*
* Exit ST = dereferenced value
* pExState->err_num = error number if error
*
* Returns TRUE if successful
* FALSE if error
*
* The resultant node is set to the contents of the location
* pointed to by the operand node.
*/
LOCAL bool_t NEAR FASTCALL EvalFetch (bnode_t bn)
{
if (EvalLChild (bn)) {
return (FetchOp (ST));
}
return (FALSE);
}
/*** EvalThisInit - initialize this calculation
*
* fSuccess = EvalThisInit (bn)
*
* Entry bn = based pointer to node
*
* Exit TempThis = stack top
*
* Returns TRUE if successful
* FALSE if error
*/
LOCAL bool_t NEAR FASTCALL EvalThisInit (bnode_t bn)
{
Unreferenced(bn);
*pvThis = *ST;
if (EVAL_IS_CLASS (pvThis)) {
ResolveAddr(pvThis);
return TRUE;
}
else if (EVAL_IS_PTR (pvThis)) {
if (EVAL_STATE (pvThis) == EV_lvalue) {
FetchOp (pvThis);
}
else {
EVAL_SYM (pvThis) = EVAL_PTR (pvThis);
EVAL_STATE (pvThis) = EV_lvalue;
// Remove a level of indirection from the resultant type.
RemoveIndir (pvThis);
EVAL_IS_REF (pvThis) = FALSE;
return (TRUE);
}
}
// we should not initialize the this address unless the stack top
// is a class or a pointer to class
pExState->err_num = ERR_INTERNAL;
return (FALSE);
}
/*** EvalThisConst - Adjust this temp by constant
*
* fSuccess = EvalThisConst (bn)
*
* Entry bn = based pointer to node containing constant
*
* Exit EVAL_SYM_OFF (TempThis) adjusted by constant
*
* Returns TRUE if successful
* FALSE if error
*/
LOCAL bool_t NEAR FASTCALL EvalThisConst (bnode_t bn)
{
if (EvalLChild (bn) == TRUE) {
EVAL_SYM_OFF (pvThis) += ((padjust_t)(&pnodeOfbnode(bn)->v[0]))->disp;
return (SetNodeType (pvThis, ((padjust_t)(&pnodeOfbnode(bn)->v[0]))->btype));
}
return (FALSE);
}
/*** EvalThisExpr - Adjust this temp by expression
*
* fSuccess = EvalThisExpr (bn)
*
* Entry bn = based pointer to node containing expression
*
* Exit EVAL_SYM_OFF (TempThis) adjusted by expression
* newaddr = oldaddr + *(*(oldaddr + vbptroff) + vbindex)
*
* Returns TRUE if successful
* FALSE if error
*
* The evaluation of this node will result in
*
* pvThis = (pvThis + vbpoff) + *(*(pvThis +vbpoff) + vbdisp)
* where
* pvThis = address of base class
* ap = current address point
*/
LOCAL bool_t NEAR FASTCALL EvalThisExpr (bnode_t bn)
{
padjust_t pa = (padjust_t)(&pnodeOfbnode(bn)->v[0]);
// we set the node types of the pointer to char FAR * to prevent the
// PlusMinus () code from attempting an array indexing operation
if (EvalLChild (bn) == TRUE) {
return (CalcThisExpr (pa->vbptr, pa->vbpoff, pa->disp, pa->btype));
}
return (FALSE);
}
/*** CalcThisExpr - Adjust this temp by expression
*
* fSuccess = CalcThisExpr (vbptr, vbpoff, disp, btype)
*
* Entry vbptr = type index of virtual base pointer
* vbpoff = offset of vbptr from this pointer
* disp = index of virtual base displacement from *vbptr
* btype = type index of base class
*
* Exit EVAL_SYM_OFF (TempThis) adjusted by expression
* newaddr = oldaddr + *(*(oldaddr + vbptroff) + vbindex)
*
* Returns TRUE if successful
* FALSE if error
*
* The evaluation of this node will result in
*
* pvThis = (pvThis + vbpoff) + *(*(pvThis + vbpoff) + vbdisp)
* where
* pvThis = address of base class
*/
LOCAL bool_t NEAR FASTCALL CalcThisExpr (CV_typ_t vbptr, OFFSET vbpoff,
OFFSET disp, CV_typ_t btype)
{
// we set the node types of the pointer to char FAR * to prevent the
// PlusMinus () code from attempting an array indexing operation
if (PushStack (pvThis) == TRUE) {
EVAL_PTR (ST) = EVAL_SYM (ST);
EVAL_STATE (ST) = EV_rvalue;
if ((SetNodeType (ST, (CV_typ_t)(ADDR_IS_OFF32(*SHpADDRFrompCXT(pCxt)) ? T_32PFCHAR : T_PFCHAR)) == TRUE) &&
(InitConst (vbpoff) == TRUE) &&
(PlusMinus (OP_plus) == TRUE) &&
(PushStack (ST) == TRUE) &&
(DerefVBPtr (vbptr)) &&
(InitConst (disp) == TRUE) &&
(PlusMinus (OP_plus) == TRUE) &&
(FetchOp (ST) == TRUE) &&
(PlusMinus (OP_plus) == TRUE)) {
SetNodeType (ST, btype);
EVAL_STATE (ST) = EV_lvalue;
EVAL_SYM (ST) = EVAL_PTR (ST);
*pvThis = *ST;
return (PopStack ());
}
}
return (FALSE);
}
/** DerefVBPtr - dereference virtual base pointer
*
* flag = DerefVBPtr (type)
*
* Entry type = type index of virtual base pointer
* ST = address of virtual base pointer as T_PFCHAR
*
* Exit ST = virtual base pointer
*
* Returns TRUE if no error
* FALSE if error
*/
LOCAL bool_t NEAR PASCAL DerefVBPtr (CV_typ_t type)
{
// The operand cannot be a register variable
DASSERT (!(EVAL_IS_REG (ST)));
DASSERT (type != 0);
DASSERT (EVAL_IS_BPREL (ST) == FALSE);
DASSERT (EVAL_IS_REGREL (ST) == FALSE);
if (type != 0) {
if (SetNodeType (ST, type) == TRUE) {
EVAL_STATE (ST) = EV_lvalue;
EVAL_SYM (ST) = EVAL_PTR (ST);
if (!EvalUtil (OP_fetch, ST, NULL, EU_LOAD | EU_TYPE)) {
return (FALSE);
}
// The resultant node is basically identical to the child except
// that its EVAL_SYM field is equal to the actual contents of
// the pointer:
if (EVAL_IS_BASED (ST)) {
if (!NormalizeBase (ST)) {
return(FALSE);
}
}
// Remove a level of indirection from the resultant type.
RemoveIndir (ST);
EVAL_IS_REF (ST) = FALSE;
return (TRUE);
}
}
return (FALSE);
}
/*** EvalAssign - Perform an assignment operation
*
* fSuccess = EvalAssign (bn)
*
* Entry bn = based pointer to assignment node
*
* Exit
*
* pExState->err_num = error number if error
*
* Returns TRUE if successful
* FALSE if error
*/
LOCAL bool_t NEAR FASTCALL EvalAssign (bnode_t bn)
{
if (!EvalLChild (bn) || !EvalRChild (bn)) {
return (FALSE);
}
return (Assign (NODE_OP (pnodeOfbnode(bn))));
}
/*** Assign - Perform an assignment operation
*
* fSuccess = Assign (op)
*
* Entry op = assignment operator
*
* Exit
*
* pExState->err_num = error number if error
*
* Returns TRUE if successful
* FALSE if error
*/
LOCAL bool_t NEAR FASTCALL Assign (op_t op)
{
extern CV_typ_t eqop[];
op_t nop;
// Left operand must have evaluated to an lvalue
if (EVAL_STATE (STP) != EV_lvalue) {
pExState->err_num = ERR_NEEDLVALUE;
return (FALSE);
}
if (EVAL_IS_REF (ST)) {
if (FetchOp (ST) == FALSE) {
return (FALSE);
}
}
if (EVAL_IS_REF (STP)) {
if (FetchOp (STP) == FALSE) {
return (FALSE);
}
}
if (EVAL_IS_ENUM (ST)) {
SetNodeType (ST, ENUM_UTYPE (ST));
}
if (EVAL_IS_ENUM (STP)) {
SetNodeType (STP, ENUM_UTYPE (STP));
}
/*
* if the rhs is a bit-field then convert to the underlying type
*/
if (EVAL_IS_BITF( ST )) {
EVAL_TYP( ST ) = BITF_UTYPE( ST );
}
if (op == OP_eq) {
// for simple assignment, load both nodes
if (!EvalUtil (OP_eq, ST, NULL, EU_LOAD)) {
return (FALSE);
}
if (EVAL_IS_BASED (ST) && !((EVAL_TYP (STP) == T_SHORT) ||
(EVAL_TYP (STP) == T_USHORT) || (EVAL_TYP (STP) == T_INT2) ||
(EVAL_TYP (STP) == T_UINT2))) {
// if the value to be stored is a based pointer and the type
// of the destination is not an int, then normalize the pointer.
// A based pointer can be stored into an int without normalization.
if (!NormalizeBase (ST)) {
return (FALSE);
}
}
if (EVAL_IS_BASED (STP)) {
// if the location to be stored into is a based pointer and the
// value to be stored is a pointer or is a long value not equal
// to zero, then the value is denormalized
if (EVAL_IS_PTR (ST) ||
(((EVAL_TYP (ST) == T_LONG) || (EVAL_TYP(ST) == T_ULONG)) &&
(EVAL_ULONG (ST) != 0L)) ||
(((EVAL_TYP (ST) == T_INT4) || (EVAL_TYP(ST) == T_UINT4)) &&
(EVAL_ULONG (ST) != 0L))) {
//M00KLUDGE - this should go through CastNode
if (!DeNormalizePtr (ST, STP)) {
return (FALSE);
}
}
}
}
else {
// map assignment operator to arithmetic operator
// push address onto top of stack and load the value and
// perform operation
if (!PushStack (STP) || !PushStack (STP)) {
pExState->err_num = ERR_NOMEMORY;
return (FALSE);
}
switch (nop = eqop[op - OP_multeq]) {
case OP_plus:
case OP_minus:
PlusMinus (nop);
break;
default:
Arith (nop);
}
// The top of the stack now contains the value of the memory location
// modified by the value. Move the value to the right operand of the
// assignment operand.
// M00KLUDGE - this will not work with variable sized stack entries
*STP = *ST;
PopStack ();
}
// store result
if (EVAL_IS_BITF (STP)) {
// store bitfield
return (SBitField ());
}
else if (EVAL_IS_PTR (STP)) {
if (!CastNode (ST, EVAL_TYP (STP), PTR_UTYPE (STP))) {
return FALSE;
}
if (ADDR_IS_LI (EVAL_PTR (ST)) == TRUE) {
SHFixupAddr (&EVAL_PTR (ST));
}
EVAL_VAL (STP) = EVAL_VAL (ST);
}
else {
if (!CastNode (ST, EVAL_TYP (STP), EVAL_TYP (STP))) {
return FALSE;
}
EVAL_VAL (STP) = EVAL_VAL (ST);
}
PopStack ();
EVAL_STATE (ST) = EV_rvalue;
return (UpdateMem (ST));
}
/** FetchOp - fetch pointer value
*
* fSuccess = FetchOp (pv)
*
* Entry ST = pointer node
*
* Exit EVAL_SYM (ST) = pointer value
*
* Returns TRUE if pointer value fetched without error
* FALSE if error
*/
LOCAL bool_t NEAR FASTCALL FetchOp (peval_t pv)
{
// load the value and perform implicit type conversions.
if (!EvalUtil (OP_fetch, pv, NULL, EU_LOAD | EU_TYPE)) {
return (FALSE);
}
// The resultant node is basically identical to the child except
// that its EVAL_SYM field is equal to the actual contents of
// the pointer:
if (EVAL_IS_BASED (pv)) {
if (!NormalizeBase (pv)) {
return(FALSE);
}
}
EVAL_SYM (pv) = EVAL_PTR (pv);
EVAL_STATE (pv) = EV_lvalue;
// Remove a level of indirection from the resultant type.
RemoveIndir (pv);
EVAL_IS_REF (pv) = FALSE;
return (TRUE);
}
/** InitConst - initialize constand on evaluation stack
*
* fSuccess = InitConst (const)
*
* Entry const = constant value
*
* Exit value field of ST = constant eval node
*
* Returns TRUE if node added without error
* FALSE if error
*/
LOCAL bool_t NEAR FASTCALL InitConst (long off)
{
eval_t evalT;
peval_t pvT;
pvT = &evalT;
CLEAR_EVAL (pvT);
EVAL_STATE (pvT) = EV_constant;
if ((SCHAR_MIN <= off) && (off <= SCHAR_MAX)) {
SetNodeType(pvT, T_CHAR);
EVAL_CHAR(pvT) = (char) off;
} else if ((SHRT_MIN <= off) && (off <= SHRT_MAX)) {
SetNodeType(pvT, T_SHORT);
EVAL_SHORT(pvT) = (short) off;
} else {
SetNodeType (pvT, T_LONG);
EVAL_LONG (pvT) = off;
}
return (PushStack (pvT));
}
/** SBitField - store value into bitfield
*
* fSuccess = SBitField ()
*
* Entry STP = result bitfield
* ST = value
*
* Exit value field of STP = new field value
*
* Returns TRUE if field inserted without error
* FALSE if error
*/
LOCAL bool_t NEAR FASTCALL SBitField ()
{
ushort cBits; // Number of bits in field
ushort pos; // Bit position of field
ushort mask; // Bit mask
ulong mask_l; // 32 bit version
uchar mask_c; // 8 bit version
LARGE_INTEGER mask_q; // 64-bit version
CV_typ_t uType;
bool_t retval;
// get information on the bit field. Shift counts are limited to 5 bits
// to emulate the hardware
pos = (ushort)(BITF_POS (STP) & 0x3f);
cBits = BITF_LEN (STP);
uType = BITF_UTYPE (STP);
PushStack (STP);
SetNodeType (ST, uType);
EVAL_STATE (ST) = EV_lvalue;
if (!LoadSymVal (ST)) {
return (FALSE);
}
CastNode (STP, uType, uType);
switch (uType) {
case T_CHAR:
case T_RCHAR:
case T_UCHAR:
mask_c = (uchar) ((1 << cBits) - 1);
EVAL_UCHAR (STP) = (uchar) (EVAL_UCHAR (STP) & mask_c);
EVAL_UCHAR (ST) = (uchar) ((EVAL_UCHAR (ST) &
~(mask_c << pos)) | (EVAL_UCHAR (STP) << pos));
break;
case T_SHORT:
case T_USHORT:
case T_INT2:
case T_UINT2:
mask = (ushort) ((1 << cBits) - 1);
EVAL_USHORT (STP) = (ushort) (EVAL_USHORT (STP) & mask);
EVAL_USHORT (ST) = (ushort) ((EVAL_USHORT (ST) &
~(mask << pos)) | (EVAL_USHORT (STP) << pos));
break;
case T_LONG:
case T_ULONG:
case T_INT4:
case T_UINT4:
mask_l = ((1L << cBits) - 1);
EVAL_ULONG (STP) = EVAL_ULONG (STP) & mask_l;
EVAL_ULONG (ST) = (EVAL_ULONG (ST) &
~(mask_l << pos)) | (EVAL_ULONG (STP) << pos);
break;
case T_QUAD:
case T_UQUAD:
case T_INT8:
case T_UINT8:
//
// first make sure the bit value is appropriately sized.
//
if (cBits <= 32) {
mask_q.LowPart = ((1L << cBits) -1);
mask_q.HighPart = 0;
} else {
mask_q.LowPart = 0xffffffff;
mask_q.HighPart = ((1L << (cBits-32))-1);
}
(EVAL_QUAD(STP)).QuadPart &= mask_q.QuadPart;
//
// now clear out the bit field in the ST
//
mask_q.QuadPart = mask_q.QuadPart << pos;
mask_q.QuadPart = ~mask_q.QuadPart;
(EVAL_QUAD(STP)).QuadPart &= mask_q.QuadPart;
//
// finally, put the new bit value in
//
mask_q.QuadPart = (EVAL_QUAD(STP)).QuadPart << pos;
(EVAL_QUAD(STP)).QuadPart |= mask_q.QuadPart;
break;
default:
DASSERT (FALSE);
return (FALSE);
}
retval = UpdateMem (ST);
PopStack ();
#if 0
switch (uType) {
case T_CHAR:
case T_RCHAR:
case T_UCHAR:
EVAL_CHAR (ST) <<= (8 - cBits - pos);
EVAL_CHAR (ST) >>= (8 - cBits);
break;
case T_SHORT:
case T_INT2:
case T_UINT2:
case T_USHORT:
EVAL_SHORT (ST) <<= (16 - cBits - pos);
EVAL_SHORT (ST) >>= (16 - cBits);
break;
case T_LONG:
case T_ULONG:
case T_INT4:
case T_UINT4:
EVAL_LONG (ST) <<= (32 - cBits - pos);
EVAL_LONG (ST) >>= (32 - pos);
break;
case T_QUAD:
case T_UQUAD:
case T_INT8:
case T_UINT8:
// If this is ever re-instantiated, add 64-bit stuff here.
}
#endif
*STP = *ST;
PopStack ();
return (retval);
}
/*** PlusMinus - Perform an addition or subtraction operation
*
* fSuccess = PlusMinus (op)
*
* Entry op = OP_plus or OP_minus
*
* Exit STP = STP op ST and stack popped
* pExState->err_num = error number if error
*
* Returns TRUE if successful
* FALSE if error
*
* DESCRIPTION
* Special handling is required when one or both operands are
* pointers. Otherwise, the arguments are passed on to Arith().
*/
LOCAL bool_t NEAR FASTCALL PlusMinus (op_t op)
{
ulong cbBase;
eval_t evalT;
peval_t pvT;
if (EVAL_IS_REF (ST)) {
if (FetchOp (ST) == FALSE) {
return (FALSE);
}
}
if (EVAL_IS_REF (STP)) {
if (FetchOp (STP) == FALSE) {
return (FALSE);
}
}
if (EVAL_IS_ENUM (ST)) {
SetNodeType (ST, ENUM_UTYPE (ST));
}
if (EVAL_IS_ENUM (STP)) {
SetNodeType (STP, ENUM_UTYPE (STP));
}
// Check to see if either operand is a pointer.
// If so, the operation is special. Otherwise,
// hand it to Arith ().
if (!EVAL_IS_PTR (STP) && !EVAL_IS_PTR (ST)) {
return (Arith (op));
}
// Load values and perform implicit type coercion if required.
if (!EvalUtil (op, STP, ST, EU_LOAD)) {
return (FALSE);
}
// Perform the evaluation. There are two cases:
//
// I) ptr + int, int + ptr, ptr - int
// II) ptr - ptr
//
// Do some common setup first.
pvT = &evalT;
if ((op == OP_plus) || !(EVAL_IS_PTR (ST))) {
// Case (I). ptr + int, int + ptr, ptr - int
if (!EVAL_IS_PTR (STP)) {
// Switch so int is on right
*pvT = *STP;
*STP = *ST;
*ST = *pvT;
}
// if pointer node is BP relative, compute actual address
*pvT = *STP;
RemoveIndir (pvT);
cbBase = TypeSize (pvT);
// The resultant node has the same type as the pointer:
ResolveAddr(STP);
EVAL_STATE(STP) = EV_rvalue;
// Cast the increment node to an unsigned long.
CastNode (ST, T_ULONG, T_ULONG);
// Assign the proper value to the resultant node.
if (op == OP_plus)
EVAL_PTR_OFF (STP) += (UOFFSET)(EVAL_ULONG (ST) * cbBase);
else
EVAL_PTR_OFF (STP) -= (UOFFSET)(EVAL_ULONG (ST) * cbBase);
}
else {
// Case (II): ptr - ptr. The result is of type ptrdiff_t and
// is equal to the distance between the two pointers (in the
// address space) divided by the size of the items pointed to:
if (EVAL_TYP (STP) != EVAL_TYP (ST)) {
pExState->err_num = ERR_OPERANDTYPES;
return (FALSE);
}
*pvT = *STP;
RemoveIndir (pvT);
cbBase = TypeSize (pvT);
EVAL_STATE (STP) = EV_rvalue;
// we know we are working with pointers so we do not
// have to check EVAL_IS_PTR (pv)
if (EVAL_IS_BASED (STP)) {
NormalizeBase (STP);
}
if (EVAL_IS_BASED (ST)) {
NormalizeBase (ST);
}
if (EVAL_IS_NPTR (STP) || EVAL_IS_FPTR (STP)) {
SetNodeType (STP, T_SHORT);
EVAL_SHORT (STP) = (short) (EVAL_PTR_OFF (STP) - EVAL_PTR_OFF (ST));
EVAL_SHORT (STP) /= (ushort) cbBase;
}
else if (EVAL_IS_NPTR32 (STP) || EVAL_IS_FPTR32 (STP)) {
SetNodeType (STP, T_ULONG);
EVAL_ULONG (STP) = EVAL_PTR_OFF (STP) - EVAL_PTR_OFF (ST);
EVAL_ULONG (STP) /= cbBase;
}
else {
SetNodeType (STP, T_LONG);
// M00KLUDGE This will not work in 32 bit mode
EVAL_LONG (STP) =
((((ushort)EVAL_PTR_SEG (STP)) << 16) + EVAL_PTR_OFF (STP))
- ((((ushort)EVAL_PTR_SEG (ST)) << 16) + EVAL_PTR_OFF (ST));
EVAL_LONG (STP) /= cbBase;
}
}
return(PopStack ());
}
/** EvalRelat - Perform relational and equality operations
*
* fSuccess = EvalRelat (bn)
*
* Entry bn = based pointer to node
*
* Returns TRUE if no evaluation error
* FALSE if evaluation error
*
* Description
* If both operands are arithmetic, passes them on to Arith().
* Otherwise (one or both operands pointers), does the evaluation
* here.
*
*/
LOCAL bool_t NEAR FASTCALL EvalRelat (bnode_t bn)
{
if (!EvalLChild (bn) || !EvalRChild (bn)) {
return (FALSE);
}
return (Relational (NODE_OP (pnodeOfbnode(bn))));
}
/** Relational - Perform relational and equality operations
*
* fSuccess = Relational (op)
*
* Entry op = OP_lt, OP_lteq, OP_gt, OP_gteq, OP_eqeq, or OP_bangeq
*
* Returns TRUE if no evaluation error
* FALSE if evaluation error
*
* Description
* If both operands are arithmetic, passes them on to Arith().
* Otherwise (one or both operands pointers), does the evaluation
* here.
*
*/
LOCAL bool_t NEAR FASTCALL Relational (op_t op)
{
int result;
ushort segL;
ushort segR;
UOFFSET offL;
UOFFSET offR;
if (EVAL_IS_REF (ST)) {
if (FetchOp (ST) == FALSE) {
return (FALSE);
}
}
if (EVAL_IS_REF (STP)) {
if (FetchOp (STP) == FALSE) {
return (FALSE);
}
}
if (EVAL_IS_ENUM (ST)) {
SetNodeType (ST, ENUM_UTYPE (ST));
}
if (EVAL_IS_ENUM (STP)) {
SetNodeType (STP, ENUM_UTYPE (STP));
}
// Check to see if either operand is a pointer.
// If so, the operation is special. Otherwise,
// hand it to Arith ().
if (!EVAL_IS_PTR (STP) && !EVAL_IS_PTR (ST)) {
return (Arith (op));
}
if (EvalUtil (op, ST, STP, EU_LOAD | EU_TYPE) == FALSE) {
return (FALSE);
}
// Both nodes should now be typed as either near or far
// pointers.
DASSERT (EVAL_IS_PTR (STP) && EVAL_IS_PTR (ST));
// For the relational operators ('<', '<=', '>', '>='),
// only offsets are compared. For the equality operators ('==', '!='),
// both segments and offsets are compared.
if (ADDR_IS_LI (EVAL_PTR (STP))) {
SHFixupAddr (&EVAL_PTR (STP));
}
if (ADDR_IS_LI (EVAL_PTR (ST))) {
SHFixupAddr (&EVAL_PTR (ST));
}
segL = EVAL_PTR_SEG (STP);
segR = EVAL_PTR_SEG (ST);
offL = EVAL_PTR_OFF (STP);
offR = EVAL_PTR_OFF (ST);
switch (op) {
case OP_lt:
result = (offL < offR);
break;
case OP_lteq:
result = (offL <= offR);
break;
case OP_gt:
result = (offL > offR);
break;
case OP_gteq:
result = (offL >= offR);
break;
case OP_eqeq:
if (ADDR_IS_FLAT(EVAL_PTR(STP))) {
result = (offL == offR);
} else {
result = ((segL == segR) && (offL == offR));
}
break;
case OP_bangeq:
if (ADDR_IS_FLAT(EVAL_PTR(STP))) {
result = (offL != offR);
} else {
result = ((segL != segR) || (offL != offR));
}
break;
default:
//DASSERT (FALSE);
pExState->err_num = ERR_INTERNAL;
return (FALSE);
}
EVAL_STATE (STP) = EV_rvalue;
if (ADDR_IS_OFF32(*SHpADDRFrompCXT(pCxt))) {
EVAL_LONG (STP) = result;
SetNodeType (STP, T_LONG);
} else {
EVAL_SHORT (STP) = (short) result;
SetNodeType (STP, T_SHORT);
}
return (PopStack ());
}
/*** EvalUScope - Do unary :: scoping
*
* fSuccess = EvalUScope (bn);
*
* Entry pvRes = based pointer to unary scoping node
*
* Exit pvRes = evaluated left node of pvRes
*
* Returns TRUE if evaluation successful
* FALSE if error
*/
LOCAL bool_t NEAR FASTCALL EvalUScope (bnode_t bn)
{
register bool_t retval;
CXT cxt;
// save current context packet and set current context to module scope
cxt = *pCxt;
SHGetCxtFromHmod (SHHMODFrompCXT (pCxt), pCxt);
retval = EvalLChild (bn);
*pCxt = cxt;
return (retval);
}
/*** DoBScope - Do binary :: scoping
*
* fSuccess = DoBScope (pn);
*
* Entry pvRes = pointer to binary scoping node
*
* Returns TRUE if evaluation successful
* FALSE if error
*/
LOCAL bool_t NEAR FASTCALL EvalBScope (bnode_t bn)
{
peval_t pv;
pv = &pnodeOfbnode(NODE_LCHILD (pnodeOfbnode(bn)))->v[0];
if (CLASS_GLOBALTYPE (pv) == TRUE) {
// the left member of the scope operator was a type not in class
// scope. We presumably have an empty stack so we need to fake
// up a stack entry
PushStack (pv);
}
return (StructEval (bn));
}
/*** EvalPreIncDec - Do ++expr or --expr
*
* fSuccess = EvalPreIncDec (bnode_t bn);
*
* Entry bn = based pointer to node
*
* Exit ST decremented or incremented
* pExState->err_num = error number if error
*
* Returns TRUE if successful
* FALSE if error
*/
LOCAL bool_t NEAR FASTCALL EvalPreIncDec (bnode_t bn)
{
op_t nop = OP_plus;
if (!EvalLChild (bn)) {
return(FALSE);
}
if (NODE_OP (pnodeOfbnode(bn)) == OP_predec) {
nop = OP_minus;
}
// push the entry on the stack and then perform incmrement/decrement
PushStack (ST);
// load left node and store as return value
if (EvalUtil (nop, ST, NULL, EU_LOAD)) {
// do the post-increment or post-decrement operation and store
if (PrePost (nop)) {
EVAL_STATE (STP) = EV_lvalue;
if (Assign (OP_eq)) {
return (TRUE);
}
}
}
return (FALSE);
}
/*** EvalPostIncDec - Do expr++ or expr--
*
* fSuccess = EvalPostIncDec (op);
*
* Entry bn = based pointer to node
*
* Exit ST decremented or incremented
* pExState->err_num = error number if error
*
* Returns TRUE if successful
* FALSE if error
*/
LOCAL bool_t NEAR FASTCALL EvalPostIncDec (bnode_t bn)
{
eval_t evalT;
peval_t pvT = &evalT;
op_t nop = OP_plus;
if (!EvalLChild (bn)) {
return(FALSE);
}
if (NODE_OP (pnodeOfbnode(bn)) == OP_postdec) {
nop = OP_minus;
}
// push the entry on the stack and then perform incmrement/decrement
PushStack (ST);
// load left node and store as return value
if (EvalUtil (nop, ST, NULL, EU_LOAD)) {
*pvT = *ST;
// do the post-increment or post-decrement operation and store
if (PrePost (nop)) {
EVAL_STATE (STP) = EV_lvalue;
if (Assign (OP_eq)) {
*ST = *pvT;
return (TRUE);
}
}
}
return (FALSE);
}
/** PrePost - perform the increment operation
*
* fSuccess = PrePost (op);
*
* Entry op = operation to perform (OP_plus or OP_minus)
*
* Exit increment/decrement performed and result stored in memory
* DebErr set if error
*
* Returns TRUE if no error
* FALSE if error
*/
LOCAL bool_t NEAR FASTCALL PrePost (op_t op)
{
if (InitConst (1) == TRUE) {
return (PlusMinus (op));
}
return (FALSE);
}
/*** EvalBang - Perform logical negation operation
*
* fSuccess = EvalBang (bn)
*
* Entry bn = based pointer to node
*
* Exit ST = pointer to negated value
* pExState->err_num = error number if error
*
* Returns TRUE if successful
* FALSE if error
*
* DESCRIPTION
* Checks for a pointer operand; if found, handles it here, otherwise
* passes it on to Unary ().
*/
LOCAL bool_t NEAR FASTCALL EvalBang (bnode_t bn)
{
int result;
ushort seg;
UOFFSET off;
if (!EvalLChild (bn)) {
return (FALSE);
}
// load the value and perform implicit type conversion.
if (!EvalUtil (OP_bang, ST, NULL, EU_LOAD)) {
return (FALSE);
}
if (EVAL_IS_REF (ST)) {
if (FetchOp (ST) == FALSE) {
return (FALSE);
}
}
// If the operand is not of pointer type, just pass it on to Unary
if (!(EVAL_IS_PTR (ST)))
return (Unary (OP_bang));
// The result is 1 if the pointer is a null pointer and 0 otherwise
// Note that for a near pointer, we compare the offset against
// 0, while for a far pointer we compare both segment and offset.
seg = EVAL_PTR_SEG (ST);
off = EVAL_PTR_OFF (ST);
if (EVAL_IS_NPTR (ST) || EVAL_IS_NPTR32 (ST)) {
result = (off == 0);
}
else {
result = ((seg == 0) && (off == 0));
}
CLEAR_EVAL (ST);
EVAL_STATE (ST) = EV_rvalue;
EVAL_SHORT (ST) = (short) result;
return (SetNodeType (ST, T_USHORT));
}
/*** EvalDMember - Perform a dot member access ('.*')
*
* fSuccess = EvalDMember (bn)
*
* Entry bn = based pointer to node
*
* Exit ST = value of member
* pExState->err_num = error number if error
*
* Returns TRUE if successful
* FALSE if error
*/
LOCAL bool_t NEAR FASTCALL EvalDMember (bnode_t bn)
{
Unreferenced(bn);
pExState->err_num = ERR_OPNOTSUPP;
return (FALSE); //M00KLUDGE - not implemented
}
/*** EvalPMember - Perform a pointer to member access ('->*')
*
* SYNOPSIS
* fSuccess = EvalPMember (bn)
*
* ENTRY
* pvRes Pointer to node in which result is to be stored
* pvLeft Pointer to left operand node
* pvRight Pointer to right operand node
*
* RETURNS
* TRUE if successful, FALSE if not and sets DebErr
*
* DESCRIPTION
*
* NOTES
*/
LOCAL bool_t NEAR FASTCALL EvalPMember (bnode_t bn)
{
Unreferenced(bn);
// Check to make sure the left operand is a struct/union pointer.
// To do this, remove a level of indirection from the node's type
// and see if it's a struct or union.
pExState->err_num = ERR_OPNOTSUPP;
return (FALSE);
}
/*** EvalPointsTo - Perform a structure access ('->')
*
* fSuccess = EvalPointsTo (bn)
*
* Entry bRight = based pointer to node
*
* Exit ST = value node for member
*
* Returns TRUE if successful
* FALSE if error
*
*/
LOCAL bool_t NEAR FASTCALL EvalPointsTo (bnode_t bn)
{
if (!EvalLChild (bn)) {
return (FALSE);
}
if (!FetchOp (ST)) {
return (FALSE);
}
// The result is simple -- (*ST).pnRight. The call to StructEval ()
// will set the error code if it fails.
if (EVAL_STATE (ST) == EV_rvalue) {
return (StructElem (bn));
}
else {
return (StructEval (bn));
}
}
/*** EvalArray - Perform an array access ('[]')
*
* fSuccess = EvalArray (bn)
*
* Entry bn = based pointer to array node
*
* Returns TRUE if successful
* FALSE if error
*
* Obtains the contents of an array member. This is done by
* calling PlusMinus() and DoFetch().
*/
LOCAL bool_t NEAR FASTCALL EvalArray (bnode_t bn)
{
ushort index;
eval_t evalT;
peval_t pvT;
if (EvalLChild (bn) && EvalRChild (bn)) {
if (EVAL_IS_ARRAY (STP) || EVAL_IS_ARRAY (ST)) {
// above check is for array[3] or 3[array]
if (EvalUtil (OP_lbrack, STP, ST, EU_LOAD) && PlusMinus (OP_plus)) {
return (FetchOp (ST));
}
}
else if (EVAL_IS_PTR (STP)) {
// this code is a hack to allow the locals and quick watch windows
// display the virtual function table. The GetChildTM generates
// an expression of the form a.__vfuncptr[n]. This means that the
// evaluation of a.__vfuncptr on the left sets STP to a pointer
// node and ThisAddress to the adjusted this pointer. Note that
// it turns out that symbol address of STP and ThisAddress are
// the same
pvT = &evalT;
*pvT = *STP;
SetNodeType (pvT, PTR_UTYPE (pvT));
if (EVAL_IS_VTSHAPE (pvT) && (EVAL_STATE (ST) == EV_constant) &&
((index = EVAL_USHORT (ST)) < VTSHAPE_COUNT (pvT))) {
index = EVAL_USHORT (ST);
PopStack ();
DASSERT ((EVAL_SYM_OFF (pvThis) == EVAL_SYM_OFF (ST)) &&
(EVAL_SYM_SEG (pvThis) == EVAL_SYM_SEG (ST)));
return (VFuncAddress (ST, index));
}
else {
if (EvalUtil (OP_lbrack, STP, ST, EU_LOAD) && PlusMinus (OP_plus)) {
return (FetchOp (ST));
}
}
}
}
return (FALSE);
}
/*** EvalCast - Perform a type cast operation
*
* fSuccess = EvalCast (bn)
*
* Entry bn = based pointer to cast node
*
* Exit
*
* Returns TRUE if successful
* FALSE if error
*
*/
LOCAL bool_t NEAR FASTCALL EvalCast (bnode_t bn)
{
if (!EvalRChild (bn) ) {
return (FALSE);
}
return CastST( bn );
}
LOCAL bool_t NEAR FASTCALL CastST (bnode_t bn)
{
peval_t pv;
peval_t pvL;
if (!EvalUtil (OP_cast, ST, NULL, EU_LOAD)) {
return (FALSE);
}
DASSERT (!EVAL_IS_CLASS (ST));
// Cast the node to the desired type. if the cast node is a member node,
// then the stack top is cast by changing the pointer value by the amount
// in the value and then setting the type of the stack top to the type
// of the left node
pv = (peval_t)&pnodeOfbnode(bn)->v[0];
pvL = &pnodeOfbnode((NODE_LCHILD (pnodeOfbnode(bn))))->v[0];
if (EVAL_MOD (pvL) != 0) {
EVAL_MOD (ST) = EVAL_MOD (pvL);
}
if (EVAL_IS_MEMBER (pv) == TRUE) {
// a cast of pointer to derived to pointer to base is not done
// for a null value
if (EVAL_PTR_OFF (ST) != 0) {
if (Eval (MEMBER_THISEXPR (pv)) == FALSE) {
return (FALSE);
}
*ST = *pvThis;
EVAL_STATE (ST) = EV_rvalue;
EVAL_PTR (ST) = EVAL_SYM (pvThis);
}
return (SetNodeType (ST, EVAL_TYP (pvL)));
}
else {
if (EVAL_IS_PTR (pvL)) {
return (CastNode (ST, EVAL_TYP (pvL), PTR_UTYPE (pvL)));
}
else {
return (CastNode (ST, EVAL_TYP (pvL), EVAL_TYP (pvL)));
}
}
}
/*** EvalByteOps - Handle 'by', 'wo' and 'dw' operators
*
* fSuccess = EvalByteOps (bn)
*
* Entry bn = based pointer to node
*
* Exit ST = pointer to value
*
* Returns TRUE if successful
* FALSE if error
*
* DESCRIPTION
* Evaluates the contents of the address operand as a byte
* ('by'), word ('wo') or dword ('dw'):
*
* Operand Result
* ------- ------
* <register> *(uchar *)<register>
* <address> *(uchar *)<address>
* <variable> *(uchar *)&variable
*
* Where (uchar *) is replaced by (uint *) for the 'wo' operator,
* or by (ulong *) for the 'dw' operator.
*
*/
LOCAL bool_t NEAR FASTCALL EvalByteOps (bnode_t bn)
{
CV_typ_t type;
register op_t op;
if (!EvalLChild (bn)) {
return (FALSE);
}
// If the operand is an lvalue and it is a register,
// load the value of the register; otherwise, use the
// address of the variable.
//
// If the operand is not an lvalue, use its value as is.
if (EVAL_STATE (ST) == EV_lvalue) {
if (EVAL_IS_REG (ST)) {
if (!LoadVal (ST)) {
pExState->err_num = ERR_INTERNAL;
return (FALSE);
}
else {
type = T_USHORT;
}
}
else {
if ((type = NODE_STYPE (pnodeOfbnode(bn))) == 0) {
// unable to find proper pointer type
return (FALSE);
}
ResolveAddr( ST );
EVAL_STATE(ST) = EV_rvalue;
EVAL_PTR (ST) = EVAL_SYM (ST);
SetNodeType (ST, type);
}
}
// Now cast the node to (char far *), (int far *) or
// (long far *). If the type is char, uchar, short
// or ushort, we want to first cast to (char *) so
// that we properly DS-extend (casting (int)8 to (char
// far *) will give the result 0:8).
type = EVAL_TYP (ST);
//DASSERT(IS_PRIMITIVE (typ));
if (CV_TYP_IS_REAL (type)) {
pExState->err_num = ERR_OPERANDTYPES;
return (FALSE);
}
if ((op = NODE_OP (pnodeOfbnode(bn))) == OP_by) {
type = T_PFUCHAR;
}
else if (op == OP_wo) {
type = T_PFUSHORT;
}
else if (op == OP_dw) {
type = T_PFULONG;
}
if (CastNode (ST, type, type) == FALSE) {
return (FALSE);
}
return (FetchOp (ST));
}
/*** EvalSegOp - Handle ':' segmentation operator
*
* fSuccess = EvalSegOp (bn)
*
* Entry bn = based pointer to node
*
* Exit EVAL_SYM (ST) = seg (STP): offset (ST)
*
* Returns TRUE if successful
* FALSE if error
*
* DESCRIPTION
* Both operands must have integral values (but cannot
* be long or ulong). The result of op1:op2 is a (char
* far *) with segment equal to op1 and offset equal to
* op2.
*
* NOTES
*/
LOCAL bool_t NEAR FASTCALL EvalSegOp (bnode_t bn)
{
if (!EvalLChild (bn) || !EvalRChild (bn)) {
return(FALSE);
}
#ifndef WIN32
// check to make sure that neither operand is of type long or ulong.
if ((EVAL_TYP (STP) == T_LONG) ||
(EVAL_TYP (STP) == T_ULONG) ||
(EVAL_TYP (ST) == T_LONG) ||
(EVAL_TYP (ST) == T_ULONG) ||
(EVAL_TYP (STP) == T_INT4) ||
(EVAL_TYP (STP) == T_UINT4) ||
(EVAL_TYP (ST) == T_INT4) ||
(EVAL_TYP (ST) == T_UINT4)) {
pExState->err_num = ERR_OPERANDTYPES;
return (FALSE);
}
#endif
/*
* Load values and perform implicit type coercion if required.
*
* OP_segop and OP_segopReal use the same parameters so just choose
* one to pass into EvalUtil
*/
if (!EvalUtil (OP_segop, STP, ST, EU_LOAD | EU_TYPE)) {
return(FALSE);
}
//DASSERT ((EVAL_TYP (STP) == T_SHORT) || (EVAL_TYP (STP) == T_USHORT));
//DASSERT ((EVAL_TYP (ST) == T_SHORT) || (EVAL_TYP (ST) == T_USHORT));
EVAL_STATE (STP) = EV_rvalue;
EVAL_PTR_SEG (STP) = EVAL_USHORT (STP);
EVAL_PTR_OFF (STP) = EVAL_ULONG (ST);
if (NODE_OP(pnodeOfbnode(bn)) == OP_segopReal) {
ADDR_IS_REAL(EVAL_PTR(STP)) = TRUE;
}
SHUnFixupAddr( &EVAL_PTR(STP) );
if (ADDR_IS_OFF32(EVAL_PTR(STP))) {
SetNodeType (STP, T_32PFCHAR);
} else {
SetNodeType (STP, T_PFCHAR);
}
return (PopStack ());
}
/** Unary - Evaluate the result of a unary arithmetic operation
*
* fSuccess = Unary (op)
*
* Entry op = Operator (OP_...)
*
* Returns TRUE if no error during evaluation
* FALSE if error during evaluation
*
* DESCRIPTION
* Evaluates the result of an arithmetic operation. The unary operators
* dealt with here are:
*
* ! ~ - +
*
* Pointer arithmetic is NOT handled; all operands must be of
* arithmetic type.
*/
LOCAL bool_t NEAR FASTCALL Unary (op_t op)
{
bool_t fIsFloat = FALSE;
bool_t fIsDouble = FALSE;
bool_t fIsLDouble = FALSE;
bool_t fIsSigned;
bool_t fResInt;
int iRes;
LARGE_INTEGER liRes, liL;
ULARGE_INTEGER uliRes, uliL;
FLOAT10 ldRes;
FLOAT10 ldL;
double dRes, dL;
float fRes, fL;
CV_typ_t typRes;
if (EVAL_IS_REF (ST)) {
if (FetchOp (ST) == FALSE) {
return (FALSE);
}
}
// Load the values and perform implicit type conversion.
if (!EvalUtil (op, ST, NULL, EU_LOAD | EU_TYPE))
return (FALSE);
// The resultant type is an int or larger.
typRes = EVAL_TYP (ST);
if (ADDR_IS_OFF32(*SHpADDRFrompCXT(pCxt))) {
if (TypeSizePrim(typRes) < 4) {
typRes = T_LONG;
}
} else {
if (TypeSizePrim(typRes) < 2) {
typRes = T_SHORT;
}
}
if (CV_TYP_IS_REAL (typRes) == TRUE) {
fIsFloat = (CV_SUBT (typRes) == CV_RC_REAL32);
fIsDouble = (CV_SUBT (typRes) == CV_RC_REAL64);
fIsLDouble = (CV_SUBT (typRes) == CV_RC_REAL80);
}
fIsSigned = CV_TYP_IS_SIGNED (typRes);
fResInt = FALSE;
// Common code. Since we're going to do most of our arithmetic
// in either long, ulong or double, we do the casts and get the
// value of the operands here rather than repeating this code
// in each arm of the switch statement.
if (fIsFloat) {
fL = EVAL_FLOAT (ST);
}
else if (fIsDouble) {
dL = EVAL_DOUBLE (ST);
}
else if (fIsLDouble) {
ldL = EVAL_LDOUBLE (ST);
}
else if (fIsSigned) {
CastNode (ST, T_QUAD, T_QUAD);
liL = EVAL_QUAD (ST);
}
else {
// unsigned
CastNode (ST, T_UQUAD, T_UQUAD);
uliL = EVAL_UQUAD (ST);
}
// Finally, do the actual arithmetic operation.
switch (op) {
case OP_bang:
// Operand is of arithmetic type; result is always int.
fResInt = TRUE;
if (fIsFloat) {
iRes = !fL;
}
else if (fIsDouble) {
iRes = !dL;
}
else if (fIsLDouble) {
iRes = R10Not(ldL);
}
else if (fIsSigned) {
iRes = liL.QuadPart == 0;
}
else {
iRes = uliL.QuadPart == 0;
}
break;
case OP_tilde:
// operand must be integral.
//DASSERT (!fIsReal);
if (fIsSigned) {
liRes.LowPart = ~liL.LowPart;
liRes.HighPart = ~liL.HighPart;
}
else {
uliRes.LowPart = ~uliL.LowPart;
uliRes.HighPart = ~uliL.HighPart;
}
break;
case OP_negate:
if (fIsFloat) {
fRes = -fL;
}
else if (fIsDouble) {
dRes = -dL;
}
else if (fIsLDouble) {
R10Uminus(&ldRes, ldL);
}
else if (fIsSigned) {
liRes.QuadPart = liL.QuadPart * -1;
}
else {
uliRes.QuadPart = uliL.QuadPart * -1;
}
break;
case OP_uplus:
if (fIsFloat) {
fRes = fL;
}
else if (fIsDouble) {
dRes = dL;
}
else if (fIsLDouble) {
ldRes = ldL;
}
else if (fIsSigned) {
liRes = liL;
}
else {
uliRes = uliL;
}
break;
default:
DASSERT (FALSE);
pExState->err_num = ERR_INTERNAL;
return (FALSE);
}
// Now set up the resultant node and coerce back to the correct
// type:
EVAL_STATE (ST) = EV_rvalue;
if (fResInt) {
if (ADDR_IS_OFF32(*SHpADDRFrompCXT(pCxt))) {
EVAL_LONG (ST) = (long) iRes;
SetNodeType (ST, T_LONG);
} else {
EVAL_SHORT (ST) = (short) iRes;
SetNodeType (ST, T_SHORT);
}
}
else {
if (fIsFloat) {
EVAL_FLOAT (ST) = fRes;
SetNodeType (ST, T_REAL32);
}
else if (fIsDouble) {
EVAL_DOUBLE (ST) = dRes;
SetNodeType (ST, T_REAL64);
}
else if (fIsLDouble) {
EVAL_LDOUBLE (ST) = ldRes;
SetNodeType (ST, T_REAL80);
}
else if (fIsSigned) {
EVAL_QUAD (ST) = liRes;
SetNodeType (ST, T_QUAD);
}
else {
EVAL_UQUAD (ST) = uliRes;
SetNodeType (ST, T_UQUAD);
}
CastNode (ST, typRes, typRes);
}
}
/** Arith - Evaluate the result of an arithmetic operation
*
* fSuccess = Arith (op)
*
* Entry op = Operator (OP_...)
*
* Returns TRUE if no error during evaluation
* FALSE if error during evaluation
*
* DESCRIPTION
* Evaluates the result of an arithmetic operation. The operators
* dealt with here are:
*
* * / %
* + -
* == !=
* < <= > >=
* << >>
* & ^ |
*
* Pointer arithmetic is NOT handled; all operands must be of
* arithmetic type.
*/
LOCAL bool_t NEAR FASTCALL Arith (op_t op)
{
bool_t fIsFloat = FALSE;
bool_t fIsDouble = FALSE;
bool_t fIsLDouble = FALSE;
bool_t fIsSigned;
bool_t fResInt;
int iRes;
long lRes, lL, lR;
ulong ulRes, ulL, ulR;
float fRes, fL, fR;
double dRes, dL, dR;
FLOAT10 ldRes;
FLOAT10 ldL;
FLOAT10 ldR;
CV_typ_t typRes;
if (EVAL_IS_REF (STP)) {
if (FetchOp (STP) == FALSE) {
return (FALSE);
}
}
if (EVAL_IS_REF (ST)) {
if (FetchOp (ST) == FALSE) {
return (FALSE);
}
}
if (EVAL_IS_ENUM (ST)) {
SetNodeType (ST, ENUM_UTYPE (ST));
}
if (EVAL_IS_ENUM (STP)) {
SetNodeType (STP, ENUM_UTYPE (STP));
}
// Resolve identifiers and check the node types. If the nodes
// pass validation, they should not be pointers (only arithmetic
// operands are handled by this routine).
// Load the values and perform implicit type conversion.
if (!EvalUtil (op, STP, ST, EU_LOAD | EU_TYPE))
return (FALSE);
// The resultant type is the same as the type of the left-hand
// side (assume for now we don't have the special int-result case).
typRes = PerformUAC(EVAL_TYP (STP), EVAL_TYP(ST));
if (CV_TYP_IS_REAL (typRes) == TRUE) {
fIsFloat = (CV_SUBT (typRes) == CV_RC_REAL32);
fIsDouble = (CV_SUBT (typRes) == CV_RC_REAL64);
fIsLDouble = (CV_SUBT (typRes) == CV_RC_REAL80);
}
fIsSigned = CV_TYP_IS_SIGNED (typRes);
fResInt = FALSE;
// Common code. Since we're going to do most of our arithmetic
// in either long, ulong or double, we do the casts and get the
// value of the operands here rather than repeating this code
// in each arm of the switch statement.
if (fIsLDouble) {
CastNode (STP, T_REAL80, T_REAL80);
ldL = EVAL_LDOUBLE (STP);
CastNode (ST, T_REAL80, T_REAL80);
ldR = EVAL_LDOUBLE (ST);
} else
if (fIsDouble) {
CastNode (STP, T_REAL64, T_REAL64);
dL = EVAL_DOUBLE (STP);
CastNode (ST, T_REAL64, T_REAL64);
dR = EVAL_DOUBLE (ST);
}
else if (fIsFloat) {
CastNode (STP, T_REAL32, T_REAL32);
fL = EVAL_FLOAT (STP);
CastNode (ST, T_REAL32, T_REAL32);
fR = EVAL_FLOAT (ST);
}
else if (fIsSigned) {
CastNode (STP, T_LONG, T_LONG);
lL = EVAL_LONG (STP);
CastNode (ST, T_LONG, T_LONG);
lR = EVAL_LONG (ST);
}
else {
// unsigned
CastNode (STP, T_ULONG, T_ULONG);
ulL = EVAL_ULONG (STP);
CastNode (ST, T_ULONG, T_ULONG);
ulR = EVAL_ULONG (ST);
}
// Finally, do the actual arithmetic operation.
switch (op) {
case OP_eqeq:
case OP_bangeq:
case OP_lt:
case OP_gt:
case OP_lteq:
case OP_gteq:
{
// This is kind of a strange way to do things, but it should
// be pretty obvious what's going on, and it saves code.
int fEq;
int fLt;
fResInt = TRUE;
if (fIsLDouble) {
fEq = R10Equal(ldL, ldR);
fLt = R10Lt(ldL, ldR);
} else
if (fIsDouble) {
fEq = (dL == dR);
fLt = (dL < dR);
}
else if (fIsFloat) {
fEq = (fL == fR);
fLt = (fL < fR);
}
else if (fIsSigned) {
fEq = (lL == lR);
fLt = (lL < lR);
}
else {
fEq = (ulL == ulR);
fLt = (ulL < ulR);
}
switch (op) {
case OP_eqeq:
iRes = fEq;
break;
case OP_bangeq:
iRes = !fEq;
break;
case OP_lt:
iRes = fLt;
break;
case OP_gt:
iRes = !fLt && !fEq;
break;
case OP_lteq:
iRes = fLt || fEq;
break;
case OP_gteq:
iRes = !fLt || fEq;
break;
}
}
break;
case OP_plus:
if (fIsLDouble) {
R10Plus(&ldRes, ldL, ldR);
} else
if (fIsDouble) {
dRes = dL + dR;
}
else if (fIsFloat) {
fRes = fL + fR;
}
else if (fIsSigned) {
lRes = lL + lR;
}
else {
ulRes = ulL + ulR;
}
break;
case OP_minus:
if (fIsLDouble) {
R10Minus(&ldRes, ldL, ldR);
} else
if (fIsDouble) {
dRes = dL - dR;
}
else if (fIsFloat) {
fRes = fL - fR;
}
else if (fIsSigned) {
lRes = lL - lR;
}
else {
ulRes = ulL - ulR;
}
break;
case OP_mult:
if (fIsLDouble) {
R10Times(&ldRes, ldL, ldR);
} else
if (fIsDouble) {
dRes = dL * dR;
}
else if (fIsFloat) {
fRes = fL * fR;
}
else if (fIsSigned) {
lRes = lL * lR;
}
else {
ulRes = ulL * ulR;
}
break;
case OP_div:
// This looks big, but I can't figure out how to do it
// with ||'s. Besides, Hans claims it will tail merge
// on the error conditions anyway.
if (fIsLDouble) {
if (R10Equal(ldR, Real10_Zero)) {
pExState->err_num = ERR_DIVIDEBYZERO;
return (FALSE);
}
R10Divide(&ldRes, ldL, ldR);
} else
if (fIsDouble) {
if (dR == (double)0.0) {
pExState->err_num = ERR_DIVIDEBYZERO;
return (FALSE);
}
dRes = dL / dR;
}
else if (fIsFloat) {
if (fR == (float)0.0) {
pExState->err_num = ERR_DIVIDEBYZERO;
return (FALSE);
}
fRes = fL / fR;
}
else if (fIsSigned) {
if (lR == (long)0) {
pExState->err_num = ERR_DIVIDEBYZERO;
return (FALSE);
}
lRes = lL / lR;
}
else {
if (ulR == (unsigned long)0) {
pExState->err_num = ERR_DIVIDEBYZERO;
return (FALSE);
}
ulRes = ulL / ulR;
}
break;
case OP_mod:
// Both operands must be integral.
//DASSERT(!fIsReal);
if (fIsSigned) {
if (lR == (long)0) {
pExState->err_num = ERR_DIVIDEBYZERO;
return (FALSE);
}
lRes = lL % lR;
}
else {
if (ulR == (unsigned long)0) {
pExState->err_num = ERR_DIVIDEBYZERO;
return (FALSE);
}
ulRes = ulL % ulR;
}
break;
case OP_shl:
// Both operands must be integral.
//DASSERT(!fIsReal);
if (fIsSigned) {
lRes = lL << lR;
}
else {
ulRes = ulL << ulR;
}
break;
case OP_shr:
// Both operands must be integral.
//DASSERT(!fIsReal);
if (fIsSigned) {
lRes = lL >> lR;
}
else {
ulRes = ulL >> ulR;
}
break;
case OP_and:
// Both operands must have integral type.
//DASSERT(!fIsReal);
if (fIsSigned) {
lRes = lL & lR;
}
else {
ulRes = ulL & ulR;
}
break;
case OP_or:
// Both operands must have integral type.
//DASSERT(!fIsReal);
if (fIsSigned) {
lRes = lL | lR;
}
else {
ulRes = ulL | ulR;
}
break;
case OP_xor:
// Both operands must have integral type.
//DASSERT(!fIsReal);
if (fIsSigned) {
lRes = lL ^ lR;
}
else {
ulRes = ulL ^ ulR;
}
break;
default:
pExState->err_num = ERR_INTERNAL;
//DASSERT(FALSE);
return (FALSE);
}
// Now set up the resultant node and coerce back to the correct
// type:
EVAL_STATE (STP) = EV_rvalue;
if (fResInt) {
if (ADDR_IS_OFF32(*SHpADDRFrompCXT(pCxt))) {
EVAL_LONG (STP) = iRes;
SetNodeType (STP, T_LONG);
} else {
EVAL_SHORT (STP) = (short) iRes;
SetNodeType (STP, T_SHORT);
}
}
else {
if (fIsLDouble) {
EVAL_LDOUBLE (STP) = ldRes;
SetNodeType (STP, T_REAL80);
} else
if (fIsDouble) {
EVAL_DOUBLE (STP) = dRes;
SetNodeType (STP, T_REAL64);
}
else if (fIsFloat) {
EVAL_FLOAT (STP) = fRes;
SetNodeType (STP, T_REAL32);
}
else {
if (fIsSigned) {
EVAL_LONG (STP) = lRes;
SetNodeType (STP, T_LONG);
}
else {
EVAL_ULONG (STP) = ulRes;
SetNodeType (STP, T_ULONG);
}
CastNode (STP, typRes, typRes);
}
}
return (PopStack ());
}
/*** EvalUtil - Set up nodes for evaluation
*
* fSuccess = EvalUtil (op, pvLeft, pvRight, wFlags)
*
* Entry pvLeft = pointer to left operand node
* pvRight = pointer to right operand node, or NULL
* wFlags = EU_...
*
* Exit pvLeft and pvRight loaded and/or typed as requested
*
* Returns TRUE if successful
* FALSE if error
*/
LOCAL bool_t NEAR FASTCALL EvalUtil (op_t op, peval_t pvLeft, peval_t pvRight, ushort wFlags)
{
// Load the value of the node(s).
if (wFlags & EU_LOAD) {
switch (EVAL_STATE (pvLeft)) {
case EV_lvalue:
if (!LoadVal (pvLeft)) {
pExState->err_num = ERR_NOTEVALUATABLE;
return (FALSE);
}
break;
case EV_rvalue:
case EV_constant:
break;
case EV_type:
if (EVAL_IS_STMEMBER (pvLeft)) {
if (!LoadVal (pvLeft)) {
pExState->err_num = ERR_NOTEVALUATABLE;
return (FALSE);
}
else {
break;
}
}
default:
pExState->err_num = ERR_SYNTAX;
return (FALSE);
}
if (pvRight != NULL) {
switch (EVAL_STATE (pvRight)) {
case EV_lvalue:
if (!LoadVal (pvRight)) {
pExState->err_num = ERR_NOTEVALUATABLE;
return (FALSE);
}
break;
case EV_rvalue:
case EV_constant:
break;
case EV_type:
if (EVAL_IS_STMEMBER (pvRight)) {
if (!LoadVal (pvRight)) {
pExState->err_num = ERR_NOTEVALUATABLE;
return (FALSE);
}
else {
break;
}
}
default:
pExState->err_num = ERR_SYNTAX;
return (FALSE);
}
}
}
// Perform implicit type coercion.
if (wFlags & EU_TYPE) {
TypeNodes (op, pvLeft, pvRight);
}
return (TRUE);
}
LOCAL bool_t NEAR FASTCALL
EvalFuncIdent(
bnode_t bn
)
/*++
Routine Description:
description-of-function.
Arguments:
argument-name - Supplies | Returns description of argument.
.
.
Return Value:
return-value - Description of conditions needed to return value. - or -
None.
--*/
{
peval_t pvF;
eval_t evalF;
peval_t pvRet;
eval_t evalRet;
ushort type;
SHREG reg;
if (!EvalLChild(bn)) {
return FALSE;
}
if (EVAL_IS_PTR(ST)) {
FetchOp(ST);
}
pvF = &evalF;
*pvF = *ST;
if (EVAL_IS_METHOD (ST)) {
if ((FCN_PROPERTY (pvF) == CV_MTvirtual) ||
(FCN_PROPERTY (pvF) == CV_MTintro)) {
/*
* we have a virtual function. We now need to find the vfuncptr
* which is stored at the this pointer and then walk down the
* shape table to find the offset of the virtual function pointer
* note that we use pvRet to read the vfuncptr
*/
pvRet = &evalRet;
*pvRet = *pvThis;
SetNodeType (pvRet, FCN_VFPTYPE (pvF));
if (!EvalUtil (OP_fetch, pvRet, NULL, EU_LOAD)) {
return (FALSE);
}
EVAL_SYM_OFF (pvRet) = EVAL_PTR_OFF (pvRet) + FCN_VTABIND (pvF);
EVAL_SYM_SEG (pvRet) = EVAL_PTR_SEG (pvRet);
EVAL_STATE (pvRet) = EV_lvalue;
if (FCN_FARCALL (pvF) == TRUE) {
type = T_PFUCHAR;
}
else {
if (ADDR_IS_OFF32(*SHpADDRFrompCXT(pCxt))) {
type = T_32PUCHAR;
} else {
type = T_PUCHAR;
}
}
SetNodeType (pvRet, type);
if (!EvalUtil (OP_fetch, pvRet, NULL, EU_LOAD)) {
return (FALSE);
}
EVAL_SYM (pvF) = EVAL_PTR (pvRet);
reg.hReg = CV_REG_CS;
GetReg (&reg, pCxt);
EVAL_SYM_SEG (pvF) = reg.Byte2;
}
}
*ST = *pvF;
return TRUE;
} /* EvalFuncIdent() */
/** EvalFunction - Perform an function call
*
* fSuccess = EvalFunction (pn)
*
* Entry bn = based pointer to OP_fcn
*
* Exit ST = result of function call
* pExState->err_num = error number if error
*
* Returns TRUE if successful
* FALSE if error
*/
LOCAL bool_t NEAR FASTCALL EvalFunction (bnode_t bn)
{
bnode_t bnRight = NODE_RCHILD (pnodeOfbnode(bn));
bnode_t bnT;
eval_t evalRet;
peval_t pvRet;
eval_t evalF;
peval_t pvF;
bnode_t bnA;
peval_t pvA;
SHREG spReg;
bool_t retval;
UOFFSET maxSP = 0;
CV_typ_t typArg;
pargd_t pa;
ushort type;
SHREG reg;
ADDR fcnAddr;
HDEP hFunc;
#ifdef TARGET_PPC
/* We need this for some PPC cases to do an extra
* level of dereferencing.
*/
int ppc_extra_deref=FALSE;
#endif
/*
* the left child must resolve to a function address and BP must not
* be zero and the overlay containing the function must be loaded
*/
if ((pExState->frame.BP.off == 0) && (pExState->style != EEBPADDRESS)) {
pExState->err_num = ERR_FCNCALL;
return (FALSE);
}
/*
* Save current registers. All returns from this point must restore the
* registers or there will be memory loss
*/
if (DHSetupExecute(&hFunc) != 0) {
pExState->err_num = ERR_NOMEMORY;
return (FALSE);
}
#ifdef TARGET_MIPS
spReg.hReg = CV_M4_IntSP;
#endif
#ifdef TARGET_PPC
spReg.hReg = CV_PPC_GPR1;
#endif
#ifdef TARGET_i386
if (ADDR_IS_OFF32(*SHpADDRFrompCXT(pCxt))) {
spReg.hReg = CV_REG_ESP;
} else {
spReg.hReg = CV_REG_SP;
}
#endif
#ifdef TARGET_ALPHA
spReg.hReg = CV_ALPHA_IntSP;
#endif
GetReg (&spReg, pCxt);
/*
* Evaluate argument nodes until end of arguments reached and count
* arguments
*
* if we are evaluating for breakpoint address, we do not need to
* evaluate the arguments.
*/
if (pExState->style != EEBPADDRESS) {
for (bnT = bnRight;
NODE_OP (pnodeOfbnode(bnT)) != OP_endofargs;
bnT = NODE_RCHILD (pnodeOfbnode(bnT))) {
/*
* Check to make sure the current node is for an argument
*/
if (NODE_OP (pnodeOfbnode(bnT)) != OP_arg) {
pExState->err_num = ERR_INTERNAL;
goto fcnerror;
}
/*
* Setup and evaluate the current node
*/
bnA = NODE_LCHILD (pnodeOfbnode(bnT));
pvA = &pnodeOfbnode(bnA)->v[0];
pa = (pargd_t)&pnodeOfbnode(bnT)->v[0];
typArg = pa->type;
if (Eval (bnA) == FALSE) {
goto fcnerror;
}
/*
* Base on the type and value of the current argument, push any
* additional information needed onto the stack.
*
* STRINGS: The string will need to be pushed on the stack and
* the address of the string is passed as the argument.
*/
if ((EVAL_STATE (ST) == EV_constant) && (EVAL_TYP (pvA) == T_PCHAR)) {
if (PushString (ST, &spReg, typArg) == FALSE) {
return (FALSE);
}
}
/*
* if the OP_arg node contains a nonzero type (not vararg),
* cast the stack top to the specified value
*/
else if (pa->flags.ref == TRUE) {
/*
* for a reference argument, the following happens
* if the actual is a constant, cast and push onto
* the stack and pass the address. If the actual
* is a variable of the correct type, pass the address.
* If the actual is a variable of the wrong type, load
* and attempt to cast to the correct type, push the
* value onto the stack and pass the address. If the
* actual is a complex type, pass the address. If the
* formal is a base class of the actual, cast the
* address and pass that.
*/
if (EVAL_STATE (ST) == EV_constant) {
// push the casted constant onto the stack
if (!CastNode (ST, pa->utype, pa->utype)) {
goto fcnerror;
}
PushRef (ST, &spReg, pa->type);
}
/*
* Classes are pushed on the stack
* and the address of the pushed area is pushed on
* the stack.
*/
else if (EVAL_IS_CLASS (ST)) {
SetNodeType (ST, T_32FCVPTR);
if (!CastNode (ST, pa->type, pa->type)) {
goto fcnerror;
}
if (EVAL_IS_BPREL(ST)) {
EVAL_IS_BPREL(ST) = FALSE;
EVAL_SYM_OFF(ST) += pExState->frame.BP.off;
EVAL_SYM_SEG(ST) = pExState->frame.SS;
ADDR_IS_LI( EVAL_SYM( ST )) = FALSE;
SHUnFixupAddr(&EVAL_SYM(ST));
SHFixupAddr(&EVAL_SYM(ST));
}
if (EVAL_IS_REGREL(ST)) {
SHREG reg;
EVAL_IS_REGREL(ST) = FALSE;
reg.hReg = EVAL_REGREL (ST);
if (GetReg(&reg, pCxt) == NULL) {
DASSERT(FALSE);
return (FALSE);
}
EVAL_SYM_OFF (ST) += reg.Byte4;
EVAL_SYM_SEG (ST) = pExState->frame.SS;
ADDR_IS_LI (EVAL_SYM (ST)) = FALSE;
SHUnFixupAddr (&EVAL_SYM (ST));
}
EVAL_PTR( ST ) = EVAL_SYM( ST );
}
else {
/*
* process a "simple" variable
*/
if (!EvalUtil (OP_function, ST, NULL, EU_LOAD)) {
goto fcnerror;
}
/*
* if the variable is not of the correct type,
* load and cast the value to the correct type,
* push the value onto the stack and pass that
* address to the function
*/
if (EVAL_TYP (ST) != pa->type) {
if (!CastNode (ST, pa->utype, pa->utype)) {
goto fcnerror;
}
}
PushRef (ST, &spReg, pa->type);
}
}
else {
/*
* an actual that is not a reference cannot be a class.
* Load the value and cast it to the proper type.
*/
if (EVAL_IS_CLASS (ST)) {
pExState->err_num = ERR_CANTCONVERT;
goto fcnerror;
}
if (!EvalUtil (OP_function, ST, NULL, EU_LOAD) ||
!CastNode (ST, typArg, typArg)) {
goto fcnerror;
}
}
}
}
/*
* evaluate left hand side of tree to get function address
*/
if (!EvalLChild (bn)){
goto fcnerror;
}
if (EVAL_IS_PTR (ST)) {
FetchOp (ST);
}
/*
* the stack top is the function address node. We save this information
* and pop the function node. We then push the argument left to right
* using the SP relative offset from the bind that is stored in the
* address field of the OP_arg node.
*/
/*
* The evaluation of the left node also processed the this pointer
* adjustment. ThisAddress contains the value of the this pointer
*/
pvF = &evalF;
*pvF = *ST;
/*
* set type of this pointer if method
*/
pvRet = &evalRet;
if (EVAL_IS_METHOD (ST)) {
ResolveAddr( pvThis );
if ((FCN_PROPERTY (pvF) == CV_MTvirtual) ||
(FCN_PROPERTY (pvF) == CV_MTintro)) {
/*
* we have a virtual function. We now need to find the vfuncptr
* which is stored at the this pointer and then walk down the
* shape table to find the offset of the virtual function pointer
* note that we use pvRet to read the vfuncptr
*/
*pvRet = *pvThis;
SetNodeType (pvRet, FCN_VFPTYPE (pvF));
if (!EvalUtil (OP_fetch, pvRet, NULL, EU_LOAD)) {
return (FALSE);
}
EVAL_SYM_OFF (pvRet) = EVAL_PTR_OFF (pvRet) + FCN_VTABIND (pvF);
EVAL_SYM_SEG (pvRet) = EVAL_PTR_SEG (pvRet);
EVAL_STATE (pvRet) = EV_lvalue;
if (FCN_FARCALL (pvF) == TRUE) {
type = T_PFUCHAR;
}
else {
if (ADDR_IS_OFF32(*SHpADDRFrompCXT(pCxt))) {
type = T_32PUCHAR;
} else {
type = T_PUCHAR;
}
}
SetNodeType (pvRet, type);
if (!EvalUtil (OP_fetch, pvRet, NULL, EU_LOAD)) {
return (FALSE);
}
#ifdef TARGET_PPC
// On the PPC make sure to deref the function-descriptor
// (we are left pointing to the FD instead of the actual
// function entry point).
ppc_extra_deref = TRUE;
#endif
EVAL_SYM (pvF) = EVAL_PTR (pvRet);
reg.hReg = CV_REG_CS;
GetReg (&reg, pCxt);
EVAL_SYM_SEG (pvF) = reg.Byte2;
}
}
#ifdef TARGET_PPC
/* If what we have in our hands is a function descriptor, we
* must set up the right address to get the entry point.
*/
if (ppc_extra_deref) {
eval_t teval = *pvF;
EVAL_SYM_SEG (&teval) = EVAL_PTR_SEG (&teval);
EVAL_STATE (&teval) = EV_lvalue;
SetNodeType(&teval, T_32PUCHAR);
if (!EvalUtil (OP_fetch, &teval, NULL, EU_LOAD)) {
return (FALSE);
}
EVAL_SYM (pvF) = EVAL_PTR (&teval);
}
#endif /* TARGET_PPC */
if (pExState->style == EEBPADDRESS) {
*ST = *pvF;
return (TRUE);
}
/*
* set type of return node
*/
*pvRet = *ST;
SetNodeType (pvRet, FCN_RETURN (pvRet));
EVAL_VALLEN (pvRet) = (ushort)TypeSize (pvRet);
EVAL_STATE (pvRet) = EV_rvalue;
PopStack ();
/*
* for some return types, pascal and fastcalls requires a hidden
* argument pointing to space allocated on the user's stack large
* enough to hold the return value.
*/
switch (FCN_CALL (pvF)) {
#ifdef TARGET_i386
case FCN_THIS:
case FCN_STD:
case FCN_C:
/*
* In the 32-bit world --
* if the return value is > 4 bytes AND it is not a
* real then allocate space on the stack to hold it.
*/
if (ADDR_IS_FLAT(EVAL_SYM(pvF))) {
if (!EVAL_IS_REF(pvRet) &&
((!CV_IS_PRIMITIVE(EVAL_TYP(pvRet)) &&
((EVAL_VALLEN (pvRet) > 4) &&
(CV_TYPE ( EVAL_TYP (pvRet)) != CV_REAL))))) {
ADDR_IS_LI (EVAL_SYM (pvRet)) = FALSE;
EVAL_STATE (pvRet) = EV_lvalue;
spReg.Byte4 -= (EVAL_VALLEN (pvRet) + 3) & ~3;
EVAL_ULONG (pvRet) = spReg.Byte4;
EVAL_SYM_OFF (pvRet) = spReg.Byte4;
EVAL_SYM_SEG (pvRet) = pExState->frame.SS;
}
}
break;
case FCN_PASCAL:
// If the return value is larger than 4 bytes, then allocate
// space on the stack and set the return node
// to point to this address
if (!EVAL_IS_REF (pvRet) &&
((!CV_IS_PRIMITIVE (EVAL_TYP (pvRet)) ||
(CV_TYPE (EVAL_TYP (pvRet)) == CV_REAL) ||
(EVAL_VALLEN (pvRet) > 4)))) {
ADDR_IS_LI (EVAL_SYM (pvRet)) = FALSE;
EVAL_STATE (pvRet) = EV_lvalue;
if (!ADDR_IS_FLAT (EVAL_SYM (pvRet))) {
spReg.Byte2 -= (ushort) ((EVAL_VALLEN (pvRet) + 1) & ~1);
EVAL_SYM_OFF (pvRet) = spReg.Byte2;
EVAL_USHORT (pvRet) = spReg.Byte2;
EVAL_SYM_SEG (pvRet) = pExState->frame.SS;
}
else {
spReg.Byte4 -= (EVAL_VALLEN (pvRet) + 1) & ~1;
EVAL_SYM_OFF (pvRet) = spReg.Byte4;
EVAL_ULONG (pvRet) = spReg.Byte4;
EVAL_SYM_SEG (pvRet) = pExState->frame.SS;
}
}
break;
case FCN_FAST:
// If the return value is not real and is larger than 4 bytes,
// then allocate space on the stack and set the return node
// to point to this address. For fastcall, real values are
// returned on the numeric coprocessor stack
if (!EVAL_IS_REF (pvRet) &&
((!CV_IS_PRIMITIVE (EVAL_TYP (pvRet)) &&
((EVAL_VALLEN (pvRet) > 4) &&
(CV_TYPE (EVAL_TYP (pvRet)) != CV_REAL))))) {
ADDR_IS_LI (EVAL_SYM (pvRet)) = FALSE;
EVAL_STATE (pvRet) = EV_lvalue;
if (!ADDR_IS_FLAT (EVAL_SYM (pvRet))) {
spReg.Byte2 -= (ushort) ((EVAL_VALLEN (pvRet) + 1) & ~1);
EVAL_SYM_OFF (pvRet) = spReg.Byte2;
EVAL_USHORT (pvRet) = spReg.Byte2;
EVAL_SYM_SEG (pvRet) = pExState->frame.SS;
}
else {
spReg.Byte4 -= (EVAL_VALLEN (pvRet) + 1) & ~1;
EVAL_SYM_OFF (pvRet) = spReg.Byte4;
EVAL_ULONG (pvRet) = spReg.Byte4;
EVAL_SYM_SEG (pvRet) = pExState->frame.SS;
}
}
break;
#endif // TARGET_i386
#ifdef TARGET_PPC
case FCN_PPC:
/*
* This was already taken care of in the bind phase
*/
break;
#endif // TARGET_PPC
#ifdef TARGET_MIPS
case FCN_MIPS:
/*
* This was already taken care of in the bind phase
*/
break;
#endif // TARGET_MIPS
#ifdef TARGET_ALPHA
case FCN_ALPHA:
/*
* This was already taken care of in the bind phase
*/
break;
#endif // TARGET_ALPHA
default:
DASSERT (FALSE);
pExState->err_num = ERR_INTERNAL;
return (FALSE);
}
/*
* push arguments for the function
*/
if (PushArgs (pnodeOfbnode(bnRight), &spReg, &maxSP) == FALSE) {
goto fcnerror;
}
if (EVAL_STATE (pvRet) == EV_lvalue) {
if (!PushOffset (EVAL_SYM_OFF (pvRet), &spReg, &maxSP,
/*sizeof (CV_uoff16_t)*/ sizeof(CV_uoff32_t))) {
return (FALSE);
}
}
/*
* This is a C++ function. We therefore need to push in the pointer
* to this.
*/
if (EVAL_IS_METHOD (pvF)) {
SetNodeType (pvThis, FCN_THIS (pvF));
if (EVAL_TYP(pvThis) == T_NOTYPE) {
/*
* This is a no-op -- This means that we just referenced
* a static element.
*/
} else if (EVAL_IS_NPTR32 (pvThis)) {
SHREG argReg;
switch(FCN_CALL( pvF ) ) {
case FCN_THIS:
#ifdef TARGET_i386
argReg.hReg = CV_REG_ECX;
argReg.Byte4 = EVAL_SYM_OFF( pvThis );
SetReg(&argReg, pCxt);
#else
DASSERT(FCN_CALL(pvThis) == FCN_THIS);
return (FALSE);
#endif
break;
case FCN_PPC:
#ifdef TARGET_PPC
argReg.hReg = CV_PPC_GPR3;
argReg.Byte4 = EVAL_SYM_OFF( pvThis );
argReg.Byte4High = 0;
SetReg(&argReg, pCxt);
#else
if (!PushOffset (EVAL_SYM_OFF (pvThis), &spReg, &maxSP,
sizeof (CV_uoff32_t))) {
return (FALSE);
}
#endif
break;
case FCN_MIPS:
#ifdef TARGET_MIPS
argReg.hReg = CV_M4_IntA0;
argReg.Byte4 = EVAL_SYM_OFF( pvThis );
SetReg(&argReg, pCxt);
#else
if (!PushOffset (EVAL_SYM_OFF (pvThis), &spReg, &maxSP,
sizeof (CV_uoff32_t))) {
return (FALSE);
}
#endif
break;
case FCN_ALPHA:
#ifdef TARGET_ALPHA
argReg.hReg = CV_ALPHA_IntA0;
argReg.Byte4 = EVAL_SYM_OFF( pvThis );
argReg.Byte4High = 0;
SetReg(&argReg, pCxt);
#else
if (!PushOffset (EVAL_SYM_OFF (pvThis), &spReg, &maxSP,
sizeof (CV_uoff32_t))) {
return (FALSE);
}
#endif
break;
}
}
}
// Call the user's procedure
#ifdef TARGET_MIPS
spReg.Byte4 -= (UOFFSET) maxSP;
#endif
#ifdef TARGET_PPC
spReg.Byte4 -= (UOFFSET) maxSP;
#endif
#ifdef TARGET_i386
if (ADDR_IS_OFF32(*SHpADDRFrompCXT(pCxt))) {
spReg.Byte4 -= (UOFFSET) maxSP;
} else {
spReg.Byte2 -= (ushort) maxSP;
}
#endif
#ifdef TARGET_ALPHA
spReg.Byte4 -= (UOFFSET) maxSP;
#endif
SetReg (&spReg, pCxt);
fcnAddr = EVAL_SYM (pvF);
// make sure that the execution model is Native, if it is not
// then return ERR_CALLSEQ.
{
WORD wModel;
SYMPTR pSym;
UOFFSET obMax = 0xFFFFFFFF;
SHModelFromAddr(&fcnAddr, &wModel, (char FAR *)&pSym, (UOFFSET FAR *)&obMax );
if ( wModel != CEXM_MDL_native ) {
// not native calling sequence, return error
pExState->err_num = ERR_CALLSEQ;
goto fcnerror;
}
}
if (ADDR_IS_LI (fcnAddr)) {
SHFixupAddr (&fcnAddr);
}
if (DHStartExecute(hFunc, &fcnAddr, TRUE, EVAL_IS_FFCN (pvF)? SHFar:SHNear) != 0) {
pExState->err_num = ERR_EXCEPTION;
goto fcnerror;
}
// Procedure succeeded, set return information and set flag to force
// update
is_assign = TRUE;
PushStack (pvRet);
if (EVAL_TYP (ST) == T_VOID) {
retval = TRUE;
} else {
switch (FCN_CALL (pvF)) {
case FCN_STD:
case FCN_C:
case FCN_THIS:
retval = StoreC (pvF);
break;
case FCN_PASCAL:
retval = StoreP ();
break;
case FCN_PPC:
retval = StorePPC(pvF);
break;
case FCN_MIPS:
retval = StoreMips(pvF);
break;
case FCN_ALPHA:
retval = StoreAlpha(pvF);
break;
case FCN_FAST:
retval = StoreF ();
break;
default:
goto fcnerror;
}
}
if (retval == TRUE) {
if (DHCleanUpExecute(hFunc)) {
return (FALSE);
} else {
EVAL_STATE (ST) = EV_rvalue;
return (TRUE);
}
}
fcnerror:
DHCleanUpExecute(hFunc);
return (FALSE);
}
/** PushArgs - push arguments
*
* fSuccess = PushArgs (pnArg, pspReg, pmaxSP);
*
* Entry pnArg = pointer to argument nodes
* pspReg = pointer to register structure for SP value
* pmaxSP = pointer to location to store maximum SP relative offset
*
* Exit arguments pushed onto stack
*
* Returns TRUE if parameters pushed without error
* FALSE if error during push
*/
LOCAL bool_t NEAR PASCAL PushArgs (pnode_t pnArg, SHREG FAR *pspReg, UOFFSET FAR *pmaxSP)
{
SHREG argReg;
#ifdef TARGET_PPC
SHREG tmpReg;
#endif
// The arguments have been evaluated left to right which means that the
// rightmost argument is at ST. We need to recurse down the right side
// of the argument tree to find the OP_arg node that corresponds to the
// stack top.
if (NODE_OP (pnArg) == OP_endofargs) {
return (TRUE);
}
if (!PushArgs (pnodeOfbnode(NODE_RCHILD (pnArg)), pspReg, pmaxSP)) {
return (FALSE);
}
else {
#ifdef TARGET_i386
if (((pargd_t)&(pnArg->v[0]))->flags.isreg == TRUE) {
argReg.hReg = ((pargd_t)&(pnArg->v[0]))->reg;
switch (argReg.hReg & 0xff) {
case CV_REG_AL:
case CV_REG_CL:
case CV_REG_DL:
case CV_REG_BL:
case CV_REG_AH:
case CV_REG_CH:
case CV_REG_DH:
argReg.Byte1 = EVAL_UCHAR (ST);
break;
case CV_REG_ST0:
case CV_REG_ST1:
case CV_REG_ST2:
case CV_REG_ST3:
case CV_REG_ST4:
case CV_REG_ST5:
case CV_REG_ST6:
case CV_REG_ST7:
memcpy(&argReg.Byte10, &EVAL_DOUBLE(ST), sizeof(FLOAT10));
break;
default:
argReg.Byte2 = EVAL_USHORT (ST);
break;
case CV_REG_EAX:
case CV_REG_ECX:
case CV_REG_EDX:
case CV_REG_CR0:
case CV_REG_CR1:
case CV_REG_CR2:
case CV_REG_CR3:
case CV_REG_CR4:
case CV_REG_DR0:
case CV_REG_DR1:
case CV_REG_DR2:
case CV_REG_DR3:
case CV_REG_DR4:
case CV_REG_DR5:
case CV_REG_DR6:
case CV_REG_DR7:
case CV_REG_PSEUDO1:
case CV_REG_PSEUDO2:
case CV_REG_PSEUDO3:
case CV_REG_PSEUDO4:
case CV_REG_PSEUDO5:
case CV_REG_PSEUDO6:
case CV_REG_PSEUDO7:
case CV_REG_PSEUDO8:
case CV_REG_PSEUDO9:
argReg.Byte4 = EVAL_ULONG( ST );
break;
}
if ((argReg.hReg >> 8) != CV_REG_NONE) {
switch (argReg.hReg >> 8) {
case CV_REG_DX:
case CV_REG_ES:
argReg.Byte2High = *(((ushort FAR *)&(EVAL_ULONG (ST))) + 1);
break;
}
}
SetReg (&argReg, pCxt);
}
#endif
#ifdef TARGET_PPC
if (((pargd_t)&(pnArg->v[0]))->flags.isreg == TRUE) {
ushort reg = ((pargd_t)&(pnArg->v[0]))->reg;
argReg.hReg = (reg & 0xff);
switch (argReg.hReg) {
case CV_PPC_GPR3:
case CV_PPC_GPR4:
case CV_PPC_GPR5:
case CV_PPC_GPR6:
case CV_PPC_GPR7:
case CV_PPC_GPR8:
case CV_PPC_GPR9:
case CV_PPC_GPR10:
argReg.Byte4 = EVAL_ULONG(ST);
*pmaxSP = max( *pmaxSP, ((pargd_t)&pnArg->v[0])->SPoff );
break;
case CV_PPC_FPR1:
case CV_PPC_FPR2:
case CV_PPC_FPR3:
case CV_PPC_FPR4:
case CV_PPC_FPR5:
case CV_PPC_FPR6:
case CV_PPC_FPR7:
case CV_PPC_FPR8:
case CV_PPC_FPR9:
case CV_PPC_FPR10:
case CV_PPC_FPR11:
case CV_PPC_FPR12:
case CV_PPC_FPR13:
if (EVAL_TYP(ST) == T_REAL32) {
argReg.Byte8 = (double) (EVAL_FLOAT(ST));
} else {
argReg.Byte8 = EVAL_DOUBLE(ST);
}
*pmaxSP = max( *pmaxSP, ((pargd_t)&pnArg->v[0])->SPoff );
/*
* Floating point values are passed in FPRs as well as GPRs.
*/
switch (reg >>= 8) {
case CV_PPC_GPR3:
case CV_PPC_GPR4:
case CV_PPC_GPR5:
case CV_PPC_GPR6:
case CV_PPC_GPR7:
case CV_PPC_GPR8:
case CV_PPC_GPR9:
case CV_PPC_GPR10:
SetReg (&argReg, pCxt);
argReg.hReg = reg;
memcpy(&argReg.Byte4, &EVAL_FLOAT(ST), sizeof(float));
break;
case (CV_PPC_GPR3<<4)|CV_PPC_GPR4 :
case (CV_PPC_GPR5<<4)|CV_PPC_GPR6 :
case (CV_PPC_GPR7<<4)|CV_PPC_GPR8 :
case (CV_PPC_GPR9<<4)|CV_PPC_GPR10:
SetReg (&argReg, pCxt);
tmpReg.hReg = (reg & 0xf);
tmpReg.Byte4 = argReg.Byte4High;
SetReg (&tmpReg, pCxt);
argReg.hReg = ((reg >> 4) & 0xf);
break;
}
break;
default:
DASSERT(FALSE);
break;
}
SetReg (&argReg, pCxt);
}
#endif
#ifdef TARGET_MIPS
if (((pargd_t)&(pnArg->v[0]))->flags.isreg == TRUE) {
argReg.hReg = ((pargd_t)&(pnArg->v[0]))->reg;
switch (argReg.hReg) {
case CV_M4_IntA0:
case CV_M4_IntA1:
case CV_M4_IntA2:
case CV_M4_IntA3:
argReg.Byte4 = EVAL_ULONG( ST );
*pmaxSP = max( *pmaxSP, ((pargd_t)&pnArg->v[0])->SPoff );
break;
case CV_M4_FltF12:
case CV_M4_FltF14:
memcpy(&argReg.Byte4, &EVAL_FLOAT( ST ), sizeof(float));
*pmaxSP = max( *pmaxSP, ((pargd_t)&pnArg->v[0])->SPoff );
break;
case (CV_M4_IntA3<<8)|CV_M4_IntA2:
case (CV_M4_FltF13<<8)|CV_M4_FltF12:
case (CV_M4_FltF15<<8)|CV_M4_FltF14:
memcpy(&argReg.Byte1, &EVAL_DOUBLE( ST ), sizeof(double));
*pmaxSP = max( *pmaxSP, ((pargd_t)&pnArg->v[0])->SPoff );
break;
default:
DASSERT(FALSE);
break;
}
SetReg (&argReg, pCxt);
}
#endif
#ifdef TARGET_ALPHA
if (((pargd_t)&(pnArg->v[0]))->flags.isreg == TRUE) {
argReg.hReg = ((pargd_t)&(pnArg->v[0]))->reg;
switch (argReg.hReg) {
case CV_ALPHA_IntA0:
case CV_ALPHA_IntA1:
case CV_ALPHA_IntA2:
case CV_ALPHA_IntA3:
case CV_ALPHA_IntA4:
case CV_ALPHA_IntA5:
*((PLARGE_INTEGER) & argReg.Byte4) = EVAL_QUAD( ST );
*pmaxSP = max( *pmaxSP, ((pargd_t)&pnArg->v[0])->SPoff );
break;
case CV_ALPHA_FltF16:
case CV_ALPHA_FltF17:
case CV_ALPHA_FltF18:
case CV_ALPHA_FltF19:
case CV_ALPHA_FltF20:
case CV_ALPHA_FltF21:
memcpy(&argReg.Byte1, &EVAL_DOUBLE( ST ), sizeof(double));
*pmaxSP = max( *pmaxSP, ((pargd_t)&pnArg->v[0])->SPoff );
break;
default:
DASSERT(FALSE);
break;
}
SetReg (&argReg, pCxt);
}
#endif // ALPHA
else if (!PushUserValue (ST, (pargd_t)&pnArg->v[0], pspReg, pmaxSP)) {
pExState->err_num = ERR_PTRACE;
return (FALSE);
}
}
PopStack ();
return (TRUE);
}
/** PushRef - push referenced value onto stack
*
* fSuccess = PushRef (pv, spReg, reftype);
*
* Entry pv = value
* spReg = pointer to sp register structure
* reftype = type of the reference
*
* Exit string pushed onto user stack
* SP register structure updated to reflect size of string
*
* Returns TRUE if return value stored without error
* FALSE if error during store
*/
LOCAL bool_t NEAR PASCAL PushRef (peval_t pv, SHREG FAR *spReg, CV_typ_t reftype)
{
uint cbVal;
bool_t retval = TRUE;
Unreferenced( reftype );
switch (EVAL_STATE (pv)) {
case EV_lvalue:
// for an lvalue, change the node to a reference to the lvalue
EVAL_PTR (pv) = EVAL_SYM (pv);
CastNode (pv, T_FCVPTR, T_FCVPTR);
break;
case EV_rvalue:
case EV_constant:
cbVal = ((uint)TypeSize (pv) + 3) & ~3;
// decrement stack pointer to allocate room for string
spReg->Byte4 -= cbVal;
// get current SS value and set symbol address to SS:SP
EVAL_SYM_SEG (pv) = pExState->frame.SS;
EVAL_SYM_OFF (pv) = spReg->Byte4;
ADDR_IS_FLAT(EVAL_SYM(pv)) = TRUE;
EVAL_STATE (pv) = EV_lvalue;
ADDR_IS_LI (EVAL_SYM (pv)) = FALSE;
retval = (PutDebuggeeBytes (EVAL_SYM (pv), cbVal, EVAL_PVAL (pv), EVAL_TYP(pv)) == cbVal);
EVAL_PTR (pv) = EVAL_SYM (pv);
if (retval == FALSE) {
pExState->err_num = ERR_PTRACE;
}
break;
default:
DASSERT (FALSE);
retval = FALSE;
break;
}
return (retval);
}
/** PushString - push constant string onto stack
*
* fSuccess = PushString (pv, spReg, typArg);
*
* Entry pv = value describing string
* spReg = pointer to sp register structure
* typArg = type of resultant pointer node
*
* Exit string pushed onto user stack
* SP register structure updated to reflect size of string
*
* Returns TRUE if return value stored without error
* FALSE if error during store
*/
LOCAL bool_t NEAR PASCAL PushString (peval_t pv, SHREG FAR *spReg, CV_typ_t typArg)
{
char FAR *pb;
char FAR *pbEnd;
uint cbVal;
bool_t errcnt = 0;
bool_t fWide;
ushort zero = 0;
ushort FillCnt;
ushort ch;
OFFSET spSave;
// compute location and length of string note that pointer points to
// initial " or L" of string and the length includes the initial ' or
// L" and the ending ". The byte count must be rounded to even parity
// because of restrictions on the stack. If the string is a wide
// character string, then the C runtime must be called to translate the
// string.
pb = pExStr + EVAL_ITOK (pv);
pbEnd = pb + EVAL_CBTOK (pv) - 1;
if ((fWide = (*pb == 'L')) == TRUE) {
// skip wide character leader and compute number of bytes for stack
// we add two bytes for forcing a zero termination
pb++;
cbVal = 2 * (EVAL_CBTOK (pv) - 3);
FillCnt = 2;
}
else {
cbVal = EVAL_CBTOK (pv) - 2;
FillCnt = 1;
}
DASSERT (*pb == '"');
pb++;
// decrement stack pointer to allocate room for string. We know that
// the string actually pushed can be no longer than cbVal + FillCnt.
// It can be shorter because of escaped characters such as \n and \001
if (!ADDR_IS_OFF32(*SHpADDRFrompCXT(pCxt))) {
spReg->Byte4 &= 0xffff;
}
spReg->Byte4 -= (cbVal + FillCnt);
spReg->Byte4 &= ~3; // round down to correct stack size
spSave = spReg->Byte4;
SetNodeType (pv, typArg);
// get current SS value and set symbol address to SS:SP
EVAL_SYM_SEG (pv) = pExState->frame.SS;
EVAL_SYM_OFF (pv) = spReg->Byte4;
ADDR_IS_FLAT(EVAL_SYM(pv)) = ADDR_IS_FLAT(*SHpADDRFrompCXT(pCxt));
ADDR_IS_OFF32(EVAL_SYM(pv)) = ADDR_IS_OFF32(*SHpADDRFrompCXT(pCxt));
ADDR_IS_REAL(EVAL_SYM(pv)) = ADDR_IS_REAL(*SHpADDRFrompCXT(pCxt));
ADDR_IS_LI (EVAL_SYM (pv)) = FALSE;
EVAL_STATE (pv) = EV_lvalue;
if (fWide == FALSE) {
// move characters one at a time onto the user's stack, converting
// while moving.
while (pb < pbEnd) {
if ((ch = *pb++) == '\\') {
GetEscapedChar (&pb, &ch);
}
if (PutDebuggeeBytes (EVAL_SYM (pv), sizeof (char), &ch, T_RCHAR) != sizeof (char)) {
errcnt++;
}
EVAL_SYM_OFF (pv) += sizeof (char);
}
}
else {
// M00BUG - this is a fake routine until the runtime routines are
// M00BUG - available to do the correct translation. We will also
// M00BUG - need to get the locale state from the user's space for
// M00BUG - for the translation
while (pb < pbEnd) {
ch = *pb++;
// move wide characters onto the user's stack
if (PutDebuggeeBytes (EVAL_SYM (pv), 2, &ch, T_WCHAR) != 2) {
errcnt++;
}
EVAL_SYM_OFF (pv) += 2 * sizeof (char);
}
}
if (PutDebuggeeBytes (EVAL_SYM (pv), FillCnt, &zero, (fWide ? T_WCHAR : T_RCHAR)) != FillCnt) {
errcnt++;
}
EVAL_SYM_OFF (pv) = spSave;
EVAL_PTR (pv) = EVAL_SYM (pv);
if (errcnt != 0) {
pExState->err_num = ERR_PTRACE;
return (FALSE);
}
return (TRUE);
}
/** StoreC - store return value for C call
*
* fSuccess = StoreC (pvF);
*
* Entry pvF = pointer to function descriptor
*
* Exit return value stored in ST
*
* Returns TRUE if return value stored without error
* FALSE if error during store
*/
LOCAL bool_t NEAR PASCAL StoreC (peval_t pvF)
{
SHREG argReg;
ushort len;
ADDR addr;
Unreferenced( pvF );
if (EVAL_IS_PTR (ST)) {
/*
** The result is a 16-bit pointer. Use DX:AX for far pointers
** and DS:AX for near pointers.
*/
if (EVAL_IS_NPTR(ST) || EVAL_IS_FPTR(ST)) {
if (EVAL_IS_NPTR(ST)) {
argReg.hReg = ((CV_REG_DX << 8) | CV_REG_AX);
} else {
argReg.hReg = ((CV_REG_DS << 8) | CV_REG_AX);
}
GetReg (&argReg, pCxt);
EVAL_PTR_OFF (ST) = argReg.Byte2;
EVAL_USHORT (ST) = argReg.Byte2;
EVAL_PTR_SEG (ST) = argReg.Byte2High;
} else {
DASSERT( EVAL_IS_NPTR32(ST) || EVAL_IS_FPTR32(ST) );
argReg.hReg = CV_REG_EAX;
GetReg( &argReg, pCxt );
EVAL_PTR_OFF (ST) = argReg.Byte4;
EVAL_ULONG (ST) = argReg.Byte4;
if ( EVAL_IS_NPTR32( ST )) {
EVAL_PTR_SEG (ST) = pExState->frame.DS;
} else {
argReg.hReg = CV_REG_DX;
GetReg( &argReg, pCxt );
EVAL_PTR_SEG (ST) = argReg.Byte2;
}
ADDR_IS_OFF32(EVAL_PTR(ST)) = TRUE;
ADDR_IS_FLAT(EVAL_PTR (ST)) = TRUE;
}
}
/*
* Floating point value returned; return location system dependent
*/
else if ((EVAL_TYP (ST) == T_REAL32) ||
(EVAL_TYP (ST) == T_REAL64) ||
(EVAL_TYP (ST) == T_REAL80)) {
if (ADDR_IS_FLAT(*SHpADDRFrompCXT(pCxt)) || EVAL_TYP(ST) == T_REAL80) {
/*
* For the flat world (i.e. nt) the return value is on the
* top of the floating point stack.
*/
argReg.hReg = CV_REG_ST0;
GetReg(&argReg, pCxt);
memcpy(&EVAL_LDOUBLE(ST), &argReg.Byte10, sizeof(FLOAT10));
switch( EVAL_TYP ( ST )) {
case T_REAL32:
EVAL_FLOAT(ST) = R10CastToFloat(EVAL_LDOUBLE(ST));
break;
case T_REAL64:
EVAL_DOUBLE(ST) = R10CastToDouble(EVAL_LDOUBLE(ST));
break;
case T_REAL80:
break;
}
} else if (ADDR_IS_OFF32(*SHpADDRFrompCXT(pCxt))) {
/*
* for the 32-bit non NT world --- HELP!!!!
*/
DASSERT(FALSE);
return FALSE;
} else {
/*
* for the dos world AX has a pointer to the address containning
* the return value. Return value is correctly sized.
*/
argReg.hReg = ((CV_REG_DS << 8) | CV_REG_AX);
GetReg(&argReg, pCxt);
AddrInit(&addr, 0, argReg.Byte2High, argReg.Byte2,
FALSE, FALSE, FALSE,
ADDR_IS_REAL(*SHpADDRFrompCXT(pCxt)));
if (GetDebuggeeBytes(addr, EVAL_VALLEN(ST),
(char FAR *) &EVAL_DOUBLE(ST), EVAL_TYP(ST)) != (UINT)EVAL_VALLEN(ST)) {
return FALSE;
}
}
}
else if ((EVAL_TYP (ST) == T_CHAR) || (EVAL_TYP (ST) == T_RCHAR)) {
argReg.hReg = CV_REG_AL;
GetReg (&argReg, pCxt);
EVAL_SHORT (ST) = argReg.Byte1;
}
else if (EVAL_TYP (ST) == T_UCHAR) {
argReg.hReg = CV_REG_AL;
GetReg (&argReg, pCxt);
EVAL_USHORT (ST) = argReg.Byte1;
}
else {
if (ADDR_IS_OFF32(*SHpADDRFrompCXT(pCxt))) {
len = EVAL_VALLEN (ST);
argReg.hReg = CV_REG_EAX;
GetReg (&argReg, pCxt);
/*
** Check for prmitive types (i.e. long or short) and for
** classes which are of lenght less that 3
*/
if (CV_IS_PRIMITIVE (EVAL_TYP (ST)) ||
(EVAL_IS_CLASS (ST) && (len < 4) && (len != 3))) {
if (len <= 2) {
EVAL_USHORT(ST) = argReg.Byte2;
} else {
DASSERT( len == 4 );
EVAL_ULONG (ST) = argReg.Byte4;
}
} else {
/*
** DS:EAX points to the return value
*/
EVAL_SYM_OFF (ST) = argReg.Byte4;
argReg.hReg = CV_REG_DS;
GetReg(&argReg, pCxt);
EVAL_SYM_SEG (ST) = argReg.Byte2;
ADDR_IS_LI ( EVAL_SYM (ST)) = FALSE;
if (GetDebuggeeBytes(EVAL_SYM(ST), EVAL_VALLEN(ST),
(char FAR *)&EVAL_VAL(ST), EVAL_TYP(ST)) != (UINT)EVAL_VALLEN(ST)) {
pExState->err_num = ERR_PTRACE;
return FALSE;
}
}
} else {
len = EVAL_VALLEN (ST);
argReg.hReg = ((CV_REG_DX << 8) | CV_REG_AX);
GetReg (&argReg, pCxt);
if (CV_IS_PRIMITIVE (EVAL_TYP (ST)) ||
(EVAL_IS_CLASS (ST) && (len < 4) && (len != 3))) {
EVAL_USHORT (ST) = argReg.Byte2;
if (len > 2) {
*(((ushort FAR *)&(EVAL_ULONG (ST))) + 1) = argReg.Byte2High;
}
}
else {
// treat (DS)DX:AX as the pointer to the return value
EVAL_SYM_OFF (ST) = argReg.Byte2;
argReg.hReg = CV_REG_DS;
GetReg (&argReg, pCxt);
EVAL_SYM_SEG (ST) = argReg.Byte2;
ADDR_IS_LI (EVAL_SYM (ST)) = FALSE;
if (GetDebuggeeBytes (EVAL_SYM (ST), EVAL_VALLEN (ST),
(char FAR *)&EVAL_VAL (ST), EVAL_TYP(ST)) != (UINT)EVAL_VALLEN (ST)) {
pExState->err_num = ERR_PTRACE;
return (FALSE);
}
}
}
}
return (TRUE);
}
/** StoreF - store return value for fast call
*
* fSuccess = StoreF ();
*
* Entry ST pointer to eval describing return value
*
* Exit return value stored
*
* Returns TRUE if return value stored without error
* FALSE if error during store
*/
LOCAL bool_t NEAR PASCAL StoreF (void)
{
SHREG argReg;
int len;
if (EVAL_IS_PTR (ST)) {
/*
* The results is a 16 bit pointer. Use DX:AX for far pointers and
* DS:AX for near pointers.
*/
if (EVAL_IS_NPTR(ST) || EVAL_IS_FPTR(ST)) {
if (EVAL_IS_NPTR( ST)) {
argReg.hReg = ((CV_REG_DX << 8) | CV_REG_AX);
} else {
argReg.hReg = ((CV_REG_DS << 8) | CV_REG_AX);
}
GetReg( &argReg, pCxt );
EVAL_PTR_OFF( ST ) = EVAL_USHORT( ST ) = argReg.Byte2;
EVAL_PTR_SEG( ST ) = argReg.Byte2High;
} else {
/*
* assume no 32-bit far pointers
*/
DASSERT( EVAL_IS_NPTR32( ST ) );
argReg.hReg = CV_REG_EAX;
GetReg( &argReg, pCxt );
EVAL_PTR_OFF( ST ) = EVAL_ULONG( ST ) = argReg.Byte4;
EVAL_PTR_SEG( ST ) = pExState->frame.DS;
/*
* For far pointers use DX not DS
*/
ADDR_IS_FLAT( EVAL_PTR( ST )) = TRUE;
}
}
else if (CV_IS_PRIMITIVE (EVAL_TYP(ST)) &&
(CV_TYPE (EVAL_TYP (ST)) == CV_REAL)) {
/*
* return value is real, read value from the coprocessor
* stack and cast to proper size
*/
argReg.hReg = CV_REG_ST0;
GetReg (&argReg, pCxt);
memcpy(&EVAL_DOUBLE(ST), &argReg.Byte10, sizeof(FLOAT10));
switch( EVAL_TYP ( ST )) {
case T_REAL32:
EVAL_FLOAT(ST) = R10CastToFloat(EVAL_LDOUBLE(ST));
break;
case T_REAL64:
EVAL_DOUBLE(ST) = R10CastToDouble(EVAL_LDOUBLE(ST));
break;
case T_REAL80:
break;
}
}
else if ((EVAL_TYP (ST) == T_CHAR) || (EVAL_TYP (ST) == T_RCHAR)) {
argReg.hReg = CV_REG_AL;
GetReg (&argReg, pCxt);
EVAL_SHORT (ST) = argReg.Byte1;
}
else if (EVAL_TYP (ST) == T_UCHAR) {
argReg.hReg = CV_REG_AL;
GetReg (&argReg, pCxt);
EVAL_USHORT (ST) = argReg.Byte1;
}
else {
if (ADDR_IS_OFF32(*SHpADDRFrompCXT(pCxt))) {
len = EVAL_VALLEN (ST);
argReg.hReg = CV_REG_EAX;
GetReg (&argReg, pCxt);
/*
** Check for prmitive types (i.e. long or short) and for
** classes which are of lenght less that 3
*/
if (CV_IS_PRIMITIVE (EVAL_TYP (ST)) ||
(EVAL_IS_CLASS (ST) && (len < 4) && (len != 3))) {
if (len <= 2) {
EVAL_USHORT(ST) = argReg.Byte2;
} else {
DASSERT( len == 4 );
EVAL_ULONG (ST) = argReg.Byte4;
}
} else {
/*
** DS:EAX points to the return value
*/
EVAL_SYM_OFF (ST) = argReg.Byte4;
argReg.hReg = CV_REG_DS;
GetReg(&argReg, pCxt);
EVAL_SYM_SEG (ST) = argReg.Byte2;
ADDR_IS_LI ( EVAL_SYM (ST)) = FALSE;
if (GetDebuggeeBytes(EVAL_SYM(ST), EVAL_VALLEN(ST),
(char FAR *)&EVAL_VAL(ST), EVAL_TYP(ST)) != (UINT)EVAL_VALLEN(ST)) {
pExState->err_num = ERR_PTRACE;
return FALSE;
}
}
} else {
len = EVAL_VALLEN (ST);
argReg.hReg = ((CV_REG_DX << 8) | CV_REG_AX);
GetReg (&argReg, pCxt);
if (CV_IS_PRIMITIVE (EVAL_TYP (ST)) ||
(EVAL_IS_CLASS (ST) && (len < 4) && (len != 3))) {
EVAL_USHORT (ST) = argReg.Byte2;
if (len > 2) {
*(((ushort FAR *)&(EVAL_ULONG (ST))) + 1) = argReg.Byte2High;
}
}
else {
// treat (DS)DX:AX as the pointer to the return value
EVAL_SYM_OFF (ST) = argReg.Byte2;
argReg.hReg = CV_REG_DS;
GetReg (&argReg, pCxt);
EVAL_SYM_SEG (ST) = argReg.Byte2;
ADDR_IS_LI (EVAL_SYM (ST)) = FALSE;
if (GetDebuggeeBytes (EVAL_SYM (ST), EVAL_VALLEN (ST),
(char FAR *)&EVAL_VAL (ST), EVAL_TYP(ST)) != (UINT)EVAL_VALLEN (ST)) {
pExState->err_num = ERR_PTRACE;
return (FALSE);
}
}
}
}
return (TRUE);
}
/** StoreMips - store return value for Mips call
*
* fSuccess = StoreMips (pvF);
*
* Entry pvF = pointer to function descriptor
*
* Exit return value stored in ST
*
* Returns TRUE if return value stored without error
* FALSE if error during store
*/
LOCAL bool_t NEAR PASCAL StoreMips (peval_t pvF)
{
SHREG argReg;
ushort len;
Unreferenced( pvF );
DASSERT( EVAL_TYP(ST) != T_REAL80 );
/*
* Floating point values are returned in f0 (Real) or f0:f1 (float)
*/
if ((EVAL_TYP (ST) == T_REAL32) ||
(EVAL_TYP (ST) == T_REAL64) ) {
argReg.hReg = (CV_M4_FltF1 << 8) | CV_M4_FltF0;
GetReg ( &argReg, pCxt );
if (EVAL_TYP (ST) == T_REAL32) {
EVAL_FLOAT(ST) = *((float *) &argReg.Byte4);
} else {
EVAL_DOUBLE(ST) = *((double *) &argReg.Byte4);
}
}
else if ((EVAL_TYP (ST) == T_CHAR) || (EVAL_TYP (ST) == T_RCHAR)) {
argReg.hReg = CV_M4_IntV0;
GetReg( &argReg, pCxt );
EVAL_SHORT( ST ) = argReg.Byte1;
}
else if (EVAL_TYP (ST) == T_UCHAR) {
argReg.hReg = CV_M4_IntV0;
GetReg( &argReg, pCxt );
EVAL_USHORT( ST ) = argReg.Byte1;
}
else if (EVAL_IS_PTR (ST)) {
DASSERT( EVAL_IS_NPTR32(ST) );
argReg.hReg = CV_M4_IntV0;
GetReg( &argReg, pCxt );
EVAL_PTR_OFF (ST) = argReg.Byte4;
EVAL_ULONG (ST) = argReg.Byte4;
EVAL_PTR_SEG (ST) = 0;
ADDR_IS_FLAT( EVAL_PTR (ST)) = TRUE;
ADDR_IS_OFF32( EVAL_PTR (ST)) = TRUE;
ADDR_IS_REAL( EVAL_PTR( ST)) = FALSE;
ADDR_IS_LI( EVAL_PTR (ST)) = FALSE;
}
else {
len = EVAL_VALLEN(ST);
argReg.hReg = CV_M4_IntV0;
GetReg( &argReg, pCxt );
/*
* Check for primitive lengths
*/
if (CV_IS_PRIMITIVE (EVAL_TYP (ST)) ||
(EVAL_IS_CLASS (ST) && (len < 4) && (len != 3))) {
if (len <= 2) {
EVAL_USHORT(ST) = argReg.Byte2;
} else {
EVAL_ULONG (ST) = argReg.Byte4;
}
} else {
EVAL_SYM_OFF (ST) = argReg.Byte4;
EVAL_SYM_SEG (ST) = 0;
ADDR_IS_FLAT( EVAL_SYM (ST)) = TRUE;
ADDR_IS_OFF32( EVAL_SYM (ST)) = TRUE;
ADDR_IS_LI( EVAL_SYM (ST)) = FALSE;
if (GetDebuggeeBytes(EVAL_SYM(ST), EVAL_VALLEN(ST),
(char *)&EVAL_VAL(ST), EVAL_TYP(ST))
!= (UINT)EVAL_VALLEN(ST)) {
pExState->err_num = ERR_PTRACE;
return FALSE;
}
}
}
return (TRUE);
} /* StoreMips() */
/** StorePPC - store return value for PPC call
*
* fSuccess = StorePPC (pvF);
*
* Entry pvF = pointer to function descriptor
*
* Exit return value stored in ST
*
* Returns TRUE if return value stored without error
* FALSE if error during store
*/
LOCAL bool_t NEAR PASCAL StorePPC (peval_t pvF)
{
SHREG argReg;
ushort len;
Unreferenced( pvF );
DASSERT( EVAL_TYP(ST) != T_REAL80 );
/*
* Floating point values are returned in FPR1
*/
if ((EVAL_TYP (ST) == T_REAL32) ||
(EVAL_TYP (ST) == T_REAL64) ) {
argReg.hReg = (CV_PPC_FPR1);
GetReg ( &argReg, pCxt );
if (EVAL_TYP (ST) == T_REAL32) {
EVAL_FLOAT(ST) = (float) argReg.Byte8;
} else {
EVAL_DOUBLE(ST) = *((double *) &argReg.Byte4);
}
}
else if ((EVAL_TYP (ST) == T_CHAR) || (EVAL_TYP (ST) == T_RCHAR)) {
argReg.hReg = CV_PPC_GPR3;
GetReg( &argReg, pCxt );
EVAL_SHORT( ST ) = argReg.Byte1;
}
else if (EVAL_TYP (ST) == T_UCHAR) {
argReg.hReg = CV_PPC_GPR3;
GetReg( &argReg, pCxt );
EVAL_USHORT( ST ) = argReg.Byte1;
}
else if (EVAL_IS_PTR (ST)) {
DASSERT( EVAL_IS_NPTR32(ST) );
argReg.hReg = CV_PPC_GPR3;
GetReg( &argReg, pCxt );
EVAL_PTR_OFF (ST) = argReg.Byte4;
EVAL_ULONG (ST) = argReg.Byte4;
EVAL_PTR_SEG (ST) = 0;
ADDR_IS_FLAT( EVAL_PTR (ST)) = TRUE;
ADDR_IS_OFF32( EVAL_PTR (ST)) = TRUE;
ADDR_IS_REAL( EVAL_PTR( ST)) = FALSE;
ADDR_IS_LI( EVAL_PTR (ST)) = FALSE;
}
else {
len = EVAL_VALLEN(ST);
argReg.hReg = CV_PPC_GPR3;
GetReg( &argReg, pCxt );
/*
* Check for primitive lengths
*/
if (CV_IS_PRIMITIVE (EVAL_TYP (ST)) ||
(EVAL_IS_CLASS (ST) && (len < 4) && (len != 3))) {
if (len <= 2) {
EVAL_USHORT(ST) = argReg.Byte2;
} else {
EVAL_ULONG (ST) = argReg.Byte4;
}
} else {
EVAL_SYM_OFF (ST) = argReg.Byte4;
EVAL_SYM_SEG (ST) = 0;
ADDR_IS_FLAT( EVAL_SYM (ST)) = TRUE;
ADDR_IS_OFF32( EVAL_SYM (ST)) = TRUE;
ADDR_IS_LI( EVAL_SYM (ST)) = FALSE;
if (GetDebuggeeBytes(EVAL_SYM(ST), EVAL_VALLEN(ST),
(char *)&EVAL_VAL(ST), EVAL_TYP(ST))
!= (UINT)EVAL_VALLEN(ST)) {
pExState->err_num = ERR_PTRACE;
return FALSE;
}
}
}
return (TRUE);
} /* StorePPC() */
/** StoreAlpha - store return value for Alpha call
*
* fSuccess = StoreAlpha (pvF);
*
* Entry pvF = pointer to function descriptor
*
* Exit return value stored in ST
*
* Returns TRUE if return value stored without error
* FALSE if error during store
*
*/
LOCAL bool_t NEAR PASCAL StoreAlpha (peval_t pvF)
{
SHREG argReg;
ushort len;
Unreferenced( pvF );
DASSERT( EVAL_TYP(ST) != T_REAL80 );
if (CV_TYP_IS_REAL ( EVAL_TYP (ST) ) ) {
union {
float f;
double d;
unsigned long l[2];
} u;
/*
* Floating point values are returned in f0
*/
argReg.hReg = CV_ALPHA_FltF0;
GetReg ( &argReg, pCxt );
//
// The SHREG is unaligned; this compiler can only do aligned
// loads and stores of floating points.
//
u.l[0] = argReg.Byte4;
u.l[1] = argReg.Byte4High;
if (EVAL_TYP (ST) == T_REAL64) {
EVAL_DOUBLE(ST) = u.d;
return (TRUE);
}
if (EVAL_TYP (ST) == T_REAL32) {
//
// This does the conversion from double to single
//
u.f = (float)u.d;
EVAL_FLOAT (ST) = u.f;
return (TRUE);
}
}
/*
* All other values are returned in IntV0 (r0)
*/
argReg.hReg = CV_ALPHA_IntV0;
GetReg( &argReg, pCxt);
switch( EVAL_TYP(ST) ) {
case T_CHAR:
case T_RCHAR:
EVAL_SHORT( ST ) = argReg.Byte1;
return (TRUE);
break;
case T_UCHAR:
EVAL_USHORT( ST ) = argReg.Byte1;
return (TRUE);
break;
}
if (EVAL_IS_PTR (ST)) {
DASSERT( EVAL_IS_NPTR32(ST) );
EVAL_PTR_OFF (ST) = argReg.Byte4;
EVAL_ULONG (ST) = argReg.Byte4;
EVAL_PTR_SEG (ST) = 0;
ADDR_IS_OFF32 ( EVAL_PTR (ST)) = TRUE;
ADDR_IS_FLAT ( EVAL_PTR (ST)) = TRUE;
ADDR_IS_LI( EVAL_PTR (ST)) = FALSE;
}
else {
len = EVAL_VALLEN(ST);
/*
* Check for primitive lengths
*/
if (CV_IS_PRIMITIVE (EVAL_TYP (ST)) ||
(EVAL_IS_CLASS (ST) && (len <= 4) && (len != 3))) {
if (len <= 2) {
EVAL_USHORT(ST) = argReg.Byte2;
} else {
EVAL_ULONG (ST) = argReg.Byte4;
}
} else {
EVAL_SYM_OFF (ST) = argReg.Byte4;
EVAL_SYM_SEG (ST) = 0;
ADDR_IS_LI (EVAL_SYM (ST)) = FALSE;
if (GetDebuggeeBytes(EVAL_SYM(ST), EVAL_VALLEN(ST),
(char *)&EVAL_VAL(ST), EVAL_TYP(ST))
!= (UINT)EVAL_VALLEN(ST)) {
pExState->err_num = ERR_PTRACE;
return FALSE;
}
}
}
return (TRUE);
} /* StoreAlpha() */
/** StoreP - store return value for pascal call
*
* fSuccess = StoreP ();
*
* Entry ST = pointer to node describing return value
*
* Exit return value stored
*
* Returns TRUE if return value stored without error
* FALSE if error during store
*/
LOCAL bool_t NEAR PASCAL StoreP ()
{
SHREG argReg;
#pragma message ("Pascal call needs to have 32-bit work done")
if (EVAL_IS_PTR (ST)) {
argReg.hReg = ((CV_REG_DX << 8) | CV_REG_AX);
GetReg (&argReg, pCxt);
EVAL_PTR_OFF (ST) = argReg.Byte2;
if (EVAL_VALLEN (ST) > 2) {
EVAL_PTR_SEG (ST) = argReg.Byte2High;
}
if (EVAL_IS_NPTR (ST) || EVAL_IS_NPTR32 (ST)) {
// for near pointer, pointer DS:AX
EVAL_PTR_SEG (ST) = pExState->frame.DS;
}
}
else if (CV_TYPE (EVAL_TYP (ST)) == CV_REAL) {
// read real return value from the value pointed to by either
// DS:AX (near) or DX:AX (far)
// if (EVAL_IS_NFCN (ST)) {
// for near return, pointer to return variable is DS:AX
argReg.hReg = (CV_REG_DS << 8) | CV_REG_AX;
// }
// else {
// for far return, pointer to return variable is DX:AX
// argReg.hReg = ((CV_REG_DX << 8) | CV_REG_AX);
// }
GetReg (&argReg, pCxt); // M00FLAT32
EVAL_SYM_SEG (ST) = argReg.Byte2High;
EVAL_SYM_OFF (ST) = argReg.Byte2;
ADDR_IS_LI (EVAL_SYM (ST)) = FALSE;
if (GetDebuggeeBytes (EVAL_SYM (ST), EVAL_VALLEN (ST),
(char FAR *)&EVAL_DOUBLE (ST), EVAL_TYP(ST)) != (UINT)EVAL_VALLEN (ST)) {
return (FALSE);
}
#if 0
if (EVAL_TYP (ST) == T_REAL32) {
CastNode (ST, T_REAL64, T_REAL64);
}
#endif
}
else if ((EVAL_TYP (ST) == T_CHAR) || (EVAL_TYP (ST) == T_RCHAR)) {
argReg.hReg = CV_REG_AL;
GetReg (&argReg, pCxt);
EVAL_SHORT (ST) = argReg.Byte1;
}
else if (EVAL_TYP (ST) == T_UCHAR) {
argReg.hReg = CV_REG_AL;
GetReg (&argReg, pCxt);
EVAL_USHORT (ST) = argReg.Byte1;
}
else {
argReg.hReg = ((CV_REG_DX << 8) | CV_REG_AX);
GetReg (&argReg, pCxt);
EVAL_USHORT (ST) = argReg.Byte2;
if (EVAL_VALLEN (ST) > 2) {
*(((ushort FAR *)&(EVAL_ULONG (ST))) + 1) = argReg.Byte2High;
}
if (EVAL_IS_PTR (ST) && (EVAL_IS_NPTR (ST) || EVAL_IS_NPTR32(ST))) {
// for near pointer, pointer DS:AX
EVAL_PTR_SEG (ST) = pExState->frame.DS;
}
}
return (TRUE);
}
/** PushUserValue - push value onto user stack
*
* fSuccess = PushUserValue (pv, pa, pspReg, pmaxSP)
*
* Entry pv = pointer to value
* pa = pointer to argument data describing stack offset
* spReg = pointer to register packet for stack pointer
* pmaxSP = pointer to location to store maximum SP relative offset
*
* Exit value pushed onto user stack
*
* Returns TRUE if value pushed
* FALSE if error in push
*/
LOCAL bool_t NEAR PASCAL PushUserValue (peval_t pv, pargd_t pa, SHREG FAR *pspReg, UOFFSET FAR *pmaxSP)
{
ADDR addrStk;
uint offsize;
*pmaxSP = max (*pmaxSP, pa->SPoff);
addrStk = EVAL_SYM (pv);
addrStk.addr.seg = pExState->frame.SS; //M00FLAT32
if (ADDR_IS_OFF32(*SHpADDRFrompCXT(pCxt))) {
addrStk.addr.off = pspReg->Byte4 - pa->SPoff;
ADDR_IS_FLAT(addrStk) = TRUE;
} else {
addrStk.addr.off = pspReg->Byte2 - pa->SPoff;
ADDR_IS_FLAT(addrStk) = FALSE;
}
ADDR_IS_LI (addrStk) = FALSE;
if (EVAL_IS_PTR (pv)) {
// since pointers are stored strangely, we have to put them
// in two pieces. First we store the offset (16 or 32 bits)
if (ADDR_IS_LI (EVAL_PTR (pv))) {
SHFixupAddr (&EVAL_PTR (pv));
}
offsize = ADDR_IS_FLAT(addrStk) ? sizeof (CV_uoff32_t): sizeof (CV_uoff16_t);
if (PutDebuggeeBytes (addrStk, offsize, &EVAL_PTR_OFF (pv),
(ADDR_IS_FLAT(addrStk). ? T_USHORT: T_ULONG)) == offsize) {
if (EVAL_IS_NPTR (pv) || EVAL_IS_NPTR32 (pv)) {
return (TRUE);
}
else {
addrStk.addr.off += offsize;
if (PutDebuggeeBytes (addrStk, sizeof (_segment),
(char FAR *)&EVAL_PTR_SEG (pv), T_SEGMENT) == sizeof (_segment)) {
return (TRUE);
}
}
}
}
else {
if (PutDebuggeeBytes (addrStk, pa->vallen,
(char FAR *)&EVAL_VAL (pv), EVAL_TYP(pv)) == (UINT)pa->vallen) {
return (TRUE);
}
}
pExState->err_num = ERR_PTRACE;
return (FALSE);
}
/** PushOffset - push address value for pascal and fastcall
*
* fSuccess = PushOffset (offset, pspReg, pmaxSP, size);
*
* Entry offset = offset from user's SP of return value
* pspReg = pointer to register structure for SP
* pmaxSP = pointer to location to store maximum SP relative offset
* size = size in bytes of value to be pushed
*
* Exit
*
* Returns TRUE if offset pushed
* FALSE if error
*
* Note Can be used to push segment also
*/
LOCAL bool_t NEAR PASCAL PushOffset (UOFFSET offset, SHREG FAR *pspReg,
UOFFSET FAR *pmaxSP, uint size)
{
ADDR addrStk = {0};
*pmaxSP += size;
addrStk.addr.seg = pExState->frame.SS;
if (size == 2) {
addrStk.addr.off = pspReg->Byte2 - *pmaxSP;
} else {
addrStk.addr.off = pspReg->Byte4 - *pmaxSP;
}
if (PutDebuggeeBytes (addrStk, size, (char FAR *)&offset,
T_USHORT) == size) {
return (TRUE);
}
else {
pExState->err_num = ERR_PTRACE;
return (FALSE);
}
}
/*** StructElem - Extract a structure element from stack
*
* fSuccess = StructElem (bn)
*
* Entry bn = based pointer to operator node
* ST = address of struct (initial this address)
*
* Exit ST = value node for member
*
* Returns TRUE if successful
* FALSE if error
*
*/
LOCAL bool_t NEAR FASTCALL StructElem (bnode_t bnOp)
{
peval_t pvOp;
peval_t pvR;
bnode_t bnR;
char FAR *pS;
pvOp = &pnodeOfbnode(bnOp)->v[0];
bnR = NODE_RCHILD (pnodeOfbnode(bnOp));
pvR = &pnodeOfbnode(bnR)->v[0];
if (EVAL_IS_MEMBER (pvOp) == FALSE) {
pExState->err_num = ERR_NEEDLVALUE;
return (FALSE);
}
SetNodeType (ST, EVAL_TYP (pvR));
EVAL_VALLEN (ST) = (ushort)TypeSize (ST);
pS = (char FAR *)&EVAL_VAL (ST);
pS += MEMBER_OFFSET (pvOp);
_fmemmove (&EVAL_VAL (ST), pS, EVAL_VALLEN (ST));
return (TRUE);
}
/*** StructEval - Perform a structure access (., ->, ::, .*, ->*)
*
* fSuccess = StructEval (bn)
*
* Entry bn = based pointer to operator node
* ST = address of struct (initial this address)
*
* Exit ST = value node for member
*
* Returns TRUE if successful
* FALSE if error
*
*/
LOCAL bool_t NEAR FASTCALL StructEval (bnode_t bn)
{
peval_t pv;
peval_t pvR;
bnode_t bnR;
CV_typ_t typ;
bool_t retval;
eval_t evalT;
peval_t pvT;
if (EVAL_IS_REF (ST)) {
if (!FetchOp (ST)) {
return (FALSE);
}
EVAL_IS_REF (ST) = FALSE;
}
// point to the eval_t field of the operator node. This field will
// contain the data needed to adjust the this pointer (*ST). For
// any structure reference (., ->, ::, .*, ->*), the stack top is
// the initial value of the this pointer
pv = &pnodeOfbnode(bn)->v[0];
DASSERT (EVAL_IS_MEMBER (pv));
if (MEMBER_THISEXPR (pv) == 0) {
*pvThis = *ST;
}
else if (Eval ((bnode_t)MEMBER_THISEXPR (pv)) == FALSE) {
return (FALSE);
}
if ((MEMBER_VBASE (pv) == TRUE) || (MEMBER_IVBASE (pv) == TRUE)) {
if (CalcThisExpr (MEMBER_VBPTR (pv), MEMBER_VBPOFF (pv),
MEMBER_VBIND (pv), MEMBER_TYPE (pv)) == FALSE) {
return (FALSE);
}
}
*ST = *pvThis;
if (!OP_IS_IDENT (NODE_OP (pnodeOfbnode(NODE_RCHILD (pnodeOfbnode(bn)))))) {
if ((retval = EvalRChild (bn)) == FALSE) {
return (FALSE);
}
}
else {
bnR = NODE_RCHILD (pnodeOfbnode(bn));
pvR = &pnodeOfbnode(bnR)->v[0];
if (EVAL_IS_STMEMBER (pvR)) {
*ST = *pvR;
return (TRUE);
}
else if (EVAL_IS_METHOD (pvR)) {
if ((FCN_PROPERTY (pvR) == CV_MTvirtual) ||
(FCN_PROPERTY (pvR) == CV_MTintro)) {
pvT = &evalT;
*pvT = *pvThis;
SetNodeType (pvT, FCN_VFPTYPE (pvR));
if (VFuncAddress (pvT, (FCN_VTABIND (pvR))) == FALSE) {
return (FALSE);
}
else {
*ST = *pvR;
EVAL_SYM (ST) = EVAL_PTR (pvT);
}
}
else {
*ST = *pvR;
}
return (TRUE);
}
else {
EVAL_SYM_OFF (ST) += MEMBER_OFFSET (pv);
typ = EVAL_TYP (pvR);
return (SetNodeType (ST, typ));
}
}
}
/** VFuncAddress - compute virtual function address
*
* fSuccess = VFuncAddress (pv, index)
*
* Entry pv = pointer to pointer node to adjust
* index = vtshape table index
* pvThis = initial this pointer
*
* Exit pv = adjusted pointer
*
* Returns TRUE if adjustment made
* FALSE if error
*/
LOCAL bool_t NEAR PASCAL VFuncAddress (peval_t pv, ulong index)
{
eval_t evalT;
peval_t pvT;
plfVTShape pShape;
uint desc;
ulong i;
ushort shape;
ulong ob;
pvT = &evalT;
*pvT = *pv;
SetNodeType (pvT, PTR_UTYPE (pvT));
EVAL_STATE (pvT) = EV_lvalue;
if (!EVAL_IS_VTSHAPE (pvT)) {
// the only way we should get array referencing on a pointer
// is if the pointer is a vfuncptr.
DASSERT (FALSE);
return (FALSE);
}
if (!EvalUtil (OP_fetch, pv, NULL, EU_LOAD)) {
return (FALSE);
}
CLEAR_EVAL_FLAGS (pv);
EVAL_SYM_OFF (pv) = EVAL_PTR_OFF (pv);
EVAL_SYM_SEG (pv) = EVAL_PTR_SEG (pv);
EVAL_STATE (pv) = EV_lvalue;
EVAL_IS_ADDR (pv) = TRUE;
EVAL_IS_PTR (pv) = TRUE;
// now walk down the descriptor list, incrementing the pointer
// address by the size of the entry described by the shape table
pShape = (plfVTShape)(&((TYPPTR)MHOmfLock ((HDEP)EVAL_TYPDEF (pvT)))->leaf);
for (i = 0, ob = 0; ob < index; i++) {
shape = pShape->desc[i >> 1];
desc = (shape >> ((~i & 1) * 4)) & 0x0f;
switch (desc) {
case CV_VTS_near:
EVAL_SYM_OFF (pv) += sizeof (CV_uoff16_t);
ob += sizeof(CV_uoff16_t);
break;
case CV_VTS_far:
EVAL_SYM_OFF (pv) += sizeof (CV_uoff16_t) + sizeof (_segment);
ob += sizeof (CV_uoff16_t) + sizeof (_segment);
break;
case CV_VTS_near32:
EVAL_SYM_OFF (pv) += sizeof (CV_uoff32_t);
ob += sizeof (CV_uoff32_t);
break;
case CV_VTS_far32:
EVAL_SYM_OFF (pv) += sizeof (CV_uoff32_t) + sizeof(_segment);
ob += sizeof (CV_uoff32_t) + sizeof(_segment);
break;
default:
DASSERT (FALSE);
MHOmfUnLock ((HDEP)EVAL_TYPDEF (pvT));
pExState->err_num = ERR_INTERNAL;
return (FALSE);
}
}
shape = pShape->desc[i >> 1];
desc = (shape >> ((~i & 1) * 4)) & 0x0f;
MHOmfUnLock ((HDEP)EVAL_TYPDEF (pvT));
switch (desc) {
case CV_VTS_near:
EVAL_PTRTYPE (pv) = CV_PTR_NEAR;
break;
case CV_VTS_far:
EVAL_PTRTYPE (pv) = CV_PTR_FAR;
break;
case CV_VTS_near32:
EVAL_PTRTYPE (pv) = CV_PTR_NEAR32;
break;
case CV_VTS_far32:
EVAL_PTRTYPE (pv) = CV_PTR_FAR32;
break;
default:
return (FALSE);
}
if (EvalUtil (OP_fetch, pv, NULL, EU_LOAD)) {
CLEAR_EVAL_FLAGS (pv);
EVAL_IS_ADDR (pv) = TRUE;
EVAL_IS_FCN (pv) = TRUE;
return (TRUE);
}
return (FALSE);
}