/* 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 #include #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 = (USHORT)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 = (char)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 = (char)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 = (USHORT)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 = (unsigned char)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; }