/* asmequ.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 "asmmsg.h"
/* EQU statement : There are 3 basic kinds of EQU:
1. To expression
2. To symbol( synonym )
3. All others are text macros
*/
VOID PASCAL CODESIZE assignconst ( USHORT );
char isGolbal; /* flag indicating if equ symbol was global */
/*** assignvalue - assign value to symbol
*
* assignvalue ();
*
* Entry
* Exit
* Returns
* Calls
*/
VOID PASCAL CODESIZE
assignvalue ()
{
struct eqar a;
register struct psop *pso;
register SYMBOL FARSYM *sym;
register DSCREC *dsc;
switchname ();
if (createequ(EXPR)) {
sym = symptr;
sym->attr |= M_BACKREF; /* Set we have DEFINED */
dsc = (equflag)? itemptr: expreval (&nilseg);
pso = &(dsc->dsckind.opnd);
if (noexp)
errorc (E_OPN);
/* If error, set undefined */
if (errorcode && errorcode != E_RES)
sym->attr &= ~(M_DEFINED | M_BACKREF);
if (equflag && equdef) {
if (sym->offset != pso->doffset ||
sym->symu.equ.equrec.expr.esign != pso->dsign ||
sym->symsegptr != pso->dsegment)
muldef ();
}
/* If = involves forward, don't set BACKREF */
if (M_FORTYPE & pso->dtype){
sym->attr &= ~M_BACKREF;
if (sym->attr & M_GLOBAL)
sym->attr &= ~M_GLOBAL;
}
if (pso->mode != 4 &&
!(pso->mode == 0 && pso->rm == 6) &&
!(pso->mode == 5 && pso->rm == 5) ||
pso->dflag == XTERNAL)
/* Not right kind of result */
errorc (E_IOT);
sym->symsegptr = pso->dsegment;
sym->symu.equ.equrec.expr.eassume = NULL;
if (pso->dtype == M_CODE)
sym->symu.equ.equrec.expr.eassume = pso->dcontext;
sym->length = 0;
sym->offset = pso->doffset;
/* Note: change sign */
sym->symu.equ.equrec.expr.esign = pso->dsign;
sym->symtype = pso->dsize;
if ((pso->dtype == M_RCONST || !pso->dsegment) &&
!(M_PTRSIZE & pso->dtype))
sym->symtype = 0;
if (fNeedList) {
listbuffer[1] = '=';
listindex = 3;
if (sym->symu.equ.equrec.expr.esign)
listbuffer[2] = '-';
offsetAscii (sym->offset);
copyascii ();
}
dfree ((char *)dsc );
}
}
/*** createequ - create entry for equ
*
* flag = createequ (typ, p)
*
* Entry typ = type of equ
* Exit
* Returns TRUE if equ created or found of right type
* FALSE if equ not created or found and wrong type
* Calls labelcreate, switchname
*/
UCHAR PASCAL CODESIZE
createequ (
UCHAR typ
){
equsel = typ;
switchname ();
labelcreate (0, EQU);
/* Make sure not set set fields if wrong type, flag to caller */
if (symptr->symkind != EQU || symptr->symu.equ.equtyp != typ) {
errorn (E_SDK);
return (FALSE);
}
else {
switchname ();
isGolbal = 0;
if (equsel == ALIAS){ /* lose public on pointer to alias */
isGolbal = symptr->attr & M_GLOBAL;
symptr->attr &= ~M_GLOBAL;
}
if (typ != EXPR)
symptr->symsegptr = NULL;
return (TRUE);
}
}
/*** equtext - make remainder of line into text form of EQU
*
* equtext ();
*
* Entry
* Exit
* Returns
* Calls error, skipblanks
*/
VOID PASCAL CODESIZE
equtext (
USHORT cb
){
register UCHAR *pFirst, *pT, *pOld;
if (createequ (TEXTMACRO)) {
/* find end of line & then delete trailing blanks */
pFirst = lbufp;
if (cb == ((USHORT)-1)) {
for (pT = pFirst; *pT && *pT != ';'; pT++);
for (; pT > pFirst && ISBLANK (pT[-1]) ; pT--);
lbufp = pT;
cb = pT - pFirst;
}
pOld = symptr->symu.equ.equrec.txtmacro.equtext;
pT = nalloc((USHORT)(cb+1), "equtext");
pT[cb] = NULL;
symptr->symu.equ.equrec.txtmacro.equtext =
(char *) memcpy(pT, pFirst, cb);
if (pOld)
free (pOld);
copystring (pT);
}
}
/*** equdefine - define EQU
*
* equdefine ();
*
* Entry
* Exit
* Returns
* Calls
*/
VOID PASCAL CODESIZE
equdefine ()
{
register SYMBOL FARSYM *pSY;
struct eqar a;
register char *p;
USHORT cb;
UCHAR opc = FALSE;
listbuffer[1] = '=';
switchname ();
a.dirscan = lbufp;
if (PEEKC () == '<') { /* look for <text macro> */
p = getTMstring();
a.dirscan = lbufp;
lbufp = p;
equtext ((USHORT)(a.dirscan - p - 1));
lbufp = a.dirscan;
return;
}
getatom ();
if ((*naim.pszName == '$') && (naim.pszName[1] == 0))
*naim.pszName = 0;
/*Need to check if 1st atom is an operator, otherwise
will make OFFSET an alias instead of text. */
if (fnoper ())
*naim.pszName = 0;
if (*naim.pszName && ISTERM (PEEKC ()) && !(opc = opcodesearch ())) {
/* Alias */
if (createequ (ALIAS)) {
pSY = symptr;
if (!symsrch ()) {
if (pass2)
/* Undefined */
errorn (E_SND);
/* Don't know symbol yet */
pSY->symu.equ.equrec.alias.equptr = NULL;
}
else {
/* Alias symbol is DEFINED */
pSY->attr = pSY->attr&~M_BACKREF | symptr->attr&M_BACKREF;
if (!pSY->symu.equ.equrec.alias.equptr)
pSY->symu.equ.equrec.alias.equptr = symptr;
if (pSY->symu.equ.equrec.alias.equptr != symptr) {
/* This is multiple definition */
symptr = pSY;
muldef ();
}
else {
/* See if good */
if (pSY = chasealias (pSY))
pSY->attr |= isGolbal;
}
}
}
}
else {
/* Must be text form or expr */
#ifdef BCBOPT
goodlbufp = FALSE;
#endif
lbufp = a.dirscan;
xcreflag--;
emittext = FALSE;
if (opc) { /* quick patch to allow i.e. SYM equ MOV */
equtext ((USHORT)-1);
emittext = TRUE;
xcreflag++;
return;
}
a.dsc = expreval (&nilseg);
emittext = TRUE;
xcreflag++;
/* So don't see double ref */
/* force text if OFFSET or : */
if (a.dsc->dsckind.opnd.mode != 4 &&
!(a.dsc->dsckind.opnd.mode == 0 && a.dsc->dsckind.opnd.rm == 6) &&
!(a.dsc->dsckind.opnd.mode == 5 && a.dsc->dsckind.opnd.rm == 5) ||
(errorcode && errorcode != E_SND && errorcode != E_RES) ||
(M_EXPLOFFSET|M_EXPLCOLON|M_HIGH|M_LOW) & a.dsc->dsckind.opnd.dtype ||
a.dsc->dsckind.opnd.seg != NOSEG ||
a.dsc->dsckind.opnd.dflag == XTERNAL) {
/* Not good expression */
if (errorcode != E_LTL)
errorcode = 0;
dfree ((char *)a.dsc );
lbufp = a.dirscan;
equtext ((USHORT)-1);
}
else {
/* This is expression */
itemptr = a.dsc;
switchname ();
equflag = TRUE;
assignvalue ();
equflag = FALSE;
}
}
}
/*** definesym - define symbol from command line
*
* definesym (p);
*
* Entry *p = symbol text
* Exit symbol define as EQU with value of 0
* Returns none
* Calls
*/
void PASCAL
definesym (
UCHAR *p
){
struct eqar a;
fCheckRes++;
fSkipList++;
#ifdef BCBOPT
goodlbufp = FALSE;
#endif
strcpy (lbufp = save, p);
getatom ();
if ((PEEKC() == 0 || PEEKC() == '=') && *naim.pszName) {
if (PEEKC() == '=')
SKIPC();
switchname ();
equtext ((USHORT)-1);
}
else
errorcode++;
fSkipList--;
fCheckRes--;
}
/*** defwordsize - define @WordSize using definesym()
*
* defwordsize ( );
*
* Entry
* Exit
* Returns
* Calls definesym()
*/
VOID PASCAL
defwordsize ()
{
static char wstext[] = "@WordSize=0D";
wstext[10] = wordsize + '0';
definesym(wstext);
symptr->attr |= M_NOCREF; /* don't cref @WordSize */
}
/*** chasealias - return value of alias list
*
* symb = chasealias (equsym);
*
* Entry
* Exit
* Returns
* Calls
*/
SYMBOL FARSYM * PASCAL CODESIZE
chasealias (
SYMBOL FARSYM *equsym
){
register SYMBOL FARSYM *endalias;
endalias = equsym;
do {
/* Must check to see if EQU to self */
if (endalias->symu.equ.equrec.alias.equptr == equsym) {
endalias->symu.equ.equrec.alias.equptr = NULL;
errorc (E_CEA);
return (NULL);
}
endalias = endalias->symu.equ.equrec.alias.equptr;
if (!endalias) {
errorn (E_SND);
return(NULL); /* This is undefined */
}
} while (!(endalias->symkind != EQU ||
endalias->symu.equ.equtyp != ALIAS));
/* Now check final is ok - Only constant allowed */
if (endalias->symkind == EQU &&
endalias->symu.equ.equtyp != EXPR){
errorc (E_IOT);
return (NULL);
}
return (endalias);
}
/*** getTMstring - process a string or text macro
* used by substring, catstring, sizestring, & instring
*
* char * getTMstring ();
*
* Entry lbufp points to beginning of string or TM
* Exit
* Returns Pointer to string or equtext of TM
* Calls
*/
char * PASCAL CODESIZE
getTMstring ()
{
char cc;
register char * p;
static char tms [] = "text macro";
static char digitsT[33];
char * ret = NULL;
skipblanks ();
p = lbufp;
if ((cc = *p) == '<' ) {
ret = p + 1;
while (*(++p) && (*p != '>'))
;
if (!*p)
error(E_EXP,tms);
else
*(p++) = 0;
lbufp = p;
}
else if (test4TM()) {
ret = symptr->symu.equ.equrec.txtmacro.equtext;
}
else if (cc == '%') {
pTextEnd = (char *) -1;
lbufp = p+1;
*xxradixconvert (exprconst(), digitsT) = NULL;
return (digitsT);
}
else
error(E_EXP,tms );
return (ret);
}
/*** substring - process the subStr directive
*
* substring ();
*
* Syntax:
*
* <ident> subStr <subjectString> , <startIndex> {, <length> }
*
* Defines <ident> as a TEXTMACRO.
* <subjectString> must be a TEXTMACRO or a string: " ", < >, ' '
* <startIndex>: constant expression between 1 and strlen(subjectString)
* Optional <length>: constant expression between 0 and
* (strlen(subjectString) - startIndex + 1)
*
* Entry lbufp points to beginning of subjectString
* Exit
* Returns
* Calls getTMstring
*/
VOID PASCAL CODESIZE
substring ()
{
struct eqar a;
char *p;
register USHORT cb;
char cc;
register char *subjtext;
USHORT slength;
USHORT startindex = 0;
listbuffer[1] = '=';
switchname ();
/* First find string or text macro */
if (!(subjtext = getTMstring () ))
return;
cb = strlen(subjtext);
/* then check for start index */
if (skipblanks () == ',') {
SKIPC ();
startindex = exprconst() - 1; /* get start index */
} else
error(E_EXP,"comma");
/* then check for length */
if (skipblanks () == ',') {
SKIPC ();
slength = exprconst(); /* get start index */
} else
slength = cb - startindex;
if (startindex > cb || slength > cb - startindex) {
errorc (E_VOR);
return;
}
p = lbufp;
lbufp = subjtext + startindex; /* set lbufp to start of substring */
equtext(slength); /* end of string index */
lbufp = p;
if (errorcode && symptr)
symptr->attr &= ~(M_DEFINED | M_BACKREF);
}
/*** catstring - process the catstr directive
*
* catstring ();
*
* Syntax:
*
* <ident> catStr <subjectString> {, <subjectString> } ...
*
* Defines <ident> as a TEXTMACRO.
* Each <subjectString> must be a TEXTMACRO or a string: " ", < >, ' '
*
* Entry
* Exit
* Returns
* Calls
*/
VOID PASCAL CODESIZE
catstring ()
{
struct eqar a;
register USHORT cb;
char *subjtext;
char resulttext[LBUFMAX];
USHORT cbresult = 0;
register char *p = resulttext;
listbuffer[1] = '=';
switchname ();
*p = '\0';
/* First find string or text macro */
do {
if (!(subjtext = getTMstring () ))
break;
cb = strlen (subjtext);
cbresult += cb;
if(cbresult > LBUFMAX) {
errorc(E_LTL);
break;
}
memcpy (p, subjtext, cb + 1); /* + 1 copies NULL */
p += cb;
} while (skipblanks() && NEXTC () == ',');
p = --lbufp;
lbufp = resulttext;
equtext(cbresult);
lbufp = p;
if (errorcode)
symptr->attr &= ~(M_DEFINED | M_BACKREF);
}
/*** assignconst - like assignvalue, only takes value as argument
*
* assignconst (cb);
*
* Entry USHORT cb == value to assign
* Exit
* Returns
* Calls
*/
VOID PASCAL CODESIZE
assignconst (
USHORT cb
){
register SYMBOL FARSYM *sym;
struct eqar a;
if (createequ(EXPR)) {
sym = symptr;
if (errorcode)
sym->attr &= ~(M_DEFINED | M_BACKREF);
else
sym->attr |= M_BACKREF; /* Set we have DEFINED */
sym->symsegptr = NULL;
sym->symu.equ.equrec.expr.eassume = NULL;
sym->length = 0;
sym->offset = cb;
sym->symu.equ.equrec.expr.esign = 0;
sym->symtype = 0;
if (fNeedList) {
listbuffer[1] = '=';
listindex = 3;
offsetAscii (sym->offset);
copyascii ();
}
}
}
/*** sizestring - process the sizeStr directive
*
* sizestring ();
*
* Syntax:
*
* <ident> sizeStr <subjectString>
*
* Defines <ident> as a EXPR.
* The <subjectString> must be a TEXTMACRO or a string: " ", < >, ' '
*
* Entry
* Exit
* Returns
* Calls
*/
VOID PASCAL CODESIZE
sizestring ()
{
register USHORT cb = 0;
char *p;
switchname ();
/* First find string or text macro */
if (p = getTMstring () )
cb = strlen (p);
assignconst (cb);
}
/*** instring - process the instr directive
*
* instring ();
*
* Syntax:
*
* <ident> inStr { <startIndex> } , <subjectString> , <searchString>
*
* Defines <ident> as a TEXTMACRO.
* <startIndex>: constant expression between 1 and strlen(subjectString)
* <subjectString> must be a TEXTMACRO or a string: " ", < >, ' '
* <searchString> must be a TEXTMACRO or a string: " ", < >, ' '
*
* Entry lbufp points to beginning of subjectString
* Exit
* Returns
* Calls getTMstring
*/
char * strstr();
VOID PASCAL CODESIZE
instring ()
{
register char *p;
register USHORT cb = 0;
register char cc;
char *subjtext;
char *searchtext;
USHORT startindex = 1;
switchname ();
/* First find start index */
p = lbufp;
if ((cc = *p) != '"' && cc != '\'' && cc != '<' && !test4TM ()) {
lbufp = p;
startindex = exprconst(); /* get start index */
if (lbufp != p)
if (skipblanks () == ',')
SKIPC ();
else
error(E_EXP,"comma");
} else
lbufp = p;
if (subjtext = getTMstring () ) {
cb = strlen(subjtext);
if (startindex < 1 || startindex > cb)
errorc (E_VOR);
if (skipblanks () == ',')
SKIPC ();
else
error(E_EXP,"comma");
/* then check for searchtext */
if (searchtext = getTMstring () ) {
p = subjtext + startindex - 1;
if (p = strstr (p, searchtext))
cb = p - subjtext + 1;
else
cb = 0;
}
}
assignconst (cb);
}