diff options
Diffstat (limited to '')
-rw-r--r-- | private/windbg/eecan/debbind.c | 7616 |
1 files changed, 7616 insertions, 0 deletions
diff --git a/private/windbg/eecan/debbind.c b/private/windbg/eecan/debbind.c new file mode 100644 index 000000000..4641235ef --- /dev/null +++ b/private/windbg/eecan/debbind.c @@ -0,0 +1,7616 @@ +/* debbind.c - Expression evaluator bind routines + * + * GLOBAL + * Bind Main evaluation routine + * + * + * DESCRIPTION + * Routines to bind the expression tree. + * + */ + + +#define TY_SIGNED 0x000001 +#define TY_UNSIGNED 0x000002 +#define TY_CHAR 0x000004 +#define TY_SHORT 0x000008 +#define TY_LONG 0x000010 +#define TY_FLOAT 0x000020 +#define TY_DOUBLE 0x000040 +#define TY_SEGMENT 0x000080 +#define TY_CLASS 0x000100 +#define TY_STRUCT 0x000200 +#define TY_UNION 0x000400 +#define TY_REF 0x000800 +#define TY_NEAR 0x001000 +#define TY_FAR 0x002000 +#define TY_HUGE 0x004000 +#define TY_POINTER 0x008000 +#define TY_UDT 0x010000 +#define TY_VOID 0x020000 +#define TY_CONST 0x040000 +#define TY_VOLATILE 0x080000 +#define TY_INT 0x100000 + +#define TY_ARITH (TY_SIGNED | TY_UNSIGNED | TY_CHAR | TY_SHORT | TY_LONG | TY_FLOAT | TY_DOUBLE) +#define TY_INTEGRAL (TY_CHAR | TY_SHORT | TY_LONG | TY_INT) +#define TY_REAL (TY_FLOAT | TY_DOUBLE) +#define TY_NOTREAL (TY_SIGNED | TY_UNSIGNED | TY_CHAR | TY_SHORT | TY_INT) +#define TY_PTR (TY_NEAR | TY_FAR | TY_HUGE | TY_POINTER) +#define TY_AGGR (TY_CLASS | TY_STRUCT | TY_UNION) +#define TY_SIGN (TY_SIGNED | TY_UNSIGNED) + +#ifdef TARGET_PPC +static char szAltSymName[512]; +#endif + +struct typrec { + uchar token[10]; + unsigned long flags; +}; +static struct typrec Predef[] = { + { "\006""signed", TY_SIGNED}, + { "\010""unsigned", TY_UNSIGNED}, + { "\004""void", TY_VOID}, + { "\004""char", TY_CHAR}, + { "\003""int", TY_INT}, + { "\005""short", TY_SHORT}, + { "\004""long", TY_LONG}, + { "\005""float", TY_FLOAT}, + { "\006""double", TY_DOUBLE}, + { "\010""_segment", TY_SEGMENT}, + { "\006""struct", TY_STRUCT}, + { "\005""class", TY_CLASS}, + { "\005""union", TY_UNION}, + { "\001""*", TY_POINTER}, + { "\001""&", TY_REF}, + { "\004""near", TY_NEAR}, + { "\005""_near", TY_NEAR}, + { "\003""far", TY_FAR}, + { "\004""_far", TY_FAR}, + { "\004""huge", TY_HUGE}, + { "\005""_huge", TY_HUGE}, + { "\005""const", TY_CONST}, +#if 0 + /* + * For the present we are going to ignore the volatile keyword. This + * has some implications for C++ which we are going to ignore but + * may become importain later. We need to solve the problem of + * differning between: + * char volatile * (character is volatile) and + * char * volatile (pointer is volatile) + */ + { "\010""volatile", TY_VOLATILE}, +#else + { "\010""volatile", 0}, +#endif + { "", 0} +}; + + +// Table to map from assignment operator to evaluation operator +// Depends upon number and order of assignment operators + +CV_typ_t eqop[OP_oreq + 1 - OP_multeq] = { + OP_mult, + OP_div, + OP_mod, + OP_plus, + OP_minus, + OP_shl, + OP_shr, + OP_and, + OP_xor, + OP_or + }; + +#define Arith Arith_E +#define PlusMinus PlushMinus_E +#define PrePost PrePost_E +#define Unary Unary_E + +LOCAL bool_t FASTCALL AddrOf (bnode_t); +LOCAL bool_t FASTCALL Arith (op_t); +LOCAL bool_t BinaryOverload (bnode_t); +LOCAL bool_t FASTCALL Bind (bnode_t); +LOCAL bool_t FASTCALL BindLChild (bnode_t); +LOCAL bool_t FASTCALL BindRchild (bnode_t); +LOCAL bool_t FASTCALL BindAddrOf (bnode_t); +LOCAL bool_t FASTCALL BindBinary (bnode_t); +LOCAL bool_t FASTCALL BindArray (bnode_t); +LOCAL bool_t FASTCALL BindAssign (bnode_t); +LOCAL bool_t FASTCALL BindBang (bnode_t); +LOCAL bool_t FASTCALL BindBasePtr (bnode_t); +LOCAL bool_t FASTCALL BindByteOps(bnode_t); +LOCAL bool_t FASTCALL BindCast (bnode_t); +LOCAL bool_t FASTCALL BindConst (bnode_t); +LOCAL bool_t FASTCALL BindContext (bnode_t); +LOCAL bool_t FASTCALL BindExeContext (bnode_t); +LOCAL bool_t FASTCALL BindDot (bnode_t bn); +LOCAL bool_t FASTCALL BindFetch (bnode_t); +LOCAL bool_t FASTCALL BindFunction (bnode_t); +LOCAL bool_t FASTCALL BindDMember (bnode_t); +LOCAL bool_t FASTCALL BindPlusMinus (bnode_t); +LOCAL bool_t FASTCALL BindPMember (bnode_t); +LOCAL bool_t FASTCALL BindPointsTo (bnode_t); +LOCAL bool_t FASTCALL BindPostIncDec (bnode_t); +LOCAL bool_t FASTCALL BindPreIncDec (bnode_t); +LOCAL bool_t FASTCALL BindRelat (bnode_t); +LOCAL bool_t FASTCALL BindBScope (bnode_t); +LOCAL bool_t FASTCALL BindSegOp (bnode_t); +LOCAL bool_t FASTCALL BindSizeOf (bnode_t); +LOCAL bool_t FASTCALL BindSymbol (bnode_t); +LOCAL bool_t FASTCALL BindUnary (bnode_t); +LOCAL bool_t FASTCALL BuildType (CV_typ_t *, ulong *, ushort *, ushort *, ushort *); +LOCAL bool_t FASTCALL BindUScope (bnode_t); +LOCAL bool_t FASTCALL CastBinary (op_t); +LOCAL bool_t CastPtrToPtr (bnode_t); +LOCAL bool_t FASTCALL ContextToken (char * *, char * *, short *); +LOCAL HDEP DupETree (ushort, pstree_t *); +LOCAL bool_t FASTCALL FastCallReg (pargd_t, peval_t, ushort *); +LOCAL bool_t FASTCALL FcnCast (bnode_t bn); +LOCAL bool_t FASTCALL Fetch (void); +LOCAL bool_t FindUDT (bnode_t, peval_t, char *, char *, uchar); +LOCAL bool_t FASTCALL Function (bnode_t); +LOCAL uchar FASTCALL GetID (char *); +LOCAL bool_t FASTCALL GetStructTDef (char *, int, pnode_t); +LOCAL bool_t FASTCALL MipsCallReg (pargd_t, peval_t, uint *); +LOCAL bool_t FASTCALL AlphaCallReg (pargd_t, peval_t, uint *); +LOCAL bool_t FASTCALL PPCCallReg (pargd_t, peval_t, uint *); +LOCAL bool_t FASTCALL ParseType (bnode_t); +LOCAL bool_t FASTCALL PlusMinus(op_t); +LOCAL bool_t FASTCALL PrePost (op_t); +LOCAL bool_t FASTCALL PushCArgs (peval_t, pnode_t, UOFFSET *, int, peval_t); +LOCAL bool_t FASTCALL PushFArgs (peval_t, pnode_t, UOFFSET *, peval_t); +LOCAL bool_t FASTCALL PushMArgs (peval_t, pnode_t, UOFFSET *, peval_t); +LOCAL bool_t FASTCALL PushMArgs2 (peval_t, pnode_t, UOFFSET *, int, uint, peval_t); +LOCAL bool_t FASTCALL PushAArgs (peval_t, pnode_t, UOFFSET *, peval_t); +LOCAL bool_t FASTCALL PushAArgs2 (peval_t, pnode_t, UOFFSET *, int, uint, peval_t); +LOCAL bool_t FASTCALL PushPPCArgs (peval_t, pnode_t, UOFFSET *, peval_t); +LOCAL bool_t FASTCALL PushPPCArgs2 (peval_t, pnode_t, UOFFSET *, int, uint *, peval_t); +LOCAL bool_t FASTCALL PushPArgs (peval_t, pnode_t, UOFFSET *, peval_t); +LOCAL bool_t FASTCALL PushTArgs (peval_t, pnode_t, UOFFSET *, int, peval_t); +LOCAL bool_t FASTCALL SBitField (pnode_t); +LOCAL bool_t FASTCALL SearchRight (bnode_t); +LOCAL CV_typ_t SetImpClass (PCXT, long *); +LOCAL bool_t FASTCALL Unary (op_t); +LOCAL bool_t UnaryOverload (bnode_t); +LOCAL bool_t PointsToOverload (bnode_t); + +LOCAL bool_t FASTCALL BindError (bnode_t); +LOCAL bool_t FASTCALL BindTRUE (bnode_t); + +static bool_t BindingFuncArgs = FALSE; +bnode_t bnOp; // based node pointer when binding the right side of + // ., ->, +// Bind dispatch table + +LOCAL bool_t (FASTCALL *pBind[]) (bnode_t) = { +#define OPCNT(name, val) +#define OPCDAT(opc) +#define OPDAT(op, opfprec, opgprec, opclass, opbind, opeval, opwalk) opbind, +#include "debops.h" +#undef OPDAT +#undef OPCDAT +#undef OPCNT +}; + + + +/* + * Defines relating to the MIPS and ALPHA calling convention + * One nibble is used for each register argument position + * There are a max of four for MIPS, six for ALPHA, twenty-two + * for PPC + */ + + +#define PARAM_EMPTY 0 +#define PARAM_INT 1 +#define PARAM_FLOAT 2 +#define PARAM_DOUBLE 3 +#define PARAM_SKIPPED 4 + +#ifdef TARGET_PPC +#define IS_PARAM_TYPE(mask, n, type) ((mask[(n) >> 3] & (7 << 4*((n) & 0x7))) == type) +#else +#define IS_PARAM_TYPE(mask, n, type) ((*mask & (3 << 4*n)) == type) +#endif +#define IS_PARAM_EMPTY(mask, n) (IS_PARAM_TYPE(mask, n, PARAM_EMPTY)) +#define IS_PARAM_INT(mask, n) (IS_PARAM_TYPE(mask, n, PARAM_INT)) +#define IS_PARAM_FLOAT(mask, n) (IS_PARAM_TYPE(mask, n, PARAM_FLOAT)) +#define IS_PARAM_DOUBLE(mask, n) (IS_PARAM_TYPE(mask, n, PARAM_DOUBLE)) +#define IS_PARAM_SKIPPED(mask, n) (IS_PARAM_TYPE(mask, n, PARAM_SKIPPED)) + + +#ifdef TARGET_PPC +#define SET_PARAM_TYPE(mask, n, type) (mask[(n) >> 3] |= (type << 4*((n) & 0x7))) +#else +#define SET_PARAM_TYPE(mask, n, type) (*mask |= (type << 4*n)) +#endif +#define SET_PARAM_INT(mask, n) SET_PARAM_TYPE(mask, n, PARAM_INT) +#define SET_PARAM_FLOAT(mask, n) SET_PARAM_TYPE(mask, n, PARAM_FLOAT) +#define SET_PARAM_DOUBLE(mask, n) SET_PARAM_TYPE(mask, n, PARAM_DOUBLE) +#define SET_PARAM_SKIPPED(mask, n) SET_PARAM_TYPE(mask, n, PARAM_SKIPPED) + +#if DBG +ULONG fShowNodes; +void +PrintNodeOp( + int NodeOp + ) +{ + char *szName; + + switch (NodeOp) { + case OP_addrof : szName = "OP_addrof \n"; break; + case OP_lbrack : szName = "OP_lbrack \n"; break; + case OP_eq : szName = "OP_eq \n"; break; + case OP_multeq : szName = "OP_multeq \n"; break; + case OP_diveq : szName = "OP_diveq \n"; break; + case OP_modeq : szName = "OP_modeq \n"; break; + case OP_pluseq : szName = "OP_pluseq \n"; break; + case OP_minuseq : szName = "OP_minuseq \n"; break; + case OP_shleq : szName = "OP_shleq \n"; break; + case OP_shreq : szName = "OP_shreq \n"; break; + case OP_andeq : szName = "OP_andeq \n"; break; + case OP_xoreq : szName = "OP_xoreq \n"; break; + case OP_oreq : szName = "OP_oreq \n"; break; + case OP_bscope : szName = "OP_bscope \n"; break; + case OP_bang : szName = "OP_bang \n"; break; + case OP_baseptr : szName = "OP_baseptr \n"; break; + case OP_mult : szName = "OP_mult \n"; break; + case OP_div : szName = "OP_div \n"; break; + case OP_mod : szName = "OP_mod \n"; break; + case OP_shl : szName = "OP_shl \n"; break; + case OP_shr : szName = "OP_shr \n"; break; + case OP_and : szName = "OP_and \n"; break; + case OP_xor : szName = "OP_xor \n"; break; + case OP_or : szName = "OP_or \n"; break; + case OP_andand : szName = "OP_andand \n"; break; + case OP_oror : szName = "OP_oror \n"; break; + case OP_caststar : szName = "OP_caststar \n"; break; + case OP_castplus : szName = "OP_castplus \n"; break; + case OP_castminus : szName = "OP_castminus \n"; break; + case OP_castamp : szName = "OP_castamp \n"; break; + case OP_by : szName = "OP_by \n"; break; + case OP_wo : szName = "OP_wo \n"; break; + case OP_dw : szName = "OP_dw \n"; break; + case OP_cast : szName = "OP_cast \n"; break; + case OP_const : szName = "OP_const \n"; break; + case OP_context : szName = "OP_context \n"; break; + case OP_dotmember : szName = "OP_dotmember \n"; break; + case OP_dot : szName = "OP_dot \n"; break; + case OP_endofargs : szName = "OP_endofargs \n"; break; + case OP_grouped : szName = "OP_grouped \n"; break; + case OP_thisinit : szName = "OP_thisinit \n"; break; + case OP_thisconst : szName = "OP_thisconst \n"; break; + case OP_thisexpr : szName = "OP_thisexpr \n"; break; + case OP_noop : szName = "OP_noop \n"; break; + case OP_lparen : szName = "OP_lparen \n"; break; + case OP_rparen : szName = "OP_rparen \n"; break; + case OP_lcurly : szName = "OP_lcurly \n"; break; + case OP_rcurly : szName = "OP_rcurly \n"; break; + case OP_incr : szName = "OP_incr \n"; break; + case OP_decr : szName = "OP_decr \n"; break; + case OP_arg : szName = "OP_arg \n"; break; + case OP_fcnend : szName = "OP_fcnend \n"; break; + case OP_rbrack : szName = "OP_rbrack \n"; break; + case OP_lowprec : szName = "OP_lowprec \n"; break; + case OP_comma : szName = "OP_comma \n"; break; + case OP_execontext : szName = "OP_execontext \n"; break; + case OP_fetch : szName = "OP_fetch \n"; break; + case OP_function : szName = "OP_function \n"; break; + case OP_identFunc : szName = "OP_identFunc \n"; break; + case OP_pmember : szName = "OP_pmember \n"; break; + case OP_plus : szName = "OP_plus \n"; break; + case OP_minus : szName = "OP_minus \n"; break; + case OP_pointsto : szName = "OP_pointsto \n"; break; + case OP_postinc : szName = "OP_postinc \n"; break; + case OP_postdec : szName = "OP_postdec \n"; break; + case OP_preinc : szName = "OP_preinc \n"; break; + case OP_predec : szName = "OP_predec \n"; break; + case OP_lt : szName = "OP_lt \n"; break; + case OP_lteq : szName = "OP_lteq \n"; break; + case OP_gt : szName = "OP_gt \n"; break; + case OP_gteq : szName = "OP_gteq \n"; break; + case OP_eqeq : szName = "OP_eqeq \n"; break; + case OP_bangeq : szName = "OP_bangeq \n"; break; + case OP_segop : szName = "OP_segop \n"; break; + case OP_segopReal : szName = "OP_segopReal \n"; break; + case OP_sizeof : szName = "OP_sizeof \n"; break; + case OP_ident : szName = "OP_ident \n"; break; + case OP_hsym : szName = "OP_hsym \n"; break; + case OP_this : szName = "OP_this \n"; break; + case OP_Opmember : szName = "OP_Opmember \n"; break; + case OP_Orightequal : szName = "OP_Orightequal \n"; break; + case OP_Oleftequal : szName = "OP_Oleftequal \n"; break; + case OP_Ofunction : szName = "OP_Ofunction \n"; break; + case OP_Oarray : szName = "OP_Oarray \n"; break; + case OP_Oplusequal : szName = "OP_Oplusequal \n"; break; + case OP_Ominusequal : szName = "OP_Ominusequal \n"; break; + case OP_Otimesequal : szName = "OP_Otimesequal \n"; break; + case OP_Odivequal : szName = "OP_Odivequal \n"; break; + case OP_Opcentequal : szName = "OP_Opcentequal \n"; break; + case OP_Oandequal : szName = "OP_Oandequal \n"; break; + case OP_Oxorequal : szName = "OP_Oxorequal \n"; break; + case OP_Oorequal : szName = "OP_Oorequal \n"; break; + case OP_Oshl : szName = "OP_Oshl \n"; break; + case OP_Oshr : szName = "OP_Oshr \n"; break; + case OP_Oequalequal : szName = "OP_Oequalequal \n"; break; + case OP_Obangequal : szName = "OP_Obangequal \n"; break; + case OP_Olessequal : szName = "OP_Olessequal \n"; break; + case OP_Ogreatequal : szName = "OP_Ogreatequal \n"; break; + case OP_Oandand : szName = "OP_Oandand \n"; break; + case OP_Ooror : szName = "OP_Ooror \n"; break; + case OP_Oincrement : szName = "OP_Oincrement \n"; break; + case OP_Odecrement : szName = "OP_Odecrement \n"; break; + case OP_Opointsto : szName = "OP_Opointsto \n"; break; + case OP_Oplus : szName = "OP_Oplus \n"; break; + case OP_Ominus : szName = "OP_Ominus \n"; break; + case OP_Ostar : szName = "OP_Ostar \n"; break; + case OP_Odivide : szName = "OP_Odivide \n"; break; + case OP_Opercent : szName = "OP_Opercent \n"; break; + case OP_Oxor : szName = "OP_Oxor \n"; break; + case OP_Oand : szName = "OP_Oand \n"; break; + case OP_Oor : szName = "OP_Oor \n"; break; + case OP_Otilde : szName = "OP_Otilde \n"; break; + case OP_Obang : szName = "OP_Obang \n"; break; + case OP_Oequal : szName = "OP_Oequal \n"; break; + case OP_Oless : szName = "OP_Oless \n"; break; + case OP_Ogreater : szName = "OP_Ogreater \n"; break; + case OP_Ocomma : szName = "OP_Ocomma \n"; break; + case OP_Onew : szName = "OP_Onew \n"; break; + case OP_Odelete : szName = "OP_Odelete \n"; break; + case OP_typestr : szName = "OP_typestr \n"; break; + case OP_uscope : szName = "OP_uscope \n"; break; + case OP_tilde : szName = "OP_tilde \n"; break; + case OP_negate : szName = "OP_negate \n"; break; + case OP_uplus : szName = "OP_uplus \n"; break; + default : szName = "UNKNOWN \n"; break; + } + OutputDebugString(szName); +} + +#endif // DBG + +/*** DoBind - bind evaluation tree tree + * + * DoBind is the public entry to this module. The bind copy of the + * parsed expression is initialized and the tree is bound in a + * leftmost bottom up order. + * + * error = DoBind (phTM, pcxt, flags) + * + * Entry phTM = pointer to handle for TM + * pcxt = pointer to context packet + * flags.fForceBind = TRUE if bind to be forced + * flags.fForceBind = FALSE if rebind decision left to binder + * flags.fEnableProlog = TRUE if function scope searched during prolog + * flags.fEnableProlog = FALSE if function scope not searched during prolog + * flags.fSupOvlOps = FALSE if overloaded operator search enabled + * flags.fSupOvlOps = TRUE if overloaded operator search suppressed + * flags.fSupBase = FALSE if base searching is not suppressed + * flags.fSupBase = TRUE if base searching is suppressed + * + * Exit pExState->hETree = handle of bound evaluation tree + * pExState->hETree->estacksize = size of evaluation stack + * pExState->state.eval_ok = FALSE + * pExState->state.bind_ok = TRUE if no errors + * + * Returns EENOERROR if syntax tree bound without error + * EENOMEMORY if unable to allocate memory + * EEGENERAL if error in bind (pExState->err_num = error) + */ + + +EESTATUS +DoBind ( + PHTM phTM, + PCXT pcxt, + uint flags + ) +{ + pstree_t pSTree; + ushort error = EENOERROR; + int excess; + + // lock the expression state structure and copy the context package + + DASSERT (*phTM != 0); + if (*phTM == 0) { + return (EECATASTROPHIC); + } + DASSERT (*phTM != 0); + if (hEStack == 0) { + if ((hEStack = MHMemAllocate (ESTACK_DEFAULT * sizeof (elem_t))) == 0) { + return (EECATASTROPHIC); + } + StackLen = (uint) (ESTACK_DEFAULT * sizeof (elem_t)); + } + pEStack = MHMemLock (hEStack); + DASSERT(pExState == NULL); + pExState = MHMemLock (*phTM); + pExState->state.fEProlog = (ushort) ((flags & BIND_fEnableProlog) == BIND_fEnableProlog); + pExState->state.fSupOvlOps = (ushort) ((flags & BIND_fSupOvlOps) == BIND_fSupOvlOps); + pExState->state.fSupBase = (ushort) ((flags & BIND_fSupBase) == BIND_fSupBase); + pExState->state.fFunction = FALSE; + if (pExState->state.parse_ok == TRUE) { + pExState->err_num = 0; + pExState->cxt = *pcxt; + if ((pExState->state.bind_ok == FALSE) || + ((flags & BIND_fForceBind) == BIND_fForceBind) || + (pExState->state.nullcontext == TRUE)) { + // the expression has not been successfully bound, the caller + // has forced the bind or the expression contains a null + // context {} that forces a bind. If none of these cases are + // true, then we can exit without rebinding + + pExState->state.bind_ok = FALSE; + pExState->state.eval_ok = FALSE; + if (pExState->hETree != 0) { + // free current evaluation tree if it exists + MHMemFree (pExState->hETree); + } + + // lock syntax tree and copy to evaluation tree for binding + + DASSERT ( pExState->hSTree != 0 ); + pSTree = MHMemLock (pExState->hSTree); + if ((pExState->hETree = MHMemAllocate (pSTree->size)) != 0) { + + // if evaluation tree is allocated, initialize and bind + + DASSERT ( pExState->hExStr != 0 ); + pExStr = MHMemLock (pExState->hExStr); + + DASSERT ( pExState->hETree != 0 ); + pTree = MHMemLock (pExState->hETree); + memcpy (pTree, pSTree, pSTree->size); + + // set pointer to context and flag fact that it is not + // a pointer into the expression tree + + pCxt = &pExState->cxt; + bnCxt = 0; + ClassExp = T_NOTYPE; + ClassImp = SetImpClass (pCxt, &ClassThisAdjust); + + // indicate that the stack is not in use by the parser + + pTree->stack_base = 0; + pTree->stack_next = 0; + + // set the evaluation stack to the default fixed buffer. + // bind will allocate a new buffer and move the pointers + // if the stack overflows. This work is effecient because + // most expressions consist of a single token. + + StackOffset = 0; + StackCkPoint = 0; + StackMax = 0; + memset (pEStack, 0, (uint)StackLen); + + // clear the stack top, stack top previous, function argument + // list pointer and based pointer to operand node + + ST = NULL; + STP = NULL; + bArgList = 0; + bnOp = 0; + if (Bind ((bnode_t)pTree->start_node) == TRUE) { + pExState->state.bind_ok = TRUE; + pExState->err_num = 0; + // set bind result in case API user asks for expression type + pExState->result = *ST; + if ((EVAL_IS_PTR (ST) == FALSE) && + ((excess = (uint)TypeSize (ST) - sizeof (val_t)) > 0)) { + // since the return value is larger than normal, we + // need to reallocate the size of the expression state + // structure to include the extra return data + + DASSERT (*phTM != 0); + MHMemUnLock (*phTM); + if ((*phTM = MHMemReAlloc (*phTM, sizeof (exstate_t) + excess)) != 0) { + + DASSERT ( *phTM != 0 ); + pExState = MHMemLock (*phTM); + memcpy (&pExState->result, ST, sizeof (eval_t)); + } + else { + + DASSERT ( *phTM != 0 ); + pExState = MHMemLock (*phTM); + pExState->err_num = ERR_NOMEMORY; + error = EEGENERAL; + } + } + if (EVAL_TYP (ST) == 0) { + error = EEGENERAL; + } + } + else { + error = EEGENERAL; + } + bArgList = 0; + bnCxt = 0; + DASSERT (pExState->hExStr != 0); + MHMemUnLock (pExState->hExStr); + DASSERT ( pExState->hETree!= 0); + MHMemUnLock (pExState->hETree); + } + else { + error = EENOMEMORY; + } + DASSERT ( pExState->hSTree!= 0); + MHMemUnLock (pExState->hSTree); + } + } + DASSERT ( *phTM != 0 ); + MHMemUnLock (*phTM); + pExState = NULL; + MHMemUnLock (hEStack); + return (error); +} + + + +/** SetImpClass - set implicit class + * + * type = SetImpClass (pCxt); + * + * Entry pCxt = pointer to context packet + * pThisAdjust = pointer to implicit this adjustor value + * + * Exit none + * + * Returns type index of implied class if context is method + * 0 if context is not method + */ + +LOCAL CV_typ_t +SetImpClass ( + PCXT pCxt, + long *pThisAdjust + ) +{ + HSYM hProc; + SYMPTR pProc; + CV_typ_t type; + CV_typ_t rettype = T_NOTYPE; + HTYPE hMFunc; + plfMFunc pMFunc; + + *pThisAdjust = 0; + if ((hProc = (HSYM)SHHPROCFrompCXT (pCxt)) != (HSYM)0) { + // the current context is within some function. Set the node + // to the type of the function and see if it is a method of a class + + pProc = (SYMPTR)MHOmfLock ((HDEP)hProc); + switch (pProc->rectyp) { + case S_LPROC16: + case S_GPROC16: + type = ((PROCPTR16)pProc)->typind; + break; + + case S_LPROC32: + case S_GPROC32: + type = ((PROCPTR32)pProc)->typind; + break; + + case S_LPROCMIPS: + case S_GPROCMIPS: + type = ((PROCPTRMIPS)pProc)->typind; + break; + + default: + DASSERT (FALSE); + MHOmfUnLock ((HDEP)hProc); + return (0); + } + MHOmfUnLock ((HDEP)hProc); +// +// MBH - bugbug - our compiler is barfing if the cast is to a HVOID, +// even though the typedef of an HTYPE is HVOID. +// + + if ((hMFunc = THGetTypeFromIndex (SHHMODFrompCXT (pCxt), type)) != (HTYPE) NULL) { + pMFunc = (plfMFunc)((&((TYPPTR)MHOmfLock ((HDEP)hMFunc))->leaf)); + if (pMFunc->leaf == LF_MFUNCTION) { + rettype = pMFunc->classtype; + *pThisAdjust = pMFunc->thisadjust; + } + MHOmfUnLock ((HDEP)hMFunc); + } + } + return (rettype); +} + + + + +/** Bind - bind a node + * + * Call the bind routine indexed by the the node type. This could + * easily be a macro but is done as a function to save code space + * + * fSuccess = Bind (bn) + * + * Entry bn = base pointer to node in evaluation tree + * + * Exit node and all children of node bound + * + * Returns TRUE if no error in bind + * FALSE if error binding node or any child of node + */ + + +LOCAL bool_t FASTCALL +Bind ( + register bnode_t bn + ) +{ +#if DBG + if (fShowNodes) { + OutputDebugString("M: "); + PrintNodeOp(NODE_OP(pnodeOfbnode(bn))); + } +#endif + return ((*pBind[NODE_OP(pnodeOfbnode(bn))])(bn)); +} + + + +/** BindLChild - bind the left child of a node + * + * Call the bind routine indexed by the the node type of the left + * child of this node. This could easily be a macro but + * is done as a function to save code space + * + * fSuccess = BindLChild (bn) + * + * Entry bn = base pointer to node in evaluation tree + * + * Exit left child and children of node bound + * + * Returns TRUE if no error in bind + * FALSE if error binding node or any child of node + */ + + + +LOCAL bool_t FASTCALL +BindLChild ( + register bnode_t bn + ) +{ + register bnode_t bnL = NODE_LCHILD (pnodeOfbnode(bn)); +#if DBG + if (fShowNodes) { + OutputDebugString("R: "); + PrintNodeOp(NODE_OP(pnodeOfbnode(bnL))); + } +#endif + + return ((*pBind[NODE_OP(pnodeOfbnode(bnL))])(bnL)); +} + + + +/** BindRChild - bind the right child of a node + * + * Call the bind routine indexed by the the node type of the right + * child of this node. This could easily be a macro but + * is done as a function to save code space + * + * fSuccess = BindRChild (bn) + * + * Entry bn = base pointer to node in evaluation tree + * + * Exit node and all children of node bound + * + * Returns TRUE if no error in bind + * FALSE if error binding left child of node or any child + */ + + + +LOCAL bool_t FASTCALL +BindRChild ( + register bnode_t bn + ) +{ + register bnode_t bnR = NODE_RCHILD (pnodeOfbnode(bn)); +#if DBG + if (fShowNodes) { + OutputDebugString("R: "); + PrintNodeOp(NODE_OP(pnodeOfbnode(bnR))); + } +#endif + + return ((*pBind[NODE_OP(pnodeOfbnode(bnR))])(bnR)); +} + + + +/** BindError - return bind error + * + * Return bind error for an attempt to bind a node. Normally this + * routine is the entry for a node type such as OP_rparen that + * should never appear in the final parse tree. + * + * FALSE = BindError (bn) + * + * Entry bn = base pointer to node in evaluation tree + * + * Exit none + * + * Returns FALSE + */ + + + +LOCAL bool_t FASTCALL +BindError ( + register bnode_t bn + ) +{ + Unreferenced( bn ); + + pExState->err_num = ERR_INTERNAL; + return (FALSE); +} + + + + +/** BindTRUE - return bind successful + * + * Return bind error for an attempt to bind a node. + * + * TRUE = BindTRUE (bn) + * + * Entry bn = base pointer to node in evaluation tree + * + * Exit none + * + * Returns TRUE + */ + + +LOCAL bool_t FASTCALL +BindTRUE ( + register bnode_t bn + ) +{ + Unreferenced( bn ); + + return (TRUE); +} + + + + +/*** BindAddrOf - Perform the address-of (&) operation + * + * fSuccess = BindAddrOf (bn) + * + * Entry pn = pointer to tree node + * + * Exit NODE_STYPE (bn) = type of stack top + * + * Returns TRUE if bind successful + * FALSE if bind error + * + * Exit pExState->err_num = error ordinal if bind error + * + */ + + +LOCAL bool_t FASTCALL +BindAddrOf ( + bnode_t bn + ) +{ + CV_typ_t type = 0; + + if (!BindLChild (bn)) { + return (FALSE); + } + if ((pExState->state.fSupOvlOps == FALSE) && EVAL_IS_CLASS (ST) && ( + CLASS_PROP (ST).ovlops == TRUE)) { + if (UnaryOverload (bn) == TRUE) { + return (TRUE); + } + } + return (AddrOf (bn)); +} + + + + +/*** BindArray - Perform an array access ([]) + * + * fSuccess = BindArray (bn) + * + * Entry bn = based pointer to node + * + * Exit ST = value of array element + * + * Returns TRUE if successful + * FALSE if error + */ + + +LOCAL bool_t FASTCALL +BindArray ( + bnode_t bn + ) +{ + eval_t evalT = {0}; + peval_t pvT; + ushort index; + plfVTShape pShape; + uint desc; + + if (BindLChild (bn) && BindRChild (bn)) { + if ((pExState->state.fSupOvlOps == FALSE) && EVAL_IS_CLASS (STP) && + (CLASS_PROP (STP).ovlops == TRUE)) { + return (BinaryOverload (bn)); + } + else + if (EVAL_IS_ARRAY (STP) || EVAL_IS_ARRAY (ST)) { + // above check is for array[3] or 3[array] + if (ValidateNodes (OP_lbrack, STP, ST) && PlusMinus (OP_plus)) { + return (Fetch ()); + } + } + else if (EVAL_IS_PTR (STP)) { + 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))) { + // we have a valid index into the shape table + // set the node to code address + pShape = (plfVTShape)(&((TYPPTR)MHOmfLock ((HDEP)EVAL_TYPDEF (pvT)))->data[0]); + desc = ((pShape->desc[index] >> 1) >> ((index & 1) * 4)) & 0x0f; + MHOmfUnLock ((HDEP)EVAL_TYPDEF (pvT)); + CLEAR_EVAL_FLAGS (STP); + EVAL_IS_ADDR (STP); + return (PopStack ()); + } + else { + if (ValidateNodes (OP_lbrack, STP, ST) && PlusMinus (OP_plus)) { + return (Fetch ()); + } + } + + } + } + return (FALSE); +} + + + + + +/*** BindAssign - Bind an assignment operation + * + * fSuccess = BindAssign (op) + * + * Entry op = operation + * + * Returns TRUE if bind successful + * FALSE if bind error + * + * Exit pExState->err_num = error ordinal if bind error + */ + + +LOCAL bool_t FASTCALL +BindAssign ( + bnode_t bn + ) +{ + CV_typ_t nop; + op_t op = NODE_OP (pnodeOfbnode(bn)); + + if (!BindLChild (bn) || !BindRChild (bn)) { + return (FALSE); + } + + // Left operand must have evaluated to an lvalue + + if (EVAL_STATE (STP) != EV_lvalue) { + pExState->err_num = ERR_NEEDLVALUE; + return (FALSE); + } + if (EVAL_IS_CLASS (STP)) { + pExState->err_num = ERR_NOCLASSASSIGN; + return (FALSE); + } + if (EVAL_IS_REF (STP)) { + RemoveIndir (STP); + } + if (EVAL_IS_REF (ST)) { + RemoveIndir (ST); + } + 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 (NODE_OP (pnodeOfbnode(bn)) == OP_eq) { + + // for simple assignment, load both nodes and do proper casting + + if (EVAL_IS_BASED (ST) && (EVAL_IS_ADDR (ST) || + (((EVAL_TYP (ST) == T_INT4) || (EVAL_TYP(ST) == T_UINT4)) && + (EVAL_ULONG (ST) != 0L)) || + (((EVAL_TYP (ST) == T_LONG) || (EVAL_TYP(ST) == T_ULONG)) && + (EVAL_ULONG (ST) != 0L)))) { + //M00KLUDGE - this should go through CastNode + if (!DeNormalizePtr (ST, STP)) { + return (FALSE); + } + } + if (EVAL_IS_BASED (STP)) { + if (!NormalizeBase (STP)) { + return (FALSE); + } + } + } + else { + // map assignment operator to arithmetic operator + // push address and value onto top of stack 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)) { + } + else if (EVAL_IS_ADDR (STP)) { + if (!EVAL_IS_ADDR (ST)) { + // M00FLAT32 - assumes equivalence between pointer and long + // M00FLAT32 - this is a problem for 32 bit model + + if (CastNode (ST, T_LONG, T_LONG) == FALSE) { + return (FALSE); + } + } + } + else if (EVAL_IS_PTR (STP)) { + if (CastNode (ST, EVAL_TYP (STP), PTR_UTYPE (STP)) == FALSE) { + return (FALSE); + } + } + else { + if (CastNode (ST, EVAL_TYP (STP), EVAL_TYP (STP)) == FALSE) { + return (FALSE); + } + } + *STP = *ST; + return (PopStack ()); + +} + + + +/*** BindBang - bind logical negation operation + * + * fSuccess = BindBang (bn) + * + * Entry bn = based pointer to node + * + * Returns TRUE if find successful + * FALSE if bind error + */ + + +LOCAL bool_t FASTCALL +BindBang ( + bnode_t bn + ) +{ + if (!BindLChild (bn)) { + return (FALSE); + } + + // we need to check for a reference to a class without losing the fact + // that this is a reference + + if (EVAL_IS_REF (ST)) { + RemoveIndir (ST); + } + if ((pExState->state.fSupOvlOps == FALSE) && EVAL_IS_CLASS (ST) && + (CLASS_PROP (ST).ovlops == TRUE)) { + return (UnaryOverload (bn)); + } + if (!ValidateNodes (OP_bang, ST, NULL)) { + 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 + + EVAL_STATE (ST) = EV_rvalue; + SetNodeType (ST, T_USHORT); + return (TRUE); +} + + + + +/*** BindBasePtr - Perform a based pointer access (:>) + * + * fSuccess = BindBasePtr (bnRight) + * + * Entry bnRight = based pointer to right operand node + * + * Exit + * + * Returns TRUE if successful + * FALSE if error + */ + + +LOCAL bool_t FASTCALL +BindBasePtr ( + bnode_t bn + ) +{ + return (BindSegOp (bn)); +} + + + + +/** BindBinary - bind an unary arithmetic operation + * + * fSuccess = BindBinary (bn) + * + * Entry bn = based pointer to node + * + * Returns TRUE if no error during evaluation + * FALSE if error during evaluation + * + */ + + +LOCAL bool_t FASTCALL +BindBinary ( + bnode_t bn + ) +{ + if (!BindLChild (bn) || !BindRChild (bn)) { + return (FALSE); + } + if (EVAL_IS_REF (STP)) { + RemoveIndir (STP); + } + if (EVAL_IS_REF (ST)) { + RemoveIndir (ST); + } + if ((pExState->state.fSupOvlOps == FALSE) && + (EVAL_IS_CLASS (ST) && (CLASS_PROP (ST).ovlops == TRUE)) || + (EVAL_IS_CLASS (STP) && (CLASS_PROP (STP).ovlops == TRUE))) { + return (BinaryOverload (bn)); + } + if (EVAL_IS_ENUM (ST)) { + SetNodeType (ST, ENUM_UTYPE (ST)); + } + if (EVAL_IS_ENUM (STP)) { + SetNodeType (STP, ENUM_UTYPE (STP)); + } + + // + // If the left hand side is a cast, patch the operator. + // + if (EVAL_STATE (STP) == EV_type) { + switch ( NODE_OP (pnodeOfbnode(bn)) ) { + case OP_mult: + NODE_OP (pnodeOfbnode(bn)) = OP_caststar; + break; + + case OP_and: + NODE_OP (pnodeOfbnode(bn)) = OP_castamp; + AddrOf( NODE_RCHILD(pnodeOfbnode(bn)) ); + break; + } + return ( CastBinary (NODE_OP (pnodeOfbnode(bn)))); + + } else { + switch ( NODE_OP (pnodeOfbnode(bn)) ) { + case OP_caststar: + NODE_OP (pnodeOfbnode(bn)) = OP_mult; + break; + + case OP_castamp: + NODE_OP (pnodeOfbnode(bn)) = OP_and; + break; + } + return (Arith (NODE_OP (pnodeOfbnode(bn)))); + } +} + + + + +/*** BindBScope - Bind binary :: scoping operator + * + * fSuccess = BindBScope (bn); + * + * Entry bn = based pointer to :: node + * + * Exit ST = evaluated class::ident + * + * Returns TRUE if bind successful + * FALSE if error + */ + + +LOCAL bool_t FASTCALL +BindBScope ( + bnode_t bn + ) +{ + CV_typ_t oldClassExp; + bool_t retval; + bnode_t oldbnOp; + char *pbName; + ushort len; + CV_typ_t CurClass; + HTYPE hBase; // handle to type record for base class + uchar *pField; // pointer to field list + char *pc; + uint tSkip; + ushort cmpflag; + peval_t pv; + bool_t fGlobal = FALSE; + search_t Name; + HR_t sRet; + CV_typ_t oldClassImp; + bnode_t OldArgList; + + // bind the left child using the current explicit class. + // set the explicit class to the type of the left child and + // bind the right hand side. Then move the right hand bind + // result over the left hand bind result and discard the stack + // top. This has the effect of bubbling the result of the right + // hand bind to the top. + + // first we must check for pClass->Class::member or Class.Class::member + + pv = &pnodeOfbnode(NODE_LCHILD (pnodeOfbnode(bn)))->v[0]; + pbName = pExStr + EVAL_ITOK (pv); + len = EVAL_CBTOK (pv); + if (bnOp != 0) { + if ((ClassExp != T_NOTYPE) || (ClassImp != T_NOTYPE)) { + if (ClassExp != T_NOTYPE) { + // search an explicit class + CurClass = ClassExp; + } + else if (ClassImp != T_NOTYPE) { + CurClass = ClassImp; + } + + // check to see if the left operand is the same class as the current + // explicit or implicit class + + if ((hBase = THGetTypeFromIndex (pCxt->hMod, CurClass)) == 0) { + pExState->err_num = ERR_BADOMF; + return (FALSE); + } + pField = (uchar *)(&((TYPPTR)MHOmfLock ((HDEP)hBase))->leaf); + tSkip = offsetof (lfClass, data[0]); + RNumLeaf (pField + tSkip, &tSkip); + pc = (char *)pField + tSkip; + if (len == (ushort)*pc) { + if (pExState->state.fCase == TRUE) { + cmpflag = strncmp (pbName, pc + 1, len); + } + else { + cmpflag = _strnicmp (pbName, pc + 1, len); + } + } + MHOmfUnLock ((HDEP)hBase); + if (cmpflag == 0) { + if (pvThisFromST (bnOp) == FALSE) { + return (FALSE); + } + PushStack (ST); + EVAL_STATE (ST) = EV_type; + goto found; + } + } + else { + fGlobal = TRUE; + } + } + + OldArgList = bArgList; + bArgList =0; + + if (BindLChild (bn) == FALSE) { + if (fGlobal == FALSE) { + // we searched an explicit or implicit class scope and did + // not find the left operand. we now must search outwards + // and find only global symbols + + oldClassImp = ClassImp; + ClassImp = T_NOTYPE; + InitSearchSym (NODE_LCHILD (pnodeOfbnode(bn)), + &(pnodeOfbnode(NODE_LCHILD (pnodeOfbnode(bn)))->v[0]), &Name, + T_NOTYPE, SCP_module | SCP_global, CLS_defn); + sRet = SearchSym (&Name); + ClassImp = oldClassImp; + switch (sRet) { + case HR_rewrite: + case HR_error: + case HR_ambiguous: + case HR_notfound: + return (FALSE); + + case HR_found: + // The symbol was in global scope and pushed onto + // the stack + fGlobal = TRUE; + break; + } + } + else { + // we did not find the symbol at global scope + return (FALSE); + } + } + else { + fGlobal = TRUE; + } + bArgList = OldArgList; + +found: + if (fGlobal == TRUE) { + // flag the fact that the left operand was not a nested type + pv = &(pnodeOfbnode(NODE_LCHILD (pnodeOfbnode(bn))))->v[0]; + CLASS_GLOBALTYPE (pv) = TRUE; + EVAL_IS_MEMBER (&pnodeOfbnode(bn)->v[0]) = TRUE; + } + if ((EVAL_STATE (ST) != EV_type) || (!EVAL_IS_CLASS (ST))) { + pExState->err_num = ERR_BSCOPE; + return (FALSE); + } + oldClassExp = ClassExp; + ClassExp = EVAL_TYP (ST); + oldbnOp = bnOp; + bnOp = bn; + if ((retval = BindRChild (bn)) == FALSE) { + return (FALSE); + } + ClassExp = oldClassExp; + bnOp = oldbnOp; + if (retval == TRUE) { + if ((fGlobal == TRUE) && + (bnOp == 0) && + (EVAL_IS_METHOD (ST) == FALSE) && + (EVAL_IS_STMEMBER (ST) == FALSE)) { + pExState->err_num = ERR_NOTSTATIC; + return (FALSE); + } + if ((EVAL_IS_METHOD (ST) == TRUE) && (FCN_NOTPRESENT (ST) == TRUE)) { + pExState->err_num = ERR_METHODNP; + return (FALSE); + } + *STP = *ST; + return (PopStack ()); + } + return (retval); +} + + + + +/*** BindByteOps - Handle 'by', 'wo' and 'dw' operators + * + * fSuccess = BindByteOps (op) + * + * Entry op = operator (OP_by, OP_wo or OP_dw) + * + * Exit + * + * 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. + * + * NOTES + */ + + +LOCAL bool_t FASTCALL +BindByteOps ( + bnode_t bn + ) +{ + op_t op; + CV_typ_t type; + + if (!BindLChild (bn)) { + return (FALSE); + } + + // Resolve identifiers and do type checking. + + if (!ValidateNodes (op = NODE_OP (pnodeOfbnode(bn)), ST, NULL)) { + return(FALSE); + } + + // If the operand is an lvalue and it is a register, + // load the value of the register. If the operand is an + // lvalue and is not a register, 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 the value is a register, the code below will set up a pointer + // to the correct type and then dereference it. The evaluation phase + // will have to actually generate the pointer. + + if (!EVAL_IS_REG (ST)) { + if (AddrOf (bn) == FALSE) { + return (FALSE); + } + } + } + else if (!EVAL_IS_PTR (ST)) { + if (CastNode (ST, T_PFUCHAR, T_PFUCHAR) == FALSE) { + pExState->err_num = ERR_OPERANDTYPES; + return (FALSE); + } + } + + // Now cast the node to (char *), (int *) or + // (long *). 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 + // *) will give the result 0:8). + + type = EVAL_TYP (ST); + + //DASSERT(CV_IS_PRIMITIVE (typ)); + + if (CV_TYP_IS_REAL (type)) { + pExState->err_num = ERR_OPERANDTYPES; + return (FALSE); + } + if (op == 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 (Fetch ()); +} + + + + +/** BindCast - bind a cast + * + * fSuccess = BindCast (bn) + * + * Entry bn = based pointer to cast node + * + * Returns TRUE if bind successful + * FALSE if bind error + */ + + +LOCAL bool_t FASTCALL +BindCast ( + bnode_t bn + ) +{ + peval_t pv; + bnode_t bnLeft; + + // Bind right node which is the value + + if (!BindRChild (bn)) { + return (FALSE); + } + bnLeft = NODE_LCHILD (pnodeOfbnode(bn)); + + // Check for casting a class to anything, not having a typestring or + // the typestring containing an error + + if (EVAL_IS_CLASS (ST) || + (NODE_OP (pnodeOfbnode(bnLeft)) != OP_typestr) || + !ParseType (bnLeft)) { + pExState->err_num = ERR_TYPECAST; + return (FALSE); + } + if (EVAL_IS_BITF (ST)) { + // change the type of the node to the underlying type + EVAL_TYP (ST) = BITF_UTYPE (ST); + } + + /* + * ansi says result is an rvalue + */ + + EVAL_STATE (ST) = EV_rvalue; + + // copy the base type node up to the cast node and then try to find a + // way to cast the stack to to the base type + + if (EVAL_IS_PTR (ST) && CastPtrToPtr (bn) == TRUE) { + // the desired type is a base class so we can just set the node type. + // the value portion of bn contains the data to cast right to left + + pv = (peval_t)&pnodeOfbnode(bnLeft)->v[0]; + return (SetNodeType (ST, EVAL_TYP (pv))); + } + else { + pv = (peval_t)&pnodeOfbnode(bnLeft)->v[0]; + if (EVAL_MOD (ST) == 0) { + // this is because of (strct *)ds:0 which did not have a mod + EVAL_MOD (ST) = EVAL_MOD (pv); + } + if (EVAL_IS_PTR (pv)) { + return (CastNode (ST, EVAL_TYP (pv), PTR_UTYPE (pv))); + } + else { + return (CastNode (ST, EVAL_TYP (pv), EVAL_TYP (pv))); + } + } +} + + + + + +/*** CastPtrToPtr - cast a pointer to derived to a pointer to base + * + * fSuccess = CastPtrToPtr (bn) + * + * Entry bn = based pointer to cast node + * ST = value to cast + * + * Exit value portion of node changed to member to indicate cast data + * + * Returns TRUE if possible to cast derived to base + * FALSE if not + */ + + +LOCAL bool_t +CastPtrToPtr ( + bnode_t bn + ) +{ + static eval_t evalD = {0}; + static eval_t evalB = {0}; + peval_t pvD = &evalD; + peval_t pvB = &evalB; + search_t Name; + + *pvD = *ST; + *pvB = *((peval_t)&(pnodeOfbnode(NODE_LCHILD (pnodeOfbnode(bn))))->v[0]); + if ((SetNodeType (pvD, PTR_UTYPE (pvD)) == FALSE) || + (SetNodeType (pvB, PTR_UTYPE (pvB)) == FALSE) || + !EVAL_IS_CLASS (pvD) || + !EVAL_IS_CLASS (pvB)) { + // we do not have pointers to classes on both sides + return (FALSE); + } + InitSearchBase (bn, EVAL_TYP (pvD), EVAL_TYP (pvB), &Name, pvB); + switch (SearchSym (&Name)) { + case HR_notfound: + break; + + case HR_found: + // remove the stack entry that was pushed by successful search + return (PopStack ()); + + case HR_rewrite: + DASSERT (FALSE); + } + return (FALSE); +} + + + + +/*** BindConst - bind constant + * + * fSuccess = BindConst (bn) + * + * Entry bn = based pointer to tree node + * + * Exit ST = constant + * + * Returns TRUE if bind successful + * FALSE if bind error + * + * + */ + + +LOCAL bool_t FASTCALL +BindConst ( + bnode_t bn + ) +{ + peval_t pv = &(pnodeOfbnode(bn))->v[0]; + + // Set the type flags back into the node, copy + // the flags and value into the evaluation stack and return + // The handle to module is set so that a cast of a constant to + // a user-defined type will work. + + EVAL_MOD (pv) = SHHMODFrompCXT(pCxt); + if (BindingFuncArgs == FALSE && EVAL_TYP (pv) == T_PCHAR) { + // we are binding a string constant (ie. "foobar") but + // not for function args... this is not allowed, since + // we can never return a correct address to the string + // that we pushed on the stack + + pExState->err_num = ERR_NOTEVALUATABLE; + return (FALSE); + } + if (SetNodeType (pv, EVAL_TYP (pv)) == TRUE) { + EVAL_STATE (pv) = EV_constant; + return (PushStack (pv)); + } + else { + return (FALSE); + } +} + + +LOCAL bool_t FASTCALL +CxtHelper ( + bnode_t bn, + HMOD hMod, + HSF hsf, + int cMod, + int cProc, + char * pProc + ) +{ + bool_t error; + eval_t evalT = {0}; + PCXF nCxf; + search_t Name; + bnode_t oldAmb; + uchar oldBindingBP; + bnode_t oldbnCxt; + CV_typ_t oldClassImp; + PCXT oldCxt; + HR_t retval; + pnode_t pn; + peval_t pvT; + long oldThisAdjust; + + /* + * initialize the context packet in the node to have the same contents + * as the current context. We will then set new fields in the order + * exe, module, proc. + */ + + nCxf = (PCXF)&(pnodeOfbnode(bn))->v[0]; + *SHpCXTFrompCXF (nCxf) = *pCxt; + SHpCXTFrompCXF(nCxf)->hProc = 0; + SHpCXTFrompCXF(nCxf)->hBlk = 0; + *SHpFrameFrompCXF (nCxf) = pExState->frame; + + /* + * set new context from handle to module + */ + + if (!SHGetCxtFromHmod ( hMod, SHpCXTFrompCXF (nCxf))) { + SHGetCxtFromHexe (SHHexeFromHmod( hMod ), SHpCXTFrompCXF (nCxf)); + } + + if(cMod > 0) { + WORD rgLn[2]; + ADDR addr; + SHOFF cbLn; + + /* + * If we have a source file, then we want to get the address + * of the first line in the source file. This is obtained + * by trying to get the address of line 1, and if does not + * exist then get the address of the first line after + * line 1 in the file. + */ + + if (SLFLineToAddr (hsf, 1, &addr, &cbLn, rgLn) || + SLFLineToAddr (hsf, rgLn[1], &addr, &cbLn, NULL)) { + SHSetCxt (&addr, SHpCXTFrompCXF (nCxf)); + } + } + + if (cProc <= 0) { + + SHpCXTFrompCXF(nCxf)->hProc = 0; + SHpCXTFrompCXF(nCxf)->hBlk = 0; + + } else { + /* + * a proc was specified, initialize the context and search for + * the proc within the current context. Note that if a proc was + * not specified, the hProc and hBlk in nCxf are null. + * + * M00SYMBOL - doesn't allow for T::foo() as proc + */ + + oldCxt = pCxt; + pCxt = SHpCXTFrompCXF (nCxf); + pvT = &evalT; + EVAL_ITOK (pvT) = pProc - pExStr; + EVAL_CBTOK (pvT) = (uchar)cProc; + + /* + * do not allow ambiguous symbols during context symbol searching + */ + + oldAmb = pExState->ambiguous; + pExState->ambiguous = 0; + oldBindingBP = BindingBP; + BindingBP = FALSE; + InitSearchSym (bn, pvT, &Name, 0, + SCP_lexical | SCP_module | SCP_global, CLS_method); + retval = SearchSym (&Name); + BindingBP = oldBindingBP; + if (pExState->ambiguous != 0) { + pExState->err_num = ERR_AMBCONTEXT; + return FALSE; + } + pExState->ambiguous = oldAmb; + switch (retval) { + case HR_rewrite: + DASSERT (FALSE); + return FALSE; + + case HR_notfound: + return FALSE; + + case HR_found: + /* + * if the symbol was found, it was pushed onto the stack + */ + + PopStack (); + if (!EVAL_IS_FCN (pvT)) { + /* + * name is not a procedure reachable from + * the specified context + */ + + return FALSE; + } + } + + /* + * attempt to set the context to the specified instance of the + * function. If the attempt fails, then set the context to + * the address of the function + */ + + if (SHGetFuncCxf (&pvT->addr, nCxf) == NULL) { + if (SHSetCxt (&pvT->addr, SHpCXTFrompCXF (nCxf)) == NULL) { + return FALSE; + } + } + pCxt = oldCxt; + if (SHHPROCFrompCXT (SHpCXTFrompCXF (nCxf)) == 0) { + return FALSE; + } + } + + /* + * save old context and implicit class and set new ones + */ + + oldCxt = pCxt; + oldbnCxt = bnCxt; + oldClassImp = ClassImp; + oldThisAdjust = ClassThisAdjust; + pCxt = SHpCXTFrompCXF (nCxf); + + // BUGBUG: BRYANT-REVIEW + // Are the fixup/unfixup calls necessary for WOW? Also, should there be a + // BindingREG or BindingTLS test? + + SHFixupAddr(SHpADDRFrompCXT(pCxt)); + SHUnFixupAddr(SHpADDRFrompCXT(pCxt)); + if (BindingBP && (cMod > 0)) + pBindBPCxt = pCxt; + bnCxt = bn; + ClassImp = SetImpClass (pCxt, &ClassThisAdjust); + pn = pnodeOfbnode(bn); + pn->pcxf = nCxf; + + error = BindLChild (bn); + + /* + * if the result of the expression is bp relative, then we must + * load the value before returning to the original context + */ + + if ((error == TRUE) && + (EVAL_STATE (ST) == EV_lvalue) && + (EVAL_IS_BPREL (ST) || EVAL_IS_REGREL (ST) || EVAL_IS_TLSREL(ST))) { + if (EVAL_IS_REF (ST)) { + if (!Fetch ()) { + return (FALSE); + } + EVAL_IS_REF (ST) = FALSE; + } + EVAL_STATE (ST) = EV_rvalue; + } + + + /* + * restore previous context and implicit class + */ + + 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; + } + ClassImp = oldClassImp; + ClassThisAdjust = oldThisAdjust; + return (error); +} /* CxtHelper() */ + + +LOCAL bool_t FASTCALL +BindContext( + bnode_t bn + ) +/*++ + +Routine Description: + + This function is used to bind a Context Operator from a parsed + expression. The routine will decompose the context operator into + its parts and then attempt to resolve them againist each other and + the rest of the expression tree rooted at the current node. + + Globals used: + + pCxt - Supplies a pointer to the current Context being used to + bind the expression + bnCxt - Supplies a based pointer to the node in the expression tree + which contains the last context operator or context restriction + operator (i.e. ::). If it is NULL then we have not yet seen one. + + NOTES: + The form of the context operator is + {[[<number>] <proc>][,[<module>][,[<exe>]]]} + + where: + <number> is a base 10 instance of the procedure on the stack. + n > 0 means count from top of stack down + n < 0 means count from current stack pointer up + n = 0 means take first instance up (will find current proc) + if no number is specfied it defaults to 0. + <proc> is the name of a procedure (if overloaded then argument + types must be given to disambiguate) which is to be found + on the stack. + <module> is the name of a module name in the exe to do the search in + <exe> is the .exe or .dll name to search in. + + parenthesis may be used in any of the above to include commas, etc. + +Arguments: + + bn - Supplies a pointer to the node to be bound. + +Return Value: + + TRUE if the expression was succesfully bound and FALSE in the event + of an error. + +--*/ + +{ + int instance = 0; + bool_t isnegative = FALSE; + char * pProc; + short cProc; + char * pMod; + short cMod; + char * pExe; + short cExe; + char * pb; + HEXE hExe = 0; + HMOD hMod = 0; + char savedChar; + + /* + * Insure that the token starts correctly + */ + + pb = pExStr + EVAL_ITOK (&(pnodeOfbnode(bn))->v[0]); + if (*pb++ != '{') /* } */ { // curly in comment is for editor + goto contextbad; + } + + /* + * skip white space and process instance specification of instance number + * where the number is base 10 and can be signed + */ + + while ((*pb == ' ') || (*pb == '\t')) { + pb++; + } + if (*pb == '-') { + isnegative = TRUE; + pb++; + } + else if (*pb == '+') { + pb++; + } + while (isdigit (*pb)) { + instance = instance * 10 + (*pb++ - '0'); + } + if (isnegative) { + instance = -instance; + } + + /* + * set the pointer to the procedure and skip to a comma that is not + * enclosed in parenthesis + */ + + if (!ContextToken (&pb, &pProc, &cProc) || + !ContextToken (&pb, &pMod, &cMod) || + !ContextToken (&pb, &pExe, &cExe)) { + return (FALSE); + } + + /* + * the null context {} forces a rebind + * this is not yet supported by the kernel so I am making this + * an error to reserve the meaning for future versions + */ + + if ((cProc == -1) && (cMod == -1) && (cExe == -1)) { + goto contextbad; + } + + /* + * process exe name + */ + + if (cExe > 0) { + /* + * find the exe handle if {...,exe} was specified + */ + + savedChar = *(pExe + cExe); + *(pExe + cExe) = 0; + hExe = SHGethExeFromName (pExe); + *(pExe + cExe) = savedChar; + if (hExe == 0) { + goto contextbad; + } + + /* + * if an exe is specified, then set module to first module in exe + * this provides us with a default in case no module was + * specified. + * + * if no modules then we have a bad set of debug info, or + * no debug info. + */ + SHWantSymbols(hExe); + if ((hMod = SHGetNextMod (hExe, hMod)) == 0) { + goto contextbad; + } + } + /* + * No exe file was specified in the context string. We therefore + * need to come up with a default answer for the exe file. + * The default is just the current EXE. + * + * Note: We know that either the module or procedure was specified. + */ + else if (cExe == -1) { + if ((hMod = SHHMODFrompCXT (pCxt)) == 0) { + /* + * there is no current module so get first module + * (from an arbitrary exe?) + * + * NOTENOTE:: jimsch -- since hExe and hMod are currently + * both 0 this will return 0!!!! + */ + + if ((hExe == 0) && (cProc != -1)) { + /* + * If a process name was specified -- use some arbitray + * exe -- it will get overridden later anyway + */ + hExe = SHGetNextExe(hExe); + } + + if ((hMod = SHGetNextMod (hExe, hMod)) == 0) { + /* + * error in context + */ + goto contextbad; + } + } + + /* + * Get the EXE for the current module + */ + + if ((hExe = SHHexeFromHmod (hMod)) == 0) { + /* + * If a procedure was specified --- who cares about the + * exe name -- chose some arbitrary value --- it will get + * overridden later + */ + + if (cProc == -1) { + goto contextbad; + } + hExe = SHGetNextExe(hExe); + if (hExe == 0) { + DASSERT(FALSE); // ???? --- may be a bad assert + goto contextbad; + } + } + } + + /* + * An empty string was specified for the exe name, This is + * currently not a legal way of specifing things. + */ + else { + goto contextbad; + } + + /* + * process module specification. At this point we have the handle to the + * exe and either the handle to the first module or the handle to the + * current module + */ + + if (cMod <= 0) { + + return CxtHelper(bn, hMod, 0, cMod, cProc, pProc); + + } else { + HMOD hModTemp; + HSF hsfTemp; + + /* + * find the module handle if {...,mod...} was specified + */ + + savedChar = *(pMod + cMod); + *(pMod + cMod) = 0; + hMod = hModTemp = (HMOD) NULL; + while (hModTemp = SHGetNextMod (hExe, hModTemp)) { + if (hsfTemp = SLHsfFromFile (hModTemp, pMod)) { + if (CxtHelper(bn, hModTemp, hsfTemp, cMod, cProc, pProc)) { + *(pMod + cMod) = savedChar; + return TRUE; + } + } + } + *(pMod + cMod) = savedChar; + if (hMod == 0) { + goto contextbad; + } + } + +contextbad: + pExState->err_num = ERR_BADCONTEXT; + return (FALSE); +} + + + +LOCAL bool_t FASTCALL +BindExeContext( + bnode_t bn + ) +/*++ + +Routine Description: + + +Arguments: + + +Return Value: + + +--*/ +{ + LSZ pb; + LSZ pb1; + char ch; + HEXE hExe = 0; + HMOD hMod = 0; + + pb = pExStr + EVAL_ITOK (&(pnodeOfbnode(bn))->v[0]); + + /* + * skip white space + */ + + while ((*pb == ' ') || (*pb == '\t')) { + pb++; + } + for (pb1=pb; *pb1 && *pb1 != '!'; ) { + pb1++; + } + ch = *pb1; + *pb1 = '\0'; + hExe = SHGethExeFromModuleName (pb); + if (!hExe) { + hExe = SHGethExeFromName (pb); + } + *pb1 = ch; + + if (hExe) { + SHWantSymbols(hExe); + hMod = SHGetNextMod (hExe, hMod); + return CxtHelper(bn, hMod, 0, 0, 0, 0); + } else { + pExState->err_num = ERR_BADCONTEXT; + return FALSE; + } +} + + + +/*** BindDMember - Perform a dot member access (.*) + * + * fSuccess = BindDMember (bnRight) + * + * Entry bnRight = based pointer to right operand node + * + * Exit + * + * Returns TRUE if successful + * FALSE if error + * + */ + +LOCAL bool_t FASTCALL +BindDMember ( + bnode_t bn + ) +{ + bool_t retval; + CV_typ_t oldClassExp; + + pExState->err_num = ERR_OPNOTSUPP; + return (FALSE); + + if (!BindLChild (bn)) { + return (FALSE); + } + if (EVAL_STATE (ST) != EV_lvalue) { + pExState->err_num = ERR_NEEDLVALUE; + return (FALSE); + } + if (EVAL_IS_REF (ST)) { + if (!Fetch ()) { + return (FALSE); + } + EVAL_IS_REF (ST) = FALSE; + } + oldClassExp = ClassExp; + ClassExp = EVAL_TYP (ST); + retval = BindRChild (bn); + ClassExp = oldClassExp; + if (retval == TRUE) { + // move element descriptor to previous stack entry and pop stack + *STP = *ST; + PopStack (); + NOTTESTED (FALSE); + // M00SYMBOL - need to check that the stack top is a pointer to member + } + return (FALSE); + +} + + + + + +/*** BindDot - Perform the dot (.) operation + * + * fSuccess = BindDot (bn) + * + * Entry pn = pointer to tree node + * bnOp = based pointer to operand node + * + * Exit NODE_STYPE (bn) = type of stack top + * + * Returns TRUE if bind successful + * FALSE if bind error + * + * Exit pExState->err_num = error ordinal if bind error + * + */ + + +LOCAL bool_t FASTCALL +BindDot ( + bnode_t bn + ) +{ + bool_t retval; + CV_typ_t oldClassExp; + ushort state; + bnode_t oldbnOp; + peval_t pv; + pnode_t pn; + pnode_t pnR; + pnode_t pnL; + + if (!BindLChild (bn)) { + return (FALSE); + } + + // + // propogate the context from the left node to the right node + // + pn = pnodeOfbnode(bn); + pnL = pnodeOfbnode(NODE_LCHILD(pnodeOfbnode(bn))); + pnR = pnodeOfbnode(NODE_RCHILD(pnodeOfbnode(bn))); + if (pnL && pnR) { + pnR->pcxf = pnL->pcxf; + } + if (pnL) { + pn->pcxf = pnL->pcxf; + } + + if (EVAL_IS_REF (ST)) { + if (!Fetch ()) { + return (FALSE); + } + EVAL_IS_REF (ST) = FALSE; + } + if (!EVAL_IS_CLASS (ST)) { + pExState->err_num = ERR_NEEDSTRUCT; + return (FALSE); + } + oldClassExp = ClassExp; + ClassExp = EVAL_TYP (ST); + if ((NODE_OP (pnodeOfbnode(NODE_RCHILD (pnodeOfbnode(bn)))) == OP_bscope) || + OP_IS_IDENT (NODE_OP (pnodeOfbnode(NODE_RCHILD (pnodeOfbnode(bn)))))) { + // + // set the based node pointer for the operator + // + oldbnOp = bnOp; + bnOp = bn; + retval = BindRChild (bn); + bnOp = oldbnOp; + } + else { + pExState->err_num = ERR_SYNTAX; + retval = FALSE; + } + ClassExp = oldClassExp; + if (retval == TRUE) { + // + // move element descriptor to previous stack entry and pop stack + // + state = EVAL_STATE (STP); + *STP = *ST; + if (state == EV_type) { + EVAL_STATE (STP) = EV_type; + } + else { + EVAL_STATE (STP) = EV_lvalue; + } + + // + // Check for and correct a.b::c case + // + pn = pnodeOfbnode(NODE_RCHILD(pnodeOfbnode(bn))); + if (NODE_OP(pn) == OP_bscope) { + pv = &pnodeOfbnode(NODE_LCHILD(pn))->v[0]; + if (EVAL_IS_CLASS(pv)) { + CLASS_GLOBALTYPE(pv) = FALSE; + } + } + return (PopStack ()); + } + return (FALSE); +} + + + + + +/*** BindFetch - Bind the fetch (*) operation + * + * fSuccess = BindFetch (bn) + * + * Entry bn = based pointer to node + * + * Returns TRUE if bind successful + * FALSE if bind error + * + * Exit pExState->err_num = error ordinal if bind error + */ + + +LOCAL bool_t FASTCALL +BindFetch ( + bnode_t bn + ) +{ + pnode_t pn; + pnode_t pnL; + + + if (!BindLChild (bn)) { + return (FALSE); + } + // + // propogate the context from the left node to this node + // + pn = pnodeOfbnode(bn); + pnL = pnodeOfbnode(NODE_LCHILD(pnodeOfbnode(bn))); + if (pnL) { + pn->pcxf = pnL->pcxf; + } + + return Fetch(); +} + + + + +/** BindFunction - bind a function call and arguments + * + * fSuccess = BindFunction (bn) + * + * Entry bn = based pointer to function node + * + * Returns TRUE if bind successful + * FALSE if bind error + */ + + +LOCAL bool_t FASTCALL +BindFunction ( + bnode_t bn + ) +{ + belem_t oldStackCkPoint = StackCkPoint; + ushort len; + uint OpDot; + ushort Right; + pnode_t pn = pnodeOfbnode(bn); + + CkPointStack (); + if (Function (bn) == TRUE) { + StackCkPoint = oldStackCkPoint; + return (TRUE); + } + + ResetStack (); + StackCkPoint = oldStackCkPoint; + if (pExState->err_num != ERR_CLASSNOTFCN) { + return (FALSE); + } + + // rewrite object (arglist) as object.operator() (arglist) + + OpDot = pTree->node_next; + Right = OpDot + sizeof (node_t) + sizeof (eval_t); + len = 2 * (sizeof (node_t) + sizeof (eval_t)); + if ((ushort)(pTree->size - OpDot) < len) { + if (!GrowETree (len)) { + pExState->err_num = ERR_NOMEMORY; + return (FALSE); + } + if (bnCxt != 0) { + // the 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]); + } + } + + // set operator node to OP_dot + + pn = pnodeOfbnode(OpDot); + memset (pn, 0, sizeof (node_t) + sizeof (eval_t)); + NODE_OP (pn) = OP_dot; + NODE_LCHILD (pn) = NODE_LCHILD (pnodeOfbnode(bn)); + NODE_RCHILD (pn) = (bnode_t)Right; + NODE_LCHILD (pnodeOfbnode(bn)) = (bnode_t)OpDot; + + // insert OP_Ofunction node as right node + + pn = pnodeOfbnode((bnode_t)Right); + memset (pn, 0, sizeof (node_t) + sizeof (eval_t)); + NODE_OP (pn) = OP_Ofunction; + + pTree->node_next += len; + return (Function (bn)); +} + + + + + +/** Functions are bound assuming the following conventions: + * + * C calling sequence + * Arguments are pushed right to left. Varargs are not cast. + * If the function is a method, the this pointer is pushed after + * all of the actuals. + * + * Returns + * char al + * short ax + * long dx:ax + * float 4 bytes pointed to by ds:ax + * float 4 bytes pointed to by dx:ax + * double 8 bytes pointed to by ds:ax + * double 8 bytes pointed to by dx:ax + * long double numeric coprocessor st0 + * struct() 1|2|4 bytes dx:ax + * struct() 3 & > 4 bytes bytes pointed to by ds:ax + * struct() 3 & > 4 bytes bytes pointed to by dx:ax + * pointer ax + * pointer dx:ax + * + * pascal calling sequence + * Arguments are pushed left to right. If the return value is a + * primitive type larger than 4 bytes or is real or is any user + * defined type that is not an alias for a primitive type, then + * the caller must allocate space on the stack and push the SS + * offset of this space as a hidden argument after all of the + * of this hidden argument after all of the actual arguments + * have been pushed. If the function is a method, then the this + * pointer is pushed as the last (hidden) argument. There must + * be an exact match on the number and types of arguments (after + * conversion). This is not a supported sequence for 32-bit systems. + * + * Returns + * char al + * short ax + * long dx:ax + * float 4 bytes pointed to by hidden argument + * double 8 bytes pointed to by hidden argument + * long double 10 bytes pointed to by hidden argument + * any UDT not primitive bytes pointed to by hidden argument + * pointer ax + * pointer dx:ax + * + * fastcall - 16 calling sequence + * Arguments are pushed left to right. If the return value is a + * real type, the it is returned in the numeric coprocessor st0. + * If the return value is a user defined type that is not an alias + * for a primitive type, then the caller must allocate space on the + * stack and push the last (hidden) argument as the SS offset of + * this space. There must be an exact match on the number and types + * of arguments (after conversion). + * + * + * Returns + * char al + * short ax + * long dx:ax + * all real values numeric coprocessor st0 + * any UDT not primitive bytes pointed to by hidden argument + * pointer ax + * pointer dx:ax + * + * fastcall - 32 calling sequence + * Arguments are pushed right to left. If the return value is a + * real type, it is returned in the numeric coprocessor st0. + * If the return value is a user defined type that is not an alias + * for a primitive type, then the caller must allocate space on the + * stack and push the first (hidden) argument as the SS offset of + * this space. There must be an exact match on the number and types + * of arguments (after conversion). + * + * Returns: + * char al + * short ax + * long eax + * all real values numeric coprocessor st0 + * any UDT not primiate bytes pointed to by hidden argument + * pointer eax + * pointer not valid + * + */ + + +LOCAL bool_t FASTCALL +Function ( + bnode_t bn + ) +{ + bnode_t bnT; + pnode_t pnT; + pnode_t pnRight; + short argc = 0; + long retsize; + bnode_t OldArgList; + eval_t evalF = {0}; + peval_t pvF; + eval_t evalRet = {0}; + peval_t pvRet; + UOFFSET SPOff = 0; + bool_t retval; + pargd_t pa; + bnode_t bnRight = NODE_RCHILD (pnodeOfbnode(bn)); + BOOL fTypeArgs = FALSE; + pnode_t pnTmp = pnodeOfbnode(bn); + + // Bind argument nodes until end of arguments reached and count arguments + + // set BindingFuncArgs to true; notifies anybody who cares that + // we are binding arguments (currently only BindConst cares) + + BindingFuncArgs = TRUE; + + for (bnT = bnRight, pnTmp = pnodeOfbnode(bnT); + NODE_OP (pnodeOfbnode(bnT)) != OP_endofargs; + bnT = NODE_RCHILD (pnodeOfbnode(bnT)), pnTmp = pnodeOfbnode(bnT)) { + + // Check that this is an argument node. If not then we have an + // internal error + + if (NODE_OP (pnodeOfbnode(bnT)) != OP_arg) { + pExState->err_num = ERR_INTERNAL; + return (FALSE); + } + + argc++; + + /* + * If can't bind this child then the whole expression fails + */ + + if (!BindLChild (bnT)) { + return (FALSE); + } else { + if (EVAL_STATE (ST) == EV_type) { + /* + * Need to make sure we are not mixing and matching types + * and values + */ + + if ((argc > 1) && (!fTypeArgs)) { + pExState->err_num = ERR_MIXTYPEANDVALUE; + return FALSE; + } + + fTypeArgs = TRUE; + + if (EVAL_TYP (ST) == T_VOID) { + /* + * if the first argument is a type void, then there + * no arguments. + */ + + if (NODE_OP( pnodeOfbnode( NODE_RCHILD( pnodeOfbnode( bnT )))) != OP_endofargs) { + pExState->err_num = ERR_SYNTAX; + return (FALSE); + } else { + /* + * truncate the argument list + */ + + NODE_OP (pnodeOfbnode(bnT)) = OP_endofargs; + argc--; + break; + } + } else { + pnT = pnodeOfbnode(bnT); + pa = (pargd_t)&(pnT->v[0]); + pa->actual = EVAL_TYP (ST); + pa->flags.isconst = EVAL_IS_CONST (ST); + pa->flags.isvolatile = EVAL_IS_VOLATILE (ST); + + /* + * tell MatchArgs that the argument is a type and + * that exact match is required. + */ + + pa->flags.istype = TRUE; + } + } else { + if ((argc > 1) && (fTypeArgs)) { + pExState->err_num = ERR_MIXTYPEANDVALUE; + return FALSE; + } + + pnT = pnodeOfbnode(bnT); + pa = (pargd_t)&(pnT->v[0]); + pa->actual = EVAL_TYP (ST); + } + } + } + + /* + * reset BindingFuncArgs + */ + + BindingFuncArgs = FALSE; + + /* + * set the argument list address for overload resolution + * This is recursive because there can be function calls on the + * left hand side of the function tree + */ + + OldArgList = bArgList; + bArgList = bnRight; + + /* + * the left child must resolve to a function address + */ + + /* + * NOTENOTE - jimsch - from languages + * + * M00SYMBOL - need to make sure symbol search returns method address + * M00SYMBOL - or vtable info + */ + + retval = BindLChild (bn); + bArgList = OldArgList; + if (retval == FALSE) { + return (FALSE); + } + + pExState->state.fFunction = TRUE; + if (EVAL_STATE (ST) == EV_type) { + if (EVAL_IS_FCN (ST)) { + return (TRUE); + } + + /* + * the function name resolved to a type. we now look for the + * name as apredefined type or a UDT and attempt to cast the + * argument toargument to that type. If the cast could be + * performed, the tree was rewrittento an OP_cast + */ + + if (FCN_NOTPRESENT (ST) == TRUE) { + return (TRUE); + } + if (argc == 1) { + return (FcnCast (bn)); + } + + // we must have at least one argument for a casting function + + pExState->err_num = ERR_ARGLIST; + return (FALSE); + } + + if (EVAL_IS_AMBIGUOUS (ST)) { + pExState->err_num = ERR_AMBIGUOUS; + return (FALSE); + } + + if (FCN_NOTPRESENT (ST) == TRUE) { + pExState->err_num = ERR_METHODNP; + return (FALSE); + } + + if (EVAL_IS_PTR (ST)) { + Fetch (); + } + + if (EVAL_IS_CLASS (ST)) { + pExState->err_num = ERR_CLASSNOTFCN; + return (FALSE); + } + + if ((EVAL_STATE (ST) != EV_lvalue) || !EVAL_IS_FCN (ST)) { + pExState->err_num = ERR_SYNTAX; + return (FALSE); + } + + /* + * the stack top is the function address node. We save this information. + * The stack now contains the arguments left to right plus the function + * node. + */ + + pvF = &evalF; + *pvF = *ST; + + /* + * If we specified only types as aguments, then we really only wanted + * to get the address of the method. This means that we need to pop + * off the arguments, and push on something representing an address + */ + + if (fTypeArgs) { + for (; argc >= 0; argc--) { + if (!PopStack()) { + DASSERT(FALSE); + pExState->err_num = ERR_INTERNAL; + return FALSE; + } + } + + pnodeOfbnode(bn)->op = OP_identFunc; + SetNodeType( pvF, T_32PCHAR); + EVAL_STATE(pvF) = EV_rvalue; + return PushStack( pvF ); + } + + /* + * do the user's stack setup. On return, the OP_arg nodes will contain + * the type of the argument and the address field will contain the offset + * of the argument relative to the user's SP. If the argument type is + * zero, then the argument is a vararg and will be pushed uncasted onto + * user's stack. + */ + + pnRight = pnodeOfbnode(bnRight); + + switch (FCN_CALL (pvF)) { +#ifdef TARGET_i386 + case FCN_STD: + case FCN_C: + retval = PushCArgs (pvF, pnRight, &SPOff, 0, ST); + break; + + case FCN_PASCAL: + if (ADDR_IS_OFF32(*SHpADDRFrompCXT(pCxt))) { + pExState->err_num = ERR_CALLSEQ; + return FALSE; + } + if (argc != FCN_PCOUNT (pvF)) { + retval = FALSE; + } else { + retval = PushPArgs (pvF, pnRight, &SPOff, ST); + } + break; + + case FCN_FAST: + if (argc != FCN_PCOUNT (pvF)) { + retval = FALSE; + } else { + retval = PushFArgs (pvF, pnRight, &SPOff, ST); + } + break; + + case FCN_THIS: + if (!ADDR_IS_OFF32(*SHpADDRFrompCXT(pCxt))) { + pExState->err_num = ERR_CALLSEQ; + return FALSE; + } + retval = PushTArgs( pvF, pnRight, &SPOff, 0, ST); + break; +#endif + +#ifdef TARGET_MIPS + case FCN_MIPS: + retval = PushMArgs (pvF, pnRight, &SPOff, ST); + break; +#endif + +#ifdef TARGET_ALPHA + + case FCN_ALPHA: + retval = PushAArgs (pvF, pnRight, &SPOff, ST); + break; +#endif + +#ifdef TARGET_PPC + case FCN_PPC: + retval = PushPPCArgs (pvF, pnRight, &SPOff, ST); + break; + +#endif + + default: + pExState->err_num = ERR_CALLSEQ; + return (FALSE); + } + + if (retval == FALSE) { + pExState->err_num = ERR_FCNERROR; + return (FALSE); + } + + /* + * We pop function node and the actual arguments + */ + + for (; argc >= 0; argc--) { + if (!PopStack ()) { + DASSERT (FALSE); + pExState->err_num = ERR_INTERNAL; + return (FALSE); + } + } + + /* + * push the type of the return value from the function. If the return + * type is void, then later attempts to use the value will cause an error + */ + + pvRet = &evalRet; + *pvRet = *pvF; + SetNodeType (pvRet, FCN_RETURN (pvF)); + + if ((retsize = TypeSize (pvRet)) > MAXRETURN) { + pExState->err_num = ERR_FCNERROR; + return (FALSE); + } + + EVAL_VALLEN (pvRet) = (ushort)retsize; + EVAL_STATE (pvRet) = EV_rvalue; + + if (!PushStack (pvRet)) { + return (FALSE); + } else { + return (TRUE); + } + +} + + + + +/*** BindPlusMinus - bind binary plus or minus + * + * fSuccess = BindPlusMinus (bn) + * + * Entry bn = based pointer to tree node + * + * Exit ST = STP +- ST + * + * Returns TRUE if bind successful + * FALSE if bind error + * + * + */ + + +LOCAL bool_t FASTCALL +BindPlusMinus ( + bnode_t bn + ) +{ + if (!BindLChild (bn) || !BindRChild (bn)) { + return (FALSE); + } + if ((pExState->state.fSupOvlOps == FALSE) && + (EVAL_IS_CLASS (ST) && (CLASS_PROP (ST).ovlops == TRUE)) || + (EVAL_IS_CLASS (STP) && (CLASS_PROP (STP).ovlops == TRUE))) { + return (BinaryOverload (bn)); + } + + if (EVAL_STATE (STP) == EV_type) { + switch ( NODE_OP (pnodeOfbnode(bn)) ) { + case OP_plus: + NODE_OP (pnodeOfbnode(bn)) = OP_castplus; + break; + + case OP_minus: + NODE_OP (pnodeOfbnode(bn)) = OP_castminus; + break; + + } + return ( CastBinary (NODE_OP (pnodeOfbnode(bn)))); + + } else { + switch ( NODE_OP (pnodeOfbnode(bn)) ) { + case OP_castplus: + NODE_OP (pnodeOfbnode(bn)) = OP_plus; + break; + + case OP_castminus: + NODE_OP (pnodeOfbnode(bn)) = OP_minus; + break; + + } + return (PlusMinus (NODE_OP (pnodeOfbnode(bn)))); + } +} + + + +/*** BindPMember - Perform a pointer to member access (->*) + * + * fSuccess = BindPMember (bnRight) + * + * Entry bnRight = based pointer to node + * + * Exit + * + * Returns TRUE if successful + * FALSE if error + */ + + +LOCAL bool_t FASTCALL +BindPMember ( + bnode_t bn + ) +{ + Unreferenced(bn); + + pExState->err_num = ERR_OPNOTSUPP; + return (FALSE); +} + + + + +/*** BindPointsTo - Perform a structure access (->) + * + * fSuccess = BindPointsTo (bn) + * + * Entry bn = based pointer to node + * + * Exit + * + * Returns TRUE if successful + * FALSE if error + */ + + +LOCAL bool_t FASTCALL +BindPointsTo ( + bnode_t bn + ) +{ + eval_t evalT = {0}; + peval_t pvT; + bool_t retval; + CV_typ_t oldClassExp; + bnode_t oldbnOp; + peval_t pv; + pnode_t pn; + pnode_t pnR; + pnode_t pnL; + + + if (!BindLChild (bn)) { + return (FALSE); + } + + // + // propogate the context from the left node to the right node + // + pnL = pnodeOfbnode(NODE_LCHILD(pnodeOfbnode(bn))); + pnR = pnodeOfbnode(NODE_RCHILD(pnodeOfbnode(bn))); + if (pnL && pnR) { + pnR->pcxf = pnL->pcxf; + } + if (EVAL_IS_REF (ST)) { + RemoveIndir (ST); + } + + if (EVAL_IS_CLASS (ST)) { + return (PointsToOverload (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. + + if (!EVAL_IS_PTR (ST)) { + pExState->err_num = ERR_NOTSTRUCTPTR; + return (FALSE); + } + pvT = &evalT; + *pvT = *ST; + RemoveIndir (pvT); + if (!EVAL_IS_CLASS (pvT)) { + pExState->err_num = ERR_NEEDSTRUCT; + return (FALSE); + } + if (!Fetch ()) { + return (FALSE); + } + if (EVAL_IS_REF (ST)) { + if (!Fetch ()) { + return (FALSE); + } + EVAL_IS_REF (ST) = FALSE; + } + oldClassExp = ClassExp; + ClassExp = EVAL_TYP (ST); + oldbnOp = bnOp; + bnOp = bn; + retval = BindRChild (bn); + ClassExp = oldClassExp; + bnOp = oldbnOp; + if (retval == TRUE) { + // move element descriptor to previous stack entry and pop stack + *STP = *ST; + EVAL_STATE (STP) = EV_lvalue; + + /* + * Check for and correct a->b::c case + */ + + + pn = pnodeOfbnode(NODE_RCHILD(pnodeOfbnode(bn))); + if (NODE_OP(pn) == OP_bscope) { + pv = &pnodeOfbnode(NODE_LCHILD(pn))->v[0]; + if (EVAL_IS_CLASS(pv)) { + CLASS_GLOBALTYPE(pv) = FALSE; + } + } + return (PopStack ()); + } + return (FALSE); +} + + + + +/*** BindPostIncDec - Bind expr++ or expr-- + * + * fSuccess = BindPostIncDec (bn); + * + * Entry bn = based pointer to node + * + * Returns TRUE if successful + * FALSE if error + * + */ + + +LOCAL bool_t FASTCALL +BindPostIncDec ( + bnode_t bn + ) +{ + register op_t nop = OP_plus; + + if (NODE_OP (pnodeOfbnode(bn)) == OP_postdec) { + nop = OP_minus; + } + + // load left node and store as return value + + if (!BindLChild (bn)) { + return(FALSE); + } + if ((pExState->state.fSupOvlOps == FALSE) && EVAL_IS_CLASS (ST) && + (CLASS_PROP (ST).ovlops == TRUE)) { + return (BinaryOverload (bn)); + } + if (!ValidateNodes (nop, ST, NULL)) { + return(FALSE); + } + + /* + * Must have an lValue at this point + */ + + if (EVAL_STATE(ST) != EV_lvalue) { + pExState->err_num = ERR_NEEDLVALUE; + return FALSE; + } + + // do the post-increment or post-decrement operation and store + + return (PrePost (nop)); +} + + + + +/*** BindPreIncDec - Bind ++expr or --expr + * + * fSuccess = BindPreIncDec (op); + * + * Entry op = operator + * + * Returns TRUE if successful + * FALSE if error + * + */ + + +LOCAL bool_t FASTCALL +BindPreIncDec ( + bnode_t bn + ) +{ + register op_t nop = OP_plus; + + if (NODE_OP (pnodeOfbnode(bn)) == OP_predec) { + nop = OP_minus; + } + if (!BindLChild (bn)) { + return(FALSE); + } + if ((pExState->state.fSupOvlOps == FALSE) && EVAL_IS_CLASS (ST) && + (CLASS_PROP (ST).ovlops == TRUE)) { + return (UnaryOverload (bn)); + } + if (!ValidateNodes (nop, ST, NULL)) { + return(FALSE); + } + + /* + * Must have an lValue at this point + */ + + if (EVAL_STATE(ST) != EV_lvalue) { + pExState->err_num = ERR_NEEDLVALUE; + return FALSE; + } + + // do the increment or decrement operation and return the result + + return (PrePost (nop)); +} + + + + +/** BindRelat - bind relational and equality operations + * + * fSuccess = BindRelat (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 FASTCALL +BindRelat ( + bnode_t bn + ) +{ + if (!BindLChild (bn) || !BindRChild (bn)) { + return (FALSE); + } + + if (EVAL_IS_REF (STP)) { + RemoveIndir (STP); + } + if (EVAL_IS_REF (ST)) { + RemoveIndir (ST); + } + + if ((pExState->state.fSupOvlOps == FALSE) && + (EVAL_IS_CLASS (ST) && (CLASS_PROP (ST).ovlops == TRUE)) || + (EVAL_IS_CLASS (STP) && (CLASS_PROP (STP).ovlops == TRUE))) { + return (BinaryOverload (bn)); + } + 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)) { + // neither side is a pointer or a reference to a pointer + return (Arith (NODE_OP (pnodeOfbnode(bn)))); + } + + // Both nodes should now be typed as either or + // pointers. + + //DASSERT ((CV_TYP_IS_PTR (EVAL_TYP (STP))) && (CV_TYP_IS_PTR (EVAL_TYP (ST)))); + + // For the relational operators (<, <=, >, >=), + // only offsets are compared. For the equality operators (==, !=), + // both segments and offsets are compared. + + EVAL_STATE (STP) = EV_rvalue; + SetNodeType ((peval_t)STP, (CV_typ_t)(ADDR_IS_OFF32(*SHpADDRFrompCXT(pCxt)) ? T_LONG : T_SHORT)); + return (PopStack ()); +} + + + + +/*** BindSegOp - Handle ':' segmentation operator + * + * fSuccess = BindSegOp (bn) + * + * Entry bn = based pointer to node + * STP = segment value + * ST = offset value + * + * Returns TRUE if successful + * FALSE is error + * + * DESCRIPTION + * Both operands must have integral values (but cannot + * be long or ulong). The result of op1:op2 is a (char + * *) with segment equal to op1 and offset equal to + * op2. + */ + + +LOCAL bool_t FASTCALL +BindSegOp ( + bnode_t bn + ) +{ + /* + * OP_segop and OP_segopReal use the same validate code so + * just choose one arbitrarily + */ + + if (!BindLChild (bn) || !BindRChild (bn) || + !ValidateNodes(OP_segop, STP, ST)) { + return(FALSE); + } + + // In addition, check to make sure that neither + // operand is of type long or ulong. + + //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; + if (ADDR_IS_OFF32(*SHpADDRFrompCXT(pCxt))) { + SetNodeType ((peval_t)STP, T_32PFCHAR); + } else { + SetNodeType ((peval_t)STP, T_PFCHAR); + } + return (PopStack ()); +} + + + + + +/*** BindSizeOf - Bind sizeof operation + * + * fSuccess = BindSizeOf (bn) + * + * Entry bn = based pointer to operand node + * + * Exit + * + * Returns TRUE if successful + * FALSE if error + */ + + +LOCAL bool_t FASTCALL +BindSizeOf ( + bnode_t bn + ) +{ + bnode_t bnLeft = NODE_LCHILD (pnodeOfbnode(bn)); + CV_typ_t type; + + type = ADDR_IS_OFF32(*SHpADDRFrompCXT(pCxt)) ? T_ULONG : T_USHORT; + + if (NODE_OP (pnodeOfbnode(bnLeft)) == OP_typestr) { + // the operand of the sizeof was a type string not an expression + // we now need to parse the type string and push a type node onto + // the stack so the following code can determine the type + if (!ParseType (bnLeft)) { + pExState->err_num = ERR_SYNTAX; + return (FALSE); + } + else if (!PushStack (&(pnodeOfbnode(bnLeft))->v[0])) { + return (FALSE); + } + } + else { + if (!BindLChild (bn)) { + return (FALSE); + } + } + + // The type of the result of a sizeof operation is unsigned int + // except for huge arrays which are long to get the full length + + EVAL_STATE (ST) = EV_constant; + if (EVAL_IS_ARRAY (ST) && (PTR_ARRAYLEN (ST) > 0xffff)) { + type = T_ULONG; + } + EVAL_ULONG (ST) = TypeSize (ST); + SetNodeType (ST, type); + (pnodeOfbnode(bn))->v[0] = *ST; + return (TRUE); +} + + + + +/*** BindSymbol - bind symbol according to scope specification mask + * + * fSuccess = BindSymbol (bn) + * + * Entry bn = based pointer to tree node + * + * Exit ST = symbol + * + * Returns TRUE if bind successful + * FALSE if bind error + * + * Exit pExState->err_num = error ordinal if bind error + * + */ + + +LOCAL bool_t FASTCALL +BindSymbol ( + bnode_t bn + ) +{ + search_t Name; + token_t Tok; + peval_t pv; +#ifdef TARGET_PPC + bool_t fFirstPass = TRUE; +#endif + + if (ClassExp == T_NOTYPE) { + + // look up the identifier using the current context and + // set the symbol information. If the symbol is a typedef + // then the state will be set to EV_type. Otherwise it will + // be set to EV_lvalue + + InitSearchSym (bn, &pnodeOfbnode(bn)->v[0], &Name, ClassExp, SCP_all, CLS_defn); +#ifdef TARGET_PPC +SSStart: +#endif + switch (SearchSym (&Name)) { + case HR_rewrite: + return (Bind (bn)); + + case HR_error: + case HR_ambiguous: + return (FALSE); + + case HR_notfound: + // if symbol was not found, search for it as a primitive + if (!ParseType (bn)) { + // if the current radix is hex and the symbol potentially + // could be a number, then change the type of the node + if (ParseConst (Name.sstr.lpName, &Tok, pExState->radix) == ERR_NONE) { + if (Tok.pbEnd == + (char *)Name.sstr.lpName + Name.sstr.cb) { + pExState->err_num = ERR_NONE; + NODE_OP (pnodeOfbnode(bn)) = OP_const; + pv = &(pnodeOfbnode(bn))->v[0]; + EVAL_ULONG (pv) = VAL_ULONG (&Tok); + if (SetNodeType (pv, Tok.typ) == TRUE) { + EVAL_STATE (pv) = EV_constant; + return (PushStack (pv)); + } + } + } +#ifdef TARGET_PPC + // The first pass through didn't find the symbol. Try again, + // this time looking for the .. name. This is to fix the case + // where the linker discards the function descriptor and COFFtoCV + // wasn't able to generate a function record. + + if (fFirstPass) { + InitSearchSym (bn, &pnodeOfbnode(bn)->v[0], &Name, ClassExp, SCP_all, CLS_defn); + if (Name.sstr.cb < (sizeof(szAltSymName) - 3)) { + memcpy(szAltSymName, "..", 2); + memcpy(szAltSymName + 2, Name.sstr.lpName, Name.sstr.cb); + *(szAltSymName + 2 + Name.sstr.cb) = '\0'; + Name.sstr.lpName = szAltSymName; + Name.sstr.cb += 2; + } + fFirstPass = FALSE; + goto SSStart; + } +#endif // TARGET_PPC + pExState->err_num = ERR_UNKNOWNSYMBOL; + return (FALSE); + } + return (PushStack (&pnodeOfbnode(bn)->v[0])); + + case HR_found: + // + // if the symbol was found, it was pushed onto the stack + // + return (TRUE); + } + } + else { + + // look up the identifier using the current context and + // set the symbol information. If the symbol is a typedef + // then the state will be set to EV_type. Otherwise it will + // be set to EV_lvalue + + InitSearchRight (bnOp, bn, &Name, CLS_defn); + switch (SearchSym (&Name)) { + case HR_rewrite: + return (Bind (bn)); + + default: + case HR_ambiguous: + return (FALSE); + + case HR_notfound: + // if symbol was not found, search for it as a primitive + if (!ParseType (bn)) { + pExState->err_num = ERR_UNKNOWNSYMBOL; + return (FALSE); + } + return (PushStack (&pnodeOfbnode(bn)->v[0])); + + case HR_found: + // + // if the symbol was found, it was pushed onto the stack + // + return (TRUE); + } + } +} + + + + +/** BindUnary - bind an unary arithmetic operation + * + * fSuccess = BindUnary (bn) + * + * Entry bn = based pointer to node + * + * Returns TRUE if no error during evaluation + * FALSE if error during evaluation + * + * DESCRIPTION + * Binds 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 FASTCALL +BindUnary ( + bnode_t bn + ) +{ + if (!BindLChild (bn)) { + return (FALSE); + } + + // we need to check for a reference to a class without losing the fact + // that this is a reference + + if (EVAL_IS_REF (ST)) { + RemoveIndir (ST); + } + if ((pExState->state.fSupOvlOps == FALSE) && EVAL_IS_CLASS (ST) && + (CLASS_PROP (ST).ovlops == TRUE)) { + return (UnaryOverload (bn)); + } + if (!ValidateNodes (NODE_OP (pnodeOfbnode(bn)), ST, NULL)) { + return (FALSE); + } + return (Unary (NODE_OP (pnodeOfbnode(bn)))); +} + + + + +/*** BindUScope - Bind unary :: scoping + * + * fSuccess = BindUScope (bnRes); + * + * Entry bnRes = based pointer to unary scoping node + * + * Exit *ST = evaluated left node of pnRes + * + * Returns TRUE if evaluation successful + * FALSE if error + */ + + +LOCAL bool_t FASTCALL +BindUScope ( + bnode_t bn + ) +{ + register bool_t retval; + CXT oldCxt; + CV_typ_t oldClassImp; + + // save current context packet and set current context to module scope + + oldCxt = *pCxt; + oldClassImp = ClassImp; + SHGetCxtFromHmod (SHHMODFrompCXT (pCxt), pCxt); + // the unary scoping operator specifically means no implicit class + ClassImp = 0; + retval = BindLChild (bn); + *pCxt = oldCxt; + ClassImp = oldClassImp; + return (retval); +} + + + +/** Second level routines. These routines are called by the various + * Bind... routines. + */ + + + + +/** AddrOf - bind an address of node + * + * fSuccess = AddrOf (bn) + * + * Entry bn = based pointer to node + * + * Returns TRUE if no error during evaluation + * FALSE if error during evaluation + * + */ + +LOCAL bool_t FASTCALL +AddrOf ( + bnode_t bn + ) +{ + CV_typ_t type; + eval_t evalT = {0}; + peval_t pvT; + CV_modifier_t Mod = {0}; + + if (!ValidateNodes (OP_addrof, ST, NULL)) + return (FALSE); + + // The operand must be an lvalue and cannot be a register variable + + if ((EVAL_STATE (ST) != EV_lvalue) && (EVAL_STATE (ST) != EV_type)) { + pExState->err_num = ERR_OPERANDTYPES; + return (FALSE); + } + +// MBH - bugbug - we want to say something more intelligent to our users. +// Can we tell the world this is in a register value? +// Where is this value picked up in the evaluate stream? +// + + if (EVAL_IS_REG (ST)) { + pExState->err_num = ERR_ADDROFREG; + return (FALSE); + } + + if (EVAL_IS_PTR (ST)) { + if (EVAL_IS_REF (ST)) { + // the address of a reference is a pointer to the value + // referred to. Get a pointer of the correct type (i.e. + // a non-reference pointer) to what the reference pointer + // points to. + + EVAL_TYP( ST ) = PTR_UTYPE(ST); + } + pvT = &evalT; + ProtoPtr (pvT, ST, FALSE, Mod); + + if (MatchType (pvT, FALSE) == MTYP_none) { + // searching the context of the pointer type for a type + // record which is a pointer record and has the current + // pointer type as its underlying type has failed, set + // the type to pointer to character + + if (EVAL_IS_NPTR (ST)) { + type = T_PCHAR; + } + else if (EVAL_IS_FPTR (ST)) { + type = T_PFCHAR; + } + else if (EVAL_IS_NPTR32 (ST)) { + type = T_32PCHAR; + } + else if (EVAL_IS_FPTR32 (ST)) { + type = T_32PFCHAR; + } + else if (ADDR_IS_OFF32(*SHpADDRFrompCXT(pCxt))) { + type = T_32PCHAR; + } else { + type = T_PHCHAR; + } + } + else { + type = EVAL_TYP (pvT); + } + } + else if (CV_IS_PRIMITIVE (EVAL_TYP (ST))) { + // if the node is primitive, then a pointer to the primitive type + // can be created. We will create the pointer as a pointer + // and assume that subsequent code will cast to a pointer if + // necessary + + if (ADDR_IS_FLAT (pCxt->addr)) { + // since I am creating a pointer, I am guessing the type + // based upon the mode of the current context packet + + type = CV_NEWMODE(EVAL_TYP (ST), CV_TM_NPTR32); + } + else { + type = CV_NEWMODE(EVAL_TYP (ST), CV_TM_NPTR); + } + } + else if (EVAL_IS_CLASS (ST)) { + pvT = &evalT; + + ProtoPtr (pvT, ST, FALSE, Mod); + if (MatchType (pvT, FALSE) == MTYP_none) { + // searching the context of the class type for a type + // record which is a pointer record and has the current + // class type as its underlying type has failed, set + // the type to pointer to special CV pointer + type = T_FCVPTR; + } + else { + type = EVAL_TYP (pvT); + } + } + else { + // we are punting here and calling the address of anything else + // a pointer to character + + type = T_PFCHAR; + } + + if ((NODE_STYPE (pnodeOfbnode(bn)) = type) == 0) { + // unable to find proper pointer type + pExState->err_num = ERR_OPERANDTYPES; + return (FALSE); + } + else { + if (EVAL_STATE (ST) != EV_type) { + EVAL_STATE (ST) = EV_rvalue; + } + return (SetNodeType (ST, type)); + } +} + + + + + +/** Arith - bind an arithmetic operation + * + * fSuccess = Arith (op) + * + * Entry op = operator (OP_...) + * + * Returns TRUE if no error during evaluation + * FALSE if error during evaluation + * + * DESCRIPTION + * Binds the result of an arithmetic operation. The binary operators + * dealt with here are: + * + * && || (both are bound here but evaluation is different) + * * / % + * + - + * == != + * < <= > >= + * << >> + * & ^ | + * + * Pointer arithmetic is NOT handled; all operands must be of + * arithmetic type. + */ + + +LOCAL bool_t FASTCALL +Arith ( + op_t op + ) +{ + CV_typ_t typRes; + bool_t fIsReal; + bool_t fIsSigned; + bool_t fResInt; + + if (EVAL_IS_REF (ST)) { + RemoveIndir (ST); + } + if (EVAL_IS_REF (STP)) { + RemoveIndir (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). + + if (EVAL_IS_ENUM (ST)) { + SetNodeType (ST, ENUM_UTYPE (ST)); + } + if (EVAL_IS_ENUM (STP)) { + SetNodeType (STP, ENUM_UTYPE (STP)); + } + if (!ValidateNodes (op, STP, ST)) { + return (FALSE); + } + if (EVAL_IS_BITF (ST)) { + SetNodeType (ST, BITF_UTYPE (ST)); + } + if (EVAL_IS_BITF (STP)) { + SetNodeType (STP, BITF_UTYPE (STP)); + } + + // M00KLUDGE - this is commented out because &&, etc. come through + // M00KLUDGE - and they allow pointers. + //DASSERT (!EVAL_IS_PTR (ST) && !EVAL_IS_PTR (STP)); + + // 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)); + + fIsReal = CV_TYP_IS_REAL (typRes); + fIsSigned = CV_TYP_IS_SIGNED (typRes); + fResInt = FALSE; + + + // Finally, check the actual arithmetic operation. + + switch (op) { + case OP_eqeq: + case OP_bangeq: + case OP_lt: + case OP_gt: + case OP_lteq: + case OP_gteq: + case OP_oror: + case OP_andand: + fResInt = TRUE; + break; + + case OP_plus: + case OP_minus: + case OP_mult: + case OP_div: + break; + + case OP_mod: + case OP_shl: + case OP_shr: + case OP_and: + case OP_or: + case OP_xor: + // Both operands must have integral type. + + DASSERT(!fIsReal); + if (fIsReal) { + return (FALSE); + } + else { + break; + } + + default: + DASSERT (FALSE); + return (FALSE); + } + + + // Now set up the resultant node and coerce back to the correct + // type: + + if (EVAL_STATE (STP) != EV_type) { + EVAL_STATE (STP) = EV_rvalue; + } + if (fResInt) { + SetNodeType ((peval_t)STP, (CV_typ_t)(ADDR_IS_OFF32(*SHpADDRFrompCXT(pCxt)) ? T_LONG : T_SHORT)); + } + else if (fIsReal) { + SetNodeType ((peval_t)STP, (CV_typ_t)typRes); + } + else if (fIsSigned) { + SetNodeType ((peval_t)STP, (CV_typ_t)T_LONG); + } + else { + SetNodeType ((peval_t)STP, (CV_typ_t)T_ULONG); + } + if (!fResInt) { + if (CastNode (STP, typRes, typRes) == FALSE) { + return (FALSE); + } + } + return (PopStack ()); +} + + +LOCAL bool_t FASTCALL +CastBinary ( + op_t op + ) +{ + CV_typ_t typRes; + bool_t fIsReal; + bool_t fIsSigned; + bool_t fResInt; + + if (EVAL_IS_REF (ST)) { + RemoveIndir (ST); + } + + if (EVAL_IS_ENUM (ST)) { + SetNodeType (ST, ENUM_UTYPE (ST)); + } + + if (EVAL_IS_BITF (ST)) { + SetNodeType (ST, BITF_UTYPE (ST)); + } + + // + // The resultant type is the same as the type of the left-hand + // side. + // + typRes = EVAL_TYP (STP); + + fIsReal = CV_TYP_IS_REAL (typRes); + fIsSigned = CV_TYP_IS_SIGNED (typRes); + fResInt = FALSE; + + // + // Now set up the resultant node and coerce back to the correct + // type: + // + EVAL_STATE (STP) = EVAL_STATE(ST); + if (fIsReal) { + SetNodeType (STP, typRes); + } else if (fIsSigned) { + SetNodeType (STP, T_LONG); + } else { + SetNodeType (STP, T_ULONG); + } + + if (!fResInt) { + if (CastNode (STP, typRes, typRes) == FALSE) { + return (FALSE); + } + } + return (PopStack ()); +} + + + +/*** Fetch - complete the fetch (*) operation + * + * fSuccess = Fetch (bn) + * + * Entry bn = based pointer to node + * + * Returns TRUE if bind successful + * FALSE if bind error + * + * Exit pExState->err_num = error ordinal if bind error + */ + + +LOCAL bool_t FASTCALL +Fetch ( + void + ) +{ + + // validate the node type + + if (!ValidateNodes (OP_fetch, ST, NULL)) { + return(FALSE); + } + if (EVAL_IS_BASED (ST)) { + if (!NormalizeBase (ST)) { + return(FALSE); + } + } + if (EVAL_STATE (ST) != EV_type) { + EVAL_STATE (ST) = EV_lvalue; + } + + // Remove a level of indirection from the resultant type. + + RemoveIndir (ST); + return (TRUE); +} + + + + +/*** PlusMinus - Perform an addition or subtraction operation + * + * fSuccess = PlusMinus (op) + * + * Entry op = operator (OP_plus or OP_Minus) + * STP = left operand + * ST = right operand + * + * Returns TRUE if bind successful + * FALSE if bind error + * + * Exit pExState->err_num = error ordinal if bind error + * + * Notes Special handling is required when one or both operands are + * pointers. Otherwise, the arguments are passed on to + * Arith (). + */ + +LOCAL bool_t FASTCALL +PlusMinus ( + op_t op + ) +{ + if (EVAL_IS_REF (STP)) { + RemoveIndir (STP); + } + if (EVAL_IS_REF (ST)) { + RemoveIndir (ST); + } + if (EVAL_IS_ENUM (ST)) { + SetNodeType (ST, ENUM_UTYPE (ST)); + } + if (EVAL_IS_ENUM (STP)) { + SetNodeType (STP, ENUM_UTYPE (STP)); + } + + /* + * If we have a code address in one item, cast it to be a + * char * + */ + + if ((EVAL_IS_LABEL(ST) || EVAL_IS_FCN(ST)) && !EVAL_IS_PTR(STP)) { + CastNode(ST, T_PFUCHAR, T_PFUCHAR); + } else if ((EVAL_IS_LABEL(STP) || EVAL_IS_FCN(STP)) && !EVAL_IS_PTR(ST)) { + CastNode(STP, T_PFUCHAR, T_PFUCHAR); + } + + // validate node types + + if (!ValidateNodes (op, STP, ST)) { + return(FALSE); + } + + // Check to see if either operand is a pointer or a reference to + // 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)); + } + + // Perform the bind. There are two cases: + // + // I) ptr + int, int + ptr, ptr - int + // II) ptr - ptr + + if ((op == OP_plus) || !(EVAL_IS_PTR (ST))) { + // Case (I). ptr + int, int + ptr, ptr - int + // The resultant node has the same type as the pointer: + if (!EVAL_IS_PTR (STP)) { + *STP = *ST; + } + if ((EVAL_STATE (STP) == EV_type) && (EVAL_STATE (ST) == EV_type)) { + EVAL_STATE (STP) = EV_type; + } + else { + EVAL_STATE (STP) = EV_lvalue; + } + } + 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); + } + if ((EVAL_STATE (STP) == EV_type) && (EVAL_STATE (ST) == EV_type)) { + EVAL_STATE (STP) = EV_type; + } + else { + 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); + } + if (EVAL_IS_NPTR32 (STP)) { + SetNodeType (STP, T_LONG); + } + else { + SetNodeType (STP, T_LONG); + } + } + return (PopStack()); +} + + + + +/** PrePost - perform the increment/decrement operation + * + * fSuccess = PrePost (op); + * + * Entry op = operation to perform (OP_plus or OP_minus) + * + * Exit increment/decrement performed and result stored in memory + * + * Returns TRUE if no error + * FALSE if error + */ + + +LOCAL bool_t FASTCALL +PrePost ( + op_t op + ) +{ + eval_t evalT = {0}; + peval_t pvT; + + // initialize the increment/decrecment to a constant 1 + + pvT = &evalT; + CLEAR_EVAL (pvT); + SetNodeType (pvT, T_USHORT); + EVAL_STATE (pvT) = EV_constant; + EVAL_USHORT (pvT) = 1; + if (!PushStack (pvT)) { + return (FALSE); + } + if (PlusMinus (op)) { + return (TRUE); + } + return (FALSE); +} + + + + +/** Unary - bind an unary arithmetic operation + * + * fSuccess = Unary (op) + * + * Entry op = operator + * ST = operand (must be dereferenced) + * + * Returns TRUE if no error during evaluation + * FALSE if error during evaluation + * + * DESCRIPTION + * Binds 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 FASTCALL +Unary ( + op_t op + ) +{ + CV_typ_t typRes; + bool_t fIsReal; + bool_t fIsSigned; + register ushort fResInt; + + if (EVAL_IS_BITF (ST)) { + SetNodeType (ST, BITF_UTYPE (ST)); + } + + DASSERT (!EVAL_IS_PTR (ST) && !EVAL_IS_CLASS (ST)); + + // 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 = EVAL_TYP (ST); + if (ADDR_IS_OFF32(*SHpADDRFrompCXT(pCxt))) { + if (TypeSizePrim(typRes) < 4) { + typRes = T_LONG; + } + } else { + if (TypeSizePrim(typRes) < 2) { + typRes = T_SHORT; + } + } + + fIsReal = CV_TYP_IS_REAL (typRes); + fIsSigned = CV_TYP_IS_SIGNED (typRes); + fResInt = FALSE; + + + // Finally, check the actual arithmetic operation. + + switch (op) { + case OP_bang: + fResInt = TRUE; + break; + + case OP_negate: + case OP_uplus: + break; + + case OP_tilde: + // The operand must have integral type. + + DASSERT (!fIsReal); + if (fIsReal) { + return (FALSE); + } + else { + break; + } + + default: + DASSERT (FALSE); + return (FALSE); + } + + + // Now set up the resultant node and coerce back to the correct + // type: + + EVAL_STATE (ST) = EV_rvalue; + if (fResInt) { + SetNodeType (ST, T_SHORT); + } + else if (fIsReal) { + SetNodeType (ST, typRes); + } + else if (fIsSigned) { + SetNodeType (ST, T_LONG); + } + else { + SetNodeType (ST, T_ULONG); + } + if (!fResInt) { + if (CastNode (ST, typRes, typRes) == FALSE) { + return (FALSE); + } + } + return (TRUE); +} + + + + + +/** Function call support routines + * + */ + +#ifdef TARGET_i386 + +LOCAL bool_t FASTCALL +PushTArgs( + peval_t pvF, + pnode_t pn, + UOFFSET * pSPOff, + int argn, + peval_t pvScr + ) + +/*++ + +routine description: + + This function deals with assignment of locations on the stack and registers + for the THIS CALL calling convention. This calling convention is used for + C++ code 32-bit x86 only. + +arguments: + + pvF - Supplies the pointer to the function description + pn - Supplies a pointer to the argument node in the tree + pSPOff - Supplies a pointer to the current SP address + argn - Supplies the count of arguements for the function + pvScr - Supplies a scratch arguement descriptor. + +return value: + + TRUE if no error and FALSE if error + +--*/ + +{ + return PushCArgs(pvF, pn, pSPOff, argn, pvScr ); +} /* PushTArgs() */ + + +/** PushCArgs - setup argument tree for C style calling + * + * fSuccess = PushCArgs (pvF, pn, pSPOff, argn); + * + * Entry pvF = pointer to function description + * pn = pointer to argument node + * pSPOff = pointer to SP relative offset counter + * argn = argument number + * + * Exit type field of node = type of formal argument + * type field of node = 0 if vararg + * *pSPOff incremented by size of formal or size of actual if vararg + * + * Returns TRUE if no error + * FALSE if error + */ + + +LOCAL bool_t FASTCALL +PushCArgs ( + peval_t pvF, + pnode_t pn, + UOFFSET *pSPOff, + int argn, + peval_t pvScr + ) +{ + CV_typ_t type; + pargd_t pa; + uint cbVal; + short argc; + farg_t argtype; + + // If C calling convention, push arguments in reverse + + if (NODE_OP (pn) == OP_endofargs) { + // set the number of required parameters + argc = FCN_PCOUNT (pvF); + switch (argtype = GetArgType (pvF, argc, &type)) { + case FARG_error: + // there is an error in the OMF or the number of arguments + // exceeds the number of formals in an exact match list + pExState->err_num = ERR_FCNERROR; + return (FALSE); + + case FARG_none: + // return TRUE if number of actuals is 0 + return (argn == 0); + + case FARG_vararg: + // if the formals count is zero then this can be + // either voidargs or varargs. We cannot tell the + // difference so we allow either case. If varargs, + // then the number of actuals must be at least one + // less than the number of formals + + if ((argc == 0) || (argn >= argc - 1)) { + return (TRUE); + } + else { + return (FALSE); + } + + case FARG_exact: + // varargs are not allowed. Exact match required + return (argc == argn); + } + } + + // recurse to end of actual argument list + + if (!PushCArgs (pvF, pnodeOfbnode(NODE_RCHILD (pn)), pSPOff, argn + 1, pvScr)) { + return (FALSE); + } + else { + switch (argtype = GetArgType (pvF, (short) argn, &type)) { + case FARG_error: + case FARG_none: + pExState->err_num = ERR_FCNERROR; + return (FALSE); + + case FARG_vararg: + case FARG_exact: + pa = (pargd_t)&(pn->v[0]); + pa->type = type; + + /* + * increment relative SP offset by size of item rounded + * up to the next word and set address field of OP_arg + * node to relative SP offset. + */ + + SetNodeType (pvScr, pa->type); + + if (ADDR_IS_OFF32(*SHpADDRFrompCXT(pCxt))) { + cbVal = (uint)(TypeSize (pvScr) + 3) & ~3; + } else { + cbVal = (uint)(TypeSize (pvScr) + 1) & ~1; + } + *pSPOff += (UOFFSET)cbVal; + if (EVAL_IS_REF (pvScr)) { + pa->flags.ref = TRUE; + pa->utype = PTR_UTYPE (pvScr); + SetNodeType (pvScr, pa->utype); + if (EVAL_IS_CLASS (pvScr)) { + pa->flags.utclass = TRUE; + } + } + pa->flags.isreg = FALSE; + pa->vallen = cbVal; + pa->SPoff = *pSPOff; + return (TRUE); + } + } +} + + + +/** PushFArgs - push arguments for fastcall call + * + * fSuccess = PushFArgs (pvF, pn, pSPOff); + * + * Entry pvF = pointer to function description + * pn = pointer to argument node + * pSPOff = pointer to SP relative offset counter + * + * Exit type field of node = type of formal argument + * *pSPOff incremented by size of formal + * + * Returns TRUE if parameters pushed without error + * FALSE if error during push + */ + + +LOCAL bool_t FASTCALL +PushFArgs( + peval_t pvF, + pnode_t pnArg, + UOFFSET * pSPOff, + peval_t pvScr + ) +{ + ushort regmask = 0; + short argn = 0; + CV_typ_t type; + pargd_t pa; + uint cbVal; + + for (; NODE_OP (pnArg) != OP_endofargs; + pnArg = pnodeOfbnode(NODE_RCHILD (pnArg))) { + switch (GetArgType (pvF, argn, &type)) { + case FARG_error: + case FARG_vararg: + pExState->err_num = ERR_FCNERROR; + return (FALSE); + + case FARG_none: + return (TRUE); + + case FARG_exact: + pa = (pargd_t)&pnArg->v[0]; + pa->type = type; + SetNodeType (pvScr, type); + if (!FastCallReg (pa, pvScr, ®mask)) { + /* + * increment relative SP offset by size of item rounded up + * to the next word and set address field of OP_arg node to + * relative SP offset. + */ + + cbVal = (uint)(TypeSize (pvScr) + 1) & ~1; + *pSPOff += (UOFFSET)cbVal; + pa->flags.isreg = FALSE; + pa->vallen = cbVal; + pa->SPoff = *pSPOff; + } + if (EVAL_IS_REF (pvScr)) { + pa->flags.ref = TRUE; + pa->utype = PTR_UTYPE (pvScr); + SetNodeType (pvScr, pa->utype); + if (EVAL_IS_CLASS (pvScr)) { + pa->flags.utclass = TRUE; + } + } + argn++; + } + } + return (TRUE); +} /* PushFArgs() */ + +/** PushPArgs - push arguments for call + * + * fSuccess = PushPArgs (pvF, pn, pSPOff); + * + * Entry pvF = pointer to function description + * pn = pointer to argument node + * pSPOff = pointer to SP relative offset counter + * + * Exit type field of node = type of formal argument + * *pSPOff incremented by size of formal + * + * Returns TRUE if parameters pushed without error + * FALSE if error during push + */ + + +LOCAL bool_t FASTCALL +PushPArgs ( + peval_t pvF, + pnode_t pnArg, + UOFFSET *pSPOff, + peval_t pvScr + ) +{ + pargd_t pa; + short argn = 0; + CV_typ_t type; + long cbVal; + + // push arguments onto stack left to right + + for (; NODE_OP (pnArg) != OP_endofargs; pnArg = pnodeOfbnode(NODE_RCHILD (pnArg))) { + switch (GetArgType (pvF, argn, &type)) { + case FARG_error: + case FARG_vararg: + pExState->err_num = ERR_FCNERROR; + return (FALSE); + + case FARG_none: + return (TRUE); + + case FARG_exact: + pa = (pargd_t)&pnArg->v[0]; + + // increment relative SP offset by size of item rounded up to the + // next word and set address field of OP_arg node to relative + // SP offset. + + pa->type = type; + SetNodeType (pvScr, type); + + // increment relative SP offset by size of item rounded up to the + // next word and set address field of OP_arg node to relative + // SP offset. + + cbVal = (ushort)(TypeSize (pvScr) + 1) & ~1; + *pSPOff += (UOFFSET)cbVal; + pa->vallen = (ushort)cbVal; + pa->SPoff = *pSPOff; + pa->flags.isreg = FALSE; + if (EVAL_IS_REF (pvScr)) { + pa->flags.ref = TRUE; + pa->utype = PTR_UTYPE (pvScr); + SetNodeType (pvScr, pa->utype); + if (EVAL_IS_CLASS (pvScr)) { + pa->flags.utclass = TRUE; + } + } + argn++; + } + } + return (TRUE); +} + + + + +/*** FastCallReg - assign fast call parameter to register + * + * fSuccess = FastCallReg (pa, pv, pmask) + * + * Entry pa = pointer to argument data + * pv = pointer to value + * pmask = pointer to allocation mask. *pmask must be + * zero on first call + * + * Exit EVAL_IS_REG (pv) = TRUE if assigned to register + * EVAL_REG (pv) = register ordinal if assigned to register + * *pmask updated if assigned to register + * + * Returns TRUE if parameter is passed in register + * FALSE if parameter is not passed in register + */ + + +LOCAL bool_t FASTCALL +FastCallReg ( + pargd_t pa, + peval_t pv, + ushort * mask + ) +{ +#define AX_PARAM 0x1 +#define DX_PARAM 0x2 +#define BX_PARAM 0x4 +#define ES_PARAM 0x8 +#define CX_PARAM 0x10 + + /* + * Two different calling conventions here. 32-bit and 16-bit + */ + + if (ADDR_IS_OFF32(*SHpADDRFrompCXT(pCxt))) { + /* + * First parameter goes into EAX, second paramter goes into EDX + */ + pa->vallen = (ushort) TypeSize( pv ); + if (pa->vallen <= 4) { + if (! (*mask & CX_PARAM) ) { + *mask |= CX_PARAM; + pa->flags.isreg = TRUE; + switch( pa->vallen ) { + case 1: pa->reg = CV_REG_CL; break; + case 2: pa->reg = CV_REG_CX; break; + case 3: pa->reg = CV_REG_ECX; break; + case 4: pa->reg = CV_REG_ECX; break; + } + } else if (! (*mask & DX_PARAM) ) { + *mask |= DX_PARAM; + pa->flags.isreg = TRUE; + switch( pa->vallen ) { + case 1: pa->reg = CV_REG_DL; break; + case 2: pa->reg = CV_REG_DX; break; + case 3: pa->reg = CV_REG_EDX; break; + case 4: pa->reg = CV_REG_EDX; break; + } + } else { + return FALSE; + } + } else { + return FALSE; + } + } else { + + if (!SetNodeType (pv, pa->type)) { + DASSERT (FALSE); + return (FALSE); + } + pa->vallen = (ushort)TypeSize (pv); + + switch (pa->type) { + case T_UCHAR: + case T_CHAR: + case T_RCHAR: + case T_USHORT: + case T_SHORT: + case T_INT2: + case T_UINT2: + /* + * assign these types to registers ax, dx,bx + * note that the character types will use the full register + */ + + int_order: + /* + * Allocation order is hard-wired + */ + + if (!(*mask & AX_PARAM)) { + *mask |= AX_PARAM; + pa->flags.isreg = TRUE; + pa->reg = pa->vallen == 1 ? CV_REG_AL : CV_REG_AX; + } + else if (!(*mask & DX_PARAM)) { + *mask |= DX_PARAM; + pa->flags.isreg = TRUE; + pa->reg = pa->vallen == 1 ? CV_REG_DL : CV_REG_DX; + } + else if (!(*mask & BX_PARAM)) { + *mask |= BX_PARAM; + pa->flags.isreg = TRUE; + pa->reg = pa->vallen == 1 ? CV_REG_BL : CV_REG_BX; + } + else { + return (FALSE); + } + break; + + case T_ULONG: + case T_LONG: + case T_INT4: + case T_UINT4: + /* + * assign long values to dx:ax + */ + + if (!(*mask & AX_PARAM) && !(*mask & DX_PARAM)) { + *mask |= AX_PARAM | DX_PARAM; + pa->flags.isreg = TRUE; + pa->reg = (CV_REG_DX << 8) | CV_REG_AX; + } + else { + return (FALSE); + } + break; + + default: + if (EVAL_IS_PTR (pv) && EVAL_IS_NPTR (pv)) { + /* + * assign short pointers (including references) + * to bx, ax, dx. Allocation order is hard-wired + */ + + if (!(*mask & BX_PARAM)) { + *mask |= BX_PARAM; + pa->flags.isreg = TRUE; + pa->reg = CV_REG_BX; + } + else { + goto int_order; // nasty tail merging of mine + } + } + else if (EVAL_IS_PTR (pv) && EVAL_IS_NPTR32 (pv)) { + DASSERT (FALSE); // M00FLAT32 + } + else { + //M00KLUDGE - it is assumed that pointers go on the stack + return (FALSE); + } + break; + } + } + return (TRUE); +} /* FastCallReg() */ + +#endif // TARGET_i386 + + +#ifdef TARGET_MIPS + +LOCAL bool_t FASTCALL +PushMArgs ( + peval_t pvF, + pnode_t pnArg, + UOFFSET *pSPOff, + peval_t pvScr + ) + +/*++ + +Routine Description: + + This routine computes the offsets for a MIPS calling convention routine. + +Arguments: + + pvF - Supplies a pointer to the function description + pn - Supplies a pointer to the arugment node + pSPOff - Supplies pointer to the Stack Pointer relative offset counter + this value is updated to reflect pushed parameters + +Return Value: + + TRUE if parameters pushed without error else FALSE + +--*/ + +{ + uint regmask = 0; + eval_t evalRet; + peval_t pvRet; + + + /* + * Must deal with return type and this parameters before + * dealing with anything else. + */ + + pvRet = &evalRet; + *pvRet = *ST; + SetNodeType( pvRet, FCN_RETURN(pvRet)); + + if (EVAL_IS_METHOD(pvF)) { + SET_PARAM_INT(®mask, 0); + } + + if (!EVAL_IS_REF(pvRet) && + !CV_IS_PRIMITIVE(EVAL_TYP(pvRet)) && + (TypeSize(pvRet) > 4) && + (CV_TYPE ( EVAL_TYP (pvRet)) != CV_REAL)) { + + if (IS_PARAM_EMPTY(®mask, 0)) { + SET_PARAM_INT(®mask, 0); + } else { + SET_PARAM_INT(®mask, 1); + } + } + + + /* + * Now deal with the actual declared parameter list. + */ + + return PushMArgs2( pvF, pnArg, pSPOff, 0, regmask, pvScr); +} + + +LOCAL bool_t FASTCALL +PushMArgs2 ( + peval_t pvF, + pnode_t pnArg, + UOFFSET *pSPOff, + int argn, + uint regmask, + peval_t pvScr + ) + +/*++ + +Routine Description: + + This routine computes the offsets for a MIPS calling convention routine. + +Arguments: + + pvF - Supplies a pointer to the function description + pn - Supplies a pointer to the arugment node + pSPOff - Supplies pointer to the Stack Pointer relative offset counter + this value is updated to reflect pushed parameters + argn - Supplies the count of arguments pushed to date + +Return Value: + + TRUE if parameters pushed without error else FALSE + +--*/ + +{ + int argc; + CV_typ_t type; + pargd_t pa; + uint cbVal; + int cbR; + farg_t argtype; + BOOL fReg; + + /* + * Arguments are pushed in reverse (C) order + */ + + if (NODE_OP(pnArg) == OP_endofargs) { + /* + * Set number of required parameters + */ + + argc = FCN_PCOUNT( pvF ); + switch( argtype = GetArgType( pvF, (short) argc, &type ) ) { + + /* + * Error in the OMF or the number of arguments + * exceeds the number of formals in an exact match list + */ + case FARG_error: + pExState->err_num = ERR_FCNERROR; + return FALSE; + + /* + * return TRUE if number of actuals is 0 + */ + + case FARG_none: + *pSPOff = 16; + return (argn == 0); + + /* + * if the formals count is zero then this can be + * either voidargs or varargs. We cannot tell + * the difference so we allow either case. If + * varargs, then the number of acutals must + * be at least one less than the number of formals + */ + + if ((argc == 0) || (argn >= argc - 1)) { + return TRUE; + } + return FALSE; + + case FARG_vararg: + // if the formals count is zero then this can be + // either voidargs or varargs. We cannot tell the + // difference so we allow either case. If varargs, + // then the number of actuals must be at least one + // less than the number of formals + + if ((argc == 0) || (argn >= argc - 1)) { + return (TRUE); + } + else { + return (FALSE); + } + + case FARG_exact: + if (*pSPOff < 16) { + *pSPOff = 16; + } else { + *pSPOff = (*pSPOff + 8 - 1) & ~(8 - 1); + } + return (argc == argn); + } + } + + /* + * Need to get the size of the item to be pushed so that we can + * do correct alignment of the stack for this data item. + */ + + switch ( argtype = GetArgType( pvF, (short) argn, &type )) { + + default: + DASSERT(FALSE); + + /* + * If no type or error then return error + */ + case FARG_error: + case FARG_none: + pExState->err_num = ERR_FCNERROR; + return FALSE; + + case FARG_vararg: + case FARG_exact: + pa = (pargd_t)&pnArg->v[0]; + pa->type = type; + pa->flags.isreg = FALSE; + + SetNodeType (pvScr, type); + + fReg = MipsCallReg( pa, pvScr, ®mask); + + /* + * We always allocate space on the stack for any argument + * even if it is placed in a register. + */ + + /* + * To compute location on stack take the size of the + * item and round to DWORDS. The stack is then aligned + * to this size. + * + * NOTENOTE??? - I don't know if this is correct for structures. + */ + + + cbVal = (uint)(TypeSize(pvScr) + 3) & ~3; + cbR = (cbVal > 8) ? 8 : cbVal; + *pSPOff = (*pSPOff + cbR - 1 ) & ~(cbR - 1); + + cbR = *pSPOff; + + *pSPOff += cbVal; + + break; + + } + + + /* + * At an actual arguement. Recurse down the list to the end + * and then process this argument + */ + + if (!PushMArgs2( pvF, pnodeOfbnode(NODE_RCHILD (pnArg)), pSPOff, + argn+1, regmask, pvScr)) { + return FALSE; + } else { + + /* + * Allocate space on stack (in increments of 4) and + * save the offset of the stack for the item. Offsets + * are saved backwards (i.e. from the end of the stack) so + * we can push them on the stack easier. + */ + + pa->SPoff = *pSPOff - cbR; + + if (EVAL_IS_REF( pvScr )) { + pa->flags.ref = TRUE; + pa->utype = PTR_UTYPE ( pvScr ); + SetNodeType (pvScr, pa->utype ); + if (EVAL_IS_CLASS (pvScr)) { + pa->flags.utclass = TRUE; + } + } + } + return (TRUE); +} /* PushMArgs() */ + + + + + +/*** MipsCallReg - assign mips call parameter to register + * + * fSuccess = MipsCallReg (pa, pv, pmask) + * + * Entry pa = pointer to argument data + * pv = pointer to value + * pmask = pointer to allocation mask. *pmask must be + * zero on first call + * + * Exit EVAL_IS_REG (pv) = TRUE if assigned to register + * EVAL_REG (pv) = register ordinal if assigned to register + * *pmask updated if assigned to register + * + * Returns TRUE if parameter is passed in register + * FALSE if parameter is not passed in register + */ + +LOCAL bool_t FASTCALL +MipsCallReg ( + pargd_t pa, + peval_t pv, + uint *mask + ) +{ + + if (!SetNodeType (pv, pa->type)) { + DASSERT (FALSE); + return (FALSE); + } + + /* + * Are there any slots free? + */ + + pa->vallen = (ushort)TypeSize (pv); + + if (!IS_PARAM_EMPTY(mask, 3)) { + return FALSE; + } + + /* + * Depending on the type we need to allocate something to the + * correct set of registers and to void other registers as + * appriopirate + */ + + switch( pa->type ) { + /* + * These are all assigned to $4, $5, $6, $7 -- which ever + * is first available. When a register is used it + * is marked as unavailable. + */ + + default: + if (pa->vallen > 4) { + break; + } + + case T_UCHAR: + case T_CHAR: + case T_RCHAR: + case T_USHORT: + case T_SHORT: + case T_INT2: + case T_UINT2: + case T_ULONG: + case T_LONG: + case T_INT4: + case T_UINT4: + case T_32PCHAR: + case T_32PUCHAR: + case T_32PRCHAR: + case T_32PWCHAR: + case T_32PINT2: + case T_32PUINT2: + case T_32PSHORT: + case T_32PUSHORT: + case T_32PINT4: + case T_32PUINT4: + case T_32PLONG: + case T_32PULONG: + case T_32PINT8: + case T_32PUINT8: + case T_32PREAL32: + case T_32PREAL48: + case T_32PREAL64: + + if (IS_PARAM_EMPTY(mask, 0)) { + SET_PARAM_INT(mask, 0); + pa->flags.isreg = TRUE; + pa->reg = CV_M4_IntA0; + + } else if (IS_PARAM_EMPTY(mask, 1)) { + SET_PARAM_INT(mask, 1); + pa->flags.isreg = TRUE; + pa->reg = CV_M4_IntA1; + + } else if (IS_PARAM_EMPTY(mask, 2)) { + SET_PARAM_INT(mask, 2); + pa->flags.isreg = TRUE; + pa->reg = CV_M4_IntA2; + + } else if (IS_PARAM_EMPTY(mask, 3)) { + SET_PARAM_INT(mask, 3); + pa->flags.isreg = TRUE; + pa->reg = CV_M4_IntA3; + + } else { + DASSERT(FALSE); + return FALSE; + + } + return TRUE; + + /* + * + */ + + case T_REAL32: + + if (IS_PARAM_EMPTY(mask, 0)) { + SET_PARAM_FLOAT(mask, 0); + pa->flags.isreg = TRUE; + pa->reg = CV_M4_FltF12; + + } else if (IS_PARAM_EMPTY(mask, 1)) { + SET_PARAM_FLOAT(mask, 1); + pa->flags.isreg = TRUE; + if (IS_PARAM_FLOAT(mask, 0)) { + pa->reg = CV_M4_FltF14; + } else { + pa->reg = CV_M4_IntA1; + } + + } else if (IS_PARAM_EMPTY(mask, 2)) { + SET_PARAM_FLOAT(mask, 2); + pa->flags.isreg = TRUE; + pa->reg = CV_M4_IntA2; + + } else if (IS_PARAM_EMPTY(mask, 3)) { + SET_PARAM_FLOAT(mask, 3); + pa->flags.isreg = TRUE; + pa->reg = CV_M4_IntA3; + } else { + DASSERT(FALSE); + return FALSE; + } + + return TRUE; + + /* + * + */ + + case T_REAL64: + + if (IS_PARAM_EMPTY(mask, 0)) { + SET_PARAM_DOUBLE(mask, 0); + SET_PARAM_DOUBLE(mask, 1); + pa->flags.isreg = TRUE; + pa->reg = ( CV_M4_FltF13 << 8 ) | CV_M4_FltF12; + + } else if (IS_PARAM_EMPTY(mask, 2)) { + SET_PARAM_DOUBLE(mask, 2); + SET_PARAM_DOUBLE(mask, 3); + pa->flags.isreg = TRUE; + + if (IS_PARAM_DOUBLE(mask, 0)) { + pa->reg = ( CV_M4_FltF15 << 8 ) | CV_M4_FltF14; + } else { + pa->reg = ( CV_M4_IntA3 << 8) | CV_M4_IntA2; + } + } else { + DASSERT(FALSE); + return FALSE; + } + + return TRUE; + + + } + + *mask = 0xffffffff; + return FALSE; +} /* MipsCallReg() */ + +#endif // TARGET_MIPS + +#ifdef TARGET_PPC + +LOCAL bool_t FASTCALL +PushPPCArgs ( + peval_t pvF, + pnode_t pnArg, + UOFFSET *pSPOff, + peval_t pvScr + ) + +/*++ + +Routine Description: + + This routine computes the offsets for a PPC calling convention routine. + +Arguments: + + pvF - Supplies a pointer to the function description + pn - Supplies a pointer to the arugment node + pSPOff - Supplies pointer to the Stack Pointer relative offset counter + this value is updated to reflect pushed parameters + +Return Value: + + TRUE if parameters pushed without error else FALSE + +--*/ + +{ + uint regmask[3]; + eval_t evalRet; + peval_t pvRet; + + regmask[0] = regmask[1] = regmask[2] = 0; + + /* + * Must deal with return type and this parameters before + * dealing with anything else. + */ + + pvRet = &evalRet; + *pvRet = *ST; + SetNodeType( pvRet, FCN_RETURN(pvRet)); + + if (EVAL_IS_METHOD(pvF)) { + SET_PARAM_INT(regmask, 0); + } + + if (!EVAL_IS_REF(pvRet) && + !CV_IS_PRIMITIVE(EVAL_TYP(pvRet)) && + (TypeSize(pvRet) > 4) && + (CV_TYPE ( EVAL_TYP (pvRet)) != CV_REAL)) { + + if (IS_PARAM_EMPTY(regmask, 0)) { + SET_PARAM_INT(regmask, 0); + } else { + SET_PARAM_INT(regmask, 1); + } + } + + + /* + * Now deal with the actual declared parameter list. + */ + + return PushPPCArgs2( pvF, pnArg, pSPOff, 0, regmask, pvScr); +} + + +LOCAL bool_t FASTCALL +PushPPCArgs2 ( + peval_t pvF, + pnode_t pnArg, + UOFFSET *pSPOff, + int argn, + uint *regmask, + peval_t pvScr + ) + +/*++ + +Routine Description: + + This routine computes the offsets for a PPC calling convention routine. + +Arguments: + + pvF - Supplies a pointer to the function description + pn - Supplies a pointer to the arugment node + pSPOff - Supplies pointer to the Stack Pointer relative offset counter + this value is updated to reflect pushed parameters + argn - Supplies the count of arguments pushed to date + +Return Value: + + TRUE if parameters pushed without error else FALSE + +--*/ + +{ + int argc; + CV_typ_t type; + pargd_t pa; + uint cbVal; + int cbR; + farg_t argtype; + BOOL fReg; + + /* + * Arguments are pushed in reverse (C) order + */ + + if (NODE_OP(pnArg) == OP_endofargs) { + /* + * Set number of required parameters + */ + + argc = FCN_PCOUNT( pvF ); + switch( argtype = GetArgType( pvF, (short) argc, &type ) ) { + + /* + * Error in the OMF or the number of arguments + * exceeds the number of formals in an exact match list + */ + case FARG_error: + pExState->err_num = ERR_FCNERROR; + return FALSE; + + /* + * return TRUE if number of actuals is 0 + */ + + case FARG_none: + *pSPOff = 24; + return (argn == 0); + + /* + * if the formals count is zero then this can be + * either voidargs or varargs. We cannot tell + * the difference so we allow either case. If + * varargs, then the number of acutals must + * be at least one less than the number of formals + */ + + if ((argc == 0) || (argn >= argc - 1)) { + return TRUE; + } + return FALSE; + + case FARG_vararg: + // I putG_vararg back in because that's what GetArgType + // returns if there are no arguments. v-matth + + // if the formals count is zero then this can be + // either voidargs or varargs. We cannot tell the + // difference so we allow either case. If varargs, + // then the number of actuals must be at least one + // less than the number of formals + + if ((argc == 0) || (argn >= argc - 1)) { + return (TRUE); + } + else { + return (FALSE); + } + + case FARG_exact: + *pSPOff = (*pSPOff + 8 - 1) & ~(8 - 1); + return (argc == argn); + } + } + + /* + * Need to get the size of the item to be pushed so that we can + * do correct alignment of the stack for this data item. + */ + + switch ( argtype = GetArgType( pvF, (short) argn, &type )) { + + default: + DASSERT(FALSE); + + /* + * If no type or error then return error + */ + case FARG_error: + case FARG_none: + pExState->err_num = ERR_FCNERROR; + return FALSE; + + case FARG_vararg: + case FARG_exact: + pa = (pargd_t)&pnArg->v[0]; + pa->type = type; + pa->flags.isreg = FALSE; + + SetNodeType (pvScr, type); + + fReg = PPCCallReg( pa, pvScr, regmask); + + /* + * We always allocate space on the stack for any argument + * even if it is placed in a register. + */ + + /* + * To compute location on stack take the size of the + * item and round to DWORDS. The stack is DWORD aligned. + * + * NOTENOTE??? - I don't know if this is correct for structures. + */ + + + cbVal = (uint)(TypeSize(pvScr) + 3) & ~3; + cbR = (cbVal > 8) ? 8 : cbVal; + *pSPOff = (*pSPOff + cbR - 1 ) & ~(cbR - 1); + + cbR = *pSPOff; + *pSPOff += cbVal; + + break; + + } + + + /* + * At an actual arguement. Recurse down the list to the end + * and then process this argument + */ + + if (!PushPPCArgs2( pvF, pnodeOfbnode(NODE_RCHILD (pnArg)), pSPOff, + argn+1, regmask, pvScr)) { + return FALSE; + } else { + DASSERT( ( argtype == FARG_exact ) || ( argtype == FARG_vararg ) ); + + /* + * Allocate space on stack (in increments of 4) and + * save the offset of the stack for the item. Offsets + * are saved backwards (i.e. from the end of the stack) so + * we can push them on the stack easier. + */ + + pa->SPoff = *pSPOff - cbR; + // A little adjustment for linkage convention. This function + // only allocates enough stack for the arguments. We need 24 + // bytes more. v-matth + if( argn == 0 ) + { + pa->SPoff = pa->SPoff + 24; + } + + if (EVAL_IS_REF( pvScr )) { + pa->flags.ref = TRUE; + pa->utype = PTR_UTYPE ( pvScr ); + SetNodeType (pvScr, pa->utype ); + if (EVAL_IS_CLASS (pvScr)) { + pa->flags.utclass = TRUE; + } + } + } + return (TRUE); +} /* PushPPCArgs2() */ + + + + + +/*** PPCCallReg - assign PPC call parameter to register + * + * fSuccess = PPCCallReg (pa, pv, pmask) + * + * Entry pa = pointer to argument data + * pv = pointer to value + * pmask = pointer to allocation mask. *pmask must be + * zero on first call + * + * Exit EVAL_IS_REG (pv) = TRUE if assigned to register + * EVAL_REG (pv) = register ordinal if assigned to register + * *pmask updated if assigned to register + * + * Returns TRUE if parameter is passed in register + * FALSE if parameter is not passed in register + */ + +LOCAL bool_t FASTCALL +PPCCallReg ( + pargd_t pa, + peval_t pv, + uint *mask + ) +{ + int i, j; + + if (!SetNodeType (pv, pa->type)) { + DASSERT (FALSE); + return (FALSE); + } + + pa->vallen = (ushort)TypeSize (pv); + + /* + * Depending on the type we need to allocate something to the + * correct set of registers and to void other registers as + * appriopirate + */ + + switch( pa->type ) { + + default: + if (pa->vallen > 8) { + // Here is where we do the "painting across" registers + // trick, if we overflow, we spill into memory. FIXME + break; + } + + case T_UCHAR: + case T_CHAR: + case T_RCHAR: + case T_USHORT: + case T_SHORT: + case T_INT2: + case T_UINT2: + case T_ULONG: + case T_LONG: + case T_INT4: + case T_UINT4: + case T_32PCHAR: + case T_32PUCHAR: + case T_32PRCHAR: + case T_32PWCHAR: + case T_32PINT2: + case T_32PUINT2: + case T_32PSHORT: + case T_32PUSHORT: + case T_32PINT4: + case T_32PUINT4: + case T_32PLONG: + case T_32PULONG: + case T_32PINT8: + case T_32PUINT8: + case T_32PREAL32: + case T_32PREAL48: + case T_32PREAL64: + + if (!IS_PARAM_EMPTY(mask, 7)) + return FALSE; + + for (i = 0; i < 8; i++) + if (IS_PARAM_EMPTY(mask, i)) { + SET_PARAM_INT(mask, i); + pa->flags.isreg = TRUE; + pa->reg = CV_PPC_GPR3 + i; + break; + } + + return TRUE; + + case T_REAL32: + + if (!IS_PARAM_EMPTY(mask, 8+13-1)) + return FALSE; + + for (i = 8; i < 8+13; i++) { + if (IS_PARAM_EMPTY(mask, i)) { + SET_PARAM_FLOAT(mask, i); + pa->flags.isreg = TRUE; + pa->reg = CV_PPC_FPR1 + i - 8; + + if (IS_PARAM_EMPTY(mask, 7)) { + for (j = 0; j < 8; j++) { + if (IS_PARAM_EMPTY(mask, j)) { + SET_PARAM_FLOAT(mask, j); + pa->reg |= (CV_PPC_GPR3 + j) << 8; + break; + } + } + } + break; + } + } + return TRUE; + + case T_REAL64: + + if (!IS_PARAM_EMPTY(mask, 8+13-1)) + return FALSE; + + for (i = 8; i < 8+13; i++) { + if (IS_PARAM_EMPTY(mask, i)) { + SET_PARAM_DOUBLE(mask, i); + pa->flags.isreg = TRUE; + pa->reg = CV_PPC_FPR1 + i - 8; + + if (IS_PARAM_EMPTY(mask, 7)) { + for (j = 0; j < 8; j+= 2) { + if (IS_PARAM_EMPTY(mask, j)) { + SET_PARAM_DOUBLE(mask, j); + pa->reg |= (CV_PPC_GPR3 + j) << 12; + if (j < 7) { + SET_PARAM_DOUBLE(mask, j+1); + pa->reg |= (CV_PPC_GPR3 + j + 1) << 8; + } + if (IS_PARAM_EMPTY(mask, j-1)) { + SET_PARAM_SKIPPED(mask, j-1); + } + break; + } + } + } + break; + } + } + + return TRUE; + } + + mask[0] = mask[1] = mask[2] = 0xffffffff; + return FALSE; +} /* PPCCallReg() */ + +#endif // TARGET_PPC + + + +#ifdef TARGET_ALPHA + +LOCAL bool_t FASTCALL +PushAArgs ( + peval_t pvF, + pnode_t pnArg, + UOFFSET *pSPOff, + peval_t pvScr + ) + +/*++ + +Routine Description: + + This routine computes the offsets for a routine using + the Alpha calling convention. + +Arguments: + + pvF - Supplies a pointer to the function description + pn - Supplies a pointer to the arugment node + pSPOff - Supplies pointer to the Stack Pointer relative offset counter + this value is updated to reflect pushed parameters + +Return Value: + + TRUE if parameters pushed without error else FALSE + +--*/ + +{ + uint regmask = 0; + eval_t evalRet; + peval_t pvRet; + + + /* + * Must deal with return type and this parameters before + * dealing with anything else. + */ + + pvRet = &evalRet; + *pvRet = *ST; + SetNodeType( pvRet, FCN_RETURN(pvRet)); + + if (EVAL_IS_METHOD(pvF)) { + SET_PARAM_INT(®mask, 0); + } + + if (!EVAL_IS_REF(pvRet) && + !CV_IS_PRIMITIVE(EVAL_TYP(pvRet)) && +// MBH - bugbug +// for us, we should check against a size of 8, not 4, +// but the other quad support is still missing, so leave it be. +// + (TypeSize(pvRet) > 4) && + (CV_TYPE ( EVAL_TYP (pvRet)) != CV_REAL)) { + + if (IS_PARAM_EMPTY(®mask, 0)) { + SET_PARAM_INT(®mask, 0); + } else { + SET_PARAM_INT(®mask, 1); + } + } + + + /* + * Now deal with the actual declared parameter list. + */ + + return PushAArgs2( pvF, pnArg, pSPOff, 0, regmask, pvScr); +} + + +LOCAL bool_t FASTCALL +PushAArgs2 ( + peval_t pvF, + pnode_t pnArg, + UOFFSET *pSPOff, + int argn, + uint regmask, + peval_t pvScr + ) + +/*++ + +Routine Description: + + Alpha - see PushAArgs, above + +Arguments: + + pvF - Supplies a pointer to the function description + pn - Supplies a pointer to the arugment node + pSPOff - Supplies pointer to the Stack Pointer relative offset counter + this value is updated to reflect pushed parameters + argn - Supplies the count of arguments pushed to date + +Return Value: + + TRUE if parameters pushed without error else FALSE + +--*/ + +{ + int argc; + CV_typ_t type; + pargd_t pa; + uint cbVal; + int cbR = 0; + farg_t argtype; + BOOL fReg; + + /* + * Arguments are pushed in reverse (C) order + */ + + if (NODE_OP(pnArg) == OP_endofargs) { + /* + * Set number of required parameters + */ + + argc = FCN_PCOUNT( pvF ); + switch( argtype = GetArgType( pvF, (short) argc, &type ) ) { + + /* + * Error in the OMF or the number of arguments + * exceeds the number of formals in an exact match list + */ + case FARG_error: + pExState->err_num = ERR_FCNERROR; + return FALSE; + + /* + * return TRUE if number of actuals is 0 + */ + + case FARG_none: + *pSPOff = 16; + return (argn == 0); + + /* + * if the formals count is zero then this can be + * either voidargs or varargs. We cannot tell + * the difference so we allow either case. If + * varargs, then the number of acutals must + * be at least one less than the number of formals + */ + + if ((argc == 0) || (argn >= argc - 1)) { + return TRUE; + } + return FALSE; + + /* + * Varargs are not allowed. Exact match required + */ + + case FARG_vararg: + // if the formals count is zero then this can be + // either voidargs or varargs. We cannot tell the + // difference so we allow either case. If varargs, + // then the number of actuals must be at least one + // less than the number of formals + + if ((argc == 0) || (argn >= argc - 1)) { + return (TRUE); + } + else { + return (FALSE); + } + + case FARG_exact: + if (*pSPOff < 16) { + *pSPOff = 16; + } else { + *pSPOff = (*pSPOff + 8 - 1) & ~(8 - 1); + } + return (argc == argn); + } + } + + /* + * Need to get the size of the item to be pushed so that we can + * do correct alignment of the stack for this data item. + */ + + switch ( argtype = GetArgType( pvF, (short) argn, &type )) { + + default: + DASSERT(FALSE); + + /* + * If no type or error then return error + */ + case FARG_error: + case FARG_none: + pExState->err_num = ERR_FCNERROR; + return FALSE; + + case FARG_vararg: + case FARG_exact: + pa = (pargd_t)&pnArg->v[0]; + pa->type = type; + pa->flags.isreg = FALSE; + + SetNodeType (pvScr, type); + + fReg = AlphaCallReg( pa, pvScr, ®mask); + + /* + * Space is only allocated on the stack for arguments + * that aren't in registers. The argument home area + * is in the stack space of the callee, so allocating + * it here would be double-allocation. + */ + + /* + * To compute location on stack take the size of the + * item and round to QUADWORDS. The stack is then aligned + * to this size. + * + * NOTENOTE??? - I don't know if this is correct for structures. + */ + + if (fReg == FALSE) { + cbVal = (uint)(TypeSize(pvScr) + 7) & ~7; + cbR = (cbVal > 16) ? 16 : cbVal; + *pSPOff = (*pSPOff + cbR - 1 ) & ~(cbR - 1); + + cbR = *pSPOff; + + *pSPOff += cbVal; + + break; + + } + } + + /* + * At an actual arguement. Recurse down the list to the end + * and then process this argument + */ + + if (!PushAArgs2( pvF, pnodeOfbnode(NODE_RCHILD (pnArg)), pSPOff, + argn+1, regmask, pvScr)) { + return FALSE; + } else { + /* + * Indicate where on the stack this goes, if it goes anywhere. + * If cbR isn't reasonable (ie 0) for Register variables, the + * routine evaluation won't work. + * They are saved backwards (i.e. from the end of the stack) so + * we can push them on the stack easier. + */ + + pa->SPoff = *pSPOff - cbR; + + if (EVAL_IS_REF( pvScr )) { + pa->flags.ref = TRUE; + pa->utype = PTR_UTYPE ( pvScr ); + SetNodeType (pvScr, pa->utype ); + if (EVAL_IS_CLASS (pvScr)) { + pa->flags.utclass = TRUE; + } + } + } + return (TRUE); +} /* PushAArgs2() */ + + + + + +/*** AlphaCallReg - assign Alpha call parameter to register + * + * fSuccess = AlphaCallReg (pa, pv, pmask) + * + * Entry pa = pointer to argument data + * pv = pointer to value + * pmask = pointer to allocation mask. *pmask must be + * zero on first call + * + * Exit EVAL_IS_REG (pv) = TRUE if assigned to register + * EVAL_REG (pv) = register ordinal if assigned to register + * *pmask updated if assigned to register + * + * Returns TRUE if parameter is passed in register + * FALSE if parameter is not passed in register + */ + +LOCAL bool_t FASTCALL +AlphaCallReg ( + pargd_t pa, + peval_t pv, + uint *mask + ) +{ + + if (!SetNodeType (pv, pa->type)) { + DASSERT (FALSE); + return (FALSE); + } + + /* + * Are there any slots free? + */ + + pa->vallen = (ushort)TypeSize (pv); + + if (!IS_PARAM_EMPTY(mask, 5)) { + return FALSE; + } + + /* + * Depending on the type we need to allocate something to the + * correct set of registers and to void other registers as + * appropriate + */ + + switch( pa->type ) { + /* + * These are all assigned to IntA0 - IntA5 -- which ever + * is first available. When a register is used it + * is marked as unavailable. + */ + + default: + if (pa->vallen > 8) { + break; + } + + case T_UCHAR: + case T_CHAR: + case T_RCHAR: + case T_USHORT: + case T_SHORT: + case T_INT2: + case T_UINT2: + case T_ULONG: + case T_LONG: + case T_INT4: + case T_UINT4: + case T_QUAD: + case T_UQUAD: + case T_INT8: + case T_UINT8: + case T_32PCHAR: + case T_32PUCHAR: + case T_32PRCHAR: + case T_32PWCHAR: + case T_32PINT2: + case T_32PUINT2: + case T_32PSHORT: + case T_32PUSHORT: + case T_32PINT4: + case T_32PUINT4: + case T_32PLONG: + case T_32PULONG: + case T_32PINT8: + case T_32PUINT8: + case T_32PREAL32: + case T_32PREAL48: + case T_32PREAL64: + + if (IS_PARAM_EMPTY(mask, 0)) { + SET_PARAM_INT(mask, 0); + pa->flags.isreg = TRUE; + pa->reg = CV_ALPHA_IntA0; + + } else if (IS_PARAM_EMPTY(mask, 1)) { + SET_PARAM_INT(mask, 1); + pa->flags.isreg = TRUE; + pa->reg = CV_ALPHA_IntA1; + + } else if (IS_PARAM_EMPTY(mask, 2)) { + SET_PARAM_INT(mask, 2); + pa->flags.isreg = TRUE; + pa->reg = CV_ALPHA_IntA2; + + } else if (IS_PARAM_EMPTY(mask, 3)) { + SET_PARAM_INT(mask, 3); + pa->flags.isreg = TRUE; + pa->reg = CV_ALPHA_IntA3; + + } else if (IS_PARAM_EMPTY(mask, 4)) { + SET_PARAM_INT(mask, 4); + pa->flags.isreg = TRUE; + pa->reg = CV_ALPHA_IntA4; + + } else if (IS_PARAM_EMPTY(mask, 5)) { + SET_PARAM_INT(mask, 5); + pa->flags.isreg = TRUE; + pa->reg = CV_ALPHA_IntA5; + + } else { + DASSERT(FALSE); + return FALSE; + + } + return TRUE; + + /* + * + */ + + case T_REAL32: + + if (IS_PARAM_EMPTY(mask, 0)) { + SET_PARAM_FLOAT(mask, 0); + pa->flags.isreg = TRUE; + pa->reg = CV_ALPHA_FltF16; + + } else if (IS_PARAM_EMPTY(mask, 1)) { + SET_PARAM_FLOAT(mask, 1); + pa->flags.isreg = TRUE; + pa->reg = CV_ALPHA_FltF17; + + } else if (IS_PARAM_EMPTY(mask, 2)) { + SET_PARAM_FLOAT(mask, 2); + pa->flags.isreg = TRUE; + pa->reg = CV_ALPHA_FltF18; + + } else if (IS_PARAM_EMPTY(mask, 3)) { + SET_PARAM_FLOAT(mask, 3); + pa->flags.isreg = TRUE; + pa->reg = CV_ALPHA_FltF19; + + } else if (IS_PARAM_EMPTY(mask, 4)) { + SET_PARAM_FLOAT(mask, 4); + pa->flags.isreg = TRUE; + pa->reg = CV_ALPHA_FltF20; + + } else if (IS_PARAM_EMPTY(mask, 5)) { + SET_PARAM_FLOAT(mask, 5); + pa->flags.isreg = TRUE; + pa->reg = CV_ALPHA_FltF21; + + } else { + DASSERT(FALSE); + return FALSE; + } + + return TRUE; + + case T_REAL64: + + if (IS_PARAM_EMPTY(mask, 0)) { + SET_PARAM_DOUBLE(mask, 0); + pa->flags.isreg = TRUE; + pa->reg = CV_ALPHA_FltF16; + + } else if (IS_PARAM_EMPTY(mask, 1)) { + SET_PARAM_DOUBLE(mask, 1); + pa->flags.isreg = TRUE; + pa->reg = CV_ALPHA_FltF17; + + } else if (IS_PARAM_EMPTY(mask, 2)) { + SET_PARAM_DOUBLE(mask, 2); + pa->flags.isreg = TRUE; + pa->reg = CV_ALPHA_FltF18; + + } else if (IS_PARAM_EMPTY(mask, 3)) { + SET_PARAM_DOUBLE(mask, 3); + pa->flags.isreg = TRUE; + pa->reg = CV_ALPHA_FltF19; + + } else if (IS_PARAM_EMPTY(mask, 4)) { + SET_PARAM_DOUBLE(mask, 4); + pa->flags.isreg = TRUE; + pa->reg = CV_ALPHA_FltF20; + + } else if (IS_PARAM_EMPTY(mask, 5)) { + SET_PARAM_DOUBLE(mask, 5); + pa->flags.isreg = TRUE; + pa->reg = CV_ALPHA_FltF21; + + } else { + DASSERT(FALSE); + return FALSE; + } + + return TRUE; + + } + + *mask = 0xffffffff; + return FALSE; +} /* MipsCallReg() */ + +#endif // TARGET_ALPHA + + +struct _OvlMap { + op_t op; + op_t ovlfcn; +}; + +struct _OvlMap BinaryOvlMap[] = { + {OP_preinc ,OP_Oincrement }, + {OP_predec ,OP_Odecrement }, + {OP_postinc ,OP_Oincrement }, + {OP_postdec ,OP_Odecrement }, + {OP_function ,OP_Ofunction }, + {OP_lbrack ,OP_Oarray }, + {OP_pmember ,OP_Opmember }, + {OP_mult ,OP_Ostar }, + {OP_div ,OP_Odivide }, + {OP_mod ,OP_Opercent }, + {OP_plus ,OP_Oplus }, + {OP_minus ,OP_Ominus }, + {OP_shl ,OP_Oshl }, + {OP_shr ,OP_Oshr }, + {OP_lt ,OP_Oless }, + {OP_lteq ,OP_Olessequal }, + {OP_gt ,OP_Ogreater }, + {OP_gteq ,OP_Ogreatequal }, + {OP_eqeq ,OP_Oequalequal }, + {OP_bangeq ,OP_Obangequal }, + {OP_and ,OP_Oand }, + {OP_xor ,OP_Oxor }, + {OP_or ,OP_Oor }, + {OP_andand ,OP_Oandand }, + {OP_oror ,OP_Ooror }, + {OP_eq ,OP_Oequal }, + {OP_multeq ,OP_Otimesequal }, + {OP_diveq ,OP_Odivequal }, + {OP_modeq ,OP_Opcentequal }, + {OP_pluseq ,OP_Oplusequal }, + {OP_minuseq ,OP_Ominusequal }, + {OP_shleq ,OP_Oleftequal }, + {OP_shreq ,OP_Orightequal }, + {OP_andeq ,OP_Oandequal }, + {OP_xoreq ,OP_Oxorequal }, + {OP_oreq ,OP_Oorequal }, + {OP_comma ,OP_Ocomma } +}; +#define BINARYOVLMAPCNT (sizeof (BinaryOvlMap)/sizeof (struct _OvlMap)) + + + + + +/** BinaryOverload - process overloaded binary operator + * + * fSuccess = BinaryOverload (bn) + * + * Entry bn = based pointer to operator node + * STP = pointer to left operand if not function operator + * ST = pointer to right operand if not function operator + * STP = pointer to argument list if function operator + * ST = pointer to class object if function operator + * + * Exit tree rewritten to function call and bound + * + * Returns TRUE if tree rewritten and bound correctly + * FALSE if error + * + * Note: If the node operator is post increment or decrement, then + * the code below will supply an implicit second argument of + * 0; + */ + + +LOCAL bool_t +BinaryOverload ( + bnode_t bn + ) +{ + ushort lenClass; + ushort lenGlobal; + HDEP hOld = 0; + HDEP hClass = 0; + HDEP hGlobal = 0; + pstree_t pOld = NULL; + pstree_t pClass = NULL; + pstree_t pGlobal = NULL; + bool_t fClass = FALSE; + bool_t fGlobal = FALSE; + bnode_t Fcn; + bnode_t Left; + bnode_t LeftRight; + bnode_t Arg1; + bnode_t Arg2; + bnode_t EndArg; + bnode_t Zero; + eval_t evalSTP = {0}; + eval_t evalST = {0}; + eval_t evalClass = {0}; + eval_t evalGlobal = {0}; + op_t OldOper = NODE_OP (pnodeOfbnode(bn)); + op_t Oper; + bool_t PostID = FALSE; + bool_t RightOp = TRUE; + peval_t pv; + ushort i; + + + // search for the overload operator name + + for (i = 0; i < BINARYOVLMAPCNT; i++) { + if (BinaryOvlMap[i].op == OldOper) { + break; + } + } + if (i == BINARYOVLMAPCNT) { + pExState->err_num = ERR_INTERNAL; + return (FALSE); + } + Oper = BinaryOvlMap[i].ovlfcn; + + lenClass = 3 * (sizeof (node_t) + sizeof (eval_t)) + sizeof (node_t) + + sizeof (node_t) + sizeof (argd_t); + + lenGlobal = 2 * (sizeof (node_t) + sizeof (eval_t)) + sizeof (node_t) + + 2 * (sizeof (node_t) + sizeof (argd_t)); + + if ((OldOper == OP_postinc) || (OldOper == OP_postdec)) { + // if we are processing post increment/decrement, then we have to + // supply the implicit zero second argument + + PostID = TRUE; + RightOp = FALSE; + lenClass += sizeof (node_t) + sizeof (eval_t); + lenGlobal += sizeof (node_t) + sizeof (eval_t); + } + + if ((hClass = DupETree (lenClass, &pClass)) == 0) { + return (FALSE); + } + if ((hGlobal = DupETree (lenGlobal, &pGlobal)) == 0) { + MHMemUnLock (hClass); + MHMemFree (hClass); + return (FALSE); + } + + // save and pop the left and right operands + + evalST = *ST; + PopStack (); + if (RightOp == TRUE) { + // if we have class--, class++ or class->, there is only one operand + // on the evaluation stack. Otherwise, we have to pop and save the + // right operand. + evalSTP = *ST; + PopStack (); + } + + // generate the expression tree for "a.operator@ (b)" + // and link it to the current node which is the made into an OP_noop + + hOld = pExState->hETree; + pOld = pTree; + pExState->hETree = hClass; + pTree = pClass; + + Fcn = (bnode_t)pTree->node_next; + Left = (bnode_t)((char *)Fcn + sizeof (node_t) + sizeof (eval_t)); + LeftRight = (bnode_t)((char *)Left + sizeof (node_t) + sizeof (eval_t)); + Arg1 = (bnode_t)((char *)LeftRight + sizeof (node_t) + sizeof (eval_t)); + EndArg = (bnode_t)((char *)Arg1 + sizeof (node_t) + sizeof (argd_t)); + if (PostID == TRUE) { + // if we are processing post increment/decrement, then we have to + // supply the implicit zero second argument + + Zero = (bnode_t)((char *)EndArg + sizeof (node_t)); // M00BUG? - removal of based + NODE_OP (pnodeOfbnode(Zero)) = OP_const; + pv = &pnodeOfbnode(Zero)->v[0]; + EVAL_STATE (pv) = EV_constant; + SetNodeType (pv, T_SHORT); + EVAL_SHORT (pv) = 0; + } + pTree->node_next += lenClass; + NODE_OP (pnodeOfbnode(Fcn)) = OP_function; + NODE_LCHILD (pnodeOfbnode(Fcn)) = Left; + NODE_OP (pnodeOfbnode(Left)) = OP_dot; + NODE_LCHILD (pnodeOfbnode(Left)) = NODE_LCHILD (pnodeOfbnode(bn)); + NODE_RCHILD (pnodeOfbnode(Left)) = LeftRight; + NODE_OP (pnodeOfbnode(LeftRight)) = Oper; + NODE_RCHILD (pnodeOfbnode(Fcn)) = Arg1; + NODE_OP (pnodeOfbnode(Arg1)) = OP_arg; + if (PostID == TRUE) { + NODE_LCHILD (pnodeOfbnode(Arg1)) = Zero; + } + else { + NODE_LCHILD (pnodeOfbnode(Arg1)) = NODE_RCHILD (pnodeOfbnode(bn)); + } + NODE_RCHILD (pnodeOfbnode(Arg1)) = EndArg; + NODE_OP (pnodeOfbnode(EndArg)) = OP_endofargs; + NODE_LCHILD (pnodeOfbnode(bn)) = Fcn; + NODE_RCHILD (pnodeOfbnode(bn)) = 0; + NODE_OP (pnodeOfbnode(bn)) = OP_noop; + + // bind method call + + CkPointStack (); + if ((fClass = Function (Fcn)) == TRUE) { + evalClass = *ST; + PopStack (); + } + if (ResetStack () == FALSE) { + pExState->err_num = ERR_INTERNAL; + return (FALSE); + } + + // the expression tree may have been altered during bind + + pClass = pTree; + hClass = pExState->hETree; + pExState->err_num = ERR_NONE; + + if ((OldOper != OP_function) && (OldOper != OP_eq) && + (OldOper != OP_lbrack)) { + + // generate the expression tree for "operator@ (a, b)" + // and link it to the current node which is the made into an OP_noop + + pExState->hETree = hGlobal; + pTree = pGlobal; + + Fcn = (bnode_t)pTree->node_next; + Left = (bnode_t)((char *)Fcn + sizeof (node_t) + sizeof (eval_t)); + Arg1 = (bnode_t)((char *)Left + sizeof (node_t) + sizeof (eval_t)); + Arg2 = (bnode_t)((char *)Arg1 + sizeof (node_t) + sizeof (argd_t)); + EndArg = (bnode_t)((char *)Arg2 + sizeof (node_t) + sizeof (argd_t)); + if (PostID == TRUE) { + // if we are processing post increment/decrement, then we have to + // supply the implicit zero second argument + + Zero = (bnode_t)((char *)EndArg + sizeof (node_t)); + NODE_OP (pnodeOfbnode(Zero)) = OP_const; + pv = &pnodeOfbnode(Zero)->v[0]; + EVAL_STATE (pv) = EV_constant; + SetNodeType (pv, T_SHORT); + EVAL_SHORT (pv) = 0; + } + pTree->node_next += lenGlobal; + NODE_OP (pnodeOfbnode(Fcn)) = OP_function; + NODE_LCHILD (pnodeOfbnode(Fcn)) = Left; + NODE_OP (pnodeOfbnode(Left)) = Oper; + NODE_RCHILD (pnodeOfbnode(Fcn)) = Arg1; + NODE_OP (pnodeOfbnode(Arg1)) = OP_arg; + NODE_LCHILD (pnodeOfbnode(Arg1)) = NODE_LCHILD (pnodeOfbnode(bn)); + NODE_RCHILD (pnodeOfbnode(Arg1)) = Arg2; + NODE_OP (pnodeOfbnode(Arg2)) = OP_arg; + if (PostID == TRUE) { + NODE_LCHILD (pnodeOfbnode(Arg2)) = Zero; + } + else { + NODE_LCHILD (pnodeOfbnode(Arg2)) = NODE_RCHILD (pnodeOfbnode(bn)); + } + NODE_RCHILD (pnodeOfbnode(Arg2)) = EndArg; + NODE_OP (pnodeOfbnode(EndArg)) = OP_endofargs; + NODE_LCHILD (pnodeOfbnode(bn)) = Fcn; + NODE_RCHILD (pnodeOfbnode(bn)) = 0; + NODE_OP (pnodeOfbnode(bn)) = OP_noop; + + // bind function call + + CkPointStack (); + if ((fGlobal = Function (Fcn)) == TRUE) { + evalGlobal = *ST; + PopStack (); + } + if (ResetStack () == FALSE) { + pExState->err_num = ERR_INTERNAL; + return (FALSE); + } + + // the expression tree may have been altered during bind + + pGlobal = pTree; + hGlobal = pExState->hETree; + pExState->err_num = ERR_NONE; + } + + if ((fClass == FALSE) && (fGlobal == FALSE)) { + pExState->err_num = ERR_NOOVERLOAD; + pExState->hETree = hOld; + pTree = pOld; + MHMemUnLock (hClass); + MHMemFree (hClass); + MHMemUnLock (hGlobal); + MHMemFree (hGlobal); + PushStack (&evalSTP); + if (PostID == FALSE) { + PushStack (&evalST); + } + return (FALSE); + } + else if ((fClass == TRUE) && (fGlobal == TRUE)) { + pExState->err_num = ERR_AMBIGUOUS; + pExState->hETree = hOld; + pTree = pOld; + MHMemUnLock (hClass); + MHMemFree (hClass); + MHMemUnLock (hGlobal); + MHMemFree (hGlobal); + return (FALSE); + } + else if (fClass == TRUE) { + pExState->hETree = hClass; + pTree = pClass; + MHMemUnLock (hGlobal); + MHMemFree (hGlobal); + MHMemUnLock (hOld); + MHMemFree (hOld); + return (PushStack (&evalClass)); + } + else { + MHMemUnLock (hClass); + MHMemFree (hClass); + MHMemUnLock (hOld); + MHMemFree (hOld); + return (PushStack (&evalGlobal)); + } +} + + + + +struct _OvlMap UnaryOvlMap[] = { + {OP_bang ,OP_Obang }, + {OP_tilde ,OP_Otilde }, + {OP_negate ,OP_Ominus }, + {OP_uplus ,OP_Oplus }, + {OP_fetch ,OP_Ostar }, + {OP_addrof ,OP_Oand }, +}; +#define UNARYOVLMAPCNT (sizeof (UnaryOvlMap)/sizeof (struct _OvlMap)) + + + + +/** UnaryOverload - process overloaded unary operator + * + * fSuccess = UnaryOverload (bn) + * + * Entry bn = based pointer to operator node + * ST = pointer to operand (actual operand if pv is reference) + * + * Exit tree rewritten to function call and bound + * + * Returns TRUE if tree rewritten and bound correctly + * FALSE if error + */ + + +LOCAL bool_t +UnaryOverload ( + bnode_t bn + ) +{ + ushort lenClass; + ushort lenGlobal; + HDEP hOld = 0; + HDEP hClass = 0; + HDEP hGlobal = 0; + pstree_t pOld = NULL; + pstree_t pClass = NULL; + pstree_t pGlobal = NULL; + bool_t fClass; + bool_t fGlobal; + bnode_t Fcn; + bnode_t Left; + bnode_t LeftRight; + bnode_t Right; + bnode_t RightRight; + eval_t evalST = {0}; + eval_t evalClass = {0}; + eval_t evalGlobal = {0}; + op_t Oper = NODE_OP (pnodeOfbnode(bn)); + ushort i; + + // search for the overload operator name + + + for (i = 0; i < UNARYOVLMAPCNT; i++) { + if (UnaryOvlMap[i].op == Oper) { + break; + } + } + if (i == UNARYOVLMAPCNT) { + pExState->err_num = ERR_INTERNAL; + return (FALSE); + } + Oper = UnaryOvlMap[i].ovlfcn; + + // the amount of space required for an overloaded unary method is + // OP_function + OP_dot + OP_ident + OP_endofargs + // There is actually another node which is the unary operand but we + // reuse that (subtree) node + + lenClass = 3 * (sizeof (node_t) + sizeof (eval_t)) + sizeof (node_t); + + // the amount of space required for an overloaded unary global is + // OP_function + OP_ident + OP_arg + OP_ident + OP_endofargs + + lenGlobal = 3 * (sizeof (node_t) + sizeof (eval_t)) + sizeof (node_t) + + sizeof (node_t) + sizeof (argd_t); + + if ((hClass = DupETree (lenClass, &pClass)) == 0) { + return (FALSE); + } + if ((hGlobal = DupETree (lenGlobal, &pGlobal)) == 0) { + MHMemUnLock (hClass); + MHMemFree (hClass); + return (FALSE); + } + + // save and pop the current stack top + + evalST = *ST; + PopStack (); + + // generate the expression tree for "a.operator@ ()" + // and link it to the current node which is the made into an OP_noop + + hOld = pExState->hETree; + pOld = pTree; + pExState->hETree = hClass; + pTree = pClass; + + Fcn = (bnode_t)pTree->node_next; + Left = (bnode_t)((char *)Fcn + sizeof (node_t) + sizeof (eval_t)); + LeftRight = (bnode_t)((char *)Left + sizeof (node_t) + sizeof (eval_t)); + Right = (bnode_t)((char *)LeftRight + sizeof (node_t) + sizeof (eval_t)); + pTree->node_next += lenClass; + NODE_OP (pnodeOfbnode(Fcn)) = OP_function; + NODE_LCHILD (pnodeOfbnode(Fcn)) = Left; + NODE_OP (pnodeOfbnode(Left)) = OP_dot; + NODE_LCHILD (pnodeOfbnode(Left)) = NODE_LCHILD (pnodeOfbnode(bn)); + NODE_RCHILD (pnodeOfbnode(Left)) = LeftRight; + NODE_OP (pnodeOfbnode(LeftRight)) = Oper; + NODE_RCHILD (pnodeOfbnode(Fcn)) = Right; + NODE_OP (pnodeOfbnode(Right)) = OP_endofargs; + NODE_LCHILD (pnodeOfbnode(bn)) = Fcn; + NODE_RCHILD (pnodeOfbnode(bn)) = 0; + NODE_OP (pnodeOfbnode(bn)) = OP_noop; + + // bind method call + + CkPointStack (); + if ((fClass = Function (Fcn)) == TRUE) { + evalClass = *ST; + PopStack (); + } + if (ResetStack () == FALSE) { + pExState->err_num = ERR_INTERNAL; + return (FALSE); + } + + // the expression tree may have been altered during bind + + pClass = pTree; + pExState->err_num = ERR_NONE; + + // generate the expression tree for "operator@ (a)" + // and link it to the current node which is the made into an OP_noop + + pExState->hETree = hGlobal; + pTree = pGlobal; + + Fcn = (bnode_t)pTree->node_next; + Left = (bnode_t)((char *)Fcn + sizeof (node_t) + sizeof (eval_t)); + Right = (bnode_t)((char *)Left + sizeof (node_t) + sizeof (eval_t)); + RightRight = (bnode_t)((char *)Right + sizeof (node_t) + sizeof (argd_t)); + pTree->node_next += lenGlobal; + NODE_OP (pnodeOfbnode(Fcn)) = OP_function; + NODE_LCHILD (pnodeOfbnode(Fcn)) = Left; + NODE_OP (pnodeOfbnode(Left)) = Oper; + NODE_RCHILD (pnodeOfbnode(Fcn)) = Right; + NODE_OP (pnodeOfbnode(Right)) = OP_arg; + NODE_LCHILD (pnodeOfbnode(Right)) = NODE_LCHILD (pnodeOfbnode(bn)); + NODE_RCHILD (pnodeOfbnode(Right)) = RightRight; + NODE_OP (pnodeOfbnode(RightRight)) = OP_endofargs; + NODE_LCHILD (pnodeOfbnode(bn)) = Fcn; + NODE_RCHILD (pnodeOfbnode(bn)) = 0; + NODE_OP (pnodeOfbnode(bn)) = OP_noop; + + // bind function call + + CkPointStack (); + if ((fGlobal = Function (Fcn)) == TRUE) { + evalGlobal = *ST; + PopStack (); + } + if (ResetStack () == FALSE) { + pExState->err_num = ERR_INTERNAL; + return (FALSE); + } + + // the expression tree may have been altered during bind + + pGlobal = pTree; + pExState->err_num = ERR_NONE; + + if ((fClass == FALSE) && (fGlobal == FALSE)) { + pExState->err_num = ERR_NOOVERLOAD; + pExState->hETree = hOld; + pTree = pOld; + MHMemUnLock (hClass); + MHMemFree (hClass); + MHMemUnLock (hGlobal); + MHMemFree (hGlobal); + PushStack (&evalST); + return (FALSE); + } + else if ((fClass == TRUE) && (fGlobal == TRUE)) { + pExState->err_num = ERR_AMBIGUOUS; + pExState->hETree = hOld; + pTree = pOld; + MHMemUnLock (hClass); + MHMemFree (hClass); + MHMemUnLock (hGlobal); + MHMemFree (hGlobal); + return (FALSE); + } + else if (fClass == TRUE) { + pExState->hETree = hClass; + pTree = pClass; + MHMemUnLock (hGlobal); + MHMemFree (hGlobal); + MHMemUnLock (hOld); + MHMemFree (hOld); + return (PushStack (&evalClass)); + } + else { + MHMemUnLock (hClass); + MHMemFree (hClass); + MHMemUnLock (hOld); + MHMemFree (hOld); + return (PushStack (&evalGlobal)); + } +} + + + + +/** PointsToOverload - process overloaded -> operator + * + * fSuccess = PointsToOverload (bn) + * + * Entry bn = based pointer to operator node + * ST = pointer to operand (actual operand if pv is reference) + * + * Exit tree rewritten to function call and bound + * + * Returns TRUE if tree rewritten and bound correctly + * FALSE if error + */ + + +LOCAL bool_t +PointsToOverload ( + bnode_t bn + ) +{ + pExState->err_num = ERR_OVLPOINTSTO; + return (FALSE); +} + + + + +/** DupETree - Duplicate Expression Tree + * + * hNew = DupETree (count, ppTree) + * + * Entry count = number of free bytes required in new expression tree + * ppTree = pointer to expression tree address + * + * Exit Current expression tree duplicated + * ppTree = address of locked expression tree + * additional memory cleared + * + * Returns 0 if expression tree not duplicated + * memory handle if expression tree duplicated + */ + +LOCAL HDEP +DupETree ( + ushort count, + pstree_t *ppTree + ) +{ + HDEP hNew; + + // copy syntax tree + + if ((hNew = MHMemAllocate (pTree->node_next + count)) == 0) { + pExState->err_num = ERR_NOMEMORY; + return (hNew); + } + *ppTree = (pstree_t)MHMemLock (hNew); + memcpy (*ppTree, pTree, pTree->node_next); + (*ppTree)->size = pTree->node_next + count; + memset ((char *)*ppTree + (*ppTree)->node_next, 0, count); + return (hNew); +} + + + + +/** Type and context parsing + * + */ + + + +/** FcnCast - check to see if function call is a functional style cast + * + * fSuccess = FcnCast (bn) + * + * Entry bn = based pointer to OP_function node which has exactly + * one argument node. + * + * Exit the OP_function node is changed to an OP_cast node + * + * Returns TRUE if the "function name" is a primitive type or a UDT + * and the tree was rewritten as an OP_cast + * FALSE if the function is not a cast node + */ + + +LOCAL bool_t FASTCALL +FcnCast ( + bnode_t bn + ) +{ + peval_t pv; + bnode_t bnLeft = NODE_LCHILD (pnodeOfbnode(bn)); + + // Check for casting a class to anything, not having a symbol or + // the symbol not being a type + + if (EVAL_IS_CLASS (ST)) { + pExState->err_num = ERR_CONSTRUCTOR; + return (FALSE); + } + if (EVAL_IS_BITF (STP)) { + // change the type of the node to the underlying type + EVAL_TYP (STP) = BITF_UTYPE (STP); + } + NODE_OP (pnodeOfbnode(bn)) = OP_cast; + NODE_RCHILD (pnodeOfbnode(bn)) = NODE_LCHILD (pnodeOfbnode(NODE_RCHILD (pnodeOfbnode(bn)))); + + // copy the base type node up to the cast node and then try to find a + // way to cast the stack to to the base type + + pv = (peval_t)&pnodeOfbnode(bnLeft)->v[0]; + PopStack (); + if (CastPtrToPtr (bn) == TRUE) { + // the desired type is a base class so we can just set the node type. + // the value portion of bn contains the data to cast right to left + + return (SetNodeType (ST, EVAL_TYP (pv))); + } + else { + return (CastNode (ST, EVAL_TYP (pv), PTR_UTYPE (pv))); + } +} + + + + +/** GetID - get identifier length from string + * + * len = GetID (pb) + * + * Entry pb = pointer to string + * + * Exit none + * + * Returns length of next token + * if *pb is a digit, len = 0 + */ + + +LOCAL uchar FASTCALL +GetID ( + char *pb + ) +{ + char *start = pb; + char c = *pb++; + + if (isdigit (c)) + return (0); + if ((c == '*') || (c == '&')) + return (1); + while (iscsym(c) || c == '$' || c == '@') { + c = *pb++; + } + /* return length of string */ + return ((uchar)(pb - start - 1)); +} + + + +/** ParseType - parse a type string + * + * fSuccess = ParseType (bn) + * + * Entry bn = based pointer to node referencing "(typestring)" + * + * Exit + * + * Returns TRUE if valid type string + * FALSE if error in type string + */ + + +LOCAL bool_t FASTCALL +ParseType ( + bnode_t bn + ) +{ + pnode_t pn = pnodeOfbnode(bn); + char *pb; + char *pbEnd; + peval_t pv; + bool_t cmpflag; + uchar len; + ulong mask = 0; + CV_typ_t type = 0; + ushort mode = 0; + ushort btype = 0; + ushort size = 0; + struct typrec *p; + eval_t evalT = {0}; + peval_t pvT = &evalT; + CV_modifier_t Mod = {0}; + bool_t searchmask; + MTYP_t retval; + + pb = pExStr + EVAL_ITOK (&pn->v[0]); + pbEnd = pb + EVAL_CBTOK (&pn->v[0]); + if (*pb == '(') { + pb++; + pbEnd--; + } + pv = &pn->v[0]; + EVAL_TYPDEF (pv) = 0; + for (;;) { + while (isspace (*pb)) + ++pb; + if (pb >= pbEnd) { + // end of type string + break; + } + if (*pb == 0) { + goto typebad; + } + len = GetID (pb); + if ((cmpflag = len) == 0) { + goto typebad; + } + else { + for (p = Predef; p->token[0] != 0; p++) { + if ((p->token[0] == len) && + ((cmpflag = strncmp ((char *)&p->token[1], pb, len)) == 0)) { + break; + } + } + if (cmpflag == 0) { + // a predefined token was encountered + mask |= p->flags; + } + else { + if (((mask & TY_UDT) != 0) || + !FindUDT (bn, pvT, pExStr, pb, len)) { + // we either already have a UDT or we could not + // find this one + goto typebad; + } + else { + type = EVAL_TYP (pvT); + mask |= TY_UDT; + } + } + // skip to end of token and continue + pb += len; + } + } + + // check error conditions At this point we are checking obvious errors + // such as a user defined type without a type index, multiple pointer modes, + // no valid type specifiers, mixed arithmetic types + + if (mask == 0) { + // no type specifiers found + goto typebad; + } + if (mask & TY_REF) { + //M00KLUDGE - what about int& + if (mask & TY_PTR) { + goto typebad; + } + } + switch (mask & TY_PTR) { + case TY_POINTER: + // set ambiant model from compile flag symbol + switch (SetAmbiant (TRUE)) { + default: + case CV_PTR_NEAR: + mask |= TY_NEAR; + mode = CV_TM_NPTR; + break; + + case CV_PTR_FAR: + mask |= TY_FAR; + mode = CV_TM_FPTR; + break; + + case CV_PTR_NEAR32: + mask |= TY_NEAR; + mode = CV_TM_NPTR32; + break; + + case CV_PTR_FAR32: + mask |= TY_FAR; + mode = CV_TM_FPTR32; + break; + + case CV_PTR_HUGE: + mask |= TY_HUGE; + mode = CV_TM_HPTR; + break; + } + break; + + case TY_POINTER | TY_NEAR: + mode = CV_TM_NPTR; + break; + + case TY_POINTER | TY_FAR: + mode = CV_TM_FPTR; + break; + + case TY_POINTER | TY_HUGE: + mode = CV_TM_HPTR; + break; + + case 0: + mode = CV_TM_DIRECT; + break; + + default: + // pointer mode conflict + goto typebad; + } + switch (mask & (TY_AGGR | TY_UDT)) { + case TY_UDT: + case TY_UDT | TY_CLASS: + case TY_UDT | TY_STRUCT: + case TY_UDT | TY_UNION: + case 0: + break; + + default: + // conflict in aggregrate type + goto typebad; + } + if (((mask & TY_REAL) != 0) && ((mask & TY_NOTREAL) != 0)) { + // real type specified with conflicting modifiers + goto typebad; + } + if (((mask & TY_UDT) != 0) && ((mask & TY_ARITH) != 0)) { + // user defined type and arithmetic type specified + goto typebad; + } + if ((mask & TY_SIGN) == TY_SIGN) { + // both sign modifers specified + goto typebad; + } + + if ((mask & TY_UDT) != 0) { + // user defined type specified + + *pv = *pvT; + if (CV_IS_PRIMITIVE (EVAL_TYP (pvT))) { + // if the user defined type is an alias for a primitive type + // set the pointer mode bits into the type + + type |= (mode << CV_MSHIFT); + } + else { + if ((mask & (TY_PTR | TY_REF)) == 0) { + // the UDT was not modified to a pointer or reference + type = EVAL_TYP (pvT); + } + else { + // the UDT was modified to a pointer. try to find the + // correct pointer type + + if ((mask & TY_CONST) == TY_CONST) { + Mod.MOD_const = TRUE; + } + else if ((mask & TY_VOLATILE) == TY_VOLATILE) { + Mod.MOD_volatile = TRUE; + } + ProtoPtr (pvT, pv, ((mask & TY_REF) == TY_REF), Mod); + switch (mask & TY_PTR) { + case TY_POINTER: + // set ambiant model from compile flag symbol + EVAL_PTRTYPE (pvT) = (uchar)SetAmbiant (TRUE); + break; + + case TY_POINTER | TY_NEAR: + if (mode == CV_TM_NPTR32) { + EVAL_PTRTYPE (pvT) = CV_PTR_NEAR32; + } else { + EVAL_PTRTYPE (pvT) = CV_PTR_NEAR; + } + break; + + case TY_POINTER | TY_FAR: + EVAL_PTRTYPE (pvT) = CV_PTR_FAR; + break; + + case TY_POINTER | TY_HUGE: + EVAL_PTRTYPE (pvT) = CV_PTR_HUGE; + break; + } + searchmask = ((mask & TY_CONST) == TRUE) || + ((mask & TY_VOLATILE) == TRUE); + + if (searchmask == FALSE) { + retval = MatchType (pvT, FALSE); + } + else { + retval = MatchType (pvT, TRUE); + } + switch (retval) { + case MTYP_exact: + case MTYP_inexact: + // searching the context of the class type for + // a type record which is a pointer record and + // has the current type as its underlying type + // has succeeded + + type = EVAL_TYP (pvT); + break; + + case MTYP_none: + // fake out the caster by using a created pointer + switch (mask & TY_PTR) { + case TY_POINTER: + type = T_FCVPTR; + break; + + case TY_POINTER | TY_NEAR: + type = T_NCVPTR; + break; + + case TY_POINTER | TY_FAR: + type = T_FCVPTR; + break; + + case TY_POINTER | TY_HUGE: + type = T_HCVPTR; + break; + + default: + goto typebad; + } + break; + } + } + } + } + else { + // type must be primitive or a pointer to a primitive type + + if (!BuildType (&type, &mask, &mode, &btype, &size)) { + goto typebad; + } + if ((mask & (TY_REF | TY_CONST | TY_VOLATILE)) != 0) { + // the primitive type was modified to a const, volatile or + // reference. We will need to search for a type record that + // has the primitive type as the underlying type + + SetNodeType (pv, type); + EVAL_MOD (pv) = SHHMODFrompCXT (pCxt); + *pvT = *pv; + if ((mask & TY_REF) != 0) { + ProtoPtr (pvT, pv, ((mask & TY_REF) == TY_REF), Mod); + switch (mask & TY_PTR) { + case TY_POINTER: + // set ambiant model from compile flag symbol + EVAL_PTRTYPE (pvT) = (uchar)SetAmbiant (TRUE); + break; + + case TY_POINTER | TY_NEAR: + EVAL_PTRTYPE (pvT) = CV_PTR_NEAR; + break; + + case TY_POINTER | TY_FAR: + EVAL_PTRTYPE (pvT) = CV_PTR_FAR; + break; + + case TY_POINTER | TY_HUGE: + EVAL_PTRTYPE (pvT) = CV_PTR_HUGE; + break; + } + } + else if ((mask & TY_CONST) == TY_CONST) { + EVAL_IS_CONST (pvT) = TRUE; + searchmask = TRUE; + } + else if ((mask & TY_VOLATILE) == TY_VOLATILE) { + EVAL_IS_VOLATILE (pvT) = TRUE; + searchmask = TRUE; + } + if (searchmask == FALSE) { + retval = MatchType (pvT, FALSE); + } + else { + retval = MatchType (pvT, TRUE); + } + switch (retval) { + case MTYP_exact: + case MTYP_inexact: + // searching the context of the class type for + // a type record which is a pointer record and + // has the current type as its underlying type + // has succeeded + + type = EVAL_TYP (pvT); + break; + + case MTYP_none: + goto typebad; + } + } + } + EVAL_STATE (pv) = EV_type; + return (SetNodeType (pv, type)); + + +typebad: + // If not "(type-name)" + pExState->err_num = ERR_TYPECAST; + return (FALSE); + +} + + + + + +LOCAL bool_t FASTCALL +BuildType ( + CV_typ_t *type, + ulong *mask, + ushort *mode, + ushort *btype, + ushort *size + ) +{ + + // type must be primitive or a pointer to a primitive type + + if (((*mask & TY_VOID) == 0) && + ((*mask & (TY_REAL | TY_INTEGRAL)) == 0)) { + // no type specified so set default to the int of the moment. + *mask |= (ADDR_IS_OFF32(*SHpADDRFrompCXT(pCxt)) ? TY_LONG : TY_SHORT); + } + if ((*mask & TY_REAL) != 0) { + *btype = CV_REAL; + switch (*mask & (TY_REAL | TY_LONG)) { + case TY_FLOAT: + *size = CV_RC_REAL32; + break; + + case TY_DOUBLE: + *size = CV_RC_REAL64; + break; + + case TY_DOUBLE | TY_LONG: +#if defined( LONG_DOUBLE_80 ) + *size = CV_RC_REAL80; +#endif +#if defined( LONG_DOUBLE_64 ) + *size = CV_RC_REAL64; +#endif + break; + + default: + DASSERT (FALSE); + return (FALSE); + } + } + else if ((*mask & TY_INTEGRAL) != 0) { + if (*mask & TY_INT) { + *btype = CV_INT; + // user specified int possibly along with sign and size + switch (*mask & (TY_SIGN | TY_SHORT | TY_LONG)) { + case 0: + case TY_SIGNED: + // + *size = (ADDR_IS_OFF32(*SHpADDRFrompCXT(pCxt))) ? CV_RI_INT4 : CV_RI_INT2; + break; + + case TY_SHORT: + case TY_SHORT | TY_SIGNED: + // set default integral types to signed two byte int + *size = CV_RI_INT2; + break; + + case TY_UNSIGNED: + *size = (ADDR_IS_OFF32(*SHpADDRFrompCXT(pCxt))) ? CV_RI_UINT4 : CV_RI_UINT2; + break; + + case TY_SHORT | TY_UNSIGNED: + // set default integral types to signed two byte int + *size = CV_RI_UINT2; + break; + + case TY_LONG: + case TY_LONG | TY_SIGNED: + // set default integral types to signed two byte int + *size = CV_RI_INT4; + break; + + case TY_LONG | TY_UNSIGNED: + // set default integral types to signed two byte int + *size = CV_RI_UINT4; + break; + + default: + DASSERT (FALSE); + return (FALSE); + } + } + else if ((*mask & TY_CHAR) != 0) { + // user specified a character type + + switch (*mask & TY_SIGN) { + case 0: + // if no sign was specified, we are looking for a + // real character + + *btype = CV_INT; + *size = CV_RI_CHAR; + break; + + case TY_SIGNED: + *btype = CV_SIGNED; + *size = CV_IN_1BYTE; + break; + + case TY_UNSIGNED: + *btype = CV_UNSIGNED; + *size = CV_IN_1BYTE; + break; + } + } + else { + switch (*mask & TY_SIGN) { + case 0: + // set default integral types to signed + *mask |= TY_SIGNED; + case TY_SIGNED: + *btype = CV_SIGNED; + break; + + case TY_UNSIGNED: + *btype = CV_UNSIGNED; + break; + } + switch (*mask & TY_INTEGRAL) { + case TY_CHAR: + *size = CV_IN_1BYTE; + break; + + case TY_SHORT: + *size = CV_IN_2BYTE; + break; + + case TY_LONG: + *size = CV_IN_4BYTE; + break; + } + } + + } + else if ((*mask & TY_VOID) != 0) { + if (*mask & (TY_ARITH | TY_REAL | TY_AGGR | TY_SIGN) != 0) { + return (FALSE); + } + *btype = CV_SPECIAL; + *size = CV_SP_VOID; + } + else { + DASSERT (FALSE); + return (FALSE); + } + + *type = (*mode << CV_MSHIFT) | (*btype << CV_TSHIFT) | (*size << CV_SSHIFT); + return (TRUE); +} + + + + +/** FindUDT - find user defined type + * + * fSuccess = FindUDT (bn, pv, pStr, pb, len) + * + * Entry pv = pointer to evaluation node + * pStr = pointer to beginning of input string + * pb = pointer to structure name + * len = length of name + * + * Exit EVAL_TYP (pv) = type index + * + * Returns TRUE if UDT found + * FALSE if error + * + * Looks in the current module only. + */ + + +LOCAL bool_t +FindUDT ( + bnode_t bn, + peval_t pv, + char *pStr, + char *pb, + uchar len + ) +{ + search_t Name; + + EVAL_TYP (pv) = 0; + EVAL_ITOK (pv) = pb - pStr; + EVAL_CBTOK (pv) = len; + + // M00SYMBOL - need to allow for T::U::V::type + + InitSearchSym (bn, pv, &Name, 0, SCP_all, CLS_enumerate | CLS_ntype); + // modify search to look only for UDTs + + Name.sstr.searchmask = SSTR_symboltype; + Name.sstr.symtype = S_UDT; + switch (SearchSym (&Name)) { + case HR_notfound: + break; + + case HR_found: + // if the symbol was found, it was pushed onto the stack + PopStack (); + if (EVAL_STATE (pv) == EV_type) { + return (TRUE); + } + break; + + case HR_rewrite: + DASSERT (FALSE); + return (FALSE); + } + return (FALSE); +} + + + +LOCAL bool_t FASTCALL +ContextToken( + char * * ppStr, + char * * ppTok, + short * pcTok + ) +/*++ + +Routine Description: + + This function will parse a string looking for the next legal item + in a context token. These are defined as strings delimiated by + either commas or right brackets in which the number of parentheses + is balanced. + +Arguments: + + ppStr - Supplies a pointer to the string to be parsed + ppTok - Returns a pointer to the start of the context token + pcTok - Returns the number of characters in the token + +Return Value: + + TRUE if a token was successfully found, and FALSE on error + +--*/ + +{ + int cParenOpen = 0; + short pdepth = 0; + char ch; + int cchTok; + char * pStr = *ppStr; + + /* + * Skip leading white space + */ + + while (iswspace(*pStr)) { + pStr++; + } + + /* + * If at the end of the context specifier then return -1 for the + * character count to indicate that the token does not exist + */ + + if (*pStr == '}') { + *pcTok = -1; + *ppStr = pStr; + return (TRUE); + } + + /* + * Start scaning over the token string. Balance all parentheses + * so that we get the entire expression. Check for a paren + * off the front since we don't care to look at it. + */ + + cchTok = 0; + while (*pStr == '(') { + cParenOpen += 1; + pStr++; + pdepth += 1; + } + *ppTok = pStr; +#ifdef DBCS + while ((ch = *pStr, (pStr = CharNext(pStr)), ch) != 0) { + /* + * increment count of characters in token + */ + cchTok += pStr - CharPrev(*ppTok,pStr); +#else + while ((ch = *pStr++) != 0) { + /* + * increment count of characters in token + */ + + cchTok += 1; +#endif + switch (ch) { + /* + * increment parentheses depth + */ + + case '(': + pdepth++; + break; + + /* + * Decrement parentheses depth -- checking for overflow + */ + + case ')': + if (--pdepth < 0) { + return (FALSE); + } else if (pdepth == 0) { + if (cParenOpen) { + /* + * for a parentheses enclosed string, adjust count and + * skip blanks to either , or } that terminates the + * token. Any other character is an error + */ + + cParenOpen -= 1; + cchTok -= 1; + + /* + * Make sure that all of the openning parens + * are accounted for + */ + + while (cParenOpen) { + while (iswspace(*pStr)) { + pStr++; + } + if (*pStr != ')') { + *pcTok = cchTok; + *ppStr = pStr; + return FALSE; + } + cParenOpen -= 1; + } + + /* + * Skip over any more white space and the next character + * must be either a comma or a close bracket to mark + * the end of this token. + */ + + while (iswspace(*pStr)) { + pStr++; + } + + switch (*pStr) { + case ',': + /* + * skip over the , terminating the token + */ + pStr++; + + case '}': + *pcTok = cchTok; + *ppStr = pStr; + return (TRUE); + + default: + *pcTok = cchTok; + *ppStr = pStr; + return (FALSE); + } + } + } + break; + + default: + if (pdepth > 0) { + /* + * any character inside parentheses is ignored + */ + break; + } + /* + * decrement character count of token and reset pointer to } + * so next scan will find it + */ + + else if (ch == '}') { + pStr -= 1; + cchTok -= 1; + *pcTok = cchTok; + *ppStr = pStr; + return (TRUE); + } + /* + * decrement character count of token but leave pointer past comma + * so next scan will find following token + */ + + else if (ch == ',') { + cchTok -= 1; + *pcTok = cchTok; + *ppStr = pStr; + return (TRUE); + } + break; + } + } + *pcTok = cchTok; + *ppStr = pStr; + return (FALSE); +} /* ContextToken() */ + + + + + +/** InitSearchSym - initialize symbol search + * + * InitSearchSym (bn, pName, iClass, scope, clsmask) + * + * Entry bn = based pointer to node of symbol + * pName = pointer to symbol search structure + * iClass = initial class if explicit class reference + * scope = mask describing scope of search + * clsmask = mask describing permitted class elements + * + * Exit search structure initialized for SearchSym + * + * Returns pointer to search symbol structure + */ + + +void +InitSearchSym ( + bnode_t bn, + peval_t pv, + psearch_t pName, + CV_typ_t iClass, + ushort scope, + ushort clsmask + ) +{ + op_t op = NODE_OP (pnodeOfbnode(bn)); + + // set starting context for symbol search to current context + + memset (pName, 0, sizeof (*pName)); + pName->initializer = INIT_sym; + pName->pfnCmp = FNCMP; + pName->pv = pv; + pName->scope = scope; + pName->clsmask = clsmask; + pName->CXTT = *pCxt; + pName->bn = bn; + pName->bnOp = 0; + + // set pointer to symbol name + + if ((op >= OP_this) && (op <= OP_Odelete)) { + pName->sstr.lpName = (uchar *)&OpName[op - OP_this].str[1]; + pName->sstr.cb = OpName[op - OP_this].str[0]; + } + else { + pName->sstr.lpName = (uchar *)pExStr + EVAL_ITOK (pv); + pName->sstr.cb = EVAL_CBTOK (pv); + } + pName->state = SYM_init; + if ((pName->ExpClass = iClass) != 0) { + // restrict searching to class scope + pName->scope &= SCP_class; + } +} + + + + +/** InitSearchRight - initialize right symbol search + * + * InitSearchRight (bnOp, bn, pName, clsmask) + * + * Entry bnOp = based pointer to node of operator + * bn = based pointer to node of symbol + * pName = pointer to symbol search structure + * iClass = initial class if explicit class reference + * scope = mask describing scope of search + * clsmask = mask describing permitted class elements + * + * Exit search structure initialized for SearchSym + * + * Returns pointer to search symbol structure + */ + + +void +InitSearchRight ( + bnode_t bnOp, + bnode_t bn, + psearch_t pName, + ushort clsmask + ) +{ + peval_t pv = &pnodeOfbnode(bn)->v[0]; + pnode_t pn = pnodeOfbnode(bn); + op_t op = NODE_OP (pnodeOfbnode(bn)); + + // set starting context for symbol search to current context + + memset (pName, 0, sizeof (*pName)); + pName->initializer = INIT_right; + pName->pfnCmp = FNCMP; + pName->pv = pv; + pName->scope = SCP_class; + pName->clsmask = clsmask; + pName->CXTT = pn->pcxf ? pn->pcxf->cxt : *pCxt; + pName->bn = bn; + pName->bnOp = bnOp; + + // set pointer to symbol name + if ((op >= OP_this) && (op <= OP_Odelete)) { + pName->sstr.lpName = (uchar *)&OpName[op - OP_this].str[1]; + pName->sstr.cb = OpName[op - OP_this].str[0]; + } + else { + pName->sstr.lpName = (uchar *)pExStr + EVAL_ITOK (pv); + pName->sstr.cb = EVAL_CBTOK (pv); + } + pName->state = SYM_init; + // restrict searching to class scope + pName->ExpClass = ClassExp; + pName->scope = SCP_class; +} |