You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1011 lines
30 KiB
1011 lines
30 KiB
/* 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();
|
|
}
|