/* asmexpr.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 <ctype.h>
#include "asm86.h"
#include "asmfcn.h"
#include "asmctype.h"
#include "asmexpr.h"
#include "asmmsg.h"
extern UCHAR opprec [];
extern char fValidSym, addplusflagCur;
/*** endstring - check for end of string
*
* flag = endstring ();
*
* Entry delim = string delimiter character
* Exit none
* Returns TRUE if at end of string
* FALSE if not at end of string
* Calls error
* Note Double occurances of delimiter character are returned as a
* single occurance of the delimiter character.
*/
UCHAR PASCAL CODESIZE
endstring ()
{
register UCHAR cc;
if ((cc = PEEKC ()) == 0) {
/* End of line before delim */
errorc (E_UEL);
return (TRUE);
}
else if (cc == delim) {
/* check for escaped quote character */
SKIPC ();
if ((cc = PEEKC ()) != delim) {
BACKC ();
return (TRUE);
}
}
return (FALSE);
}
/*** oblititem - release parse stack record
*
* oblititem (arg);
*
* Entry *arg = parse stack record
* Exit parse stack record released
* Returns none
* Calls free
*/
VOID PASCAL CODESIZE
oblititem (
register DSCREC *arg
){
register char c;
if ((c = arg->itype) == ENDEXPR || c == OPERATOR || c == OPERAND)
dfree( (UCHAR *)arg );
}
/*** flteval - Look at ST | ST(i) and create entry
*
* flteval ();
*
* Entry *ptr = parse stack entry
* Exit
* Returns
* Calls
*/
VOID PASCAL CODESIZE
flteval ()
{
*itemptr = emptydsc;
/* ST means ST(0) */
/* We are 8087 stack */
itemptr->dsckind.opnd.dtype = M_RCONST | M_FLTSTACK;
/* Need + if ST(i) */
addplusflagCur = (PEEKC () == '(');
}
/*** createitem - make item entry
*
* createitem (itemkind, itemsub, p);
*
* Entry itemkind = kind of item
* itemsub =
* *p = activation record
* Exit
* Returns
* Calls
* Note If symbol, look further to see if EQU, record name
* and do appropriate thing.
*/
VOID PASCAL CODESIZE
createitem (
UCHAR itemkind,
UCHAR itemsub
){
register struct psop *pso; /* parse stack operand structure */
switch (itemkind) {
case OPERAND:
/* Create default record */
itemptr = defaultdsc ();
pso = &(itemptr->dsckind.opnd);
switch (itemsub) {
case ICONST:
pso->doffset = val;
break;
case ISIZE:
#ifdef V386
pso->doffset = (long) (SHORT) varsize;
#else
pso->doffset = varsize;
#endif
pso->s++; /* note for expr evaluator */
break;
case IUNKNOWN:
pso->dflag = INDETER;
break;
case ISYM:
createsym ();
break;
}
break;
case OPERATOR:
itemptr = dalloc();
itemptr->dsckind.opr.oidx = opertype;
break;
}
/* Set type of entry */
itemptr->itype = itemkind;
}
/*** numeric - evaluate numeric string
*
* numeric (count, base, p);
*
* Entry count = number of characters in string
* base = conversion base
* *p = activation record
* Exit
* Returns
* Calls
*/
VOID PASCAL CODESIZE
numeric (
SHORT cnt,
SHORT base
){
register UCHAR t;
register long temp = 0;
OFFSET maxInt;
maxInt = (fArth32)? OFFSETMAX: 0xffff;
if (base > 10)
for (; cnt; cnt--) {
if ((t = MAP (NEXTC ()) - '0') > 9)
t -= 'A' - '9' - 1;
if (t >= base)
errorc (E_NDN);
if ((temp = temp * base + t) > maxInt)
errorc (E_DVZ);
}
else
for (; cnt; cnt--) {
if ((t = NEXTC () - '0') >= base)
errorc (E_NDN);
if ((temp = temp * base + t) > maxInt)
errorc (E_DVZ);
}
val = temp;
}
/*** evalconst - evaluate constant
*
* type = evalconst (p);
*
* Entry *p = parser activation record
* Exit numeric item added to parse stack entry
* Returns type of item added to parse stack
* Calls
*/
void PASCAL CODESIZE
evalconst ()
{
register char cc;
register SHORT i = 0;
char *endscan, *begscan;
SHORT rbase;
begscan = lbufp;
while (isxdigit (cc = PEEKC ())) {
SKIPC ();
i++;
}
switch (MAP (cc)) {
case 'H':
rbase = 16;
SKIPC ();
break;
case 'O':
case 'Q':
rbase = 8;
SKIPC ();
break;
default:
BACKC ();
switch (MAP (NEXTC ())) {
case 'B':
rbase = 2;
i--;
break;
case 'D':
rbase = 10;
i--;
break;
default:
if (cc == '.')
errorcSYN ();
if (radixescape)
rbase = 10;
else
rbase = radix;
break;
}
break;
}
endscan = lbufp;
lbufp = begscan;
numeric (i, rbase);
lbufp = endscan;
}
/*** evalstring - evaluate quoted string
*
* type = evalstring ();
*
* Entry
* Exit new item added to parse stack
* Returns type of item added to stack
* Calls
*/
char PASCAL CODESIZE
evalstring ()
{
register USHORT i, max;
max = 2;
if (cputype & P386)
max += 2;
delim = NEXTC (); /* Set delim for string */
i = 0;
val = 0;
while (!endstring () && i <= max) {
val = (val << 8) + ((UCHAR)NEXTC ());
i++;
}
if (i == 0)
errorc (E_EMS);
else if (i > max) { /* Too long */
while (!endstring ())
SKIPC ();
errorcSYN ();
}
if (PEEKC () == delim)
SKIPC ();
createitem (OPERAND, ICONST);
return (OPERAND);
}
/*** getitem - get next item on line
*
* getitem (p);
*
* Entry *p = activation record
* Exit *itemptr = description of item
* Returns
* Calls
*/
char PASCAL CODESIZE
getitem (
struct ar *p
){
register char cc;
#ifdef FIXCOMPILERBUG
char cc1;
#endif
if (fValidSym)
return (evalalpha (p));
/* The compiler bug looses the correct value for cc when optimization is
turned on. This in turn caused an exception to occure near getitem+1C0.
The bogus code below sidesteps the problem. */
#ifdef FIXCOMPILERBUG // This was put in to get around a MIPS compiler bug(12/3/90)
cc1 = skipblanks();
if (ISTERM (cc1))
return (ENDEXPR);
cc = cc1;
#else
if (ISTERM (cc = skipblanks()))
return (ENDEXPR);
#endif
if (LEGAL1ST (cc))
return (evalalpha (p));
/* token is not alpha string or .string (.TYPE) operator */
if (ISOPER (cc)) {
SKIPC ();
switch (cc) {
case '(':
opertype = OPLPAR;
break;
case '+':
opertype = OPPLUS;
break;
case '-':
opertype = OPMINUS;
break;
case '*':
opertype = OPMULT;
break;
case '/':
opertype = OPDIV;
break;
case ')':
opertype = OPRPAR;
break;
case '.':
errorcSYN ();
opertype = OPDOT;
break;
case ',': /* should never get here, for density */
break;
default:
if (cc == '[')
opertype = OPLBRK;
else if (cc == ']')
opertype = OPRBRK;
else if (cc == ':')
opertype = OPCOLON;
break;
}
operprec = opprec [opertype];
createitem (OPERATOR, ISYM);
return (OPERATOR);
}
else if (isdigit (cc)){
evalconst ();
createitem (OPERAND, ICONST);
return (OPERAND);
}
else if ((cc == '"') || (cc == '\''))
/* String may be made into constant if <=2 */
return (evalstring ());
else
return (ENDEXPR);
}
/*** defaultdsc - create a default parse stack entry
*
* ptr = defaultdsc ();
*
* Entry none
* Exit none
* Returns *ptr = default parse stack entry
* Calls malloc
*/
DSCREC * PASCAL CODESIZE
defaultdsc ()
{
register DSCREC *valu;
valu = dalloc();
*valu = emptydsc;
return (valu);
}
VOID PASCAL
makedefaultdsc ()
{
register struct psop *p; /* parse stack operand structure */
emptydsc.itype = OPERAND;
p = &emptydsc.dsckind.opnd;
p->dtype = xltsymtoresult[REC];
p->dflag = KNOWN;
p->fixtype = FCONSTANT;
}
/*** checksegment - see if sreg is correct segment register for variable
*
* routine ();
*
* Entry
* Exit
* Returns
* Calls
*/
char PASCAL CODESIZE
checksegment (
UCHAR sreg,
register struct ar *p
){
register SYMBOL FARSYM *segctx;
register SYMBOL FARSYM *segptr;
if (sreg != NOSEG) { /* NOseg never found */
/* Current Sreg assume */
segctx = regsegment[sreg];
/* Assume looking for left arg to : */
segptr = p->curresult->dsckind.opnd.dcontext;
if (!segptr) /* If no :, use segment */
segptr = p->curresult->dsckind.opnd.dsegment;
if (segptr && segctx) {
#ifndef FEATURE
if (segctx == pFlatGroup) /* flat space matchs all */
goto found;
#endif
/* if same segorg or ptr is segment ... and Same group */
if (segctx == segptr ||
(segptr->symkind == SEGMENT &&
segctx == segptr->symu.segmnt.grouptr)) {
found:
p->segovr = sreg;
p->curresult->dsckind.opnd.dcontext = segctx;
return (TRUE);
}
}
}
return (FALSE);
}
/*** findsegment - find segment for variable
*
* routine ();
*
* Entry
* Exit
* Returns
* Calls
*/
VOID PASCAL CODESIZE
findsegment (
UCHAR dseg,
register struct ar *p
){
register struct psop *pso; /* parse stack operand structure */
pso = &(p->curresult->dsckind.opnd);
if ((M_DATA & p->rstype) &&
(pso->dsegment || pso->dcontext) &&
p->linktype != FCONSTANT && pso->fixtype != FOFFSET && emittext) {
/* Should find segment */
if (!checksegment (dseg, p)) {
/* If not in default */
checksegment (CSSEG, p);
checksegment (ESSEG, p);
checksegment (SSSEG, p);
checksegment (DSSEG, p);
#ifdef V386
if (cputype&P386)
{
checksegment (FSSEG, p);
checksegment (GSSEG, p);
}
#endif
if (p->segovr == NOSEG)
/* If not found,UNKNOWN */
p->segovr = NOSEG+1;
}
}
}
/*** exprop - process expression operator
*
* exprop (p);
*
* Entry
* Exit
* Returns
* Calls
*/
VOID PASCAL CODESIZE
exprop (
register struct ar *p
){
register struct dscrec *pTop = itemptr;
p->curprec = operprec; /* Get prec of new operator */
if (!p->lastitem) /* start */
pTop->prec = 0;
else
pTop->prec = p->lastitem->prec;
switch (pTop->dsckind.opr.oidx) {
case OPRPAR:
if (--p->parenlevel >= 0)
break;
/* Unmatched right paren is from count dup (xx) */
p->parenlevel = 0;
BACKC ();
dfree((char *)pTop);
p->exprdone = TRUE;
return;
case OPRBRK:
if (--p->bracklevel >= 0)
break;
p->exprdone = TRUE;
return;
case OPLPAR:
p->parenlevel++;
goto leftComm;
case OPLBRK:
p->bracklevel++;
leftComm:
/* See if could have no oper in which case kludge + */
if ((p->lastitem || p->addplusflag) &&
p->lastitem->itype != OPERATOR) {
/* make + OPERATOR */
opertype = OPPLUS;
createitem (OPERATOR, ISYM);
p->bracklevel--;
exprop(p);
p->bracklevel++;
p->lastprec = 6;
}
break;
default:
pTop->prec = p->curprec;
break;
}
p->unaryflag = FALSE;
if (pTop->dsckind.opr.oidx == OPPLUS ||
pTop->dsckind.opr.oidx == OPMINUS) {
if (!p->lastitem)
p->unaryflag = TRUE;
else if (p->lastitem->itype == OPERATOR)
p->unaryflag = !(p->lastitem->dsckind.opr.oidx == OPRPAR ||
p->lastitem->dsckind.opr.oidx == OPRBRK);
}
if (p->unaryflag ||
(p->curprec > p->lastprec &&
!(pTop->dsckind.opr.oidx == OPRPAR ||
pTop->dsckind.opr.oidx == OPRBRK))) {
/* Push OPERATOR */
pTop->previtem = p->lastitem;
p->lastitem = pTop;
if (p->unaryflag) {
if (pTop->dsckind.opr.oidx == OPPLUS)
pTop->dsckind.opr.oidx = OPUNPLUS;
else
pTop->dsckind.opr.oidx = OPUNMINUS;
pTop->prec = p->lastprec;
p->lastprec = 10;
}
else
p->lastprec = p->curprec;
if (pTop->dsckind.opr.oidx == OPLPAR ||
pTop->dsckind.opr.oidx == OPLBRK)
p->lastprec = 0;
}
else /* Evaluate top OPERATOR */
evaluate (p);
}
/*** forceimmed - generate error if value is not immediate
*
* routine ();
*
* Entry
* Exit
* Returns
* Calls
*/
VOID PASCAL CODESIZE
forceimmed (
register DSCREC *dsc
){
if (dsc->dsckind.opnd.mode != 4)
/* Must be constant */
errorc (E_CXP);
}
/*** exprconst - check for constant expression
*
* routine ();
*
* Entry
* Exit
* Returns
* Calls
*/
OFFSET PASCAL CODESIZE
exprconst ()
{
char sign;
register OFFSET ret;
ret = exprsmag(&sign);
if (sign) {
/* change to simple unary minus
* pso->doffset = 65535 - ret + 1; */
ret = -ret;
if (!fArth32)
ret &= 0xffff;
}
return (ret);
}
/*** exprsmag - evaluate constant expression and return sign/magnitude
*
* ushort = exprsmag (sign, magnitude);
*
* Entry none
* Exit sign = TRUE if sign of result is set
* magnitude = magnitude of result
* Returns 16 bit integer result
* Calls expreval
*/
OFFSET PASCAL CODESIZE
exprsmag (
char *sign
){
register struct psop *pso; /* parse stack operand structure */
register OFFSET ret;
DSCREC *dsc;
dsc = expreval (&nilseg);
forceimmed (dsc);
pso = &(dsc->dsckind.opnd);
*sign = pso->dsign;
ret = pso->doffset;
dfree ((char *)dsc );
return (ret);
}