|
|
/* asmpars.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 <string.h>
#include "asm86.h"
#include "asmfcn.h"
#include "asmctype.h"
extern void closefile(void);
static char parsedflag; char fNeedList; static char iod[] = "instruction, directive, or label"; char cputext[22] = "@Cpu="; char tempText[32]; USHORT coprocproc;
/* an array of pointers to the function parsers */
VOID (PASCAL CODESIZE * rgpHandler[])(void) = {
parse, macrobuild, irpxbuild, commentbuild, strucbuild };
/*** dopass - initialize and execute pass
* * dopass (); * * Entry * Exit * Returns * Calls */
VOID PASCAL dopass () {
/* Common pass initialize */
cputype = DEF_CPU; X87type = DEF_X87; radix = 10;
#ifdef XENIX287
definesym("@Cpu=0507h"); #else
definesym("@Cpu=0101h"); #endif
definesym("@Version=510");
pagewidth = DEF_LISTWIDTH; condflag = origcond; crefinc = 0; fSkipList = 0; errorlineno = 1; fCrefline = 1; fCheckRes = (pass2 && warnlevel >= 1); fNeedList = listconsole || (lsting && (pass2 | debug));
subttlbuf[0] = NULL; modulename = NULL; pcsegment = NULL; pcproc = NULL; startaddr = NULL; localbase = 0; macrolevel = 0; linessrc = 0; linestot = 0; condlevel = 0; lastcondon = 0; pcoffset = 0; pageminor = 0; errorcode = 0; fPass1Err = 0; iProc = 0; iProcCur = 0;
radixescape = FALSE; titleflag = FALSE; elseflag = FALSE; initflag = FALSE; strucflag = FALSE; fPutFirstOp = FALSE; fArth32 = FALSE;
listflag = TRUE; generate = TRUE; xcreflag = TRUE;
pagemajor = 1; crefcount = 1; expandflag = LISTGEN; pagelength = NUMLIN; pageline = NUMLIN - 1;
memset(listbuffer, ' ', LISTMAX); memset(regsegment, 0, sizeof(regsegment));/* No segments assumed*/
strcpy(tempText, "@F=@0");
if (tempLabel){ definesym(tempText); tempText[1] = 'B'; tempText[4] = '@'; definesym(tempText); tempText[4] = '0'; }
tempLabel = 0;
/* Dispatch to do pass */
handler = HPARSE; if (! setjmp(forceContext)) lineprocess (RREADSOURCE, NULL);
while (pFCBCur->pFCBParent) closefile (); }
/*** lineprocess - processs next line
* * lineprocess (tread); * * Entry tread = reader routine * Exit * Returns * Calls * Note Uses handler to decide which parsing routine to use */
#if !defined XENIX286 && !defined FLATMODEL
# pragma check_stack+
#endif
VOID CODESIZE lineprocess ( char tread, MC *pMC ){ VOID (PASCAL CODESIZE * pHandler)(void);
lastreader = tread; pHandler = rgpHandler[handler];
do { /* dispatch to reader to put line into lbuf */
/* Clear opcode area if listing */
if (crefinc) { crefcount += crefinc - 1; crefline (); crefcount++; crefinc = 0; }
if (tread == RREADSOURCE)
readfile (); else macroexpand (pMC);
if (popcontext) break;
linestot++;
(*pHandler)();
if (swaphandler) {
swaphandler = FALSE; pHandler = rgpHandler[handler]; }
} while (1);
popcontext = FALSE; if (macrolevel == 0) fPutFirstOp = FALSE; }
#if !defined XENIX286 && !defined FLATMODEL
# pragma check_stack-
#endif
/*** parse - parse line and dispatch
* * parse (); * * Entry * Exit * Returns * Calls */
VOID PASCAL CODESIZE parse () { static SHORT ret, i; static char *nextAtom;
startscan: opcref = REF_OTHER << 4 | REF_OTHER; listindex = 1; optyp = -1; /* Haven't looked up first token */
/* Scan 1st atom on line and check delimiter */
if (!getatom () && ISTERM(PEEKC())) { /* quick out for comment line */ listline (); return; }
if (naim.pszName[0] == '%' && naim.pszName[1] == 0) { /* expand all text macros */ *begatom = ' '; substituteTMs(); getatom(); }
parsedflag = labelflag = FALSE; /* Have not recognized line yet */
if (generate) switch (PEEKC ()) { case ':': /* Form: <name>: xxxxx */ /* name */
nextAtom = lbufp;
if (*naim.pszName == 0)
errorcSYN (); else {
/* create a temporary label of the form @@: */
if (fProcArgs > 0) {/* build stack frame for procs */ buildFrame(); return; }
if (naim.ucCount == 2 && *(SHORT *)naim.pszName == ('@'<<8 | '@')) {
tempText[1] = 'B'; definesym(tempText); symptr->attr |= M_NOCREF;
lbufp = &tempText[3]; getatom(); labelcreate (CSNEAR, CLABEL); symptr->symu.clabel.iProc = iProcCur;
pTextEnd = (char *)-1; *xxradixconvert((long)++tempLabel, &tempText[4]) = NULL;
tempText[1] = 'F'; definesym(tempText); symptr->attr |= M_NOCREF; } else {
/* define NEAR label */ labelcreate (CSNEAR, CLABEL);
if (lbufp[1] == ':')
nextAtom++;
else if (!errorcode) { /* don't add if redef */
symptr->symu.clabel.iProc = iProcCur; symptr->alpha = NULL;
/* addLocal needs takes a null-terminated list */ addLocal(symptr); } } }
/* get next token on line after label */
lbufp = nextAtom+1;
if (!getatom ()) goto Done;
break;
case '=': SKIPC (); assignvalue (); goto Done;
default: /* Form: <name> xxxxx
* Could have <name> <DIR2 directive> so * check 2nd atom */
secondDirect (); break; }
/* If PARSEDflag is off, then statement has not been recognized so
see if atom is a macro name, directive or opcode */
if (!parsedflag){
/* look up Macros & struc only when in true part of condition */
if (generate) {
xcreflag--; ret = symsrch(); xcreflag++;
if (ret)
switch (symptr->symkind) {
case EQU: if (symptr->symu.equ.equtyp == TEXTMACRO) {
#ifdef BCBOPT
goodlbufp = FALSE; #endif
/* cref reference to text macro symbol now */ /* as it will be overwritten by expandTM */ crefnew (REF); crefout ();
/* replaces text macro with text */
expandTM (symptr->symu.equ.equrec.txtmacro.equtext); goto startscan; } break;
case MACRO: macrocall (); return;
case STRUC: strucinit (); goto Done;
case REC: recordinit (); goto Done;
} }
if (! firstDirect() && generate) {
if (fProcArgs > 0){ /* build stack frame for procs */ buildFrame(); return; }
emitline();
if (opcodesearch ()) if (opctype < OPCODPARSERS) opcode ();
else if (X87type & cpu) { fltopcode (); } else error(E_EXP,iod);
else if (*naim.pszName != '\0') error (E_EXP,iod);
} }
/* When we get here, the statement has been parsed and all that is
* left to do is make sure that the line ends with ; or <cr>. If * we are currently under a FALSE conditional, don't bother to check * for proper line end since won't have scanned it. */ Done: if (generate) { if (!ISTERM (skipblanks())) errorc (E_ECL); /* Questionable syntax(bad line end)*/ #ifdef BCBOPT
} else { goodlbufp = FALSE; #endif
} listline (); }
/*** secondDirect - parse those instructions which require a label
* * secondDirect * * Entry * Exit * Returns * Calls */
VOID PASCAL CODESIZE secondDirect () { static char *oldlbufp; static char *saveBegatom; static char *saveEndatom;
optyp = 0; fndir (); /* sets to non zero if found */
if (generate && optyp == (char)0) {
saveBegatom = begatom; saveEndatom = endatom; oldlbufp = lbufp;
switchname (); getatom (); if (fndir2 ()) { /* Have recognized */ parsedflag = TRUE; /* Switch back to 1st atom and dispatch */ switchname (); labelflag = TRUE;
switch (optyp) { case TCATSTR: catstring (); break; case TENDP: procend (); break; case TENDS: /* End segment */ ptends (); break; case TEQU: equdefine (); break; case TGROUP: groupdefine (); break; case TINSTR: instring (); break; case TLABEL: /* <name> LABEL <type> Type is one of
NEAR, FAR | BYTE, WORD, DWORD, QWORD, TBYTE Also can be record or structure name in which case set type = length */
switchname (); getatom (); if (fnsize ()) if (varsize) { switchname (); /* Label in name */ labelcreate (varsize, CLABEL); symptr->symu.clabel.type = typeFet(varsize); } else errorc (E_TIL); else if (!symFet () || !(symptr->symkind == STRUC || symptr->symkind == REC)) errorc (E_UST); else { switchname (); labelcreate (symptr->symtype, CLABEL); symptr->symu.clabel.type = typeFet(varsize); } break; case TMACRO: macrodefine (); break; case TPROC: procdefine (); break; case TRECORD: recorddefine (); break; case TSEGMENT: segdefine (); break; case TSIZESTR: sizestring (); break; case TSTRUC: strucdefine (); break; case TSUBSTR: substring (); break; case TDB: case TDD: case TDQ: case TDT: case TDW: case TDF: datadefine (); break; } labelflag = FALSE; } else { /* Is not a legal 2nd atom directive, but could be
<strucname> or <recordname> */
if (symFetNoXref () && (symptr->symkind == STRUC || symptr->symkind == REC)) {
switchname (); /* Get 1st token back */
parsedflag = TRUE; labelflag = TRUE;
/* Atom is a skeleton name for
* RECORD or STRUC so have form: * <name> <skel> */
if (symptr->symkind == STRUC) strucinit (); else recordinit (); } else { begatom = saveBegatom; endatom = saveEndatom; lbufp = oldlbufp;
switchname (); /* must be directive or opcode in 1st atom, so get
back to that state be rescanning */ } } } }
/*** firstDirect - parse a first token directive
* * * Entry optyp maybe set, via pars2 * 0 - not a token * -1 - haven't looked up token yet * other - valid token # of dir * * Returns TRUE if it processed a directive */
SHORT PASCAL CODESIZE firstDirect () {
if (optyp == (char)0 || (optyp == ((char)-1) && !fndir ())) return(FALSE);
if (generate || (opkind & CONDBEG) || optyp == TCOMMENT || optyp == TFPO) {
switch (optyp) { case TASSUME: BACKC (); do { SKIPC (); assumeitem (); } while (PEEKC () == ','); break;
case TCOMMENT: comdir (); break; case TOUT: outdir (); break; case TELSE: elsedir (); break; case TEND: enddir (); break; case TENDIF: endifdir (); break; case TENDM: /* Block nesting */ errorc (E_BNE); break; case TERR: case TERR1: case TERR2: case TERRDIF: case TERRIDN: case TERRB: case TERRDEF: case TERRE: case TERRNZ: case TERRNB: case TERRNDEF: errdir (); break; case TEVEN: evendir (2); break; case TALIGN: evendir (0); break; case TEXITM: exitmdir (); break; case TEXTRN: BACKC (); do { SKIPC (); externitem (); } while (PEEKC() == ','); break; case TIF: case TIF1: case TIF2: case TIFDIF: case TIFIDN: case TIFB: case TIFDEF: case TIFE: case TIFNB: case TIFNDEF: conddir (); break; case TINCLUDE: includedir (); break; case TIRP: case TIRPC: irpxdir (); break; case TLOCAL: if (langType) defineLocals(); break; case TNAME: namedir (); break; case TORG: orgdir (); break; case TPAGE: setpage (); break; case TPUBLIC: BACKC (); do { SKIPC (); publicitem (); } while (PEEKC () == ','); break; case TPURGE: BACKC (); do { SKIPC (); purgemacro (); } while (PEEKC () == ','); break; case TREPT: reptdir (); break; case TCREF: xcreflag = TRUE; break; case TLALL: expandflag = LIST; break; case TLFCOND: condflag = TRUE; break; case TLIST: listflag = TRUE; break; case TRADIX: radixdir (); break; case TSALL: expandflag = SUPPRESS; break; case TSFCOND: condflag = FALSE; break; case TSUBTTL: storetitle (subttlbuf); break; case TTFCOND: if (pass2) { condflag = (origcond? FALSE: TRUE); origcond = condflag; } break; case TTITLE: if (titleflag) errorc (E_RSY); else storetitle (titlebuf); titleflag = TRUE; break; case TXALL: expandflag = LISTGEN; break; case TXCREF: if (ISTERM (PEEKC ())) xcreflag = loption; else { BACKC (); do { SKIPC (); xcrefitem (); } while (PEEKC () == ','); } break; case TXLIST: listflag = FALSE; break; case TDB: case TDD: case TDQ: case TDT: case TDW: case TDF: datadefine (); break;
case T8087: X87type = PX87; goto setatcpu;
case T287: X87type = PX87|PX287; goto setX;
case T387: X87type = PX87|PX287|PX387; setX: if (X87type > cputype) errorc(E_TIL);
goto setatcpu;
case T8086:
cputype = P86; X87type = PX87; goto setcpudef;
case T186:
cputype = P186; X87type = PX87; goto setcpudef;
case T286C:
cputype = P186|P286; X87type = PX87|PX287; goto setcpudef;
case T286P:
cputype = P186|P286|PROT; X87type = PX87|PX287; goto setcpudef;
#ifdef V386
case T386C:
init386(0);
cputype = P186|P286|P386; goto set386;
case T386P: init386(1);
cputype = P186|P286|P386|PROT; set386: X87type = PX87|PX287|PX387; fltemulate = FALSE; fArth32 |= TRUE; #endif
setcpudef: #ifdef V386
wordszdefault = (char)wordsize = (cputype&P386)? 4: 2; defwordsize();
if (pcsegment) if (pcsegment->symu.segmnt.use32 > wordsize) errorc(E_CPU); else wordsize = pcsegment->symu.segmnt.use32; #endif
setatcpu: coprocproc = (X87type << 8) + (cputype | 1); pTextEnd = (UCHAR *) -1; *xxradixconvert((OFFSET)coprocproc, cputext + 5) = 0; definesym(cputext);
break;
case TSEQ: segalpha = FALSE; break; case TALPHA: segalpha = TRUE; break;
case TDOSSEG: fDosSeg++; break;
case TMODEL: model(); break;
case TMSEG: openSeg(); break;
case TMSTACK: createStack(); break;
case TINCLIB: includeLib(); break;
case TFPO: fpoRecord(); break;
case TCOMM: BACKC (); do { SKIPC (); commDefine ();
} while (PEEKC() == ','); break; } } return(TRUE); }
/*** setpage - set page length and width
* * setpage (); * * Entry * Exit * Returns * Calls */
VOID PASCAL CODESIZE setpage () { register char cc; SHORT i;
if (ISTERM (cc = PEEKC ())) { /* position to bottom of page if no operands */ if (listflag) pageline = pagelength - 1; } else if (cc == '+') { if (ISBLANK (NEXTC ())) skipblanks (); if (listflag) newpage (); } else { if (cc != ',') { /* set page length */ if ((i = (SHORT)exprconst ()) > 9 && i < 256) pagelength = i; else errorc (E_VOR); if (pageminor + pagemajor == 1) /* Adjust so page length right */ pageline = (pagelength - NUMLIN) + pageline; } if (PEEKC () == ',') { SKIPC (); /* set page width */ if ((i = (SHORT)exprconst ()) > LINEMAX || i < 60) errorc (E_VOR); else pagewidth = i; } } }
/*** ptends - process ends statement
* * ptends (); * * Entry * Exit * Returns * Calls */
VOID PASCAL CODESIZE ptends () { if (!symFet() || !pcsegment) errorc (E_BNE);
/* Make sure segname is correct */ else if (pcsegment != symptr) errorc (E_BNE); else { if (symptr->symkind != SEGMENT) errorc (E_BNE); else { if (pcmax <= pcoffset) symptr->symu.segmnt.seglen = pcoffset; else symptr->symu.segmnt.seglen = pcmax; /* S a v e s e g me n t P C */ symptr->offset = pcoffset;
if (pcsegment->symu.segmnt.use32 == 2) {
if (pcoffset > 0x10000) errorc(E_286 & ~E_WARN1);
if (pcsegment->symu.segmnt.hascode && pcsegment->symu.segmnt.seglen > 0xFFDC) errorc( E_286 ); }
pcdisplay (); /* must do before lose pcsegment */ pcsegment = symptr->symu.segmnt.lastseg; #ifdef V386
if (pcsegment) wordsize = pcsegment->symu.segmnt.use32; else wordsize = wordszdefault; #endif
symptr->symu.segmnt.lastseg = NULL; /* Replace later pcsegment <> NULL block with following
block. pcmax must be reset on leaving seg. */ if (pcsegment) { /* Restore PC and max offset so far in
segment */ pcoffset = (*pcsegment).offset; pcmax = pcsegment->symu.segmnt.seglen;
strnfcpy(&segName[8], pcsegment->nampnt->id); } else { /* If no seg, PC and max are 0 */ pcoffset = 0; pcmax = 0; segName[8] = NULL; } } definesym(segName); } defwordsize(); }
|