1472 lines
34 KiB
C
1472 lines
34 KiB
C
|
/* 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 = -(long)p->right;
|
||
|
if (p->valleft)
|
||
|
if (p->valleft->dsckind.opnd.dsign)
|
||
|
/* p->left = 65535 - p->left + 1; */
|
||
|
p->left = -(long)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 = -(long)argl;
|
||
|
argr = (USHORT)(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 = (USHORT)(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 = (USHORT)(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 = (USHORT)((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 = (USHORT)((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 = -(long)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 = (USHORT)(
|
||
|
(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 = (USHORT)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 = (USHORT)a.left;
|
||
|
if ((M_DATA & psol->dtype)
|
||
|
&& !(M_DATA & psor->dtype))
|
||
|
psor->dcontext = NULL;
|
||
|
/* Change code/data */
|
||
|
psor->dtype = (USHORT)(
|
||
|
(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 = (USHORT)((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 = (USHORT)((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.
|
||
|
*/
|