/* asmrec.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"
struct recpars {
SYMBOL FARSYM *recptr;
SYMBOL FARSYM *curfld;
OFFSET recval;
};
struct recdef {
USHORT fldcnt;
USHORT reclen;
SYMBOL FARSYM *recptr;
SYMBOL FARSYM *curfld;
short i;
};
VOID PASCAL CODESIZE recordspec PARMS((struct recdef *));
VOID PASCAL CODESIZE recfill PARMS((struct recpars *));
static OFFSET svpc = 0;
static struct duprec FARSYM *pDUPCur;
/*** checkvalue - insure value will fit in field
*
* checkvalue (width, sign, magnitude)
*
* Entry width = width of field
* sign = sign of result
* magnitude= magnitude of result
* Exit none
* Returns adjusted value
* Calls none
*/
OFFSET PASCAL CODESIZE
checkvalue (
register SHORT width,
register char sign,
register OFFSET mag
){
register OFFSET mask;
if (width == sizeof(OFFSET)*8)
mask = OFFSETMAX;
else
mask = (1 << width) - 1;
if (!sign) {
if (width < sizeof(OFFSET)*8)
if (mag > mask) {
errorc (E_VOR);
mag = mask;
}
}
else {
mag = OFFSETMAX - mag;
mag++;
if (width < sizeof(OFFSET)*8)
if ((mag ^ OFFSETMAX) & ~mask) {
errorc (E_VOR);
mag = mask;
}
}
return (mag & mask);
}
/*** recordspec - parse record field specification fld:wid[=val]
*
* recordspec (p);
*
* Entry p = pointer to record definition structure
* Exit
* Returns
* Calls
*/
VOID PASCAL CODESIZE
recordspec (
register struct recdef *p
){
register SYMBOL FARSYM *fldptr;
register USHORT width;
register struct symbrecf FARSYM *s;
char sign;
OFFSET mag;
getatom ();
if (*naim.pszName) {
if (!symFet ())
symcreate (M_DEFINED | M_BACKREF, RECFIELD);
else {
if (symptr->symu.rec.recptr != p->recptr ||
M_BACKREF & symptr->attr)
errorn (E_SMD);
symptr->attr |= M_BACKREF;
}
crefdef ();
s = &(symptr->symu.rec);
if (symptr->symkind != RECFIELD)
/* Not field */
errorn (E_SDK);
else {
/* Ptr to field */
fldptr = symptr;
if (!p->curfld)
p->recptr->symu.rsmsym.rsmtype.rsmrec.reclist = fldptr;
else
p->curfld->symu.rec.recnxt = fldptr;
/* New last field */
p->curfld = fldptr;
s->recptr = p->recptr;
s->recnxt = NULL;
p->fldcnt++;
if (NEXTC () != ':')
error (E_EXP,"colon");
/* Get field width */
width = exprconst ();
if (skipblanks () == '=') {
SKIPC ();
mag = exprsmag (&sign);
}
else {
sign = FALSE;
mag = 0;
}
if (width == 0 ||
p->reclen + width > wordsize*8) {
STRNFCPY (save, p->curfld->nampnt->id);
/*Overflow */
error (E_VOR, save);
width = 0;
}
s->recinit = checkvalue (width, sign, mag);
s->recmsk = (OFFSET)((1L << width) - 1);
s->recwid = width;
p->reclen += width;
}
}
}
/*** recorddefine - parse record definition
*
* recorddefine ();
*
* Entry
* Exit
* Returns
* Calls
*/
VOID PASCAL CODESIZE
recorddefine ()
{
struct recdef a;
struct symbrecf FARSYM *s;
register SHORT cbRec;
a.reclen = 0;
a.fldcnt = 0;
checkRes();
if (!symFet ()) {
/* Make record */
symcreate (M_DEFINED | M_BACKREF, REC);
}
else
symptr->attr |= M_BACKREF;
/* This is def */
crefdef ();
if (symptr->symkind != REC)
/* Wasn't record */
errorn (E_SDK);
else {
/* Leftmost bit of record */
a.reclen = 0;
/*No record filed yet */
a.curfld = NULL;
/* In case error */
symptr->symu.rsmsym.rsmtype.rsmrec.reclist = NULL;
/* Pointer to record name */
a.recptr = symptr;
/* Parse record field list */
BACKC ();
do {
SKIPC ();
recordspec (&a);
} while (skipblanks() == ',');
/* Length of record in bits */
cbRec = a.reclen;
a.recptr->length = cbRec;
a.recptr->offset = (OFFSET)((1L << cbRec) - 1);
a.recptr->symtype = (cbRec > 16 )? 4: ((cbRec > 8)? 2: 1);
/* # of fields in record */
a.recptr->symu.rsmsym.rsmtype.rsmrec.recfldnum = a.fldcnt;
/* 1st field */
a.curfld = a.recptr->symu.rsmsym.rsmtype.rsmrec.reclist;
}
/* For all the fields adjust the shift (stored in offset),
* initial value and mask so the last field is right justified */
while (a.curfld) {
s = &(a.curfld->symu.rec);
/* Start of field */
cbRec = (cbRec > s->recwid)? cbRec - s->recwid: 0;
/* Shift count */
a.curfld->offset = cbRec;
s->recinit <<= cbRec;
s->recmsk <<= cbRec;
a.curfld = s->recnxt; /* Next field */
}
}
/*** recfill - get initial value for field in list
*
* recfill (p);
*
* Entry
* Exit
* Returns
* Calls
*/
VOID PASCAL CODESIZE
recfill (
register struct recpars *p
){
register char cc;
struct symbrecf FARSYM *s;
char sign;
OFFSET mag, t;
if (!p->curfld) {
/* More fields than exist */
errorc (E_MVD);
}
else {
s = &(p->curfld->symu.rec);
if ((cc = skipblanks ()) == ',' || cc == '>') {
/* Use default value */
t = s->recinit;
}
else {
/* Have an override */
mag = exprsmag (&sign);
t = checkvalue (s->recwid, sign, mag);
/* Scale value */
t <<= p->curfld->offset;
}
/* Add in new field */
if (s->recwid)
p->recval = (p->recval & ~(s->recmsk)) | t;
p->curfld = s->recnxt;
}
}
/*** recordparse - parse record specification
*
* recordparse ();
*
* Entry
* Exit
* Returns
* Calls
*/
OFFSET PASCAL CODESIZE
recordparse ()
{
struct recpars a;
struct symbrecf FARSYM *s;
a.recptr = symptr; /* Current record */
if (PEEKC () != '<')
error (E_EXP,"<"); /* Must have < */
else
SKIPC ();
/* No value yet */
a.recval = 0;
/* 1st field in record */
a.curfld = a.recptr->symu.rsmsym.rsmtype.rsmrec.reclist;
BACKC ();
do { /* Fill in values */
SKIPC ();
recfill (&a);
} while (skipblanks () == ',');
while (a.curfld) {
/* Fill in remaining defaults */
s = &(a.curfld->symu.rec);
if (s->recwid)
a.recval = (a.recval & ~(s->recmsk)) | s->recinit;
a.curfld = s->recnxt;
}
if (NEXTC () != '>') /* Must have > */
error (E_EXP,">");
return (a.recval); /* Value of record */
}
/*** recordinit - parse record allocation
*
* recordinit ();
*
* Entry
* Exit
* Returns
* Calls
*/
VOID PASCAL CODESIZE
recordinit ()
{
initflag = TRUE;
strucflag = FALSE; /* This is RECORD init */
recptr = symptr;
optyp = TDB;
if (symptr->symtype == 2)
optyp = TDW;
#ifdef V386
else if (symptr->symtype == 4)
optyp = TDD;
#endif
datadefine ();
initflag = FALSE;
}
/*** nodecreate - create one DUP record
*
* nodecreate ();
*
* Entry
* Exit
* Returns
* Calls
*/
struct duprec FARSYM * PASCAL CODESIZE
nodecreate ()
{
register struct duprec FARSYM *node;
node = (struct duprec FARSYM *)falloc (sizeof (*node), "nodecreate");
node->rptcnt = 1;
node->itemcnt = 0;
node->duptype.dupnext.dup = NULL;
node->itemlst = NULL;
node->dupkind = NEST;
return (node);
}
/*** strucdefine - define structure
*
* strucdefine ();
*
* Entry
* Exit
* Returns
* Calls
*/
VOID PASCAL CODESIZE
strucdefine ()
{
checkRes();
if (!symFet()) {
/* Make STRUC */
symcreate (M_DEFINED | M_BACKREF, STRUC);
}
else
symptr->attr |= M_BACKREF;
/* This is definition */
crefdef ();
if (symptr->symkind != STRUC)
errorn (E_SDK);
else {
symptr->attr |= M_BACKREF;
recptr = symptr; /* Pointer to STRUC name */
recptr->symu.rsmsym.rsmtype.rsmstruc.strucfldnum = 0;
if (! pass2) {
recptr->symu.rsmsym.rsmtype.rsmstruc.type = typeIndex;
typeIndex += 3;
if (pStrucCur)
pStrucCur->alpha = recptr;
else
pStrucFirst = recptr;
pStrucCur = recptr;
}
/* No labeled fields yet */
recptr->symu.rsmsym.rsmtype.rsmstruc.struclist = NULL;
/* Delete old STRUC */
scandup (recptr->symu.rsmsym.rsmtype.rsmstruc.strucbody, oblitdup);
recptr->symu.rsmsym.rsmtype.rsmstruc.strucbody = nodecreate ();
struclabel = NULL; /* No named fields */
strucprev = NULL; /* No body yet */
count = 0; /* No fields yet */
strucflag = TRUE; /* We are STRUC not RECORD */
svpc = pcoffset; /* Save normal PC */
pcoffset = 0; /* Relative to STRUC begin */
swaphandler = TRUE; /* Switch to STRUC builder */
handler = HSTRUC;
}
}
/*** strucbuild - build the struc block
*
* strucbuild ();
*
* Entry
* Exit
* Returns
* Calls
*/
VOID PASCAL CODESIZE
strucbuild ()
{
labelflag = FALSE;
optyp = 0;
getatom ();
#ifndef FEATURE
if (naim.pszName[0] == '%' && naim.pszName[1] == 0) { /* expand all text macros */
*begatom = ' ';
substituteTMs();
getatom();
}
#endif
/* First, look for IF, ELSE & ENDIF stuff */
if (fndir () && (opkind & CONDBEG)) {
firstDirect();
}
else if (generate && *naim.pszName) {
/* next, classify the current token, which is either
* and ENDS, data label or data name */
if (optyp == 0 || !fndir2 ()){
/* first token was a label */
switchname ();
getatom ();
optyp = 0;
if (!fndir2 ())
errorc(E_DIS);
labelflag = TRUE; /* Do have label */
switchname ();
}
if (optyp == TENDS) {
if (!symFet () || symptr != recptr)
errorc(E_BNE);
/* Have end of STRUC */
handler = HPARSE;
swaphandler = TRUE;
strucflag = FALSE;
recptr->symu.rsmsym.rsmtype.rsmstruc.strucfldnum =
/* # of fields */
recptr->symu.rsmsym.rsmtype.rsmstruc.strucbody->itemcnt;
if (pcoffset & 0xFFFF0000)
errorc (E_DVZ);
recptr->symtype = pcoffset; /* Size of STRUC */
recptr->length = 1;
pcdisplay ();
/* Restore PC */
pcoffset = svpc;
}
else if (! (optyp >= TDB && optyp <= TDW))
errorc (E_DIS);
else { /* Have another line of body */
if (!strucprev) {
/* Make first node */
strucprev = nodecreate ();
recptr->symu.rsmsym.rsmtype.rsmstruc.strucbody->
duptype.dupnext.dup = strucprev;
}
else {
strucprev->itemlst = nodecreate ();
strucprev = strucprev->itemlst;
}
recptr->symu.rsmsym.rsmtype.rsmstruc.strucbody->itemcnt++;
/* Add new data line to STRUC */
datadefine ();
strucprev->decltype = optyp;
}
}
if (generate) {
if (!ISTERM (skipblanks()))
errorc (E_ECL);
}
listline ();
}
struct srec {
struct duprec FARSYM *curfld;
USHORT curlen;
};
/*** createduprec - create short data record with null data
*
* createduprec ();
*
* Entry
* Exit
* Returns
* Calls
*/
struct duprec FARSYM * PASCAL CODESIZE
createduprec ()
{
register struct duprec FARSYM *newrec;
newrec = (struct duprec FARSYM *)falloc (sizeof (*newrec), "createduprec");
newrec->rptcnt = 1;
/* Not a DUP */
newrec->itemcnt = 0;
newrec->itemlst = NULL;
newrec->dupkind = ITEM;
/* this also clears ddata and dup in other variants of struc */
newrec->duptype.duplong.ldata = NULL;
newrec->duptype.duplong.llen = 1;
return (newrec);
}
/*** strucerror - generate structure error message
*
* strucerror ();
*
* Entry
* Exit
* Returns
* Calls
*/
struct duprec FARSYM * PASCAL CODESIZE
strucerror (
SHORT code,
struct duprec FARSYM *node
){
errorc (code);
/* Get rid of bad Oitem */
oblitdup (node);
/* Make up a dummy */
return (createduprec ());
}
/*** strucfill - fill in structure values
*
* strucfill ();
*
* Entry
* Exit
* Returns
* Calls
*/
VOID PASCAL CODESIZE
strucfill ()
{
register struct duprec FARSYM *pOver;
register struct duprec FARSYM *pInit;
register char *cp;
char svop;
short i, cbCur;
struct datarec drT;
if (!pDUPCur) {
errorc (E_MVD);
return;
}
if (skipblanks() == ',' || PEEKC() == '>') {
/* use default values */
pOver = createduprec ();
}
else {
/* Save operation type */
svop = optyp;
/* Original directive type */
optyp = pDUPCur->decltype;
pOver = datascan (&drT); /* Get item */
optyp = svop;
pInit = pDUPCur->duptype.dupnext.dup;
cbCur = pInit->duptype.duplong.llen;
if (pOver->dupkind == NEST)
/* Bad override val */
pOver = strucerror (E_ODI, pOver);
else if (pDUPCur->itemcnt != 1 || pInit->itemcnt)
/* Can't override field */
pOver = strucerror (E_FCO, pOver);
else if (pOver->dupkind != pInit->dupkind) {
if (pInit->dupkind == ITEM)
cbCur = pInit->duptype.dupitem.ddata->dsckind.opnd.dsize;
}
if (pOver->dupkind == LONG) {
/* If too long, truncate */
if ((i = pOver->duptype.duplong.llen) < cbCur) {
/* Space fill short (after reallocating more space) */
if (!(pOver->duptype.duplong.ldata =
realloc (pOver->duptype.duplong.ldata, cbCur)))
memerror("strucfil");
cp = pOver->duptype.duplong.ldata + i;
for (; i < cbCur; i++)
*cp++ = ' ';
}
else if (pOver->duptype.duplong.llen > cbCur)
errorc (E_OWL);
pOver->duptype.duplong.llen = cbCur;
}
if ((pOver->dupkind == pInit->dupkind) &&
(pOver->dupkind == ITEM) && !errorcode)
pOver->duptype.dupitem.ddata->dsckind.opnd.dsize =
pInit->duptype.dupitem.ddata->dsckind.opnd.dsize;
}
pDUPCur = pDUPCur->itemlst;
if (strucoveride)
strclastover->itemlst = pOver;
else
strucoveride = pOver;
strclastover = pOver;
}
/*** strucparse - parse structure specification
*
* strucparse ();
*
* Entry
* Exit
* Returns
* Calls
*/
struct duprec FARSYM * PASCAL CODESIZE
strucparse ()
{
/* No items yet */
strucoveride = NULL;
recptr = symptr;
if (skipblanks () != '<')
error (E_EXP,"<");
/* 1st default field */
pDUPCur = recptr->symu.rsmsym.rsmtype.rsmstruc.strucbody->duptype.dupnext.dup;
initflag = FALSE;
strucflag = FALSE;
/* Build list of overrides */
do {
SKIPC ();
strucfill ();
} while (skipblanks () == ',');
initflag = TRUE;
strucflag = TRUE;
while (pDUPCur) {/* Fill rest with overrides */
/* Make dummy entry */
strclastover->itemlst = createduprec ();
strclastover = strclastover->itemlst;
/* Advance to next field */
pDUPCur = pDUPCur->itemlst;
}
if (PEEKC () != '>')
error (E_EXP,">");
else
SKIPC ();
return (recptr->symu.rsmsym.rsmtype.rsmstruc.strucbody);
}
/*** strucinit - initialize structure
*
* strucinit ();
*
* Entry
* Exit
* Returns
* Calls
*/
VOID PASCAL CODESIZE
strucinit ()
{
initflag = TRUE;
strucflag = TRUE;
recptr = symptr;
optyp = TMACRO;
datadsize[TMACRO - TDB] = recptr->symtype;
datadefine ();
initflag = FALSE;
strucflag = FALSE;
}