diff options
author | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
---|---|---|
committer | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
commit | e611b132f9b8abe35b362e5870b74bce94a1e58e (patch) | |
tree | a5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/sdktools/masm/asmeval.c | |
download | NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2 NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip |
Diffstat (limited to 'private/sdktools/masm/asmeval.c')
-rw-r--r-- | private/sdktools/masm/asmeval.c | 1472 |
1 files changed, 1472 insertions, 0 deletions
diff --git a/private/sdktools/masm/asmeval.c b/private/sdktools/masm/asmeval.c new file mode 100644 index 000000000..7c4be84a0 --- /dev/null +++ b/private/sdktools/masm/asmeval.c @@ -0,0 +1,1472 @@ +/* asmeval.c -- microsoft 80x86 assembler +** +** microsoft (r) macro assembler +** copyright (c) microsoft corp 1986. all rights reserved +** +** randy nevin +** +** 10/90 - Quick conversion to 32 bit by Jeff Spencer +*/ + +#include <stdio.h> +#include "asm86.h" +#include "asmfcn.h" +#include "asmexpr.h" + + +char parseset[] = {14, + OPUNPLUS, OPPLUS, + OPMINUS, OPUNMINUS, + OPHIGH, OPLOW, + OPDOT, OPOFFSET, + OPCOLON, OPLPAR, + OPLBRK, OPTHIS, + OPSHORT, OPPTR}; + +/* POPvalue pops a operand from the top of the evaluation stack + If the item is not an operand or the stack is empty, an + error is generated and a value of 0 is supplied. The operand + is returned to the caller in <valu> and is a result type + operand. The original operand will not be a result unless it + has been already used. The operand entry is destroyed and a + result operand is created for constants and symbols( which + are not record/struc names or fields ). */ + + + + +/*** valerror - process error in operand entry + * + * valerror (p); + * + * Entry + * Exit + * Returns + * Calls + */ + + + +VOID PASCAL CODESIZE +valerror ( + register struct ar *p +){ + DSCREC *oldlast; + + /* Operand was expected */ + errorc (E_OPN); + /* save expr stack */ + oldlast = p->lastitem; + p->lastitem = defaultdsc (); + /* Point to rest */ + p->lastitem->previtem = oldlast; +} + + + + +/*** popvalue - pop operand entry off parse stack + * + * dscrec = popvalue (p); + * + * Entry + * Exit + * Returns + * Calls + */ + + + +DSCREC * PASCAL CODESIZE +popvalue ( + register struct ar *p +){ + register DSCREC *valu; + + if (!p->lastitem) + valerror (p); + if (p->lastitem->itype != OPERAND) + valerror (p); + /* If not operand, insert one at LASTitem */ + /* In case need to convert */ + valu = p->lastitem; + /* Assume won't convert */ + /* Pop operand off stack */ + p->lastitem = valu->previtem; + return (valu); +} + + + + +/*** popoperator - pop next operator from stack + * + * op = popoperator (p); + * + * Entry *p = parse stack entry + * Exit + * Returns operator + * Calls + */ + + +UCHAR PASCAL CODESIZE +popoperator ( + register struct ar *p +){ + register char op; + + if (!p->lastitem) { + errorc( E_OPR ); /* expected operator */ + return( (char)OPPLUS ); /* use '+' as default */ + } + else { + if (p->lastitem->itype != OPERATOR) { + errorc( E_OPR ); /* expected operator */ + return( (char)OPPLUS ); /* use '+' as default */ + } + else { + /* Return OPERATOR number */ + op = p->lastitem->dsckind.opr.oidx; + /* Pop OPERATOR off stack */ + itemptr = p->lastitem; + p->lastitem = p->lastitem->previtem; + return (op); + } + } +} + + +/* Evaluate is called to evaluate part of the expression. It is + usually called just before a lower precedence is pushed, but + also when the expression is complete and for close parens of + various kinds regadless of precedence. The amount of the + expression stack evauated depends on the caller. There are + 3 cases: + + 1. Lower precedence OPERATOR( 3+4*5 AND 3 ). Evaluate + back until left paren or precedence<= OPERATOR. If + paren, leave on stack. + + 2. A paren of some kind( )>] ). Evaluate back to match- + ing paren. Leave paren off stack. If any other paren + seen, cause error. + + 3. End of expression( ENDexpr TRUE ). Evaluate all that + is left of expression. + + */ + +/*** pushpar - push paren or bracket back onto stack + * + * routine (); + * + * Entry + * Exit + * Returns + * Calls + */ + + +VOID PASCAL CODESIZE +pushpar ( + register struct evalrec *p +){ + itemptr->previtem = p->p->lastitem; + p->p->lastitem = itemptr; + /* So OPERATOR not removed */ + itemptr = NULL; +} +/* EVALtop evaluates the top OPERATOR on the stack and its + operands and produces CURresult as a result. It assumes that + the stack is arranged as follows: + + Operand( If not already result type, will convert ) + + OPERATOR( <> will cause error, [ executes as OPERATOR + ( will not evaluate, but whether stays on + stack is determined by PARENflag ) + + Operand ( If not result, will convert. If OPERATOR is + unary, will not be looked for. Special check + for +/- used as unary. ) + + Any deviation from the above will cause an error to be + generated by popvalue/popoperator. */ + + +/*** signadjust - calculate offset and sign of result and put in right operand + * + * routine (); + * + * Entry + * Exit + * Returns + * Calls + * Note Right and left operands may be switched + */ + + +VOID PASCAL CODESIZE +signadjust ( + UCHAR minus, + register struct exprec *p +){ + register struct psop *psol; /* parse stack operand structure */ + register struct psop *psor; /* parse stack operand structure */ + DSCREC *t; + OFFSET maxInt; + char fOverflow = FALSE; + + maxInt = (fArth32)? OFFSETMAX: 0xffff; + + psor = &(p->valright->dsckind.opnd); + psol = &(p->valleft->dsckind.opnd); + + if (psol->s) /* arthmethic on data size item - NEAR/FAR */ + errorc(E_TIL); + + if (minus) + psor->dsign = !psor->dsign; + + if (psol->dsegment || psol->dflag == XTERNAL || + (M_FLTSTACK & psol->dtype)) { + /* Want to preserve Left operand */ + t = p->valleft; + p->valleft = p->valright; + p->valright = t; + p->right = p->left; + p->left = p->valleft->dsckind.opnd.doffset; + psor = &(p->valright->dsckind.opnd); + psol = &(p->valleft->dsckind.opnd); + } + if (psol->dflag == UNDEFINED) + psor->dtype = M_CODE | M_FORTYPE; + + if (psor->dflag == UNDEFINED && !(psol->dtype & M_PTRSIZE)) + psol->dsize = 0; + + if (psol->dsign == psor->dsign) { + /* Signs are same */ + fOverflow = (((maxInt - p->right) + 1) == p->left); + p->right = p->right + p->left; + } else if (p->right > p->left) + /* Different signs */ + p->right = p->right - p->left; + else { + p->right = p->left - p->right; + psor->dsign = !psor->dsign; + } + + if (p->right == 0 && !fOverflow) + psor->dsign = FALSE; + if (psor->dsign && (psor->dtype & M_SEGRESULT)) + errorc (E_OSA); + psor->doffset = p->right; +} + + + + +/*** foldsigns - force evaluating 17 bit signed values back to 16 bits + * + * routine (); + * + * Entry + * Exit + * Returns + * Calls + */ + + +VOID PASCAL CODESIZE +foldsigns ( + register struct exprec *p +){ + /* the forms inside the comments seem to be trying to manage + * things as unsigned short even though they are stored in a + * larger field--ie this would be running as a cross assembler + * from a 32 bit host to a 16 bit object. since for the 386, + * we keep all this stuff as long, this turns out to be a bad + * approach. so without completely understanding what is going + * on, I am doing a simple negate (on the OFFSET field, which + * is probably an unsigned long) rather than trying to preserve + * the odd typing of the previous version -Hans, 19/9/86 */ + + if (p->valright->dsckind.opnd.dsign) + /* p->right = 65535 - p->right + 1; */ + p->right = -p->right; + if (p->valleft) + if (p->valleft->dsckind.opnd.dsign) + /* p->left = 65535 - p->left + 1; */ + p->left = -p->left; +} + + + + +/*** shiftoper - execute shift left or right + * + * result = shiftoper (p); + * + * Entry *p = parse stack entry + * Exit none + * Returns shifted value + * Calls + */ + + +OFFSET PASCAL CODESIZE +shiftoper ( + register struct exprec *p +){ + register OFFSET argl; + register USHORT argr; + + argl = p->valleft->dsckind.opnd.doffset; + if (p->valleft->dsckind.opnd.dsign) + argl = -argl; + argr = p->valright->dsckind.opnd.doffset; + if (p->valright->dsckind.opnd.dsign) { + errorc (E_SCN); + return (argl); + } + else if (sizeof(OFFSET)*8 < argr) + return (0); + else if (p->stkoper == OPSHL) + return (argl << argr); + else + return (argl >> argr); +} + +/* VALcheck is used by all OPERATOR execute routines to make + sure their arguments are correct. If the arguments are + expected to be some kind of result( i.e. not a structure + or record item or data size ), the old argument is destroy- + ed and DEFAULTdsc is called to create a substitute. Error + messages are also generated on type mismatches. A number + of procedures of the form: VALUExxxx are called, these + check if the given argument is of that type and if not, + generate an error and a value of zero. There is one kludge + in this procedure, the LENGTH OPERATOR should work with + records and structures, but these are still in the form of + <Isym> records so they will work with MASK, ... + The operand types are as follows: + + Callabs May be unary or binary. In any case, all + values must have a NIL segment. + + Clsize May be unary or binary. If unary, value must + be a size( which is: structure name, -2 .. n + or BYTE WORD ... ). If binary, left value is + a size. + + Csame Is always binary. If not results, coerce them. + Both must belong to the same segment and not + be external. + + Cdata Is always unary. Result must be associated + with data( Dtype is [data] ). Exception if + LENGTH OPERATOR and is record or record field + in which case converts to approriate result + record. + + Ccode Is always unary. Result must be associated + with code( Dtype is [code] ). + + Crec Is always unary. Value must be record field + or record name. + + Cseg Is always unary. Value must have a segment. + + Cvar Always unary. Value must be constant or data + or code. + + Clseg Always binary. The left value must be a + SEGresult or a segment register. + + Coneabs Always binary. One of the values must be a + constant. + + Csamabs Always binary. Either both values have the + same segment or the second value is a constant + + */ + + + + +/*** valconst - give error if value is not constant + * + * routine (); + * + * Entry + * Exit + * Returns + * Calls + */ + + +VOID PASCAL CODESIZE +valconst ( + register DSCREC *arg +){ + if (!(M_RCONST & arg->dsckind.opnd.dtype) || + arg->dsckind.opnd.dsegment || + arg->dsckind.opnd.dflag == XTERNAL) + /* Not constant */ + errorc (E_CXP); +} + + +/*** valusize - check size of operand + * + * val = valusize (arg); + * + * Entry + * Exit + * Returns + * Calls + */ + + +USHORT PASCAL CODESIZE +valuesize ( + register DSCREC *arg +){ + if (!fArth32) + arg->dsckind.opnd.doffset = (long) (SHORT) arg->dsckind.opnd.doffset; + + if (arg->dsckind.opnd.doffset == 0) { + /* 0 means no size */ + errorc (E_OHS); + return (0); + } + else if (arg->dsckind.opnd.doffset >= CSFAR_LONG) + return (xltsymtoresult[PROC]); + else + return (xltsymtoresult[DVAR]); +} + + + + +/*** valcheck - check operand value + * + * valcheck (valtype, unary, p); + * + * Entry + * Exit + * Returns + * Calls + */ + + +VOID PASCAL CODESIZE +valcheck ( + UCHAR valtype, + UCHAR unary, + register struct exprec *p +){ + register struct psop *psol; /* parse stack operand structure */ + register struct psop *psor; /* parse stack operand structure */ + + psol = &(p->valleft->dsckind.opnd); + psor = &(p->valright->dsckind.opnd); + /* Should give error if have 2 externals */ + if (p->valleft) + if (psol->dflag == XTERNAL && psor->dflag == XTERNAL) + errorc (E_IUE); + switch (valtype) { + case CALLABS: + valconst (p->valright); + if (!unary) + valconst (p->valleft); + break; + case CLSIZE: + if (unary) + psor->dtype = valuesize (p->valright); + else + psol->dtype = valuesize (p->valleft); + break; + case CSAME: + if (psol->dsegment != psor->dsegment) + errorc (E_OMM); + break; + case CDATA: + if ((p->stkoper != OPLENGTH) || !psor->dextptr + || (psor->dflag == XTERNAL)) { + if (!(M_DATA & psor->dtype) && + (psor->dlength == 0)) + errorc (E_ASD); + } + else { + /* Special case for LENGTH */ + p->valleft = defaultdsc (); + /* Create value */ + p->valleft->prec = p->valright->prec; + psol = &(p->valleft->dsckind.opnd); + psol->dlength = psor->dextptr->length; + /* Lose old value */ + oblititem (p->valright); + p->valright = p->valleft; + p->valleft = NULL; + psor = psol; + psol = NULL; + } + break; + case CCODE: + if (!(M_CODE & p->valright->dsckind.opnd.dtype)) + errorc (E_ASC); + break; + case CREC: + if (!psor->dextptr || psor->dflag == XTERNAL) + errorc (E_RRF); + break; + case CSEG: + if (!psor->dsegment && psor->dflag != XTERNAL + || (M_REGRESULT & psor->dtype)) + errorc (E_OSG); + break; + case CLSEG: + if (M_SEGRESULT & psol->dtype) { + /* ??? if (!psor->dsegment || (psor->dtype & M_RCONST)) + errorc (E_IOT); ??? */ + } + else if (M_REGRESULT & psol->dtype) { + if (psol->dsegment->symu.regsym.regtype != SEGREG) + errorc (E_LOS); + } + else + errorc (E_LOS); + break; + case CONEABS: + if (psor->dsegment && psol->dsegment) + errorc (E_OOC); + break; + case CSAMABS: + if (psor->dsegment && + psol->dsegment != psor->dsegment) + errorc (E_OSA); + break; + } + p->right = psor->doffset; + if (p->valleft) + p->left = psol->doffset; +} + + + + +/*** regcheck - check for <arg> a register in [...] + * + * routine (); + * + * Entry + * Exit + * Returns + * Calls + */ + + +DSCREC * PASCAL CODESIZE +regcheck ( + DSCREC *arg, + UCHAR minus, + register struct exprec *ptr +){ + struct psop *pso; /* parse stack operand structure */ + register struct ar *pAR; + USHORT reg; + + pso = &(arg->dsckind.opnd); + pAR = ptr->p->p; + + if (M_REGRESULT & pso->dtype) { + + /* Is some register */ + if (ptr->p->parenflag || pAR->bracklevel) { + + /* Have index reg in []s */ + /* Lose size based on register */ + + pso->dsize = 0; + reg = pso->dsegment->offset; + + /* Must be index or ptr reg */ + + switch(pso->dsegment->symu.regsym.regtype) + { + default: + errorc (E_IBR); + break; + case INDREG: + if (reg <= 5) + + /* Have base reg BX | BP */ + + if (pAR->base) + errorc (E_DBR); + else + pAR->base = reg; + + else /* Have index reg DI | SI */ + + if (pAR->index) + errorc (E_DIR); + else + pAR->index = reg; + break; +#ifdef V386 + case DWRDREG: + + /* Have 386 reg in []s */ + + if (minus == 2) + { + if (pAR->index & 0xf) + errorc(E_DIR); + + pAR->index |= 8 | reg; + } + else if (pAR->base) + { + if (pAR->index) + errorc(E_DIR); + + if (reg == 4) { + + /* swap base with index + * to allow [index][eSp] */ + + pAR->index = pAR->base; + pAR->base = 4|8; + } + else + pAR->index = reg|8; + } + else + pAR->base = reg|8; + + break; +#endif /* V386 */ + } + if (minus == TRUE && (ptr->valright == arg)) + errorc (E_IUR); + + oblititem (arg); + return (defaultdsc ()); + } + else { + errorc(E_IUR); + return (arg); + } + } + +#ifdef V386 /* scaled indexing modes */ + + else if (minus == 2 && (M_RCONST & pso->dtype)) + { + if (pAR->index&0x70) + errorc(E_MBR); + + if (highWord(arg->dsckind.opnd.doffset)) + goto scaleErr; + + switch((SHORT) arg->dsckind.opnd.doffset) { + + case 1: + pAR->index |= 0x10; + break; + case 2: + pAR->index |= 0x20; + break; + case 4: + pAR->index |= 0x30; + break; + case 8: + pAR->index |= 0x40; + break; + + scaleErr: + default: + error(E_EXP, "scale value of 1,2,4 or 8"); + } + oblititem (arg); + return (defaultdsc ()); + } +#endif /* V386 */ + + else return (arg); +} + + + + +/*** idxcheck - check for arg to +- is register + * + * routine (); + * + * Entry + * Exit + * Returns + * Calls + * Note See if arg to +/- is register, in which case see if should + * be stored in Ridx or Rbas due to []s + */ + + +VOID PASCAL CODESIZE +idxcheck ( + UCHAR minus, + register struct exprec *p +){ + p->valleft = regcheck (p->valleft, minus, p); + p->valright = regcheck (p->valright, minus, p); + p->right = p->valright->dsckind.opnd.doffset; + p->left = p->valleft->dsckind.opnd.doffset; +} + + + +/*** makeGrpRel - make an offset group relative + * + * routine (); + * + * Entry + * Exit + * Returns + * Calls + */ + + +VOID PASCAL CODESIZE +makeGrpRel ( + register struct psop *p +){ + if (!(p->dtype&M_EXPLCOLON) && p->dsegment && + p->dsegment->symkind == SEGMENT && p->dsegment->symu.segmnt.grouptr){ + + p->dtype |= M_GROUPSEG; + p->dcontext = p->dsegment->symu.segmnt.grouptr; + } +} + + + +/*** evaltop - evaluate top entry + * + * routine (); + * + * Entry + * Exit + * Returns + * Calls + */ + + +VOID PASCAL CODESIZE +evaltop ( + struct evalrec *ptr +){ + register struct psop *psol; /* parse stack operand structure */ + register struct psop *psor; /* parse stack operand structure */ + struct exprec a; + + a.p = ptr; + /* Get right operand */ + a.valright = popvalue (a.p->p); + itemptr = NULL; + if (a.p->p->lastitem) { + + /* Get OPERATOR */ + a.stkoper = popoperator (a.p->p); + a.valleft = NULL; + /* assume is unary */ + if (!inset (a.stkoper, unaryset)) + /* Not unary OPERATOR */ + a.valleft = (a.stkoper == OPUNPLUS || a.stkoper == OPUNMINUS) + ? defaultdsc() : popvalue (a.p->p); + /* Save for EVALtop */ + a.p->idx = a.stkoper; + if (a.valleft) + a.valleft->prec = a.valright->prec; + psol = &(a.valleft->dsckind.opnd); + psor = &(a.valright->dsckind.opnd); + + switch (a.stkoper) { + + /* All OPERATORs are executed thru this CASE statement. The + * VALcheck routine makes sure operands are of the correct + * type and may create dummy entries in the case of the real + * operand not being of type result when required. The REStype + * routine uses it's argument to know what part of the result + * record should be kept and the type of the result. Unary + * and binary OPERATORs both return their results in VALright. */ + + case OPAND: + case OPOR: + case OPXOR: + /* Make sure operands ok */ + valcheck (CALLABS, FALSE, &a); + /* Must work on 16 bits */ + foldsigns (&a); + switch (a.stkoper) { + case OPAND: + psor->doffset = a.left & a.right; + break; + case OPOR: + psor->doffset = a.left | a.right; + break; + case OPXOR: + psor->doffset = a.left ^ a.right; + break; + } + psor->dsign = FALSE; + /* Must clear out Dsign in case was signed value */ + break; + case OPNOT: + /* TRUE constant arg */ + valcheck (CALLABS, TRUE, &a); + foldsigns (&a); + psor->doffset = ~a.right; + psor->dsign = FALSE; + if (optyp == TDB && + (psor->doffset & ((OFFSET) ~0xff)) == ((OFFSET) ~0xff)) + psor->doffset &= 0xFF; +#ifdef V386_noCode + + if (!(cputype & P386)) /* truncate result to 16 bits */ + psor->doffset &= 0xffff; /* for compatablity */ +#endif + break; + case OPSHL: + case OPSHR: + valcheck (CALLABS, FALSE, &a); + psor->doffset = shiftoper (&a); + psor->dsign = FALSE; + break; + case OPSEG: + /* Must have segment */ + valcheck (CSEG, TRUE, &a); + + if (psor->dcontext && !(psor->dtype&M_EXPLCOLON)) + psor->dsegment = psor->dcontext; + + psor->dtype = (psor->dtype&M_FORTYPE) | M_SEGRESULT| M_RCONST; + psor->doffset = 0; + psor->dsign = FALSE; + + break; + case OPDOT: + /* See if idx reg */ + idxcheck (FALSE, &a); + valcheck (CONEABS, FALSE, &a); + psol = &(a.valleft->dsckind.opnd); + psor = &(a.valright->dsckind.opnd); + if (psor->dsize) + psol->dsize = psor->dsize; + /* Adjust signs on records */ + signadjust (FALSE, &a); + psol = &(a.valleft->dsckind.opnd); + psor = &(a.valright->dsckind.opnd); + break; + case OPUNPLUS: + case OPPLUS: + /* See if idx reg */ + idxcheck (FALSE, &a); + valcheck (CONEABS, FALSE, &a); + psol = &(a.valleft->dsckind.opnd); + psor = &(a.valright->dsckind.opnd); + /* Adjust signs on records */ + signadjust (FALSE, &a); + psol = &(a.valleft->dsckind.opnd); + psor = &(a.valright->dsckind.opnd); + break; + case OPUNMINUS: + case OPMINUS: + idxcheck (TRUE, &a); + if (psor->dsegment == psol->dsegment && + psol->dsegment) { + if (psol->dtype & M_SEGRESULT) { + psol->dtype = M_SEGRESULT | M_RCONST; + psol->doffset = 0; + psol->dsign = FALSE; + } + if (psor->dtype & M_SEGRESULT) { + psor->dtype = M_SEGRESULT | M_RCONST; + psor->doffset = 0; + psor->dsign = FALSE; + } + } + valcheck (CSAMABS, FALSE, &a); + signadjust (TRUE, &a); + psol = &(a.valleft->dsckind.opnd); + psor = &(a.valright->dsckind.opnd); + if (psol->dsegment) { + /* clear Dcontext if have var-var */ + psor->dtype = (psor->dtype & + (M_EXPLOFFSET | M_PTRSIZE | M_FORTYPE)) | M_RCONST; + psor->dsegment = NULL; + psor->dcontext = NULL; + psor->dsize = 0; + oblititem (a.valleft); + a.valleft = NULL; + } + break; + case OPMULT: +#ifdef V386 + if (M_REGRESULT & (psol->dtype|psor->dtype)) + { + if (cputype&P386) { + idxcheck (2, &a); + if (a.p->p->index&0x78) + break; + } else + errorc (E_IRV); + } +#endif + /* fall through */ + case OPDIV: + valcheck (CALLABS, FALSE, &a); + /* Both are constant */ + if (a.stkoper == OPMULT) + psor->doffset = a.left * a.right; + else if (a.right == 0) + errorc (E_DVZ); + else + psor->doffset = a.left / a.right; + if (psor->doffset == 0) + psor->dsign = FALSE; + else + psor->dsign = (psol->dsign != psor->dsign); + break; + case OPHIGH: + if (psor->dtype & M_RCONST) { + if (psor->dsign) { + psor->doffset = -psor->doffset; + psor->dsign = 0; + } + psor->doffset = psor->doffset >> 8 & 0xff; + } + psor->dtype |= M_HIGH; + + goto highlow; + + case OPLOW: + if (psor->dtype & M_RCONST) + psor->doffset &= 0xFF; + + psor->dtype |= M_LOW; + + highlow: + psor->dsize = 1; + if ((!(psor->dflag & XTERNAL && psor->dtype & M_EXPLOFFSET)) + && psor->dsegment + && (psor->dtype & (M_EXPLOFFSET | M_SEGRESULT + | M_REGRESULT | M_GROUPSEG | M_DATA | M_CODE))) + errorc (E_CXP); + break; + + case OPOFFSET: + psor->fixtype = FOFFSET; + + if (!(psor->dsegment || psor->dflag == XTERNAL)) + errorc(E_OSG|E_WARN2); + + if (!(M_DATA & psor->dtype)) + psor->dcontext = NULL; + psor->dtype = + (psor->dtype | + M_RCONST | M_EXPLOFFSET) & ~(M_SEGRESULT); + + if (fSimpleSeg) + makeGrpRel (psor); + + /* preserve OFFSET arg size it's a const */ + if ((psor->dsegment || + psor->dcontext || + psor->dflag == XTERNAL) && + !(M_PTRSIZE & psor->dtype)) + psor->dsize = 0; + break; + case OPLENGTH: + case OPSIZE: + /* Must be data associated */ + valcheck (CDATA, TRUE, &a); + psol = &(a.valleft->dsckind.opnd); + psor = &(a.valright->dsckind.opnd); + if (a.stkoper == OPLENGTH) + psor->doffset = psor->dlength; + else + psor->doffset = + psor->dsize * psor->dlength; + + psor->dflag &= ~XTERNAL; + break; + case OPTYPE: + a.right = psor->dsize; + oblititem (a.valright); + a.valright = defaultdsc (); + psor = &(a.valright->dsckind.opnd); + psor->doffset = a.right; + a.p->p->base = 0; + a.p->p->index = 0; + break; + case OPMASK: + case OPWIDTH: + /* Must be record or field */ + valcheck (CREC, TRUE, &a); + if (psor->dextptr && psor->dflag != XTERNAL) { + if (a.stkoper == OPWIDTH) + if (psor->dextptr->symkind == REC) + psor->doffset = psor->dextptr->length; + else + psor->doffset = psor->dextptr->symu.rec.recwid; + else if (psor->dextptr->symkind == REC) + psor->doffset = psor->dextptr->offset; + else + psor->doffset = psor->dextptr->symu.rec.recmsk; + } + break; + case OPSTYPE: + a.right = 0; + if (errorcode == 0) { + if (psor->dflag == XTERNAL) + a.right |= 0x80; /* external */ + if (psor->dflag != UNDEFINED) + a.right |= 0x20; /* defined */ + if (psor->dtype & M_DATA) + a.right |= 0x02; /* data */ + if (psor->dtype & M_CODE) + a.right |= 0x01; /* program */ + + if ((a.p->p->base == 0) && (a.p->p->index == 0)) { + + if (psor->dtype == xltsymtoresult[REGISTER]) + a.right |= 0x10; /* register */ + else if (psor->dtype & M_RCONST) + a.right |= 0x04; /* constant */ + else if (psor->dtype & M_DATA) + a.right |= 0x08; /* direct */ + + } else { + a.p->p->base = 0; + a.p->p->index = 0; + } + } + oblititem (a.valright); + a.valright = defaultdsc (); + psor = &(a.valright->dsckind.opnd); + psor->doffset = a.right; + errorcode = 0; + break; + case OPLPAR: + case OPLBRK: + if (!(a.p->parenflag || a.p->p->exprdone)) + pushpar (a.p); + else if (a.stkoper == OPLBRK) + a.valright = regcheck (a.valright, FALSE, &a); + psol = &(a.valleft->dsckind.opnd); + psor = &(a.valright->dsckind.opnd); + break; + case OPMOD: + valcheck (CALLABS, FALSE, &a); + if (a.right == 0) { + /* div 0 */ + errorc (E_DVZ); + psor->doffset = 0; + psor->dsign = FALSE; + } + else { + psor->doffset = a.left % a.right; + if (psor->doffset == 0 || !psol->dsign) + psor->dsign = FALSE; + else + psor->dsign = TRUE; + } + break; + case OPTHIS: + valcheck (CLSIZE, TRUE, &a); + /* Unary, right is size */ + psor->s = 0; + psor->dsize = a.right; + psor->doffset = pcoffset; + psor->dsegment = pcsegment; + if (a.right >= CSFAR_LONG) + psor->dcontext = regsegment[CSSEG]; + break; + case OPSHORT: + valcheck (CCODE, TRUE, &a); + /* Unary, must be code */ + psor->dtype |= M_SHRT; + break; + case OPPTR: + valcheck (CLSIZE, FALSE, &a); + if (psol->doffset >= CSFAR_LONG && + (M_RCONST == psor->dtype || + (psor->dcontext && (M_DATA&psor->dtype && !(M_CODE&psor->dtype))) )) + + errorc (E_NSO); /* Can't code_data */ + else { + psor->dsize = a.left; + if ((M_DATA & psol->dtype) + && !(M_DATA & psor->dtype)) + psor->dcontext = NULL; + /* Change code/data */ + psor->dtype = + (psor->dtype & ~(M_CODE | M_DATA) | + (psol->dtype & (M_CODE | M_DATA))) & + ~(M_FORTYPE) | (M_PTRSIZE); + } + break; + case OPEQ: + case OPGE: + case OPGT: + case OPLE: + case OPLT: + case OPNE: + valcheck (CSAME, FALSE, &a); + signadjust (TRUE, &a); + /* Do signed R=L-R */ + psol = &(a.valleft->dsckind.opnd); + psor = &(a.valright->dsckind.opnd); + + if (!fArth32) + a.right &= 0xffff; + + switch (a.stkoper) { + case OPEQ: + a.right = (a.right == 0); + break; + case OPGE: + a.right = !psor->dsign; + break; + case OPGT: + a.right = (!psor->dsign && a.right); + break; + case OPLE: + a.right = (psor->dsign || a.right == 0); + break; + case OPLT: + a.right = psor->dsign; + break; + case OPNE: + a.right = (a.right != 0); + break; + } + /* Set Dsign if result TRUE */ + psor->doffset = a.right; + psor->dsign = (a.right == 1); + psor->dcontext = NULL; + oblititem (a.valleft); + a.valleft = NULL; + break; + case OPCOLON: + /* <segment> : <var> */ + valcheck (CLSEG, FALSE, &a); + + if ((a.p->p->bracklevel || a.p->evalop == OPLBRK) && + (M_REGRESULT & (psol->dtype | psor->dtype))) + errorc(E_ISR); + + psor->dtype = (psor->dtype|M_EXPLCOLON|M_DATA) & ~M_RCONST; + + if (psol->dsegment) { + + if (psol->dsegment->symkind == GROUP) + psor->dtype |= M_GROUPSEG; + + if (!psor->dsegment && + !(M_REGRESULT & psol->dtype) && + !(a.p->p->base || a.p->p->index)) + + psor->dsegment = psol->dsegment; + } + + psor->dcontext = psol->dsegment; + break; + + } /* operator case */ + + if (!inset (a.stkoper, parseset)) { + + /* Have constant or segment result */ + + psor->dlength = 0; + + psor->dsize = 0; + psor->sized = 0; + if (a.valleft) + psol->dsize = 0; + + /* Have constant result( typeless ) */ + + if (a.stkoper != OPSEG) { + + psor->dtype = (psor->dtype & M_FORTYPE) | M_RCONST; + psor->dsegment = NULL; + + if (a.valleft) + psol->dtype &= ~M_PTRSIZE; + } + } + a.p->p->curresult = a.valright; + psor = &(a.p->p->curresult->dsckind.opnd); + + if (!fArth32 && optyp != TDD) + psor->doffset &= 0xffff; + + if (a.valleft) { + /* Might need to copy some info */ + + /* Prevent OPERATORs like +, -, . from + losing the [DATA] flag if it it is the + Left operand. This is ok, except when + surrounded by a PTR which will drop + segment override if not data type */ + + if (a.stkoper != OPCOLON) + psor->dtype |= psol->dtype & (M_DATA | M_CODE); + if (psor->dflag == KNOWN) + psor->dflag = psol->dflag; + if (!psor->dcontext) + psor->dcontext = psol->dcontext; + if (psor->dsize == 0) + psor->dsize = psol->dsize; + if (psor->fixtype == FCONSTANT) + psor->fixtype = psol->fixtype; + + psor->dtype |= psol->dtype & (M_PTRSIZE|M_EXPLOFFSET|M_FORTYPE); + /* Above makes sure PTR or OFFSET is not lost */ + oblititem (a.valleft); + a.valleft = NULL; + } + } + else { /* no operator case */ + + a.p->p->curresult = a.valright; + psor = &(a.p->p->curresult->dsckind.opnd); + a.p->parenflag = FALSE; + } + + if (!a.p->p->lastitem) { + a.p->p->lastprec = 0; + a.p->p->curresult->prec = 0; + } + else if (a.p->p->lastitem->itype == OPERATOR) { + + if ((a.p->p->lastitem->dsckind.opr.oidx == OPLBRK) || + (a.p->p->lastitem->dsckind.opr.oidx == OPLPAR)) + + /* Stop evaluating back at paren */ + a.p->p->lastprec = 0; + + else { + a.p->p->lastprec = a.p->p->lastitem->prec; + if ((a.p->p->lastitem->dsckind.opr.oidx == OPUNPLUS) || + (a.p->p->lastitem->dsckind.opr.oidx == OPUNMINUS)) + /* Force eval */ + a.p->p->lastitem->prec = a.p->p->lastprec = 20; + } + } + else + a.p->p->lastprec = a.p->p->lastitem->prec; + + if (itemptr) { + oblititem (itemptr); + itemptr = NULL; + } + + /* Hook rest of list in */ + + a.p->p->curresult->previtem = a.p->p->lastitem; + a.p->p->lastitem = a.p->p->curresult; + + /* Push result back on */ + + if (!a.p->p->curresult->previtem && a.p->p->exprdone) + a.p->p->lastitem = NULL; +} + + + + +/*** evaluate - evaluate stack + * + * routine (); + * + * Entry + * Exit + * Returns + * Calls + */ + + +VOID PASCAL CODESIZE +evaluate ( + struct ar *p +){ + struct evalrec a; + a.p = p; + a.parenflag = FALSE; + a.evalop = OPNOTHING; + /* No paren or match to find */ + a.curoper = itemptr; + + if (a.curoper) + a.parenflag = !a.p->exprdone && + (a.curoper->dsckind.opr.oidx == OPRPAR || + a.curoper->dsckind.opr.oidx == OPRBRK); + if (a.parenflag) + a.evalop = (a.curoper->dsckind.opr.oidx == OPRPAR)? OPLPAR: OPLBRK; + + do { /* Evaluate to OPERATOR */ + + evaltop (&a); + + } while (a.p->lastitem && a.p->lastitem->previtem && + (a.p->exprdone || + (!a.parenflag && a.p->lastprec >= a.p->curprec ) || + ( a.parenflag && a.idx != a.evalop)) ); + + /* stop if just value on expression stack */ + itemptr = a.curoper; + if (a.p->lastprec == 0) + a.p->lastprec = a.p->curresult->prec; + + if (!a.p->exprdone) + if (a.parenflag) {/* Push value and set prec */ + + if (!a.p->lastitem->previtem)/* start of expr */ + a.p->lastprec = 0; + else + a.p->lastprec = a.p->lastitem->previtem->prec; + + /* Restore preced */ + a.p->lastitem->prec = a.p->lastprec; + oblititem (itemptr); + itemptr = NULL; + + /* Destroy close paren */ + } + else { /* Case 1, OPERATOR eval */ + itemptr->previtem = a.p->lastitem; + a.p->lastitem = itemptr; + + /* Push OPERATOR */ + if (a.p->lastprec != 20) + a.p->lastprec = itemptr->prec; + } +} + +/* Return a descriptor record to help instruction routines + generate the right code. The items are as follows: + + mode:: Value 0..4 Corresponds to 8086 mod + + 0 No displacement unless rm=6 in which + case this is direct mode with 2 bytes. + ( Arg is code or data, no indexing ) + + 1 Memory, 8 bit sign extended displace- + ment.( Using indexing, Rconst ) + + 2 Memory, 16 bit displacement.( Using + indexing, Rconst type ) + + 3 Register, rm is register code, not + indexing mode.( Was REGresult ) + + 4 Immediate mode.( arg was Rconst, no + indexing ) + + 386 modes are represented in an analogous way: + + 3 Register, rm is register code, as above + + 4 Immediate, as above + + 5 No displacement indirect, unless rm=5, + in which case this is a direct mode with + 4 byte offset. + + 6 Memory, 8 bit signed displacement + + 7 Memory, 32 bit signed displacement + + similarly, scaled modes are indicated with + the next group. if mode > 7, then rm contains + the value of the Scaled Index Byte (SIB) and + rm is implicitly 4. + + 8 No displacement indirect, unless rm=5, + in which case this is a direct mode with + 4 byte offset. + + 9 Memory, 8 bit signed displacement + + 10 Memory, 32 bit signed displacement + + rm :: Value 0..7 Corresponds to 8086 or 80386 r/m + + Value Register Index 386 index + 0 AX AL EAX [BX][SI] [EAX] + 1 CX CL ECX [BX][DI] [ECX] + 2 DX DL EDX [BP][SI] [EDX] + 3 BX BL EBX [BP][DI] [EBX] + 4 SP AH ESP [SI] not implemented + 5 BP CH EBP [DI] Direct or [EBP] + 6 SI DH ESI Direct or [BP] [ESI] + 7 DI BH EDI [BX] [EDI] + + Ridx contained pointer to index reg( DI | SI ) + Rbas contained pointer to base reg( BX | BP ) + Both were NIL if no indexing. + 386 registers have 8 added to them while in + the ar structure's base and index fields. + this is so we can tell eax from no register + at all. + + + w :: Boolean Corresponds to 8086 w flag. TRUE if + word mode, FALSE if byte mode. + + s :: TRUE if value is -128..+127 + Dsize :: Size of var/label or PTR value + + + FIXtype :: Type of fixup to feed to EMITxxx + routines: + + Fpointer Label is FAR + Foffset Word, not constant + Fbaseseg SEG or seg/group name + Fgroupseg Offset to group + Fconstant Immediate data + Fhigh Take high of offset + Flow Take low of offset + Fnone No fixup( register ) + + Dtype :: Kind of value. Seg,group, const, Data + Dflag :: Value attr, undef,?,extern,forw,... + Doffset :: 16 bit value of result + + Dsegment:: Copy of Dsegment. Pointer to segment of + result. If NIL, is constant. Will point + to segment name or possibly name of + external if external with no segment. + + Dcontext:: Copy of Dcontext. Pointer to segment + from which to calculate offset. If : + OPERATOR used, Dcontext will be left + arg. If result is code label, will be + CS assume at time of label define. Else + will be NIL and then filled in with + segment register assume that contains + Dsegment. + + seg :: Segment register of override. If none + given, will be 4. If register is not + known, will be 5. + */ |