1005 lines
20 KiB
C
1005 lines
20 KiB
C
|
//
|
||
|
// ADDTOLST.C - Add each record from the .SBR file to the approprate list.
|
||
|
//
|
||
|
|
||
|
#define LINT_ARGS
|
||
|
|
||
|
#include "sbrfdef.h"
|
||
|
#include "mbrmake.h"
|
||
|
#include <ctype.h>
|
||
|
|
||
|
// local types
|
||
|
|
||
|
typedef struct _mstk {
|
||
|
struct _mstk FAR *pmstkPrev; // next module stack entry
|
||
|
VA vaCurMod; // saved current module
|
||
|
BOOL fDupMod; // saved dup module flag
|
||
|
BOOL fExclMod; // saved exclude module flag
|
||
|
} MSTK, FAR * PMSTK;
|
||
|
|
||
|
typedef struct _bstk {
|
||
|
struct _bstk FAR *pbstkPrev; // next block stack entry
|
||
|
VA vaOwnerProp; // saved current owner
|
||
|
} BSTK, FAR * PBSTK;
|
||
|
|
||
|
// static variables
|
||
|
|
||
|
BOOL near fDupSym = FALSE; // TRUE if adding duplicate atom
|
||
|
BOOL near cMacroDepth = 0; // depth of MACROBEG records
|
||
|
WORD near ModCnt; // count of modules
|
||
|
WORD near isbrCur; // current SBR file index
|
||
|
|
||
|
VA near vaUnknownSym = vaNil; // Unknown symbol
|
||
|
VA near vaUnknownMod = vaNil; // Unknown module
|
||
|
|
||
|
static VA near vaOwnerProp = vaNil; // ptr to current procedure
|
||
|
static BOOL near fDupMod = FALSE; // duplicate module
|
||
|
static BOOL near fExclMod = FALSE; // exclude this module
|
||
|
static BOOL near fFirstMod = TRUE; // this is 1st module of file
|
||
|
|
||
|
static PMSTK pmstkRoot; // root of module stack
|
||
|
static PBSTK pbstkRoot; // root of block stack
|
||
|
|
||
|
// forward references
|
||
|
|
||
|
static BOOL FSkipMacro(void);
|
||
|
static VOID PushMstk(VOID);
|
||
|
static VOID PushBstk(VOID);
|
||
|
static VOID PopMstk(VOID);
|
||
|
static VOID PopBstk(VOID);
|
||
|
static VOID CheckStacksEmpty(VOID);
|
||
|
|
||
|
VOID
|
||
|
SBRCorrupt (char *psz)
|
||
|
// sbr file corrupt -- print message
|
||
|
//
|
||
|
{
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
printf("Info = %s\n", psz);
|
||
|
#else
|
||
|
// to make /W3 happy
|
||
|
psz;
|
||
|
#endif
|
||
|
|
||
|
Error(ERR_SBR_CORRUPT, lszFName);
|
||
|
}
|
||
|
|
||
|
static VOID
|
||
|
PushMstk (VOID)
|
||
|
// stack the current module context -- occurs before SBR_REC_MODULE
|
||
|
//
|
||
|
{
|
||
|
PMSTK pmstk;
|
||
|
|
||
|
pmstk = LpvAllocCb(sizeof(*pmstk));
|
||
|
|
||
|
pmstk->vaCurMod = vaCurMod; // current module
|
||
|
pmstk->fDupMod = fDupMod; // dup module
|
||
|
pmstk->fExclMod = fExclMod; // exclude module
|
||
|
pmstk->pmstkPrev = pmstkRoot; // make stack links
|
||
|
pmstkRoot = pmstk; // root <- new
|
||
|
}
|
||
|
|
||
|
static VOID
|
||
|
PushBstk (VOID)
|
||
|
// stack the current block context -- occurs before SBR_REC_BLKBEG
|
||
|
//
|
||
|
{
|
||
|
PBSTK pbstk;
|
||
|
|
||
|
pbstk = LpvAllocCb(sizeof(*pbstk));
|
||
|
|
||
|
pbstk->vaOwnerProp = vaOwnerProp; // current owner
|
||
|
pbstk->pbstkPrev = pbstkRoot; // make stack links
|
||
|
pbstkRoot = pbstk; // root <- new
|
||
|
}
|
||
|
|
||
|
static VOID
|
||
|
PopMstk (VOID)
|
||
|
// restore previous module context -- occurs on SBR_REC_MODEND
|
||
|
//
|
||
|
{
|
||
|
PMSTK pmstk;
|
||
|
|
||
|
if (pmstkRoot == NULL) {
|
||
|
#ifdef DEBUG
|
||
|
SBRCorrupt("Module stack empty but MODEND was found");
|
||
|
#else
|
||
|
SBRCorrupt("");
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
vaCurMod = pmstkRoot->vaCurMod; // get previous current module
|
||
|
fDupMod = pmstkRoot->fDupMod; // get previous dup mod flag
|
||
|
fExclMod = pmstkRoot->fExclMod; // get previous excl mod flag
|
||
|
|
||
|
pmstk = pmstkRoot;
|
||
|
pmstkRoot = pmstkRoot->pmstkPrev;
|
||
|
|
||
|
FreeLpv(pmstk);
|
||
|
}
|
||
|
|
||
|
static VOID
|
||
|
PopBstk (VOID)
|
||
|
// restore previous block context -- occurs on SBR_REC_BLKEND
|
||
|
//
|
||
|
{
|
||
|
PBSTK pbstk;
|
||
|
|
||
|
if (pbstkRoot == NULL) {
|
||
|
#ifdef DEBUG
|
||
|
SBRCorrupt("Block stack empty but BLKEND was found");
|
||
|
#else
|
||
|
SBRCorrupt("");
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
vaOwnerProp = pbstkRoot->vaOwnerProp; // get previous current proc
|
||
|
|
||
|
pbstk = pbstkRoot;
|
||
|
pbstkRoot = pbstkRoot->pbstkPrev;
|
||
|
|
||
|
FreeLpv(pbstk);
|
||
|
}
|
||
|
|
||
|
static VOID
|
||
|
CheckStacksEmpty(VOID)
|
||
|
// check to make sure that both stacks are empty at the .sbr file EOF
|
||
|
//
|
||
|
{
|
||
|
if (pmstkRoot != NULL) {
|
||
|
#ifdef DEBUG
|
||
|
SBRCorrupt("Module stack not empty at EOF");
|
||
|
#else
|
||
|
SBRCorrupt("");
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
if (pbstkRoot != NULL) {
|
||
|
#ifdef DEBUG
|
||
|
SBRCorrupt("Block stack not empty at EOF");
|
||
|
#else
|
||
|
SBRCorrupt("");
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
FInExcList (LSZ lszName)
|
||
|
// Is the module name in the exclude file list?
|
||
|
//
|
||
|
{
|
||
|
EXCLINK FAR * px;
|
||
|
LSZ lszAbs;
|
||
|
|
||
|
if (OptEs && !fFirstMod) {
|
||
|
if (lszName[0] == '\0') return FALSE;
|
||
|
|
||
|
if (lszName[0] == '/' || lszName[0] == '\\') return TRUE;
|
||
|
if (lszName[1] == ':' && lszName[2] == '/') return TRUE;
|
||
|
if (lszName[1] == ':' && lszName[2] == '\\') return TRUE;
|
||
|
}
|
||
|
|
||
|
px = pExcludeFileList;
|
||
|
|
||
|
// this name is relative to the path given in the header file
|
||
|
lszAbs = ToAbsPath(lszName, r_cwd);
|
||
|
|
||
|
while (px) {
|
||
|
if ((FWildMatch (px->pxfname, lszAbs)))
|
||
|
return TRUE;
|
||
|
px = px->xnext;
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
static BOOL
|
||
|
FSkipMacro()
|
||
|
// return TRUE if this record should be skipped given that we are inside
|
||
|
// of a macro definition (i.e cMacroDepth is known to be non-zero)
|
||
|
//
|
||
|
{
|
||
|
if (!OptEm)
|
||
|
return FALSE;
|
||
|
|
||
|
if ((r_rectyp == SBR_REC_BLKBEG) ||
|
||
|
(r_rectyp == SBR_REC_BLKEND) ||
|
||
|
(r_rectyp == SBR_REC_MACROEND))
|
||
|
return FALSE;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
InstallSBR()
|
||
|
// Read the next .sbr file and add all the defs/refs/cals/cbys etc to
|
||
|
// the various lists
|
||
|
//
|
||
|
{
|
||
|
WORD nlen;
|
||
|
|
||
|
VA vaCurSym; // current symbol
|
||
|
VA vaProp; // current property
|
||
|
VA vaOrd; // current property temp
|
||
|
|
||
|
BOOL fSymSet = FALSE; // TRUE if symbol set reference
|
||
|
|
||
|
r_lineno = 0;
|
||
|
|
||
|
fExclMod = FALSE;
|
||
|
fFirstMod = TRUE; // we haven't seen the first MODULE record yet
|
||
|
|
||
|
vaUnknownSym = MbrAddAtom ("<Unknown>", TRUE); // unknown module name
|
||
|
|
||
|
if (vaUnknownMod == vaNil) {
|
||
|
|
||
|
vaUnknownMod = VaAllocGrpCb(grpMod, sizeof(MOD));
|
||
|
|
||
|
vaCurMod = vaUnknownMod;
|
||
|
|
||
|
gMOD(vaCurMod).csyms = 0;
|
||
|
cMOD.vaNameSym = vaUnknownSym;
|
||
|
pMOD(vaCurMod);
|
||
|
|
||
|
gSYM(vaUnknownSym).vaFirstProp = vaCurMod; // store pointer back to MOD
|
||
|
pSYM(vaUnknownSym);
|
||
|
ModCnt++;
|
||
|
}
|
||
|
else
|
||
|
fDupMod = (vaUnknownMod != 0);
|
||
|
|
||
|
vaCurMod = vaUnknownMod;
|
||
|
|
||
|
if (vaRootMod == vaNil)
|
||
|
vaRootMod = vaCurMod;
|
||
|
|
||
|
while (GetSBRRec() != S_EOF) {
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
if (OptD & 1) DecodeSBR ();
|
||
|
#endif
|
||
|
|
||
|
if (cMacroDepth != 0) // skip SYMBOLS in macros if true
|
||
|
if (FSkipMacro ())
|
||
|
continue;
|
||
|
|
||
|
if (fExclMod) {
|
||
|
if ((r_rectyp == SBR_REC_MODULE) ||
|
||
|
(r_rectyp == SBR_REC_SYMDEF) ||
|
||
|
(r_rectyp == SBR_REC_MODEND)) {
|
||
|
;
|
||
|
}
|
||
|
else
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
switch(r_rectyp) {
|
||
|
|
||
|
case SBR_REC_MODULE:
|
||
|
PushMstk (); // save state
|
||
|
|
||
|
r_lineno = 0; // reset line no.
|
||
|
|
||
|
fDupMod = FALSE; // go to a known state
|
||
|
fExclMod = FALSE;
|
||
|
|
||
|
if (fExclMod = FInExcList (r_bname)) {
|
||
|
#ifdef DEBUG
|
||
|
if (OptD & 256)
|
||
|
printf (" module excluded = %s\n", r_bname);
|
||
|
#endif
|
||
|
vaCurMod = vaUnknownMod;
|
||
|
}
|
||
|
else if ((vaCurMod = VaSearchModule (r_bname)) != vaNil) {
|
||
|
if (gMOD(vaCurMod).csyms == 0) {
|
||
|
fDupMod = TRUE;
|
||
|
#ifdef DEBUG
|
||
|
if (OptD & 256)
|
||
|
printf (" module redef = %s\n", r_bname);
|
||
|
#endif
|
||
|
}
|
||
|
else {
|
||
|
cMOD.csyms = 0;
|
||
|
pMOD(vaCurMod);
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
if (OptD & 256)
|
||
|
printf (" module subst = %s\n", r_bname);
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
SetVMClient(VM_ADD_MOD);
|
||
|
ModCnt++;
|
||
|
vaCurMod = VaAllocGrpCb(grpMod, sizeof(MOD));
|
||
|
gMOD(vaCurMod);
|
||
|
cMOD.vaFirstModSym = vaNil;
|
||
|
cMOD.csyms = 0;
|
||
|
cMOD.vaNameSym =
|
||
|
MbrAddAtom (ToCanonPath(r_bname, r_cwd, c_cwd), TRUE);
|
||
|
cMOD.vaNextMod = vaRootMod;
|
||
|
pMOD(vaCurMod);
|
||
|
|
||
|
vaRootMod = vaCurMod;
|
||
|
|
||
|
gSYM(cMOD.vaNameSym).vaFirstProp = vaCurMod; // ptr to MOD
|
||
|
pSYM(cMOD.vaNameSym);
|
||
|
|
||
|
SetVMClient(VM_MISC);
|
||
|
}
|
||
|
|
||
|
fFirstMod = FALSE;
|
||
|
break;
|
||
|
|
||
|
case SBR_REC_LINDEF:
|
||
|
break;
|
||
|
|
||
|
case SBR_REC_SYMDEF:
|
||
|
|
||
|
// if module is being excluded then just make the ord and prop entry
|
||
|
// in case it is referred to later.
|
||
|
|
||
|
// REVIEW For FORTRAN if ordinal is already defined
|
||
|
// REVIEW then this is a refined definition -- we
|
||
|
// REVIEW override the old definition with the new
|
||
|
// REVIEW one at this time -Rico
|
||
|
|
||
|
nlen = strlen (r_bname);
|
||
|
if (nlen > MaxSymLen) MaxSymLen = (BYTE)nlen;
|
||
|
|
||
|
vaCurSym = MbrAddAtom (r_bname, FALSE);
|
||
|
vaOrd = VaOrdAdd (); // add sym ord to ord list
|
||
|
gORD(vaOrd).vaOrdProp = VaPropAddToSym(vaCurSym);
|
||
|
pORD(vaOrd);
|
||
|
|
||
|
break;
|
||
|
|
||
|
case SBR_REC_OWNER:
|
||
|
if (!(vaProp = VaOrdFind(r_ordinal))) {
|
||
|
// emit error message in case of forward reference
|
||
|
// try to continue
|
||
|
//
|
||
|
#ifdef DEBUG
|
||
|
if (OptD & 4)
|
||
|
printf ("mbrmake: Owner Forward Reference(%d)\n",
|
||
|
r_ordinal);
|
||
|
#endif
|
||
|
break;
|
||
|
}
|
||
|
vaOwnerProp = vaProp;
|
||
|
break;
|
||
|
|
||
|
case SBR_REC_SYMREFSET:
|
||
|
fSymSet = TRUE;
|
||
|
// fall through
|
||
|
|
||
|
case SBR_REC_SYMREFUSE:
|
||
|
|
||
|
if (!(vaProp = VaOrdFind(r_ordinal))) {
|
||
|
// emit error message in case of forward reference
|
||
|
// try to continue
|
||
|
//
|
||
|
#ifdef DEBUG
|
||
|
if (OptD & 4)
|
||
|
printf ("mbrmake: Forward Reference(%d)\n", r_ordinal);
|
||
|
#endif
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
AddRefProp (vaProp);
|
||
|
break;
|
||
|
|
||
|
case SBR_REC_BLKBEG:
|
||
|
PushBstk(); // save state
|
||
|
break;
|
||
|
|
||
|
case SBR_REC_MACROBEG:
|
||
|
cMacroDepth++;
|
||
|
break;
|
||
|
|
||
|
case SBR_REC_MACROEND:
|
||
|
cMacroDepth--;
|
||
|
break;
|
||
|
|
||
|
case SBR_REC_BLKEND:
|
||
|
PopBstk();
|
||
|
break;
|
||
|
|
||
|
case SBR_REC_MODEND:
|
||
|
PopMstk();
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
SBRCorrupt ("unknown rec type");
|
||
|
Fatal ();
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
CheckStacksEmpty();
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
AddCalProp(VA vaCurProp)
|
||
|
// Add a symbol reference to the calling procedure's Calls/Uses list.
|
||
|
//
|
||
|
{
|
||
|
CAL cal;
|
||
|
|
||
|
SetVMClient(VM_SEARCH_CAL);
|
||
|
|
||
|
ENM_LIST (gPROP(vaOwnerProp).vaCalList, CAL) // proc call list
|
||
|
|
||
|
if (cCAL.vaCalProp == vaCurProp) {
|
||
|
cCAL.isbr = isbrCur;
|
||
|
cCAL.calcnt++; // multiple calls
|
||
|
ENM_PUT(CAL);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
ENM_END
|
||
|
|
||
|
cal.isbr = isbrCur;
|
||
|
cal.vaCalProp = vaCurProp; // symbol called or used
|
||
|
cal.calcnt = 1;
|
||
|
|
||
|
SetVMClient(VM_ADD_CAL);
|
||
|
|
||
|
VaAddList(&cPROP.vaCalList, &cal, sizeof(cal), grpCal);
|
||
|
|
||
|
pPROP(vaOwnerProp);
|
||
|
|
||
|
SetVMClient(VM_MISC);
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
if (OptD & 8) {
|
||
|
printf("New CAL for: ");
|
||
|
DebugDumpProp(vaOwnerProp);
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
AddCbyProp(VA vaCurProp)
|
||
|
// Add a symbol reference to it's property Called/Used by list.
|
||
|
//
|
||
|
{
|
||
|
CBY cby;
|
||
|
|
||
|
SetVMClient(VM_SEARCH_CBY);
|
||
|
|
||
|
ENM_LIST (gPROP(vaCurProp).vaCbyList, CBY) // prop called/used by list
|
||
|
|
||
|
if (cCBY.vaCbyProp == vaOwnerProp) {
|
||
|
cCBY.isbr = isbrCur;
|
||
|
cCBY.cbycnt++;
|
||
|
ENM_PUT(CBY);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
ENM_END
|
||
|
|
||
|
cby.isbr = isbrCur;
|
||
|
cby.vaCbyProp = vaOwnerProp; // symbol we are called or used by
|
||
|
cby.cbycnt = 1;
|
||
|
|
||
|
SetVMClient(VM_ADD_CBY);
|
||
|
|
||
|
VaAddList(&cPROP.vaCbyList, &cby, sizeof(cby), grpCby);
|
||
|
|
||
|
pPROP(vaCurProp);
|
||
|
|
||
|
SetVMClient(VM_MISC);
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
if (OptD & 8) {
|
||
|
printf("New CBY for: ");
|
||
|
DebugDumpProp(vaCurProp);
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
AddRefProp(VA vaCurProp)
|
||
|
// Add a symbol reference to it's property reference list.
|
||
|
//
|
||
|
{
|
||
|
VA vaRef, vaFileSym;
|
||
|
|
||
|
SetVMClient(VM_SEARCH_REF);
|
||
|
|
||
|
vaFileSym = gMOD(vaCurMod).vaNameSym;
|
||
|
|
||
|
gPROP(vaCurProp);
|
||
|
|
||
|
if (fDupMod) {
|
||
|
// try looking at the hint for this PROP if there is one, if there
|
||
|
// isn't then we're stuck -- we must search the whole REF list
|
||
|
//
|
||
|
|
||
|
if (vaRef = cPROP.vaHintRef) {
|
||
|
gREF(vaRef);
|
||
|
|
||
|
if (cREF.reflin == r_lineno) {
|
||
|
cREF.isbr = isbrCur;
|
||
|
pREF(vaRef);
|
||
|
SetVMClient(VM_MISC);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
vaRef = VaFrVp(cREF.vpNextRef);
|
||
|
if (vaRef) {
|
||
|
gREF(vaRef);
|
||
|
if (cREF.reflin == r_lineno) {
|
||
|
cREF.isbr = isbrCur;
|
||
|
pREF(vaRef);
|
||
|
cPROP.vaHintRef = vaRef;
|
||
|
pPROP(vaCurProp);
|
||
|
SetVMClient(VM_MISC);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
vaRef = VaFrVp(cPROP.vpFirstRef);
|
||
|
|
||
|
while (vaRef) {
|
||
|
gREF(vaRef);
|
||
|
if ((VaFrVp(cREF.vpFileSym) == vaFileSym) && // ignore multiple
|
||
|
(cREF.reflin == r_lineno)) { // references to same file & line
|
||
|
cREF.isbr = isbrCur;
|
||
|
pREF(vaRef);
|
||
|
cPROP.vaHintRef = vaRef;
|
||
|
pPROP(vaCurProp);
|
||
|
SetVMClient(VM_MISC);
|
||
|
return;
|
||
|
}
|
||
|
vaRef = VaFrVp(cREF.vpNextRef);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
if (vaRef = VaFrVp(cPROP.vpLastRef)) {
|
||
|
gREF(vaRef);
|
||
|
if (cREF.reflin == r_lineno &&
|
||
|
vaFileSym == VaFrVp(cREF.vpFileSym)) {
|
||
|
SetVMClient(VM_MISC);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
SetVMClient(VM_ADD_REF);
|
||
|
|
||
|
vaRef = VaAllocGrpCb(grpRef, sizeof(REF));
|
||
|
|
||
|
gREF(vaRef);
|
||
|
cREF.isbr = isbrCur;
|
||
|
cREF.reflin = r_lineno;
|
||
|
|
||
|
MkVpVa(cREF.vpFileSym, vaFileSym);
|
||
|
|
||
|
pREF(vaRef);
|
||
|
|
||
|
gPROP(vaCurProp);
|
||
|
|
||
|
AddTail (Ref, REF);
|
||
|
|
||
|
cPROP.cref++; // count references
|
||
|
cPROP.vaHintRef = vaRef;
|
||
|
|
||
|
pPROP(vaCurProp);
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
if (OptD & 8) {
|
||
|
printf("New REF for: ");
|
||
|
DebugDumpProp(vaCurProp);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
SetVMClient(VM_MISC);
|
||
|
|
||
|
if (vaOwnerProp) {
|
||
|
AddCbyProp (vaCurProp); // add to called/used by
|
||
|
AddCalProp (vaCurProp); // add to call/uses
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
AddDefProp(VA vaCurProp)
|
||
|
// Add a symbol definition to it's property definition list.
|
||
|
// -Set vaOwnerProp if symbol is an internal function.
|
||
|
{
|
||
|
DEF def;
|
||
|
VA vaFileSym;
|
||
|
|
||
|
#if 0
|
||
|
|
||
|
// if current symbol is FUNCTION and formally declared
|
||
|
// (block stack not empty), then remember it.
|
||
|
// Subsequent symbols are called by or used by this function.
|
||
|
//
|
||
|
// this is going away when all compilers support SBR_REC_OWNER
|
||
|
|
||
|
if ((r_attrib & SBR_TYPMASK) == SBR_TYP_FUNCTION)
|
||
|
if (pfblkstack != NULL && !(r_attrib & SBR_ATR_DECL_ONLY))
|
||
|
vaOwnerProp = vaCurProp;
|
||
|
#endif
|
||
|
|
||
|
vaFileSym = gMOD(vaCurMod).vaNameSym;
|
||
|
|
||
|
ENM_LIST (gPROP(vaCurProp).vaDefList, DEF) // proc def list
|
||
|
|
||
|
if ((cDEF.vaFileSym == vaFileSym) && // ignore multiple
|
||
|
(cDEF.deflin == r_lineno)) { // references to same file & line
|
||
|
cDEF.isbr = isbrCur;
|
||
|
ENM_PUT(DEF);
|
||
|
SetVMClient(VM_MISC);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
ENM_END
|
||
|
|
||
|
def.isbr = isbrCur;
|
||
|
def.deflin = r_lineno;
|
||
|
def.vaFileSym = vaFileSym;
|
||
|
|
||
|
SetVMClient(VM_ADD_DEF);
|
||
|
|
||
|
gPROP(vaCurProp);
|
||
|
|
||
|
VaAddList(&cPROP.vaDefList, &def, sizeof(def), grpDef);
|
||
|
|
||
|
pPROP(vaCurProp);
|
||
|
|
||
|
SetVMClient(VM_MISC);
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
if (OptD & 8) {
|
||
|
printf("New DEF for: ");
|
||
|
DebugDumpProp(vaCurProp);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
// don't count the definitions of the current proc as uses
|
||
|
|
||
|
if (vaOwnerProp && vaCurProp != vaOwnerProp) {
|
||
|
AddCbyProp (vaCurProp); // add to called/used by
|
||
|
AddCalProp (vaCurProp); // add to call/uses
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
VA
|
||
|
VaPropBestOfSym(VA vaSym)
|
||
|
//
|
||
|
// Returns property pointer if:
|
||
|
// 1). symbol is already defined,
|
||
|
// 2). attributes match (except for possibly ATR_DECL_ONLY)
|
||
|
//
|
||
|
// Idea is to recognize the definition of an external.
|
||
|
//
|
||
|
{
|
||
|
VA vaProp;
|
||
|
WORD sattr;
|
||
|
|
||
|
SetVMClient(VM_SEARCH_PROP);
|
||
|
|
||
|
vaProp = gSYM(vaSym).vaFirstProp;
|
||
|
|
||
|
while (vaProp) {
|
||
|
sattr = gPROP(vaProp).sattr;
|
||
|
|
||
|
if ((r_attrib & (~SBR_ATR_DECL_ONLY))
|
||
|
== (sattr & (~SBR_ATR_DECL_ONLY))) {
|
||
|
SetVMClient(VM_MISC);
|
||
|
return (vaProp);
|
||
|
}
|
||
|
|
||
|
vaProp = cPROP.vaNextProp;
|
||
|
}
|
||
|
|
||
|
SetVMClient(VM_MISC);
|
||
|
|
||
|
return vaNil;
|
||
|
}
|
||
|
|
||
|
VA
|
||
|
VaPropAddToSym(VA vaCurSym)
|
||
|
// Add a property node for the given symbol.
|
||
|
//
|
||
|
{
|
||
|
char fDupProp = FALSE;
|
||
|
VA vaCurProp;
|
||
|
|
||
|
if (vaCurProp = VaPropBestOfSym (vaCurSym)) {
|
||
|
if ( (cPROP.sattr & SBR_ATR_DECL_ONLY) &&
|
||
|
!(r_attrib & SBR_ATR_DECL_ONLY)) {
|
||
|
cPROP.sattr = r_attrib;
|
||
|
pPROP(vaCurProp);
|
||
|
}
|
||
|
fDupProp = TRUE;
|
||
|
}
|
||
|
else {
|
||
|
SetVMClient(VM_ADD_PROP);
|
||
|
|
||
|
vaCurProp = VaAllocGrpCb(grpProp, sizeof(PROP));
|
||
|
gPROP(vaCurProp);
|
||
|
cPROP.vaNameSym = vaCurSym;
|
||
|
cPROP.sattr = r_attrib;
|
||
|
|
||
|
if (gSYM(vaCurSym).vaFirstProp)
|
||
|
cPROP.vaNextProp = cSYM.vaFirstProp;
|
||
|
|
||
|
pPROP(vaCurProp);
|
||
|
|
||
|
cSYM.vaFirstProp = vaCurProp;
|
||
|
cSYM.cprop++;
|
||
|
pSYM(vaCurSym);
|
||
|
|
||
|
SetVMClient(VM_MISC);
|
||
|
}
|
||
|
|
||
|
if (!fExclMod) {
|
||
|
if (r_attrib & SBR_ATR_DECL_ONLY)
|
||
|
AddRefProp (vaCurProp); // treat extern as ref
|
||
|
else
|
||
|
AddDefProp (vaCurProp); // define others
|
||
|
}
|
||
|
|
||
|
return (vaCurProp);
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
BldModSymList ()
|
||
|
// Build each module's symbol list
|
||
|
//
|
||
|
{
|
||
|
WORD i;
|
||
|
VA vaMod, vaModSym, vaSym, vaProp;
|
||
|
|
||
|
SetVMClient(VM_BUILD_MODSYM);
|
||
|
|
||
|
// zero out module symbol counts
|
||
|
vaMod = vaRootMod;
|
||
|
while (vaMod) {
|
||
|
gMOD(vaMod);
|
||
|
cMOD.csyms = 0;
|
||
|
pMOD(vaMod);
|
||
|
vaMod = cMOD.vaNextMod;
|
||
|
}
|
||
|
|
||
|
for (i=0; i < cSymbolsMac; i++) {
|
||
|
vaSym = rgvaSymSorted[i];
|
||
|
|
||
|
if (!vaSym) continue;
|
||
|
|
||
|
vaProp = gSYM(vaSym).vaFirstProp;
|
||
|
|
||
|
while (vaProp) {
|
||
|
ENM_LIST(gPROP(vaProp).vaDefList, DEF)
|
||
|
|
||
|
vaMod = vaRootMod; // look at defs for each mod */
|
||
|
while (vaMod) {
|
||
|
if (cDEF.vaFileSym == gMOD(vaMod).vaNameSym) {
|
||
|
|
||
|
if (cMOD.vaLastModSym &&
|
||
|
gMODSYM(cMOD.vaLastModSym).vaFirstProp == vaProp)
|
||
|
goto break2; // duplicate
|
||
|
|
||
|
// belongs to this mod
|
||
|
cMOD.csyms++;
|
||
|
|
||
|
vaModSym = VaAllocGrpCb(grpModSym, sizeof(MODSYM));
|
||
|
gMODSYM(vaModSym);
|
||
|
cMODSYM.vaFirstProp = vaProp;
|
||
|
cMODSYM.vaNextModSym = 0;
|
||
|
pMODSYM(vaModSym);
|
||
|
|
||
|
if (!cMOD.vaFirstModSym)
|
||
|
cMOD.vaFirstModSym = cMOD.vaLastModSym = vaModSym;
|
||
|
else {
|
||
|
gMODSYM(cMOD.vaLastModSym).vaNextModSym = vaModSym;
|
||
|
pMODSYM(cMOD.vaLastModSym);
|
||
|
cMOD.vaLastModSym = vaModSym;
|
||
|
}
|
||
|
pMOD(vaMod);
|
||
|
break;
|
||
|
}
|
||
|
vaMod = cMOD.vaNextMod;
|
||
|
}
|
||
|
break2: ; // duplicate Modsyms will cause goto here
|
||
|
ENM_END
|
||
|
|
||
|
vaProp = cPROP.vaNextProp;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
SetVMClient(VM_MISC);
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
CleanUp()
|
||
|
// 1. Remove symbols that have no references.
|
||
|
// 2. Remove symbols that have only references
|
||
|
// 3. Connect used symbols with no definition to <Unknown>
|
||
|
//
|
||
|
{
|
||
|
WORD i;
|
||
|
VA vaSym, vaProp, vaPropNext, vaPropPrev = vaNil;
|
||
|
DEF def;
|
||
|
BOOL fDelete;
|
||
|
|
||
|
#define FExternAttr(attr) (!!(attr & SBR_ATR_DECL_ONLY))
|
||
|
#define FFunctionAttr(attr) ((attr & SBR_TYPMASK) == SBR_TYP_FUNCTION)
|
||
|
|
||
|
def.vaFileSym = vaUnknownSym;
|
||
|
def.deflin = 0;
|
||
|
def.isbr = 0xffff;
|
||
|
|
||
|
SetVMClient(VM_CLEAN_REFS);
|
||
|
|
||
|
for (i=0; i < cSymbolsMac; i++) {
|
||
|
vaSym = rgvaSymSorted[i];
|
||
|
|
||
|
vaPropPrev = vaNil;
|
||
|
|
||
|
vaProp = gSYM(vaSym).vaFirstProp;
|
||
|
|
||
|
while (vaProp) {
|
||
|
vaPropNext = gPROP(vaProp).vaNextProp;
|
||
|
fDelete = FALSE;
|
||
|
|
||
|
// figure out what to delete here
|
||
|
|
||
|
// if the symbol is used by anyone or uses anyone we must keep it
|
||
|
// regardless of all other considerations
|
||
|
//
|
||
|
if (((!cPROP.vaCalList) && (!cPROP.vaCbyList)) && (
|
||
|
// at this point we know there are only refs & defs
|
||
|
|
||
|
// if it is totally unreferenced & undefined it can go
|
||
|
(cPROP.cref == 0 && (!cPROP.vaDefList))
|
||
|
||
|
||
|
// if we're allowed to remove "useless" symbols then we try
|
||
|
((!OptIu) &&
|
||
|
// if there are only prototypes we can delete it
|
||
|
(((!cPROP.vaDefList) && FExternAttr(cPROP.sattr))
|
||
|
||
|
||
|
// or if it is unreferenced and is not a function
|
||
|
(cPROP.cref == 0 && (!FFunctionAttr(cPROP.sattr))))))) {
|
||
|
fDelete = TRUE; // nuke it
|
||
|
}
|
||
|
else if (!cPROP.vaDefList) {
|
||
|
|
||
|
// if we couldn't get rid of the thing, and there are no
|
||
|
// definitions for it then we must make a fake definition
|
||
|
// in the <Unknown> file. This will happen (in particular)
|
||
|
// for library functions that are called by someone
|
||
|
//
|
||
|
// library functions that are not called would fall under
|
||
|
// the case of a symbol with only prototypes above
|
||
|
|
||
|
VaAddList(&cPROP.vaDefList, &def, sizeof(def), grpDef);
|
||
|
pPROP(vaProp);
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
if (OptD & 32)
|
||
|
printf ("PROP unknown: %s\n", GetAtomStr (vaSym));
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
if (fDelete) {
|
||
|
#ifdef DEBUG
|
||
|
if (OptD & 32)
|
||
|
printf ("PROP deleted: %s\n", GetAtomStr (vaSym));
|
||
|
#endif
|
||
|
|
||
|
cSYM.cprop--;
|
||
|
|
||
|
if (vaPropPrev == vaNil) {
|
||
|
cSYM.vaFirstProp = vaPropNext;
|
||
|
}
|
||
|
else {
|
||
|
gPROP(vaPropPrev);
|
||
|
cPROP.vaNextProp = vaPropNext;
|
||
|
pPROP(vaPropPrev);
|
||
|
}
|
||
|
|
||
|
pSYM(vaSym);
|
||
|
}
|
||
|
else
|
||
|
vaPropPrev = vaProp; // prev = current
|
||
|
|
||
|
vaProp = vaPropNext;
|
||
|
}
|
||
|
|
||
|
if (!cSYM.cprop) {
|
||
|
#ifdef DEBUG
|
||
|
if (OptD & 32)
|
||
|
printf ("SYM deleted: %s\n", GetAtomStr (vaSym));
|
||
|
#endif
|
||
|
rgvaSymSorted[i] = vaNil;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
SetVMClient(VM_MISC);
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
FWildMatch(char *pchPat, char *pchText)
|
||
|
// return TRUE if pchText matchs pchPat in the dos wildcard sense
|
||
|
//
|
||
|
// REVIEW FWildMatch for 1.2 file name support
|
||
|
//
|
||
|
{
|
||
|
char chText, chPat;
|
||
|
|
||
|
for (;;) {
|
||
|
switch (*pchPat) {
|
||
|
|
||
|
case '\0':
|
||
|
return *pchText == '\0';
|
||
|
|
||
|
case '/':
|
||
|
case '\\':
|
||
|
if (*pchText != '/' && *pchText != '\\')
|
||
|
return FALSE;
|
||
|
|
||
|
pchText++;
|
||
|
pchPat++;
|
||
|
break;
|
||
|
|
||
|
case '.':
|
||
|
pchPat++;
|
||
|
switch (*pchText) {
|
||
|
|
||
|
case '.':
|
||
|
pchText++;
|
||
|
break;
|
||
|
|
||
|
case '\0': case '/': case '\\':
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
return FALSE;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case '*':
|
||
|
pchText += strcspn(pchText, ":./\\");
|
||
|
pchPat += strcspn(pchPat, ":./\\");
|
||
|
break;
|
||
|
|
||
|
case '?':
|
||
|
pchPat++;
|
||
|
switch (*pchText) {
|
||
|
|
||
|
case '\0': case '.': case '/': case '\\':
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
pchText++;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
chText = *pchText;
|
||
|
chPat = *pchPat;
|
||
|
|
||
|
if (islower(chText)) chText = (char)toupper(chText);
|
||
|
if (islower(chPat)) chPat = (char)toupper(chPat);
|
||
|
|
||
|
if (chText != chPat)
|
||
|
return FALSE;
|
||
|
|
||
|
pchPat++;
|
||
|
pchText++;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|