// // ADDTOLST.C - Add each record from the .SBR file to the approprate list. // #define LINT_ARGS #include "sbrfdef.h" #include "mbrmake.h" #include // 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 ("", 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 // { 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 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; } } }