/* asmirp.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 "asmctype.h"
#include <fcntl.h>
#define DMYBASE 0x80
#define nextCH() {*pText=cbText; pText = pTextCur++; cbText = 0;}
#define storeCH(c) {if (cbText>0x7f) nextCH() *pTextCur++=c; cbText++;}
char * PASCAL CODESIZE growParm( char * );
/*** irpxdir - process <irp> and <irpc> directives
*
* irpxdir ();
*
* Entry
* Exit
* Returns
* Calls
* Note Format is
* IRPC <dummy>, text | <text>
* IRP <dummy>,<param list>
*/
VOID PASCAL CODESIZE
irpxdir ()
{
register short cc; /* CHAR */
USHORT bracklevel;
char littext;
register char *pT;
char *pParmName;
createMC (1); /* Make IRPC param block */
scandummy (); /* Scan our only dummy param */
if (NEXTC () != ','){
error (E_EXP,"comma");
return;
}
pMCur->cbParms = strlen(lbufp) << 1;
pT = nalloc(pMCur->cbParms, "irpxdir: actuals");
*pT = NULL;
pMCur->rgPV[0].pActual = pMCur->pParmAct = pT;
pParmName = pMCur->pParmNames;
pMCur->pParmNames = pT;
bracklevel = 0;
if (littext = (skipblanks () == '<')) {
SKIPC ();
bracklevel = 1;
}
if (optyp == TIRP) {
if (!littext)
error (E_EXP,"<"); /* Must have < */
if (skipblanks () != '>') {
BACKC ();
do {
SKIPC ();
scanparam (TRUE);
} while (skipblanks () == ',');
}
if (NEXTC () != '>')
error (E_EXP,">");
}
else {
while (cc = NEXTC ()) {
if (littext) {
/* Only stop on > */
if (cc == '<'){
bracklevel++;
continue;
}
else if (cc == '>'){
if (--bracklevel == 0)
break;
continue;
}
}
else if (ISBLANK (cc) || ISTERM (cc)) {
BACKC ();
break;
}
*pT++ = 1; /* arg of length 1 */
*pT++ = cc; /* and the arg */
pMCur->count++;
}
*pT = NULL;
}
if (PEEKC () == '>' && littext)
SKIPC ();
swaphandler = TRUE;
handler = HIRPX;
blocklevel = 1;
pMCur->count--; /* don't count arg in repeat count */
pMCur->pParmNames = pParmName;
pMCur->iLocal++;
pMCur->svlastcondon = lastcondon;
pMCur->svcondlevel = condlevel;
pMCur->svelseflag = elseflag;
}
/*** reptdir - process repeat directive
*
* reptdir ();
*
* Entry
* Exit
* Returns
* Calls
*/
VOID PASCAL CODESIZE
reptdir ()
{
char sign;
createMC (1);
pMCur->count = exprsmag (&sign);
if (sign)
errorc (E_VOR);
if (errorcode)
pMCur->count = 0;
swaphandler = TRUE;
handler = HIRPX;
blocklevel = 1;
pMCur->svcondlevel = condlevel;
pMCur->svlastcondon = lastcondon;
pMCur->svelseflag = elseflag;
}
/*** irpxbuild - build text for IRP/IRPC block
*
* irpxbuild ();
*
* Entry
* Exit
* Returns
* Calls
*/
VOID PASCAL CODESIZE
irpxbuild ()
{
if (checkendm ()) {
if (pMCur->flags == TMACRO) {
/* Delete old text */
listfree (macroptr->symu.rsmsym.rsmtype.rsmmac.macrotext);
macroptr->symu.rsmsym.rsmtype.rsmmac.macrotext = pMCur->pTSHead;
pMCur->pParmAct = pMCur->pParmNames;
deleteMC (pMCur);
}
else {
#ifdef BCBOPT
if (fNotStored)
storelinepb ();
#endif
pMCur->pTSCur = pMCur->pTSHead;
if (!pMCur->pTSCur) /* empty macros go 0 times */
pMCur->count = 0;
macrolevel++;
handler = HPARSE;
/* Expand that body */
lineprocess (RMACRO, pMCur);
}
handler = HPARSE;
swaphandler = TRUE;
}
else {
irpcopy ();
listline ();
}
}
/*** irpcopy - copy line of text into irp/irpc/macro
*
* irpcopy ();
*
* Entry
* Exit
* Returns
* Calls
*/
char *pText, *pTextEnd;
UCHAR cbText;
char inpasschar = FALSE;
#if !defined XENIX286 && !defined FLATMODEL
# pragma check_stack+
#endif
VOID PASCAL CODESIZE
irpcopy ()
{
register char *pTextCur;
register UCHAR cc;
TEXTSTR FAR *bodyline;
char hold[LINEMAX];
USHORT siz;
pText = pTextCur = hold;
pTextEnd = pTextCur + LINEMAX - 2;
pTextCur++;
cbText = 0;
lbufp = lbuf;
if (!lsting) /* burn blanks if not listing */
skipblanks();
while ((cc = PEEKC ()) && pTextCur < pTextEnd) {
ampersand = FALSE;
if (cc == '\'' || cc == '"') {
delim = cc;
inpasschar = TRUE; /* '...' being parsed */
do {
if (cc == '&' || LEGAL1ST(cc)) { /* Could have &dummy or dummy& */
pTextCur = passatom (pTextCur);
}
else {
NEXTC();
ampersand = FALSE;
storeCH(cc);
if (pTextCur >= pTextEnd)
break;
}
} while ((cc = PEEKC ()) && (cc != delim));
inpasschar = FALSE;
if (!cc)
break;
}
if (!LEGAL1ST (cc)) {
SKIPC();
if (cc != '&' || PEEKC() == '&')
storeCH(cc);
if (cc == ';'){ /* don't translate comment */
if (PEEKC() != ';' && lsting) /* don't store ;; comment */
while (cc = NEXTC ())
storeCH(cc);
break;
}
}
else
pTextCur = passatom (pTextCur);
}
/* trim trailing spaces */
while (cbText && ISBLANK (pTextCur[-1])){
cbText--;
pTextCur--;
}
/* check to see if we ended up with a blank line */
if (cbText == 0 && pText == hold)
return;
storeCH(' '); /* space and NULL terminated */
storeCH(NULL);
*pText = cbText;
*pTextCur++ = NULL;
siz = pTextCur - hold;
bodyline = (TEXTSTR FAR *)talloc ((USHORT)(sizeof(TEXTSTR)+siz));
bodyline->size = sizeof(TEXTSTR)+siz;
bodyline->strnext = (TEXTSTR FAR *)NULL;
fMemcpy (bodyline->text, hold, siz);
if (pMCur->pTSCur)
pMCur->pTSCur->strnext = bodyline;
else
pMCur->pTSHead = bodyline;
pMCur->pTSCur = bodyline;
}
#if !defined XENIX286 && !defined FLATMODEL
# pragma check_stack-
#endif
/*** passatom - pass next atom to line
*
* ptr = passatom (ptr, lim);
*
* Entry ptr = pointer to line buffer
* lim = limit address of buffer
* Exit
* Returns
* Calls
*/
char * PASCAL CODESIZE
passatom (
register char *pTextCur
){
register UCHAR *pT, *svline;
unsigned short number;
UCHAR cbName;
UCHAR cando = FALSE;
UCHAR preconcat = FALSE; /* expanding SYM in "text&SYM" */
UCHAR postconcat = FALSE; /* expanding SYM in "SYM&text" */
if (preconcat = (PEEKC () == '&'))
SKIPC ();
svline = lbufp;
getatomend ();
cbName = lbufp - svline;
if (pTextCur + cbName > pTextEnd){
errorc (E_LNL);
return(pTextCur);
}
if (inpasschar ) {
if (ampersand) {
ampersand = FALSE;
cando = !preconcat;
}
if (PEEKC () == '&' && cbName) {
SKIPC ();
postconcat = TRUE;
}
else if (!preconcat && !cando)
goto noSubsitute;
}
for (pT = pMCur->pParmNames, number = DMYBASE;
*pT; pT += *pT+1, number++){
if (cbName == *pT &&
memcmp(naim.pszName, pT+1, *pT) == 0) {
if (cbText)
nextCH();
pTextCur[-1] = number; /* store dummy parameter index */
pText = pTextCur++;
if (postconcat && (preconcat || cando))
ampersand = TRUE;
return (pTextCur);
}
}
noSubsitute:
if (preconcat){
storeCH('&');
}
if (postconcat)
BACKC ();
if (cbName + cbText >= 0x7f)
nextCH();
memcpy(pTextCur, svline, cbName);
cbText += cbName;
pTextCur += cbName;
return (pTextCur);
}
/*** scandummy - add next atom to dummy list
*
* scandummy ();
*
* Entry
* Exit
* Returns
* Calls
*/
VOID PASCAL CODESIZE
scandummy ()
{
register MC *pMC = pMCur;
SHORT siz, offset;
/* Scan dummy name */
getatom ();
if (*naim.pszName == 0) {
if (!ISTERM (PEEKC ()))
errorc (E_ECL);
return;
}
pMC->count++;
siz = naim.ucCount;
if (pMC->cbParms < siz+2){
/* relloc the string on overflow */
pMC->cbParms = 32;
offset = pMC->pParmAct - pMC->pParmNames;
if (!(pMC->pParmNames = realloc(pMC->pParmNames, (USHORT)( offset + 32))))
memerror("scandummy");
pMC->pParmAct = pMC->pParmNames + offset;
}
*pMC->pParmAct++ = siz;
memcpy(pMC->pParmAct, naim.pszName, siz+1);
pMC->pParmAct += siz;
pMC->cbParms -= siz+1;
}
/*** growParm - grow the size of parmeter block
*
* Entry pTextCur: current text location
* pText: start of currect arg
* pTextEnd: end of string
* Returns relloced pMCparm names
*/
char * PASCAL CODESIZE
growParm (
char *pTextCur
){
register MC *pMC = pMCur;
long delta, i;
char *pTNew;
/* relloc the string on overflow */
if (!(pTNew = realloc(pMC->pParmAct, (USHORT)( pTextEnd - pMC->pParmAct + 32))))
memerror("growparm");
delta = pTNew - pMC->pParmAct;
/* Adjust all the pointers */
pMC->cbParms += 32;
for (i = 0; i <pMC->count; i++)
pMC->rgPV[i].pActual += delta;
pMC->pParmAct += delta;
pTextEnd += delta + 32;
pTextCur += delta;
pText += delta;
return (pTextCur);
}
/*** scanparam - scan a parameter for IRP and MACRO calls
*
* scanparm (irpp);
*
* Entry irpp = TRUE if parameters to be comma terminated
* irpp = FALSE if parameters to be blank or comma terminated
* Exit
* Returns none
* Calls
*/
VOID PASCAL CODESIZE
scanparam (
UCHAR irpp
){
register char *pTextCur;
register UCHAR cc;
USHORT bracklevel;
pText = pTextCur = pMCur->pParmNames;
pTextEnd = pTextCur + pMCur->cbParms;
pTextCur++;
bracklevel = 0;
if (ISBLANK (PEEKC ()))
skipblanks ();
while(1) {
if (pTextCur+1 >= pTextEnd)
pTextCur = growParm(pTextCur);
switch (cc = NEXTC ()) {
case ';':
if (bracklevel)
break;
case NULL:
BACKC ();
goto done;
case '%': /* convert %expr to character string */
pTextCur = scanvalue (pTextCur);
break;
case '\'':
case '"':
*pTextCur++ = delim = cc; /* store opening quote */
while(1) {
if (pTextCur >= pTextEnd)
pTextCur = growParm(pTextCur);
/* store next character of string */
if (!(cc = NEXTC())){
BACKC();
goto done;
}
*pTextCur++ = cc;
/* check for double quote character */
if (cc == delim) {
if (PEEKC () == delim) {
*pTextCur++ = cc;
SKIPC ();
}
else
break;
}
}
break;
case '<': /* Have start of < xxx > */
if (bracklevel)
*pTextCur++ = cc;
bracklevel++;
break;
case '>': /* Have end of < xxx > */
if (bracklevel > 1)
*pTextCur++ = cc;
else{
if (bracklevel == 0)
BACKC();
goto done;
}
bracklevel--;
break;
case '!': /* Next char is literal */
*pTextCur++ = NEXTC ();
break;
case ' ':
case '\t':
case ',':
if (bracklevel == 0 &&
(cc == ',' || !irpp)) {
BACKC ();
goto done;
}
default:
*pTextCur++ = cc;
}
}
done:
cbText = pTextCur - pText - 1; /* set byte prefix count */
if (cbText > 0xfe)
errorc(E_LNL);
*pText = cbText;
pMCur->cbParms -= cbText + 1;
if (!irpp)
pMCur->rgPV[pMCur->count].pActual = pText; /* point to arg */
pMCur->pParmNames = pTextCur; /* set pointer to parm pool */
pMCur->count++;
}
/*** scanvalue - evaluate expression and and store converted value
*
* p = scanvalue (p, lim);
*
* Entry p = pointer to location to store converted value
* lim = limit address of buffer
* Exit
* Returns pointer to next character to store into
* Calls exprconst, radixconvert, error
*/
char * PASCAL CODESIZE
scanvalue (
char *pTextCur
){
OFFSET value;
register char *lastlbuf;
SHORT errorIn;
/* look for a text macro name thats not a constant */
lastlbuf = lbufp;
getatom();
if (PEEKC() == ',' || ISTERM(PEEKC())) {
/* try a text macro subsitution */
if (symsrch () &&
symptr->symkind == EQU &&
symptr->symu.equ.equtyp == TEXTMACRO) {
lastlbuf = symptr->symu.equ.equrec.txtmacro.equtext;
while(*lastlbuf){
if (pTextCur >= pTextEnd)
pTextCur = growParm(pTextCur);
*pTextCur++ = *lastlbuf++;
}
return(pTextCur);
}
}
lbufp = lastlbuf;
return(radixconvert (exprconst(), pTextCur));
}
/*** radixconvert - convert expression to value in current radix
*
* ptr = radixconvert (value, ptr, lim);
*
* Entry value = value to convert
* ptr = location to store converted string
* lim = limit address of buffer
* Exit
* Returns pointer to next character in store buffer
* Calls error, radixconvert
*/
#if !defined XENIX286 && !defined FLATMODEL
# pragma check_stack+
#endif
char * PASCAL CODESIZE
radixconvert (
OFFSET valu,
register char *p
){
if (valu / radix) {
p = radixconvert (valu / radix, p);
valu = valu % radix;
}
else /* leading digit */
if (valu > 9) /* do leading '0' for hex */
*p++ = '0';
if (p >= pTextEnd)
p = growParm(p);
*p++ = valu + ((valu > 9)? 'A' - 10 : '0');
return (p);
}
#if !defined XENIX286 && !defined FLATMODEL
# pragma check_stack-
#endif
/*** macroexpand - expand IRP/IRPC/IRPT/MACRO
*
* buffer = irpxexpand ();
*
* Entry pMC = pointer to macro call block
* Exit lbuf = next line of expansion
* Returns pointer to expanded line
* NULL if end of all expansions
* Calls
*/
VOID PASCAL CODESIZE
macroexpand (
register MC *pMC
){
char FAR *lc;
register USHORT cc;
register UCHAR *lbp, *pParm;
register USHORT cbLeft;
if (pMC->count == 0) { /* Have reached end of expand */
done:
if (pMC->flags != TMACRO)
listfree (pMC->pTSHead);
deleteMC (pMC); /* Delete all params */
macrolevel--;
popcontext = TRUE;
exitbody = FALSE;
return;
}
while(1){
if (!pMC->pTSCur) {
/* End of this repeat */
/* Move back to body start */
pMC->pTSCur = pMC->pTSHead;
if (--pMC->count == 0)
goto done;
if (pMC->flags <= TIRPC)
pMC->rgPV[0].pActual += *pMC->rgPV[0].pActual + 1;
}
lineExpand(pMC, pMC->pTSCur->text);
pMC->pTSCur = pMC->pTSCur->strnext;
if (exitbody) { /* unroll nested if/else/endif */
lastcondon = pMC->svlastcondon;
condlevel = pMC->svcondlevel;
elseflag = pMC->svelseflag;
goto done;
}
break;
}
}
#ifndef M8086OPT
VOID CODESIZE
lineExpand (
MC *pMC,
char FAR *lc /* Macro Line */
){
register USHORT cc;
register UCHAR *lbp, *pParm;
register USHORT cbLeft;
UCHAR fLenError;
#ifdef BCBOPT
fNoCompact = FALSE;
#endif
lbufp = lbp = lbuf;
cbLeft = LBUFMAX - 1;
fLenError = FALSE;
while( cc = *lc++) {
if (cc & 0x80) {
cc &= 0x7F;
if (cc >= pMC->iLocal) {
pParm = pMC->rgPV[cc].localName;
// Error if not enough room for 6 more bytes
if( 6 > cbLeft ){
fLenError = TRUE;
break;
}
cbLeft -= 6;
*lbp++ = '?'; /* Store "??" */
*lbp++ = '?';
if (pParm[0] == NULL) { /* must recreat the name */
offsetAscii ((OFFSET) (pMC->localBase +
cc - pMC->iLocal));
*lbp++ = objectascii[0];
*lbp++ = objectascii[1];
*lbp++ = objectascii[2];
*lbp++ = objectascii[3];
}else{
/* Copy 4 bytes from pParm */
*lbp++ = pParm[0];
*lbp++ = pParm[1];
*lbp++ = pParm[2];
*lbp++ = pParm[3];
}
}
else {
pParm = pMC->rgPV[cc].pActual;
cc = *pParm;
if( cc > cbLeft ){
fLenError = TRUE;
break;
}
cbLeft -= cc;
memcpy(lbp, pParm+1, cc);
lbp += cc;
}
}
else {
if( cc > cbLeft ){ /* if line too long */
fLenError = TRUE;
break;
}
cbLeft -= cc;
fMemcpy(lbp, lc, cc);
lc += cc;
lbp += cc;
}
}
if( fLenError ){
*lbp++ = '\0'; /* Terminate the line */
errorc( E_LTL & E_ERRMASK );
}
linebp = lbp - 1;
linelength = linebp - lbufp;
if( fNeedList ){
strcpy( linebuffer, lbuf );
}
/* At exit (linebp - lbuf) == strlen( lbuf ) */
}
#endif
/*** test4TM - tests if symbol is a text macro, and whether it is
* preceded or followed by '&'
*
* flag = test4TM ();
*
* Entry lbufp points to beginning of symbol in lbuf
* Exit lbufp is advanced by getatom
* Returns TRUE if symbol is text macro, else FALSE
* Calls getatom, symsrch
*/
UCHAR PASCAL CODESIZE
test4TM()
{
UCHAR ret = FALSE;
if (!getatom ())
return (ret);
xcreflag--;
if (symsrch() && (symptr->symkind == EQU)
&& (symptr->symu.equ.equtyp == TEXTMACRO)) {
xcreflag++; /* cref reference to text macro symbol now */
crefnew (REF); /* as it will be overwritten by expandTM */
crefout ();
/* '&' will be overwritten by equtext in lbuf */
if (*(begatom - 1) == '&')
begatom--;
if (*endatom == '&')
endatom++;
ret = TRUE;
} else
xcreflag++;
return (ret);
}
/*** substituteTMs - substitute equtext for each text macro symbol on line
*
* substituteTMs ();
*
* Entry lbufp points to first non-blank character after '%' in lbuf
* Exit lbufp points to beginning of lbuf
* Calls test4TM, expandTM, getatom, skipblanks
*/
VOID PASCAL CODESIZE
substituteTMs()
{
char cc;
char delim;
UCHAR inquote;
while ((cc = PEEKC ()) && cc != ';') {
inquote = FALSE;
if (cc == '\'' || cc == '"') {
delim = cc;
cc = *(++lbufp);
inquote = TRUE;
}
do {
if (inquote && cc == '&')
SKIPC ();
if ((!inquote || cc == '&') && LEGAL1ST(PEEKC ())) {
if (test4TM())
expandTM (symptr->symu.equ.equrec.txtmacro.equtext);
continue;
}
if (!(getatom())) {
SKIPC ();
skipblanks();
}
} while (inquote && (cc = PEEKC ()) && (cc != delim));
if (inquote && (cc == delim))
SKIPC ();
}
lbufp = lbuf;
}
#ifndef M8086OPT
/*** expandTM - expand text macro in naim in lbuf/lbufp
*
* expandTM ( pReplace );
*
* Entry pReplace = replacement string
* naim = text macro
* begatom = first character in lbuf to replace
* endatom = first character in lbuf after string to replace
* linebp = points to null terminator in lbuf
* Exit lbuf = new line to be parsed
* lbufp = first character of new atom (replace string)
* linebp = points to new position of null terminator in lbuf
* Returns
* Calls
* Note Shifts characters from lbufp to make substitution of TM.
* Inserts replacement string at begatom. This function could
* be tweaked considerably for speed at the expense of readability.
*/
VOID CODESIZE
expandTM (
register char *pReplace
){
USHORT cbReplace; /* Length of the replacement string */
USHORT cbNaim; /* Length of the atom to replace */
USHORT cbLineEnd; /* Length of the line past the atom being replaced */
cbReplace = strlen( pReplace );
cbNaim = endatom - begatom; /* Get length of the current atom */
cbLineEnd = linebp - endatom + 1; /* Get length of end of line */
if ( (begatom - lbuf) + cbReplace + cbLineEnd > LBUFMAX) {
errorc (E_LTL & E_ERRMASK);
*begatom = '\0'; /* Truncate line */
}else{
if( cbReplace != cbNaim ){
/* Shift end of line */
memmove( begatom + cbReplace, endatom, cbLineEnd );
}
memcpy ( begatom, pReplace, cbReplace );
}
lbufp = begatom;
linebp = begatom + cbReplace + cbLineEnd - 1;
}
#endif /* M8086OPT */