summaryrefslogtreecommitdiffstats
path: root/private/sdktools/masm/asmeval.c
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/sdktools/masm/asmeval.c
downloadNT4.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.c1472
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.
+ */