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.
2484 lines
54 KiB
2484 lines
54 KiB
/* asmdir.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 <stdlib.h>
|
|
#include "asm86.h"
|
|
#include "asmfcn.h"
|
|
#include <fcntl.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
|
|
#ifndef XENIX286
|
|
#include <share.h>
|
|
#include <io.h>
|
|
#endif
|
|
|
|
#include "asmctype.h"
|
|
#include "asmindex.h"
|
|
#include "asmmsg.h"
|
|
|
|
extern PFPOSTRUCT pFpoHead;
|
|
extern PFPOSTRUCT pFpoTail;
|
|
extern unsigned long numFpoRecords;
|
|
|
|
SHORT CODESIZE fetLang(void);
|
|
int PASCAL CODESIZE trypathname PARMS((char *));
|
|
int PASCAL CODESIZE openincfile PARMS(( void ));
|
|
VOID PASCAL CODESIZE creatPubName (void);
|
|
extern char *siznm[];
|
|
|
|
/*** setsymbol - set attribute in symbol
|
|
*
|
|
* setsymbol (bit);
|
|
*
|
|
* Entry
|
|
* Exit
|
|
* Returns
|
|
* Calls
|
|
*/
|
|
|
|
|
|
VOID
|
|
PASCAL
|
|
CODESIZE
|
|
setsymbol (
|
|
UCHAR bit
|
|
)
|
|
{
|
|
/* Scan symbol name */
|
|
|
|
if (getatom ()) {
|
|
if (!symsrch ())
|
|
errorn (E_SND);
|
|
|
|
symptr->attr |= bit;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** publicitem - scan symbol and make PUBLIC
|
|
*
|
|
* publicitem ();
|
|
*
|
|
* Entry naim = symbol name
|
|
* Exit Global attribute set in symbol entry
|
|
* Returns none
|
|
* Calls error, scanatom, symsearch
|
|
*/
|
|
|
|
|
|
VOID
|
|
PASCAL
|
|
CODESIZE
|
|
publicitem()
|
|
{
|
|
static char newAttr;
|
|
|
|
if (getatom ()) {
|
|
|
|
newAttr = NULL;
|
|
if (fetLang() == CLANG)
|
|
newAttr = M_CDECL;
|
|
|
|
if (!symsrch ()) {
|
|
|
|
/* define forward refernced name, so global attribute
|
|
* is available on the end of pass 1 */
|
|
|
|
symcreate ( (UCHAR)(M_GLOBAL | newAttr), (UCHAR)PROC);
|
|
} else {
|
|
symptr->attr |= newAttr;
|
|
|
|
/* public is legal for an alias if target ok */
|
|
if (symptr->symkind == EQU &&
|
|
symptr->symu.equ.equtyp == ALIAS)
|
|
if (! (symptr = chasealias (symptr))) {
|
|
errorc(E_TUL);
|
|
return;
|
|
}
|
|
|
|
if (pass2) { /* catch forward reference symbol errors */
|
|
|
|
if (! (symptr->attr & M_GLOBAL))
|
|
errorn (E_IFR);
|
|
|
|
else if ((symptr->attr&~M_CDECL) == M_GLOBAL ||
|
|
!(symptr->attr & M_DEFINED))
|
|
errorn (E_SND);
|
|
|
|
}
|
|
|
|
switch (symptr->symkind) {
|
|
case PROC:
|
|
case DVAR:
|
|
case CLABEL:
|
|
if (M_XTERN & symptr->attr)
|
|
errorc (E_SAE);
|
|
break;
|
|
case EQU:
|
|
if (symptr->symu.equ.equtyp != EXPR)
|
|
errorc (E_TUL);
|
|
break;
|
|
default:
|
|
errorc (E_TUL);
|
|
}
|
|
}
|
|
creatPubName();
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
PASCAL
|
|
CODESIZE
|
|
creatPubName ()
|
|
{
|
|
symptr->attr |= M_GLOBAL;
|
|
|
|
if (caseflag == CASEX && symptr->lcnamp == NULL)
|
|
symptr->lcnamp =
|
|
#ifdef M8086
|
|
creatlname (naim.pszLowerCase);
|
|
#else
|
|
createname (naim.pszLowerCase);
|
|
#endif
|
|
}
|
|
|
|
|
|
/*** xcrefitem - scan symbol and xcref it
|
|
*
|
|
* xcrefitem ();
|
|
*
|
|
* Entry
|
|
* Exit
|
|
* Returns
|
|
* Calls
|
|
*/
|
|
|
|
|
|
VOID
|
|
PASCAL
|
|
CODESIZE
|
|
xcrefitem ()
|
|
{
|
|
if (pass2 && !loption) {
|
|
setsymbol (M_NOCREF);
|
|
creftype = CREFEND;
|
|
} else
|
|
getatom ();
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** externflag -
|
|
*
|
|
* routine ();
|
|
*
|
|
* Entry
|
|
* Exit
|
|
* Returns
|
|
* Calls
|
|
*/
|
|
|
|
|
|
VOID
|
|
PASCAL
|
|
CODESIZE
|
|
externflag (
|
|
register UCHAR kind,
|
|
register UCHAR new
|
|
)
|
|
{
|
|
switchname ();
|
|
/* Make name be extern name */
|
|
if (!new) {
|
|
/* Create symbol */
|
|
symcreate (M_XTERN | M_DEFINED,
|
|
(UCHAR)((kind == CLABEL)? DVAR: kind));
|
|
|
|
symptr->symkind = kind;
|
|
|
|
if (caseflag == CASEX)
|
|
symptr->lcnamp =
|
|
#ifdef M8086
|
|
creatlname (naim.pszLowerCase);
|
|
#else
|
|
createname (naim.pszLowerCase);
|
|
#endif /* M8086 */
|
|
symptr->symtype = varsize;
|
|
symptr->length = 1;
|
|
if (kind == EQU)
|
|
/* expr type EQU is constant */
|
|
symptr->symu.equ.equtyp = EXPR;
|
|
else
|
|
symptr->symsegptr = pcsegment;
|
|
|
|
if (pass2)
|
|
emitextern (symptr);
|
|
}
|
|
checkRes();
|
|
crefdef ();
|
|
if (! (M_XTERN & symptr->attr))
|
|
errorc (E_ALD);
|
|
else {
|
|
if (kind != symptr->symkind || symptr->symtype != varsize ||
|
|
(symptr->length != 1 && kind != EQU) &&
|
|
(symptr->symsegptr != pcsegment &&
|
|
!(fSimpleSeg && varsize == CSFAR)))
|
|
|
|
errorn (E_SDK);
|
|
else {
|
|
symptr->attr |= M_XTERN | M_BACKREF;
|
|
|
|
if (fSimpleSeg && varsize == CSFAR) {
|
|
symptr->symsegptr = NULL;
|
|
} else if (varsize == CSNEAR ||
|
|
(varsize == CSFAR && pcsegment))
|
|
|
|
symptr->symu.clabel.csassume = regsegment[CSSEG];
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*** externitem -
|
|
*
|
|
* externitem ();
|
|
*
|
|
* Entry
|
|
* Exit
|
|
* Returns
|
|
* Calls
|
|
*/
|
|
|
|
VOID
|
|
PASCAL
|
|
CODESIZE
|
|
externitem ()
|
|
{
|
|
register char new;
|
|
char newAttr;
|
|
|
|
/* Get name of external */
|
|
|
|
if (getatom ()) {
|
|
|
|
newAttr = NULL;
|
|
if (fetLang() == CLANG)
|
|
newAttr = M_CDECL;
|
|
|
|
new = symFetNoXref ();
|
|
switchname (); /* Save name of external */
|
|
|
|
if (NEXTC () != ':')
|
|
errorc (E_SYN);
|
|
|
|
else {
|
|
/* Scan name of extern type */
|
|
getatom ();
|
|
|
|
if (tokenIS("abs")) {
|
|
|
|
equsel = EXPR;
|
|
varsize = 0;
|
|
externflag (EQU, new);
|
|
} else if (!fnsize ())
|
|
errorc (E_UST);
|
|
|
|
else {
|
|
if (varsize >= CSFAR) {
|
|
/* NEAR | FAR */
|
|
externflag (CLABEL, new);
|
|
}
|
|
|
|
else /* data reference */
|
|
|
|
externflag (DVAR, new);
|
|
|
|
}
|
|
symptr->attr |= newAttr;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** segcreate - create and initialize segment
|
|
*
|
|
* segcreate (makeseg);
|
|
*
|
|
* Entry makeseg = TRUE if segement is to be make
|
|
* Exit
|
|
* Returns
|
|
* Calls
|
|
*/
|
|
|
|
|
|
VOID
|
|
PASCAL
|
|
CODESIZE
|
|
segcreate (
|
|
register UCHAR makeseg
|
|
)
|
|
{
|
|
|
|
if (pass2) /* Segment must be defined */
|
|
errorn (E_PS1);
|
|
|
|
if (makeseg)
|
|
symcreate (0, SEGMENT);
|
|
else
|
|
symptr->symkind = SEGMENT;
|
|
|
|
/* Initialize segment data */
|
|
symptr->symu.segmnt.align = -1;
|
|
symptr->symu.segmnt.use32 = -1;
|
|
symptr->symu.segmnt.combine = 7;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** addglist - add segment to group list
|
|
*
|
|
* addglist ();
|
|
*
|
|
* Entry
|
|
* Exit
|
|
* Returns
|
|
* Calls
|
|
*/
|
|
|
|
|
|
VOID
|
|
PASCAL
|
|
CODESIZE
|
|
addglist ()
|
|
{
|
|
register SYMBOL FARSYM *p, FARSYM *pSY;
|
|
|
|
p = symptr;
|
|
|
|
if (pass2)
|
|
if (!(M_DEFINED & p->attr))
|
|
errorn (E_PS1);
|
|
|
|
/* Can get segment in 2 group lists unless check
|
|
* symptr->grouptr == curgroup */
|
|
|
|
if (p->symu.segmnt.grouptr) {
|
|
if (p->symu.segmnt.grouptr != curgroup)
|
|
/* Trying to put in 2 groups */
|
|
errorc (E_SPC);
|
|
return;
|
|
}
|
|
p->symu.segmnt.grouptr = curgroup;
|
|
pSY = curgroup->symu.grupe.segptr;
|
|
|
|
if (!pSY)
|
|
curgroup->symu.grupe.segptr = p;
|
|
|
|
else {
|
|
|
|
/* scan the list of segments on the group */
|
|
|
|
do {
|
|
if (pSY == p) /* already on list */
|
|
return;
|
|
|
|
} while (pSY->symu.segmnt.nxtseg &&
|
|
(pSY = pSY->symu.segmnt.nxtseg));
|
|
|
|
/* Link into list */
|
|
pSY->symu.segmnt.nxtseg = p;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** groupitem -
|
|
*
|
|
* routine ();
|
|
*
|
|
* Entry
|
|
* Exit
|
|
* Returns
|
|
* Calls
|
|
*/
|
|
|
|
|
|
VOID
|
|
PASCAL
|
|
CODESIZE
|
|
groupitem ()
|
|
{
|
|
|
|
if (!getatom ())
|
|
error (E_EXP,"segment name");
|
|
|
|
else if (!fnoper ()) {
|
|
|
|
/* Have a segment name */
|
|
|
|
if (!symFet())
|
|
/* Forward segment, make it */
|
|
segcreate (TRUE);
|
|
|
|
/* If not segment, could be class so make undef */
|
|
if (symptr->symkind != SEGMENT)
|
|
|
|
/* If a class, consider undef instead of wrong kind */
|
|
errorn ((USHORT)((symptr->symkind == CLASS) && !pass2 ?
|
|
E_IFR : E_SDK));
|
|
|
|
else if (symptr->attr & M_DEFINED || !pass2) {
|
|
if (curgroup)
|
|
addglist ();
|
|
} else
|
|
errorn (E_PS1);
|
|
} else { /* Have error or SEG <sym> */
|
|
if (opertype != OPSEG)
|
|
/* Symbol can't be reserved */
|
|
errorn (E_RES);
|
|
else {
|
|
/* Have SEG <var> | <label> */
|
|
getatom ();
|
|
if (*naim.pszName == 0)
|
|
error (E_EXP,"variable or label");
|
|
|
|
else if (!symFet())
|
|
/* Forward reference bad */
|
|
errorc (E_IFR);
|
|
|
|
else if (1 << symptr->symkind &
|
|
(M_DVAR | M_CLABEL | M_PROC)) {
|
|
/* Segment of variable */
|
|
|
|
symptr = symptr->symsegptr;
|
|
if (!symptr)
|
|
/* Must have segment */
|
|
errorc (E_OSG);
|
|
else
|
|
addglist ();
|
|
} else
|
|
/* Wrong type */
|
|
errorc (E_TUL);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** groupdefine - define segments that form a group
|
|
*
|
|
* routine ();
|
|
*
|
|
* Entry
|
|
* Exit
|
|
* Returns
|
|
* Calls
|
|
*/
|
|
|
|
|
|
VOID
|
|
PASCAL
|
|
CODESIZE
|
|
groupdefine ()
|
|
{
|
|
if (symFet()) { /* Symbol exists */
|
|
checkRes();
|
|
if (symptr->symkind != GROUP)
|
|
/* Should have been group */
|
|
errorc (E_NGR);
|
|
|
|
symptr->attr |= M_BACKREF;
|
|
} else if (pass2)
|
|
/* Must be seen 1st on pass 1 */
|
|
errorn (E_PS1);
|
|
else {
|
|
/* Create group name */
|
|
symcreate (M_DEFINED, GROUP);
|
|
}
|
|
|
|
/* CURgroup is used by GROUPitem to know which group segment
|
|
name should be added to. If it is NIL, means that either
|
|
it is pass 2 so list already made or there was an error in
|
|
GROUP name */
|
|
|
|
curgroup = NULL;
|
|
|
|
if (! pass2) { /* Don't make list if pass 2 */
|
|
|
|
symptr->attr |= M_BACKREF | M_DEFINED;
|
|
|
|
if (symptr->symkind == GROUP)
|
|
curgroup = symptr;
|
|
}
|
|
/* Handle segment list */
|
|
BACKC ();
|
|
do {
|
|
SKIPC ();
|
|
groupitem ();
|
|
} while (PEEKC () == ',');
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** setsegment -
|
|
*
|
|
* routine ();
|
|
*
|
|
* Entry
|
|
* Exit
|
|
* Returns
|
|
* Calls
|
|
*/
|
|
|
|
|
|
VOID
|
|
PASCAL
|
|
CODESIZE
|
|
setsegment ()
|
|
{
|
|
if (pass2 && !(M_DEFINED & symptr->attr))
|
|
/* undef */
|
|
errorn (E_SND);
|
|
else
|
|
regsegment[lastsegptr->offset] = symptr;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** assumeitem -
|
|
*
|
|
* routine ();
|
|
*
|
|
* Entry
|
|
* Exit
|
|
* Returns
|
|
* Calls
|
|
* Note Form of ASSUME item is:
|
|
* <segreg> : <group> | <segment> | SEG <var> | NOTHING
|
|
* Will set XXsegment to segment or group pointer. NOTHING
|
|
* will set to NIL
|
|
*/
|
|
|
|
|
|
VOID
|
|
PASCAL
|
|
CODESIZE
|
|
assumeitem ()
|
|
{
|
|
register SYMBOL FARSYM *p;
|
|
register short j;
|
|
// int segIndex;
|
|
|
|
/* Scan segment name */
|
|
getatom ();
|
|
if (PEEKC() != ':') {
|
|
/* NOTHING or error */
|
|
if (fnoper ())
|
|
|
|
if (opertype == OPNOTHING) { /* No segments assumed*/
|
|
|
|
memset(regsegment, 0, sizeof(regsegment));
|
|
} else
|
|
/* Must have colon */
|
|
error (E_EXP,"colon");
|
|
else
|
|
/* Must have colon */
|
|
error (E_EXP,"colon");
|
|
} else if (!symsearch ()) /* get seg register - Must be defined */
|
|
errorn (E_SND);
|
|
else {
|
|
lastsegptr = p = symptr; /* At least have defined */
|
|
|
|
if (p->symkind != REGISTER ||
|
|
p->symu.regsym.regtype != SEGREG)
|
|
errorn (E_MBR);
|
|
|
|
else { /* Have segment reg so go on */
|
|
/* Save ptr to segment */
|
|
SKIPC ();
|
|
getatom ();
|
|
if (*naim.pszName == 0)
|
|
error (E_EXP,"segment, group, or NOTHING");
|
|
else
|
|
if (!fnoper ()) {
|
|
|
|
/* Must be segment or group */
|
|
|
|
if (!symFet ())
|
|
segcreate (TRUE); /* Make if not found */
|
|
|
|
p = symptr;
|
|
if (p->symkind == SEGMENT ||
|
|
p->symkind == GROUP) {
|
|
|
|
setsegment ();
|
|
#ifndef FEATURE
|
|
if (tokenIS("flat") && (cputype&P386)) {
|
|
pFlatGroup = symptr;
|
|
pFlatGroup->symkind = GROUP;
|
|
pFlatGroup->attr |= M_DEFINED | M_BACKREF;
|
|
pFlatGroup->symu.grupe.segptr = NULL;
|
|
}
|
|
#endif
|
|
} else
|
|
errorc (E_MSG);
|
|
} else {
|
|
/* Have NOTHING or SEG */
|
|
if (opertype == OPNOTHING) {
|
|
regsegment[lastsegptr->offset] = NULL;
|
|
} else if (opertype == OPSEG) {
|
|
getatom ();
|
|
if (!symFet ())
|
|
/* Must be defined on pass 1 */
|
|
errorn (E_PS1);
|
|
else {
|
|
p = symptr;
|
|
if (!(M_DEFINED & p->attr))
|
|
errorn (E_PS1);
|
|
else if (1 << p->symkind &
|
|
(M_CLABEL | M_PROC | M_DVAR)) {
|
|
if (!(M_XTERN & p->attr))
|
|
symptr = symptr->symsegptr;
|
|
p = symptr;
|
|
setsegment ();
|
|
} else
|
|
errorc (E_TUL);
|
|
}
|
|
} else
|
|
errorn (E_RES);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** evendir - process <even> directive
|
|
*
|
|
* routine ();
|
|
*
|
|
* Entry
|
|
* Exit
|
|
* Returns
|
|
* Calls
|
|
*/
|
|
|
|
|
|
VOID
|
|
PASCAL
|
|
CODESIZE
|
|
evendir (
|
|
SHORT arg
|
|
)
|
|
{
|
|
register SHORT size;
|
|
|
|
if (arg)
|
|
size = arg;
|
|
else
|
|
size = (SHORT)exprconst ();
|
|
|
|
if ((size & (size - 1)) != 0 || !size)
|
|
errorc(E_AP2);
|
|
|
|
else if (!pcsegment)
|
|
/* Not in segment */
|
|
errorc (E_MSB);
|
|
|
|
else if (pcsegment->symu.segmnt.align == 1)
|
|
/* Byte aligned */
|
|
errorc (E_NEB);
|
|
|
|
else {
|
|
if (!((USHORT) pcoffset % size))
|
|
return;
|
|
|
|
size = size - (USHORT) pcoffset % size;
|
|
|
|
while (size--)
|
|
|
|
if (!pcsegment->symu.segmnt.hascode)
|
|
|
|
emitopcode(0);
|
|
else
|
|
if (size > 0) {
|
|
size--;
|
|
emitopcode(0x87); /* two byte form is faster */
|
|
emitopcode(0xDB);
|
|
} else
|
|
emitopcode(0x90);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** namedir - process <name> directive
|
|
*
|
|
* routine ();
|
|
*
|
|
* Entry
|
|
* Exit
|
|
* Returns
|
|
* Calls
|
|
*/
|
|
|
|
|
|
VOID
|
|
PASCAL
|
|
CODESIZE
|
|
namedir ()
|
|
{
|
|
getatom ();
|
|
if (*naim.pszName == 0)
|
|
error (E_EXP,"module name");
|
|
else if (modulename)
|
|
/* Already have one */
|
|
errorc (E_RSY);
|
|
else
|
|
modulename = createname (naim.pszName);
|
|
}
|
|
|
|
/*** includeLib - process include lib directive
|
|
*
|
|
* Format : includeLib token
|
|
*/
|
|
|
|
|
|
VOID
|
|
PASCAL
|
|
CODESIZE
|
|
includeLib()
|
|
{
|
|
char *pFirst;
|
|
TEXTSTR FAR *bodyline, FAR *ptr;
|
|
register USHORT siz;
|
|
|
|
pFirst = lbufp;
|
|
|
|
while (!ISTERM (PEEKC()) && !ISBLANK (PEEKC()))
|
|
SKIPC();
|
|
|
|
siz = (USHORT)(lbufp - pFirst);
|
|
|
|
if (siz == 0 || siz > 126)
|
|
errorc(E_IIS);
|
|
|
|
if (pass2)
|
|
return;
|
|
|
|
bodyline = (TEXTSTR FAR *)talloc ((USHORT)(sizeof (TEXTSTR) + siz));
|
|
|
|
bodyline->strnext = (TEXTSTR FAR *)NULL;
|
|
bodyline->text[siz] = NULL;
|
|
|
|
fMemcpy (bodyline->text, pFirst, siz);
|
|
|
|
if (!(ptr = pLib))
|
|
pLib = bodyline;
|
|
else {
|
|
while (ptr->strnext)
|
|
ptr = ptr->strnext;
|
|
|
|
ptr->strnext = bodyline;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*** orgdir - process <org> directive
|
|
*
|
|
* routine ();
|
|
*
|
|
* Entry
|
|
* Exit
|
|
* Returns
|
|
* Calls
|
|
*/
|
|
|
|
|
|
VOID
|
|
PASCAL
|
|
CODESIZE
|
|
orgdir ()
|
|
{
|
|
register DSCREC *dsc;
|
|
|
|
dsc = expreval (&nilseg);
|
|
if (dsc->dsckind.opnd.dflag == FORREF)
|
|
/* Must be known */
|
|
errorc (E_PS1);
|
|
/* Can get <code> set and segment NIL, fix */
|
|
else if (dsc->dsckind.opnd.dsegment) {/* code var */
|
|
|
|
if (!isdirect(&(dsc->dsckind.opnd)) &&
|
|
dsc->dsckind.opnd.mode != 4)
|
|
|
|
/* Not direct */
|
|
errorc (E_IOT);
|
|
if (pcsegment != dsc->dsckind.opnd.dsegment)
|
|
/* Different segment */
|
|
errorc (E_NIP);
|
|
} else { /* Should be const */
|
|
/* Must be constant */
|
|
forceimmed (dsc);
|
|
if (dsc->dsckind.opnd.dsign)
|
|
/* And plus */
|
|
errorc (E_VOR);
|
|
}
|
|
if (dsc->dsckind.opnd.doffset < pcoffset)
|
|
if (pcmax < pcoffset)
|
|
/* If moving down, save */
|
|
pcmax = pcoffset;
|
|
/* Set new PC */
|
|
pcoffset = dsc->dsckind.opnd.doffset;
|
|
/* Display new PC */
|
|
pcdisplay ();
|
|
dfree ((char *)dsc );
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** purgemacro - process <purge> directive
|
|
*
|
|
* purgemacro ();
|
|
*
|
|
* Entry
|
|
* Exit
|
|
* Returns
|
|
* Calls
|
|
*/
|
|
|
|
|
|
VOID
|
|
PASCAL
|
|
CODESIZE
|
|
purgemacro ()
|
|
{
|
|
getatom ();
|
|
if (!symFet ())
|
|
errorn (E_SND);
|
|
|
|
else if (symptr->symkind != MACRO)
|
|
symptr->attr &= ~(M_BACKREF);
|
|
else {
|
|
if (symptr->symu.rsmsym.rsmtype.rsmmac.active)
|
|
symptr->symu.rsmsym.rsmtype.rsmmac.delete = TRUE;
|
|
else
|
|
deletemacro (symptr);
|
|
}
|
|
}
|
|
|
|
|
|
/*** deletemacro - delete macro body
|
|
*
|
|
* deletemacro (p);
|
|
*
|
|
* Entry p = pointer to macro symbol entry
|
|
* Exit macro body deleted
|
|
* Returns none
|
|
* Calls
|
|
*/
|
|
|
|
|
|
VOID
|
|
PASCAL
|
|
CODESIZE
|
|
deletemacro (
|
|
SYMBOL FARSYM *p
|
|
)
|
|
{
|
|
listfree (p->symu.rsmsym.rsmtype.rsmmac.macrotext);
|
|
p->symu.rsmsym.rsmtype.rsmmac.macrotext = NULL;
|
|
p->symu.rsmsym.rsmtype.rsmmac.active = 0;
|
|
p->symu.rsmsym.rsmtype.rsmmac.delete = FALSE;
|
|
}
|
|
|
|
|
|
|
|
/*** radixdir - process <radix> directive
|
|
*
|
|
* radixdir ();
|
|
*
|
|
* Entry
|
|
* Exit
|
|
* Returns
|
|
* Calls
|
|
*/
|
|
|
|
|
|
VOID
|
|
PASCAL
|
|
CODESIZE
|
|
radixdir ()
|
|
{
|
|
register USHORT rdx;
|
|
|
|
/* Force decimal radix */
|
|
radixescape = TRUE;
|
|
/* Get wanted radix */
|
|
rdx = (USHORT)exprconst ();
|
|
if (2 <= rdx && rdx <= 16)
|
|
radix = (char)rdx;
|
|
else
|
|
errorc (E_VOR);
|
|
radixescape = FALSE;
|
|
/* Convert radix to ascii and display */
|
|
offsetAscii ((OFFSET) radix);
|
|
copyascii ();
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** checkline - check line for delimiter
|
|
*
|
|
* flag = checkline (cc);
|
|
*
|
|
* Entry cc = chearacter to check line for
|
|
* Exit none
|
|
* Returns TRUE if cc matched in line
|
|
* FALSE if cc not matched in line
|
|
* Calls none
|
|
*/
|
|
|
|
|
|
UCHAR
|
|
PASCAL
|
|
CODESIZE
|
|
checkline (
|
|
register UCHAR cc
|
|
)
|
|
{
|
|
register UCHAR nc;
|
|
|
|
while (nc = NEXTC())
|
|
if (nc == cc)
|
|
return (TRUE);
|
|
BACKC ();
|
|
return (FALSE);
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** comment - copy characters to end of comment
|
|
*
|
|
* commentbuild ();
|
|
*
|
|
* Entry
|
|
* Exit
|
|
* Returns
|
|
* Calls
|
|
*/
|
|
|
|
|
|
VOID
|
|
PASCAL
|
|
CODESIZE
|
|
commentbuild ()
|
|
{
|
|
if (checkline ((char)delim)) {
|
|
handler = HPARSE;
|
|
swaphandler = TRUE;
|
|
}
|
|
|
|
if (!lsting) {
|
|
linebuffer[0] = '\0';
|
|
linelength = 0;
|
|
lbufp = linebuffer;
|
|
}
|
|
|
|
listline ();
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** comdir - process <comment> directive
|
|
*
|
|
* comdir ();
|
|
*
|
|
* Entry
|
|
* Exit
|
|
* Returns
|
|
* Calls
|
|
*/
|
|
|
|
|
|
VOID
|
|
PASCAL
|
|
CODESIZE
|
|
comdir ()
|
|
{
|
|
if (!PEEKC ())
|
|
error (E_EXP,"comment delimiter");
|
|
else {
|
|
/* Save delim char */
|
|
if (!checkline ((char)(delim = NEXTC ()))) {
|
|
/* Delim is not on same line */
|
|
swaphandler = TRUE;
|
|
handler = HCOMMENT;
|
|
}
|
|
}
|
|
if (!lsting) {
|
|
linebuffer[0] = '\0';
|
|
linelength = 0;
|
|
lbufp = linebuffer;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** outdir - display remainder of line to console
|
|
*
|
|
* outdir ();
|
|
*
|
|
* Entry
|
|
* Exit
|
|
* Returns
|
|
* Calls
|
|
*/
|
|
|
|
|
|
VOID
|
|
PASCAL
|
|
CODESIZE
|
|
outdir ()
|
|
{
|
|
if (!listquiet)
|
|
fprintf (stdout, "%s\n", lbufp);
|
|
lbufp = lbuf + strlen (lbuf);
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** enddir - process <end> directive
|
|
*
|
|
* enddir ();
|
|
*
|
|
* Entry
|
|
* Exit
|
|
* Returns
|
|
* Calls
|
|
*/
|
|
|
|
|
|
VOID
|
|
PASCAL
|
|
CODESIZE
|
|
enddir ()
|
|
{
|
|
if (!ISTERM (PEEKC ())) {
|
|
/* Have a start addr */
|
|
startaddr = expreval (&nilseg);
|
|
if (!(M_CODE & startaddr->dsckind.opnd.dtype))
|
|
errorc (E_ASC);
|
|
}
|
|
|
|
#ifdef BCBOPT
|
|
if (fNotStored)
|
|
storeline();
|
|
#endif
|
|
|
|
if (fSimpleSeg && pcsegment)
|
|
endCurSeg();
|
|
|
|
listline();
|
|
longjmp(forceContext, 1);
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** exitmdir - process <exitm> directive
|
|
*
|
|
* exitmdir ();
|
|
*
|
|
* Entry
|
|
* Exit
|
|
* Returns
|
|
* Calls
|
|
*/
|
|
|
|
|
|
VOID
|
|
PASCAL
|
|
CODESIZE
|
|
exitmdir ()
|
|
{
|
|
if (macrolevel == 0)
|
|
/* Must be in macro */
|
|
errorc (E_NMC);
|
|
else
|
|
/* set ExitBody since need to see conditionals */
|
|
exitbody = TRUE;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** trypathname - try to open a file in a directory
|
|
*
|
|
* trypathname (szPath);
|
|
*
|
|
* Entry lbufp = pointer to include file name
|
|
* szPath = directory to search in
|
|
* Exit Include file opened if found.
|
|
* Fully qualified name in "save"
|
|
* Returns file handle of file, or -1 if not opened
|
|
* special handle of -2 means FCB has been allocated
|
|
* Note If include file name does not begin with path separator
|
|
* character, the path separator is appended to include path.
|
|
*/
|
|
|
|
int
|
|
PASCAL
|
|
CODESIZE
|
|
trypathname (
|
|
char * szPath
|
|
)
|
|
{
|
|
char cc;
|
|
int fh;
|
|
char *p = save;
|
|
char *pe = save + LINEMAX - 2;
|
|
char *ic;
|
|
register FCB * pFCBT;
|
|
|
|
ic = szPath;
|
|
|
|
if (*ic) {
|
|
|
|
while (*ic && p < pe)
|
|
*p++ = *ic++;
|
|
|
|
if ((*(p-1) != PSEP) && (*(p-1) != ':'))
|
|
/* include path separator if not in file name */
|
|
*p++ = PSEP;
|
|
}
|
|
|
|
for (ic = lbufp; !ISTERM (cc = *ic++) && !ISBLANK (cc) && p < pe ; )
|
|
|
|
if (cc == ALTPSEP)
|
|
*p++ = PSEP;
|
|
else
|
|
*p++ = cc;
|
|
|
|
#ifdef MSDOS
|
|
if (*(p-1) == ':') /* kill 'con:' */
|
|
p--;
|
|
#endif
|
|
*p = NULL;
|
|
|
|
/* look for an existing include file on pass 2 with a fully qualified
|
|
* name */
|
|
|
|
#ifdef BCBOPT
|
|
if (pass2) {
|
|
for (pFCBT = pFCBInc->pFCBNext; pFCBT; pFCBT = pFCBT->pFCBNext) {
|
|
|
|
if (!memcmp (save, pFCBT->fname, strlen(pFCBT->fname)+1)) {
|
|
pFCBT->pbufCur = NULL;
|
|
|
|
if (pFCBT->pBCBCur = pFCBT->pBCBFirst) {
|
|
|
|
pFCBT->pBCBCur->fInUse = 1;
|
|
|
|
if (! (pFCBT->pbufCur = pFCBT->pBCBCur->pbuf))
|
|
pFCBT->fh = tryOneFile( save );
|
|
} else
|
|
pFCBT->fh = tryOneFile( save );
|
|
|
|
pFCBCur = pFCBT;
|
|
|
|
return(-2);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
return(tryOneFile( save ));
|
|
}
|
|
|
|
int
|
|
PASCAL
|
|
CODESIZE
|
|
tryOneFile(
|
|
UCHAR *fname
|
|
)
|
|
{
|
|
int iRet;
|
|
int fTryAgain;
|
|
|
|
do {
|
|
fTryAgain = FALSE;
|
|
#ifdef XENIX286
|
|
iRet = open (fname, TEXTREAD);
|
|
#else
|
|
iRet = _sopen (fname, O_RDONLY | O_BINARY, SH_DENYWR);
|
|
#endif
|
|
if ( iRet == -1 && errno == EMFILE ) { /* If out of file handles */
|
|
if ( freeAFileHandle() ) {
|
|
fTryAgain = TRUE; /* Keep trying until out of files to close */
|
|
}
|
|
}
|
|
}while ( fTryAgain );
|
|
return( iRet ); /* Return file handle or error */
|
|
}
|
|
|
|
|
|
|
|
/*** openincfile - try to find and open include file
|
|
*
|
|
* openincfile ()
|
|
*
|
|
* Entry lbufp = pointer to include file name
|
|
* inclcnt = count of -I paths from command line and INCLUDE e.v.
|
|
* inclpath[i] = pointer to path to prepend to include file name
|
|
* Exit include file opened if found on any path or current directory
|
|
* Aborts with code EX_UINC if file not found
|
|
* Returns none
|
|
* Note If include file name does not begin with path separator
|
|
* character, the path separator is appended to include path.
|
|
* For every attempt to find a file in a path, the alternate
|
|
* path separator character is used. This will improve program
|
|
* portability between DOS and XENIX.
|
|
*/
|
|
|
|
int
|
|
PASCAL
|
|
CODESIZE
|
|
openincfile ()
|
|
{
|
|
register char cc;
|
|
int fh;
|
|
SHORT i;
|
|
|
|
#ifdef MSDOS
|
|
if ((cc = *lbufp) != PSEP && cc != ALTPSEP && cc != '.' &&
|
|
lbufp[1] != ':') {
|
|
#else
|
|
if ((cc = *lbufp) != PSEP && cc != ALTPSEP && cc != '.') {
|
|
#endif /* MSDOS */
|
|
|
|
for (i = inclFirst; i < inclcnt; i++) {
|
|
if ((fh = trypathname (inclpath[i])) != -1) {
|
|
return (fh);
|
|
}
|
|
}
|
|
|
|
} else
|
|
|
|
if ((fh = trypathname ("")) != -1) {
|
|
return (fh);
|
|
}
|
|
|
|
error(E_INC, lbufp);
|
|
errordisplay ();
|
|
closeOpenFiles();
|
|
|
|
exit (EX_UINC);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*** includedir - process <include> directive
|
|
*
|
|
* includedir ();
|
|
*
|
|
* Entry lbufp = pointer to include file name
|
|
* Exit Opens include file on pass1. Gets correct buffers on pass 2
|
|
* Returns none
|
|
* Notes Notice the GOTO when correct FCB found in pass2
|
|
*/
|
|
|
|
VOID
|
|
PASCAL
|
|
CODESIZE
|
|
includedir ()
|
|
{
|
|
char lastreadT;
|
|
register FCB * pFCBT;
|
|
unsigned long filelen;
|
|
FCB * svInc;
|
|
int fh;
|
|
|
|
|
|
#ifdef BCBOPT
|
|
if (fNotStored)
|
|
storelinepb ();
|
|
#endif
|
|
|
|
listline();
|
|
|
|
/* Get here on pass 1 OR when file names didn't match */
|
|
|
|
#ifdef BCBOPT
|
|
if ((fh = openincfile()) == -2) {
|
|
pFCBT = pFCBInc = pFCBCur;
|
|
goto gotinclude;
|
|
}
|
|
#else
|
|
fh = openincfile();
|
|
#endif
|
|
|
|
pFCBT = (FCB *)
|
|
nalloc((USHORT)(sizeof(FCB) + strlen(save) + sizeof(char)),"includedir");
|
|
|
|
pFCBT->fh = fh;
|
|
|
|
strcpy (pFCBT->fname, save); // Save the file name
|
|
|
|
pFCBT->pFCBParent = pFCBCur; /* Add bidirectional linked list entry */
|
|
pFCBCur->pFCBChild = pFCBT;
|
|
|
|
#ifdef BCBOPT
|
|
if (!pass2) {
|
|
pFCBT->pFCBNext = NULL;
|
|
pFCBInc->pFCBNext = pFCBT;
|
|
pFCBInc = pFCBT;
|
|
} else
|
|
pFCBT->pbufCur = NULL;
|
|
#endif
|
|
|
|
if ((filelen = _lseek(pFCBT->fh, 0L, 2 )) == -1L)
|
|
TERMINATE1(ER_ULI, EX_UINP, save);
|
|
|
|
/* go back to beginning */
|
|
if (_lseek(pFCBT->fh, 0L, 0 ) == -1L)
|
|
TERMINATE1(ER_ULI, EX_UINP, save);
|
|
|
|
if (filelen > DEF_INCBUFSIZ << 10)
|
|
pFCBT->cbbuf = DEF_INCBUFSIZ << 10;
|
|
else
|
|
pFCBT->cbbuf = (USHORT) filelen + 1;
|
|
|
|
pFCBCur = pFCBT;
|
|
|
|
/* get a buffer */
|
|
|
|
#ifdef BCBOPT
|
|
if (fBuffering && !pass2)
|
|
pFCBT->pBCBFirst = pBCBalloc(pFCBT->cbbuf);
|
|
else
|
|
pFCBT->pBCBFirst = NULL;
|
|
|
|
pFCBT->pBCBCur = pFCBT->pBCBFirst;
|
|
#endif
|
|
|
|
|
|
#ifdef BCBOPT
|
|
gotinclude:
|
|
#endif
|
|
|
|
pFCBT->line = 0;
|
|
pFCBT->ctmpbuf = 0;
|
|
#ifdef XENIX286
|
|
pFCBT->ptmpbuf = pFCBT->buf = nalloc(pFCBT->cbbuf, "incdir");
|
|
#else
|
|
pFCBT->ptmpbuf = pFCBT->buf = falloc(pFCBT->cbbuf, "incdir");
|
|
#endif
|
|
|
|
if (crefing && pass2)
|
|
fprintf( crf.fil, "\t%s", save );
|
|
|
|
lastreadT = lastreader;
|
|
lineprocess(RREADSOURCE, NULL );
|
|
|
|
lastreader = lastreadT;
|
|
swaphandler++; /* sync local handler with global state */
|
|
fSkipList++;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** segdefine - process <segment> directive
|
|
*
|
|
* routine ();
|
|
*
|
|
* Entry
|
|
* Exit
|
|
* Returns
|
|
* Calls
|
|
* Note Format is:
|
|
* <name> SEGMENT [align] | [combine] | ['class']
|
|
* align: PARA | BYTE | WORD | PAGE | INPAGE
|
|
* combine:PUBLIC | COMMON | STACK | MEMORY | AT <expr>
|
|
*/
|
|
|
|
|
|
VOID
|
|
PASCAL
|
|
CODESIZE
|
|
segdefine ()
|
|
{
|
|
register char cc;
|
|
register SYMBOL FARSYM *p;
|
|
register SYMBOL FARSYM *pT;
|
|
|
|
if (!symFetNoXref ())
|
|
/* Create if new segment */
|
|
segcreate (TRUE);
|
|
else {
|
|
if (symptr->symkind != SEGMENT)
|
|
if (symptr->symkind == CLASS)
|
|
segcreate (FALSE);
|
|
else
|
|
/* Wasn't segment */
|
|
errorn (E_SDK);
|
|
}
|
|
strcpy(&segName[8], naim.pszName);
|
|
p = symptr;
|
|
/* Output CREF info */
|
|
crefdef ();
|
|
if (p->symkind == SEGMENT) {
|
|
|
|
if (!(pass2 || (M_BACKREF & p->attr)))
|
|
addseglist (p);
|
|
|
|
p->attr |= M_BACKREF | M_DEFINED;
|
|
if (pcsegment) {
|
|
|
|
/* Save previous segment info */
|
|
/* Save current segment PC */
|
|
pcsegment->offset = pcoffset;
|
|
pcsegment->symu.segmnt.seglen =
|
|
(pcmax > pcoffset) ? pcmax : pcoffset;
|
|
}
|
|
/* check for nested segment opens */
|
|
|
|
for (pT = pcsegment; pT;) {
|
|
|
|
if (pT == p) {
|
|
errorc(E_BNE);
|
|
goto badNest;
|
|
}
|
|
pT = pT->symu.segmnt.lastseg;
|
|
}
|
|
|
|
/* Save previous segment */
|
|
p->symu.segmnt.lastseg = pcsegment;
|
|
badNest:
|
|
/* Set new current segment */
|
|
pcsegment = p;
|
|
pcoffset = p->offset;
|
|
|
|
/* Set segment maximum offset */
|
|
pcmax = p->symu.segmnt.seglen;
|
|
|
|
/* Display where in segment */
|
|
pcdisplay ();
|
|
|
|
while (!ISTERM (cc = PEEKC ())) {
|
|
if (cc == '\'')
|
|
segclass (p);
|
|
else if (LEGAL1ST (cc))
|
|
segalign (p);
|
|
else {
|
|
error(E_EXP,"align, combine, or 'class'");
|
|
break;
|
|
}
|
|
}
|
|
#ifdef V386
|
|
if (p->symu.segmnt.use32 == (char)-1)
|
|
p->symu.segmnt.use32 = wordszdefault;
|
|
|
|
wordsize = p->symu.segmnt.use32;
|
|
|
|
defwordsize();
|
|
|
|
if (wordsize == 4 && !(cputype & P386))
|
|
errorc(E_CPU);
|
|
#endif
|
|
}
|
|
definesym(segName);
|
|
symptr->attr |= M_NOCREF; /* don't cref @curSeg */
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** addseglist - add segment to list
|
|
*
|
|
* addseglist (pseg);
|
|
*
|
|
* Entry pseg = segment symbol entry
|
|
* Exit
|
|
* Returns
|
|
* Calls
|
|
*/
|
|
|
|
|
|
VOID
|
|
PASCAL
|
|
CODESIZE
|
|
addseglist (
|
|
register SYMBOL FARSYM *pseg
|
|
)
|
|
{
|
|
register SYMBOL FARSYM *tseg;
|
|
register SYMBOL FARSYM * FARSYM *lseg;
|
|
|
|
/* Add segment to list */
|
|
if (!firstsegment) {
|
|
firstsegment = pseg;
|
|
pseg->symu.segmnt.segordered = NULL;
|
|
return;
|
|
}
|
|
tseg = firstsegment;
|
|
lseg = &firstsegment;
|
|
for (; tseg; lseg = &(tseg->symu.segmnt.segordered),
|
|
tseg = tseg->symu.segmnt.segordered) {
|
|
if (segalpha) {
|
|
if (STRFFCMP (pseg->nampnt->id, tseg->nampnt->id) < 0) {
|
|
pseg->symu.segmnt.segordered = tseg;
|
|
*lseg = pseg;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
*lseg = pseg;
|
|
pseg->symu.segmnt.segordered = NULL;
|
|
}
|
|
|
|
|
|
|
|
/*** segclass - process <segment> 'class' subdirective
|
|
*
|
|
* segclass (pseg);
|
|
*
|
|
* Entry pseg = segment symbol entry
|
|
* *lbufp = leading ' of class name
|
|
* Exit
|
|
* Returns
|
|
* Calls scanatom, skipblanks
|
|
* Note Format is:
|
|
* <name> SEGMENT [align] | [combine] | ['class']
|
|
* align: PARA | BYTE | WORD | PAGE | INPAGE
|
|
* combine:PUBLIC | COMMON | STACK | MEMORY | AT <expr>
|
|
*/
|
|
|
|
|
|
VOID
|
|
PASCAL
|
|
CODESIZE
|
|
segclass (
|
|
register SYMBOL FARSYM *pseg
|
|
)
|
|
{
|
|
SKIPC ();
|
|
getatom ();
|
|
if (NEXTC () != '\'')
|
|
/* Don't have right delim */
|
|
error (E_EXP,"'");
|
|
skipblanks ();
|
|
if (symptr->symu.segmnt.classptr) {
|
|
/* Make sure 'class' matches */
|
|
if (!symFet ())
|
|
/* Not same class */
|
|
errorc (E_SPC);
|
|
else if (symptr->symkind != CLASS &&
|
|
symptr->symkind != SEGMENT &&
|
|
symptr->symkind != GROUP)
|
|
errorn(E_SDK);
|
|
else if (symptr != pseg->symu.segmnt.classptr)
|
|
errorc (E_SPC);
|
|
} else if (*naim.pszName == 0)
|
|
errorc (E_EMS);
|
|
|
|
else if (!symFet ()) {
|
|
symcreate (M_DEFINED, SEGMENT);
|
|
symptr->symkind = CLASS;
|
|
}
|
|
checkRes();
|
|
pseg->symu.segmnt.classptr = symptr;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** segalign - process <segment> align and combine subdirectives
|
|
*
|
|
* segalign ();
|
|
*
|
|
* Entry
|
|
* Exit
|
|
* Returns
|
|
* Calls
|
|
* Note Format is:
|
|
* <name> SEGMENT [align] | [combine] | [16/32] | ['class']
|
|
* align: PARA | BYTE | WORD | PAGE | INPAGE
|
|
* combine:PUBLIC | COMMON | STACK | MEMORY | AT <expr>
|
|
* 16/32: USE16 | USE32
|
|
*/
|
|
|
|
|
|
VOID
|
|
PASCAL
|
|
CODESIZE
|
|
segalign (
|
|
register SYMBOL FARSYM *pseg
|
|
)
|
|
{
|
|
/* Scan align or combine type */
|
|
getatom ();
|
|
if (fnspar ())
|
|
switch (segidx) {
|
|
case IS_BYTE:
|
|
case IS_WORD:
|
|
#ifdef V386
|
|
case IS_DWORD:
|
|
#endif
|
|
case IS_PAGE:
|
|
case IS_PARA:
|
|
/* Some align field */
|
|
if (pseg->symu.segmnt.align == (char)-1)
|
|
pseg->symu.segmnt.align = segtyp;
|
|
else if (pseg->symu.segmnt.align != segtyp &&
|
|
(pseg->symu.segmnt.align != pseg->symu.segmnt.combine ||
|
|
pseg->symu.segmnt.align))
|
|
errorc (E_SPC);
|
|
break;
|
|
case IS_MEMORY:
|
|
case IS_PUBLIC:
|
|
case IS_STACK:
|
|
case IS_COMMON:
|
|
if (pseg->symu.segmnt.combine == 7)
|
|
pseg->symu.segmnt.combine = segtyp;
|
|
else if (pseg->symu.segmnt.combine != segtyp)
|
|
errorc (E_SPC);
|
|
break;
|
|
#ifdef V386
|
|
case IS_USE16:
|
|
if (pseg->symu.segmnt.use32 != (char)-1 &&
|
|
pseg->symu.segmnt.use32 != 2)
|
|
errorc (E_SPC);
|
|
if ((cputype&P386)==0)
|
|
errorc (E_NPA);
|
|
pseg->symu.segmnt.use32 = 2;
|
|
break;
|
|
case IS_USE32:
|
|
if (pseg->symu.segmnt.use32 != (char)-1 &&
|
|
pseg->symu.segmnt.use32 != 4)
|
|
errorc (E_SPC);
|
|
if ((cputype&P386)==0)
|
|
errorc (E_NPA);
|
|
pseg->symu.segmnt.use32 = 4;
|
|
break;
|
|
#endif
|
|
default:
|
|
/* Have AT <expr> */
|
|
pseg->symu.segmnt.locate = exprconst ();
|
|
pseg->symu.segmnt.align = 0;
|
|
pseg->symu.segmnt.combine = 0;
|
|
} else {
|
|
/* Not good align or define */
|
|
errorc (E_NPA);
|
|
}
|
|
}
|
|
|
|
|
|
/*** procdefine - start procedure block
|
|
*
|
|
* procdefine ();
|
|
*
|
|
* Parse the proc statement with optional distance parameters
|
|
*/
|
|
|
|
SYMBOL FARSYM *pArgFirst; /* pointer to first argument */
|
|
SYMBOL FARSYM *pArgCur; /* pointer to currect argment */
|
|
OFFSET offsetCur; /* current stack offset */
|
|
char bp16 [] =" PTR [BP]?"; /* template for text macro creation */
|
|
char bp32 [] =" PTR [EBP]?";
|
|
char *bp;
|
|
|
|
VOID
|
|
PASCAL
|
|
CODESIZE
|
|
procdefine ()
|
|
{
|
|
/* create PROC name with default size*/
|
|
|
|
varsize = dirsize[I_PROC];
|
|
switchname();
|
|
|
|
if (getatom ()) {
|
|
|
|
if (fnsize ()) { /* process optional near|far */
|
|
|
|
if (varsize < CSFAR)
|
|
errorc (E_TIL);
|
|
|
|
if (langType)
|
|
getatom();
|
|
} else if (!langType)
|
|
errorc (E_MSY);
|
|
|
|
}
|
|
switchname();
|
|
|
|
labelcreate (varsize, PROC);
|
|
|
|
if (symptr->symkind != PROC)
|
|
return;
|
|
|
|
/* Set previous PROC, make sure no loop possible */
|
|
|
|
if (iProcStack < PROCMAX && pcproc != symptr)
|
|
procStack[++iProcStack] = symptr;
|
|
|
|
pcproc = symptr; /* Set ptr to new PROC */
|
|
symptr->length = 1;
|
|
symptr->symu.clabel.type = typeFet(varsize);
|
|
pcproc->symu.plabel.pArgs = NULL;
|
|
|
|
if (langType)
|
|
|
|
creatPubName();
|
|
else
|
|
return;
|
|
|
|
if (iProcStack > 1) /* nested procs not allowed */
|
|
errorc(E_BNE);
|
|
|
|
iProcCur = ++iProc;
|
|
emitline();
|
|
|
|
if (! pass2) {
|
|
|
|
/* keep a chain of procedures in sorted order so we can output
|
|
* proc's in the correct order for CV */
|
|
|
|
if (pProcCur)
|
|
pProcCur->alpha = symptr;
|
|
else
|
|
pProcFirst = symptr;
|
|
}
|
|
pProcCur = symptr;
|
|
|
|
/* check and process any "uses reg1 reg2 ... " */
|
|
|
|
iRegSave = -1;
|
|
fProcArgs = ARGS_NONE;
|
|
cbProcLocals = 0;
|
|
switchname();
|
|
|
|
if (fetLang() == CLANG)
|
|
pProcCur->attr |= M_CDECL;
|
|
|
|
#ifndef FEATURE
|
|
if (tokenIS("private")) {
|
|
symptr->attr &= ~M_GLOBAL;
|
|
getatom();
|
|
}
|
|
#endif
|
|
|
|
if (tokenIS("uses")) {
|
|
|
|
char L_count = 0;
|
|
|
|
while (iRegSave < 8 && getatom()) {
|
|
|
|
L_count++;
|
|
|
|
#ifndef FEATURE
|
|
if (symsrch() && symptr->symkind == EQU
|
|
&& symptr->symu.equ.equtyp == TEXTMACRO) {
|
|
expandTM (symptr->symu.equ.equrec.txtmacro.equtext);
|
|
getatom ();
|
|
}
|
|
|
|
if (*naim.pszName)
|
|
#endif
|
|
strcpy(regSave[++iRegSave], naim.pszName);
|
|
}
|
|
if (!L_count)
|
|
errorc(E_OPN);
|
|
else
|
|
fProcArgs = ARGS_REG;
|
|
}
|
|
|
|
pTextEnd = (char *) -1;
|
|
bp = (wordsize == 2)? bp16: bp32;
|
|
|
|
offsetCur = wordsize*2; /* room for [e]bp and offset of ret addr */
|
|
if (pcproc->symtype == CSFAR)
|
|
offsetCur += wordsize; /* room for [ ]cs (16 or 32 bits) */
|
|
|
|
cbProcParms = cbProcParms - offsetCur;
|
|
|
|
scanArgs();
|
|
|
|
cbProcParms += offsetCur;
|
|
if (cbProcParms)
|
|
fProcArgs = ARGS_PARMS;
|
|
|
|
pcproc->symu.plabel.pArgs = pArgFirst;
|
|
offsetCur = 0;
|
|
}
|
|
|
|
/*** defineLocals
|
|
*
|
|
* Parse the local statment for stack based variables
|
|
*/
|
|
|
|
VOID
|
|
PASCAL
|
|
CODESIZE
|
|
defineLocals ()
|
|
{
|
|
/* check for valid active proc */
|
|
|
|
if (!pcproc || fProcArgs < 0)
|
|
return;
|
|
|
|
fProcArgs = ARGS_LOCALS;
|
|
getatom();
|
|
scanArgs();
|
|
|
|
/* tack on the the end the parm list any locals */
|
|
|
|
addLocal(pArgFirst);
|
|
|
|
cbProcLocals = offsetCur;
|
|
}
|
|
|
|
/*** addLocal - concatenate a null-terminated list of locals onto a proc
|
|
*
|
|
*/
|
|
|
|
VOID
|
|
PASCAL
|
|
CODESIZE
|
|
addLocal (
|
|
SYMBOL FARSYM *pSY
|
|
)
|
|
{
|
|
if (pcproc) {
|
|
|
|
if (!(pArgCur = pcproc->symu.plabel.pArgs))
|
|
pcproc->symu.plabel.pArgs = pSY;
|
|
|
|
else {
|
|
|
|
for (; pArgCur->alpha; pArgCur = pArgCur->alpha);
|
|
|
|
pArgCur->alpha = pSY;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
char *
|
|
PASCAL
|
|
CODESIZE
|
|
xxradixconvert (
|
|
OFFSET valu,
|
|
register char *p
|
|
)
|
|
{
|
|
if (valu / radix) {
|
|
p = xxradixconvert (valu / radix, p);
|
|
valu = valu % radix;
|
|
} else /* leading digit */
|
|
if (valu > 9) /* do leading '0' for hex */
|
|
*p++ = '0';
|
|
|
|
*p++ = (char)(valu + ((valu > 9)? 'A' - 10 : '0'));
|
|
|
|
return (p);
|
|
}
|
|
|
|
SHORT mpTypeAlign[] = { 4, 1, 2, 4};
|
|
|
|
|
|
/*** scanArgs - process an argument list into text macros
|
|
*
|
|
*
|
|
*/
|
|
|
|
|
|
SHORT
|
|
PASCAL
|
|
CODESIZE
|
|
scanArgs ()
|
|
{
|
|
struct eqar eqarT;
|
|
USHORT defKind;
|
|
USHORT defType;
|
|
USHORT defCV;
|
|
USHORT defPtrSize;
|
|
SHORT fIsPtr;
|
|
char *pLeftBrack;
|
|
char *p;
|
|
|
|
pArgFirst = pArgCur = NULL;
|
|
|
|
if (*naim.pszName)
|
|
goto First;
|
|
|
|
do {
|
|
if (PEEKC() == ',')
|
|
SKIPC();
|
|
|
|
if (!getatom())
|
|
break;
|
|
First:
|
|
switchname();
|
|
if (!createequ (TEXTMACRO))
|
|
break;
|
|
|
|
/* chain in the text macro to this procedure. You must either
|
|
do a FIFO or LIFO quque depending on calling order */
|
|
|
|
if (pProcCur->attr & M_CDECL) {
|
|
|
|
if (pArgCur)
|
|
pArgCur->alpha = symptr;
|
|
else
|
|
pArgFirst = symptr;
|
|
|
|
symptr->alpha = NULL;
|
|
} else {
|
|
pArgFirst = symptr;
|
|
symptr->alpha = pArgCur;
|
|
}
|
|
|
|
pArgCur = symptr;
|
|
|
|
if (PEEKC() == '[' && fProcArgs == ARGS_LOCALS) { /* array element given */
|
|
|
|
SKIPC();
|
|
for (pLeftBrack = lbufp; PEEKC() && PEEKC() != ']'; SKIPC());
|
|
|
|
*lbufp = ','; /* to stop expression evaluation */
|
|
lbufp = pLeftBrack;
|
|
pArgCur->length = (USHORT)exprconst ();
|
|
|
|
*lbufp++ = ']'; /* restore bracket */
|
|
}
|
|
|
|
fIsPtr = FALSE;
|
|
defType = varsize = wordsize;
|
|
|
|
if (PEEKC() == ':') { /* parse optional type information */
|
|
|
|
SKIPC();
|
|
getatom();
|
|
|
|
if (fnsize()) {
|
|
|
|
if (varsize >= CSFAR) { /* near | far given */
|
|
|
|
if (varsize == CSFAR)
|
|
defType += 2;
|
|
|
|
varsize = wordsize;
|
|
getatom();
|
|
|
|
if (! tokenIS("ptr"))
|
|
error(E_EXP, "PTR");
|
|
|
|
getatom();
|
|
} else {
|
|
defType = varsize;
|
|
goto notPtr;
|
|
}
|
|
}
|
|
|
|
else if (tokenIS("ptr")) {
|
|
if (farData[10] > '0')
|
|
defType += 2;
|
|
|
|
getatom();
|
|
} else
|
|
errorc(E_UST);
|
|
|
|
defCV = fnPtr(defType);
|
|
} else
|
|
notPtr:
|
|
defCV = typeFet(defType);
|
|
|
|
pArgCur->symu.equ.iProc = iProcCur;
|
|
pArgCur->symtype = defType;
|
|
pArgCur->symu.equ.equrec.txtmacro.type = defCV;
|
|
|
|
} while (PEEKC() == ',');
|
|
|
|
/* Now that all the parmeters have been scanned, go back through
|
|
the list and assign offsets and create the text macro string */
|
|
|
|
|
|
bp[strlen(bp)-1] = (fProcArgs == ARGS_LOCALS)? '-': '+';
|
|
|
|
for (pArgCur = pArgFirst; pArgCur; pArgCur = pArgCur->alpha) {
|
|
|
|
if (fProcArgs == ARGS_LOCALS) {
|
|
offsetCur += (offsetCur % mpTypeAlign[pArgCur->symtype % 4]) +
|
|
(pArgCur->symtype * pArgCur->length);
|
|
pArgCur->offset = -(long)offsetCur;
|
|
}
|
|
|
|
p = xxradixconvert (offsetCur, &save[100]);
|
|
if (radix == 16)
|
|
*p++ = 'h';
|
|
*p++ = ')';
|
|
*p = NULL;
|
|
|
|
strcat( strcat( strcpy (&save[1], siznm[pArgCur->symtype]),
|
|
bp), &save[100]);
|
|
*save = '(';
|
|
|
|
if (fProcArgs != ARGS_LOCALS) {
|
|
pArgCur->offset = offsetCur;
|
|
offsetCur += pArgCur->symtype + wordsize - 1;
|
|
offsetCur -= offsetCur % wordsize;
|
|
}
|
|
|
|
if (!pass2)
|
|
pArgCur->symu.equ.equrec.txtmacro.equtext = _strdup(save);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*** procbuild - check for end of PROC block
|
|
*
|
|
* procbuild ();
|
|
*
|
|
* Entry *pcproc = current PROC
|
|
* Exit *pcproc = current or previous PROC
|
|
* Returns none
|
|
* Calls endblk, parse
|
|
* Note if not end of PROC, parse line as normal. Otherwise,
|
|
* terminate block.
|
|
*/
|
|
|
|
SHORT
|
|
PASCAL
|
|
CODESIZE
|
|
procend ()
|
|
{
|
|
USHORT size;
|
|
|
|
if (!pcproc)
|
|
errorc( E_BNE );
|
|
|
|
else if (pcproc->symkind == PROC) {
|
|
|
|
if (!symFet() || symptr != pcproc)
|
|
errorc (E_BNE);
|
|
|
|
/* Length of PROC */
|
|
size = (USHORT)(pcoffset - pcproc->offset);
|
|
if (pass2 && size != pcproc->symu.plabel.proclen)
|
|
errorc (E_PHE);
|
|
|
|
fProcArgs = 0;
|
|
iProcCur = 0;
|
|
pcproc->symu.plabel.proclen = size;
|
|
/* Point to prev PROC */
|
|
pcproc = procStack[--iProcStack];
|
|
pcdisplay ();
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
|
|
/* bit flags for segment table */
|
|
|
|
#define SG_OVERIDE 1 /* name can be overriden */
|
|
#define SG_GROUP 2 /* segment belongs to dgroup */
|
|
|
|
char models[] = "SMALL\0 COMPACT\0MEDIUM\0 LARGE\0 HUGE";
|
|
char langs[] = "C\0 PASCAL\0 FORTRAN\0BASIC";
|
|
char textN[] = "_TEXT";
|
|
char farTextName[14+5];
|
|
SHORT modelWordSize;
|
|
|
|
char farCode[] = "@CodeSize=0"; /* text macros for model stuff */
|
|
char farData[] = "@DataSize=0";
|
|
char modelT[] = ".model";
|
|
|
|
/* table of segment names and attributes for the model */
|
|
|
|
struct sSeg {
|
|
char *sName; /* segment name */
|
|
UCHAR align; /* alignment */
|
|
UCHAR combine; /* combine */
|
|
char *cName; /* class name */
|
|
UCHAR flags; /* internal state flags */
|
|
|
|
} rgSeg[] = {
|
|
|
|
textN, 2, 2, "'CODE'", SG_OVERIDE,
|
|
"_DATA", 2, 2, "'DATA'", SG_GROUP,
|
|
"_BSS", 2, 2, "'BSS'", SG_GROUP,
|
|
"CONST", 2, 2, "'CONST'", SG_GROUP,
|
|
"STACK", 3, 5, "'STACK'", SG_GROUP,
|
|
"FAR_DATA", 3, 0, "'FAR_DATA'", SG_OVERIDE,
|
|
"FAR_BSS", 3, 0, "'FAR_BSS'", SG_OVERIDE
|
|
};
|
|
|
|
|
|
/*** model - process the model directive
|
|
*
|
|
*
|
|
* Note Format is:
|
|
* .MODEL SMALL|MEDIUM|COMPACT|LARGE|HUGE {,C|BASIC|FORTRAN|PASCAL}
|
|
*/
|
|
|
|
|
|
VOID
|
|
PASCAL
|
|
CODESIZE
|
|
model ()
|
|
{
|
|
register SHORT iModel;
|
|
char buffT[80];
|
|
|
|
/* get the model and classify */
|
|
|
|
getatom ();
|
|
|
|
for (iModel = 0; iModel <= 32; iModel += 8)
|
|
if (tokenIS(&models[iModel]))
|
|
goto goodModel;
|
|
|
|
errorc(E_OPN);
|
|
iModel = 0;
|
|
|
|
goodModel:
|
|
iModel /= 8; /* offset into index */
|
|
if (fSimpleSeg && iModel+1 != fSimpleSeg)
|
|
error(E_SMD, modelT);
|
|
|
|
fSimpleSeg = iModel + 1;
|
|
|
|
if (iModel > 1) { /* far code */
|
|
|
|
farCode[10]++;
|
|
rgSeg[0].sName = strcat(strcpy(farTextName, &baseName[10]), textN);
|
|
dirsize[I_PROC] = CSFAR;
|
|
} else
|
|
rgSeg[0].flags &= ~SG_OVERIDE;
|
|
|
|
|
|
if (iModel != 0 && iModel != 2 ) { /* far data */
|
|
|
|
farData[10]++;
|
|
|
|
if (iModel == 4) /* huge get a '2' */
|
|
farData[10]++;
|
|
}
|
|
#ifdef V386
|
|
|
|
if (cputype & P386)
|
|
rgSeg[0].align =
|
|
rgSeg[1].align =
|
|
rgSeg[2].align =
|
|
rgSeg[3].align =
|
|
rgSeg[5].align =
|
|
rgSeg[6].align = 5; /* make data dword aligned */
|
|
#endif
|
|
if (PEEKC() == ',') { /* language option present */
|
|
|
|
SKIPC();
|
|
getatom();
|
|
|
|
if (! (langType = fetLang()))
|
|
error(E_EXP, "C|BASIC|FORTRAN|PASCAL");
|
|
}
|
|
|
|
if (! pass2) {
|
|
|
|
modelWordSize = wordsize;
|
|
|
|
/* define the text macros, the _data segment so dgroup may
|
|
defined, dgroup and the assume */
|
|
|
|
definesym(farCode);
|
|
definesym(farData);
|
|
|
|
definesym(strcat(strcpy(buffT, "@code="), rgSeg[0].sName));
|
|
|
|
definesym("@data=DGROUP"); symptr->attr |= M_NOCREF;
|
|
definesym("@fardata=FAR_DATA"); symptr->attr |= M_NOCREF;
|
|
definesym("@fardata?=FAR_BSS"); symptr->attr |= M_NOCREF;
|
|
|
|
doLine(".code");
|
|
doLine(".data");
|
|
endCurSeg();
|
|
|
|
}
|
|
xcreflag--;
|
|
doLine("assume cs:@code,ds:@data,ss:@data");
|
|
xcreflag++;
|
|
|
|
}
|
|
|
|
SHORT
|
|
CODESIZE
|
|
fetLang()
|
|
{
|
|
SHORT iModel;
|
|
|
|
for (iModel = 0; iModel <= 24; iModel += 8)
|
|
if (tokenIS(&langs[iModel])) {
|
|
getatom();
|
|
return(iModel/8 + 1);
|
|
}
|
|
|
|
return(langType);
|
|
}
|
|
|
|
|
|
/*** openSeg - open a segment in the simplified segment
|
|
*
|
|
*
|
|
*/
|
|
|
|
|
|
VOID
|
|
PASCAL
|
|
CODESIZE
|
|
openSeg ()
|
|
{
|
|
register struct sSeg *pSEG;
|
|
char *pSegName;
|
|
char buffT[80];
|
|
|
|
if (!fSimpleSeg)
|
|
error(E_EXP, modelT);
|
|
|
|
pSEG = &rgSeg[opkind];
|
|
getatom ();
|
|
|
|
if (*naim.pszName) {
|
|
|
|
if (! (pSEG->flags & SG_OVERIDE))
|
|
errorc(E_OCI);
|
|
|
|
pSegName = naim.pszName;
|
|
} else
|
|
pSegName = pSEG->sName;
|
|
|
|
strcat( strcat( strcpy(buffT,
|
|
pSegName),
|
|
" segment "),
|
|
pSEG->cName);
|
|
|
|
if (pcsegment && opkind != 4)
|
|
endCurSeg();
|
|
|
|
doLine(buffT);
|
|
|
|
pcsegment->symu.segmnt.combine = pSEG->combine;
|
|
pcsegment->symu.segmnt.align = pSEG->align;
|
|
|
|
if (pSEG == &rgSeg[0])
|
|
regsegment[CSSEG] = pcsegment;
|
|
|
|
#ifdef V386
|
|
pcsegment->symu.segmnt.use32 = (char)modelWordSize;
|
|
wordsize = modelWordSize;
|
|
defwordsize();
|
|
#endif
|
|
|
|
if (pSEG->flags & SG_GROUP) {
|
|
|
|
doLine("DGROUP group @CurSeg");
|
|
pSEG->flags &= ~SG_GROUP;
|
|
}
|
|
}
|
|
|
|
/*** stack - create a stack segment
|
|
*
|
|
*
|
|
*/
|
|
|
|
|
|
VOID
|
|
PASCAL
|
|
CODESIZE
|
|
createStack ()
|
|
{
|
|
SHORT size;
|
|
|
|
if ((size = (SHORT)exprconst()) == 0)
|
|
size = 1024;
|
|
|
|
opkind = 4; /* index into seg table */
|
|
openSeg();
|
|
pcoffset = size;
|
|
endCurSeg();
|
|
}
|
|
|
|
VOID
|
|
PASCAL
|
|
CODESIZE
|
|
endCurSeg ()
|
|
{
|
|
xcreflag--;
|
|
doLine("@CurSeg ends");
|
|
xcreflag++;
|
|
}
|
|
|
|
|
|
|
|
/*** freeAFileHandle
|
|
*
|
|
* Free's a file handle if possible
|
|
*
|
|
* When working with deeply nested include files it is possible
|
|
* to run out of file handles. If this happens this function is
|
|
* called to temporarily close one of the include files. This is
|
|
* done by saving the current file position, closing the file and
|
|
* replacing the file handle with FH_CLOSED. Notice that the data
|
|
* buffer assosciated with the file is not destroyed. Hence readline
|
|
* can continue to read data from it until more data is needed from
|
|
* disk. There are two files that won't be closed, the main file and
|
|
* the current file.
|
|
* Associated functions:
|
|
* readmore - if neccessary, will reopen and seek to the original
|
|
* position the file.
|
|
* closefile - closes the file if it hasn't been already.
|
|
*
|
|
* return: TRUE = Was able to close a file, FALSE = Couldn't
|
|
*/
|
|
|
|
int
|
|
PASCAL
|
|
CODESIZE
|
|
freeAFileHandle ()
|
|
{
|
|
register FCB *pFCBTmp;
|
|
|
|
if ( !(pFCBTmp = pFCBMain->pFCBChild) ) {
|
|
return( FALSE ); /* The only file open is the main source */
|
|
}
|
|
/* Loop down linked list of nested include files */
|
|
while ( pFCBTmp ) {
|
|
if ( (pFCBTmp->fh != FH_CLOSED) && (pFCBTmp != pFCBCur) ) {
|
|
pFCBTmp->savefilepos = _tell( pFCBTmp->fh );
|
|
_close( pFCBTmp->fh );
|
|
pFCBTmp->fh = FH_CLOSED;
|
|
return( TRUE );
|
|
}
|
|
pFCBTmp = pFCBTmp->pFCBChild;
|
|
}
|
|
return( FALSE ); /* Couldn't find a file to close */
|
|
}
|
|
|
|
int
|
|
PASCAL
|
|
CODESIZE
|
|
fpoRecord ()
|
|
{
|
|
unsigned long dwValue[6];
|
|
char peekChar;
|
|
int i;
|
|
PFPOSTRUCT pFpo = pFpoTail;
|
|
PFPO_DATA pFpoData = 0;
|
|
|
|
if (PEEKC() != '(') {
|
|
errorc(E_PAR);
|
|
return FALSE;
|
|
}
|
|
SKIPC();
|
|
for (i=0; i<6; i++) {
|
|
dwValue[i] = exprconst();
|
|
peekChar = PEEKC();
|
|
SKIPC();
|
|
if (peekChar != ',') {
|
|
if (i < 5) {
|
|
errorc(E_FPO1);
|
|
return FALSE;
|
|
}
|
|
if (peekChar != ')') {
|
|
errorc(E_PAR);
|
|
return FALSE;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!pcproc) {
|
|
errorc(E_FPO2);
|
|
return FALSE;
|
|
}
|
|
if (pass2) {
|
|
return TRUE;
|
|
}
|
|
if (!pFpoHead) {
|
|
pFpoTail = pFpoHead = (PFPOSTRUCT)malloc(sizeof(FPOSTRUCT));
|
|
if (!pFpoHead) {
|
|
errorc(E_RRF);
|
|
return FALSE;
|
|
}
|
|
pFpo = pFpoTail;
|
|
} else {
|
|
pFpoTail->next = (PFPOSTRUCT)malloc(sizeof(FPOSTRUCT));
|
|
if (!pFpoTail->next) {
|
|
errorc(E_RRF);
|
|
return FALSE;
|
|
}
|
|
pFpo = pFpoTail->next;
|
|
pFpoTail = pFpo;
|
|
}
|
|
numFpoRecords++;
|
|
memset((void*)pFpo,0,sizeof(FPOSTRUCT));
|
|
pFpoData = &pFpo->fpoData;
|
|
if (pcproc->offset != pcoffset) {
|
|
sprintf(naim.pszName, "%s_fpo%d", pcproc->nampnt->id, numFpoRecords);
|
|
strcpy(naim.pszLowerCase, naim.pszName);
|
|
_strlwr(naim.pszLowerCase);
|
|
naim.ucCount = (unsigned char) strlen(naim.pszName);
|
|
naim.usHash = 0;
|
|
labelcreate(CSNEAR, CLABEL);
|
|
pFpo->pSymAlt = symptr;
|
|
} else {
|
|
pFpo->pSymAlt = 0;
|
|
}
|
|
pFpo->pSym = pcproc;
|
|
pFpoData->ulOffStart = pcoffset;
|
|
pFpoData->cbProcSize = 0;
|
|
pFpoData->cdwLocals = dwValue[0];
|
|
pFpoData->cdwParams = (USHORT)dwValue[1];
|
|
pFpoData->cbProlog = (USHORT)dwValue[2];
|
|
pFpoData->cbRegs = (USHORT)dwValue[3];
|
|
pFpoData->fUseBP = (USHORT)dwValue[4];
|
|
pFpoData->cbFrame = (USHORT)dwValue[5];
|
|
pFpoData->fHasSEH = 0;
|
|
return TRUE;
|
|
}
|