/* 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 #include #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 ((OFFSET)(temp = temp * base + t) > maxInt) errorc (E_DVZ); } else for (; cnt; cnt--) { if ((t = NEXTC () - '0') >= base) errorc (E_NDN); if ((OFFSET)(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 = (unsigned char)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 = -(long)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); }