-- ProcessingOrderImpl.mesa -- Last edited by Lewis on 16-Dec-81 12:32:36 -- Last edited by Satterthwaite, December 30, 1982 9:58 am DIRECTORY Alloc: TYPE USING [AddNotify, DropNotify, Handle, Notifier, Words], BcdDefs: TYPE USING [MTRecord, MTIndex, MTNull], Error: TYPE USING [ImplicitCDIncludesModule, ModuleInTwoSegments], PackagerDefs: TYPE USING [ globalData, GlobalData, packtreetype, packsttype, packpotype], ProcessingOrder: TYPE, SemanticEntry: TYPE USING [HTIndex, STIndex, STRecord], SourceBcd: TYPE USING [ ComponentKind, CTreeIndex, EnumerateModules, EnumerateModulesInConfig, IsModuleInConfig, IsTableCompiled, moduleCount, ModuleNum, nullModuleNum, ModuleNumForMti], Table: TYPE USING [Base, Limit], Tree: TYPE USING [Index, Link, Scan, Test, nullIndex], TreeOps: TYPE USING [ GetHash, GetNode, GetSe, ListHead, ListLength, ScanList, SearchList]; ProcessingOrderImpl: PROGRAM IMPORTS Alloc, Error, PackagerDefs, SourceBcd, TreeOps EXPORTS ProcessingOrder = BEGIN OPEN ProcessingOrder; POerror: PROC = {ERROR FindPOerror}; FindPOerror: PUBLIC ERROR = CODE; gd: PackagerDefs.GlobalData ← NIL; -- set by Determine table: Alloc.Handle ← NIL; tb, stb, pob: Table.Base; Notifier: Alloc.Notifier = { tb ← base[PackagerDefs.packtreetype]; stb ← base[PackagerDefs.packsttype]; pob ← base[PackagerDefs.packpotype]}; -- ********************* Global Data Structures *********************** -- orderDetermined: BOOL ← FALSE; -- Head of chain of PORecords for each module poChainHead: LONG POINTER TO POChainMap; POChainMap: TYPE = RECORD [SEQUENCE length: CARDINAL OF POIndex]; POIndex: TYPE = Table.Base RELATIVE POINTER[0..Table.Limit) TO PORecord; poNull: POIndex = POIndex.LAST; -- Indicates the next component description to process PORecord: TYPE = RECORD [ treeNode: Tree.Index, -- component description's parse tree node link: POIndex]; -- next PORecord in module's chain InitializeChainHeads: PROC = { poChainHead ← gd.zone.NEW[POChainMap[SourceBcd.moduleCount]]; FOR i: SourceBcd.ModuleNum IN [0..SourceBcd.moduleCount) DO poChainHead[i] ← poNull; ENDLOOP}; ReleaseChainHeads: PROC = { IF poChainHead # NIL THEN gd.zone.FREE[@poChainHead]}; InsertInPOChain: PROC [mti: BcdDefs.MTIndex, cdNode: Tree.Index] = { -- enter component description tree node in mti's p. o. chain mNum: SourceBcd.ModuleNum; newPO, last: POIndex; IF mti # BcdDefs.MTNull THEN { mNum ← SourceBcd.ModuleNumForMti[mti]; IF poChainHead[mNum] = poNull THEN { -- empty chain newPO ← NewPORecord[]; pob[newPO] ← PORecord[treeNode: cdNode, link: poNull]; poChainHead[mNum] ← newPO} ELSE FOR p: POIndex ← poChainHead[mNum], pob[p].link UNTIL p = poNull DO IF pob[p].treeNode = cdNode THEN RETURN; -- already in p.o. chain last ← p; REPEAT FINISHED => { newPO ← NewPORecord[]; pob[newPO] ← PORecord[treeNode: cdNode, link: poNull]; pob[last].link ← newPO}; ENDLOOP}}; NewPORecord: PROC RETURNS [newPO: POIndex] = { newPO ← table.Words[PackagerDefs.packpotype, SIZE[PORecord]]; pob[newPO] ← PORecord[treeNode: Tree.nullIndex, link: poNull]}; -- ***************** Module Processing Order Determination ****************** Determine: PUBLIC PROC = { IF orderDetermined THEN POerror[]; gd ← PackagerDefs.globalData; table ← gd.ownTable; table.AddNotify[Notifier]; InitializeChainHeads[]; EnterExplicitComponentDescs[]; EnterImplicitComponentDescs[]; EnterRemainingComponentDescs[]; -- main/ev/catchOfPL (implicit also) orderDetermined ← TRUE; VerifyModulesInOneSegment[]}; Destroy: PUBLIC PROC = { ReleaseChainHeads[]; IF table # NIL THEN {table.DropNotify[Notifier]; table ← NIL}; gd ← NIL; orderDetermined ← FALSE}; IsEmpty: PUBLIC PROC [mti: BcdDefs.MTIndex] RETURNS [reply: BOOL] = { -- return TRUE if no component description nodes to be processed for mti mNum: SourceBcd.ModuleNum = SourceBcd.ModuleNumForMti[mti]; IF ~orderDetermined THEN POerror[]; IF mNum = SourceBcd.nullModuleNum THEN POerror[]; RETURN[ poChainHead[mNum] = poNull ]}; Enumerate: PUBLIC PROC [ mti: BcdDefs.MTIndex, userProc: PROC [cdNode: Tree.Index] RETURNS [stop: BOOL]] = { -- output component description nodes to be processed for mti mNum: SourceBcd.ModuleNum = SourceBcd.ModuleNumForMti[mti]; IF ~orderDetermined THEN POerror[]; IF mNum = SourceBcd.nullModuleNum THEN POerror[]; FOR i: POIndex ← poChainHead[mNum], pob[i].link UNTIL i = poNull DO IF userProc[pob[i].treeNode] THEN RETURN; ENDLOOP}; --****** Put Explicit Component Descriptions in Processing Order Chains ****** EnterExplicitComponentDescs: PROC = { TreeOps.ScanList[gd.root, EnterExplicitCDsInSegments]}; EnterExplicitCDsInSegments: Tree.Scan = BEGIN segNode: Tree.Index = TreeOps.GetNode[t]; IF tb[segNode].name = codeSeg THEN EnterExplicitCDsInOneSeg[segNode] END; EnterExplicitCDsInOneSeg: PROC [segNode: Tree.Index] = BEGIN saveIndex: CARDINAL = gd.textIndex; gd.textIndex ← tb[segNode].info; TreeOps.ScanList[tb[segNode].son[2], EnterExplicitCDsInOneCodePack]; gd.textIndex ← saveIndex; END; EnterExplicitCDsInOneCodePack: Tree.Scan = BEGIN ProcessOneCD: Tree.Scan = BEGIN cdNode: Tree.Index = TreeOps.GetNode[t]; saveIndex: CARDINAL = gd.textIndex; gd.textIndex ← tb[cdNode].info; SELECT tb[cdNode].name FROM allComp => EnterAllCompCD[cdNode]; compItems => EnterCompItemsCD[cdNode]; exceptItems => EnterExceptItemsCD[cdNode]; ENDCASE; gd.textIndex ← saveIndex; END; cpNode: Tree.Index = TreeOps.GetNode[t]; TreeOps.ScanList[tb[cpNode].son[2], ProcessOneCD]; END; EnterAllCompCD: PROC [cdNode: Tree.Index] = BEGIN -- ComponentDesc ::= Component EnterOneModule: PROC [mti: BcdDefs.MTIndex] RETURNS [stop: BOOL] = {InsertInPOChain[mti, cdNode]; RETURN[FALSE]}; componentSE: SemanticEntry.STIndex = TreeOps.GetSe[tb[cdNode].son[1]]; WITH stb[componentSE] SELECT FROM module => InsertInPOChain[mti, cdNode]; config => SourceBcd.EnumerateModulesInConfig[ kind: prototype, configTreeNode: cNode, userProc: EnterOneModule]; ENDCASE; END; EnterCompItemsCD: PROC [cdNode: Tree.Index] = BEGIN -- ComponentDesc ::= Component [ItemList] EnterOneItem: Tree.Scan = BEGIN EnterOneModule: PROC [mti: BcdDefs.MTIndex] RETURNS [stop: BOOL] = {InsertInPOChain[mti, cdNode]; RETURN[FALSE]}; itemSE: SemanticEntry.STIndex = TreeOps.GetSe[t]; WITH stb[itemSE] SELECT FROM module => InsertInPOChain[mti, cdNode]; config => SourceBcd.EnumerateModulesInConfig[ kind: prototype, configTreeNode: cNode, userProc: EnterOneModule]; ENDCASE; END; componentSE: SemanticEntry.STIndex = TreeOps.GetSe[tb[cdNode].son[1]]; WITH stb[componentSE] SELECT FROM module => InsertInPOChain[mti, cdNode]; config => TreeOps.ScanList[tb[cdNode].son[2], EnterOneItem]; ENDCASE; END; EnterExceptItemsCD: PROC [cdNode: Tree.Index] = BEGIN -- ComponentDesc ::= Component EXCEPT [ItemList] componentSE: SemanticEntry.STIndex = TreeOps.GetSe[tb[cdNode].son[1]]; WITH stb[componentSE] SELECT FROM module => InsertInPOChain[mti, cdNode]; config => ExcludeItems[cdNode, tb[cdNode].son[2], cNode]; ENDCASE; END; ExcludeItems: PROC [ cdNode: Tree.Index, itemList: Tree.Link, configNode: SourceBcd.CTreeIndex] = BEGIN -- enter config's modules that are not (in/equal to) any item EnterModuleIfNotInList: PROC [ module: BcdDefs.MTIndex] RETURNS [stop: BOOL] = BEGIN inAnItem: BOOL; CheckIfModuleInItem: Tree.Test = BEGIN SeeIfModuleFound: PROC [mti: BcdDefs.MTIndex] RETURNS [stop: BOOL] = {IF module = mti THEN inAnItem ← TRUE; RETURN[inAnItem]}; -- item is either a module or a subconfiguration itemSE: SemanticEntry.STIndex = TreeOps.GetSe[t]; WITH stb[itemSE] SELECT FROM module => IF module = mti THEN inAnItem ← TRUE; config => SourceBcd.EnumerateModulesInConfig[ kind: prototype, configTreeNode: cNode, userProc: SeeIfModuleFound]; ENDCASE; RETURN[inAnItem]; -- continue search until found or end of list END; inAnItem ← FALSE; TreeOps.SearchList[itemList, CheckIfModuleInItem]; IF ~inAnItem THEN InsertInPOChain[module, cdNode]; RETURN[FALSE]; END; SourceBcd.EnumerateModulesInConfig[ kind: prototype, configTreeNode: configNode, userProc: EnterModuleIfNotInList]; END; --***** Put Implicit Component Descriptions in Processing Order Chains *****-- EnterImplicitComponentDescs: PROC = {TreeOps.ScanList[gd.root, EnterImplicitCDsInSegments]}; EnterImplicitCDsInSegments: Tree.Scan = BEGIN segNode: Tree.Index = TreeOps.GetNode[t]; IF tb[segNode].name = codeSeg THEN EnterImplicitCDsInOneSeg[segNode]; END; EnterImplicitCDsInOneSeg: PROC [segNode: Tree.Index] = BEGIN saveIndex: CARDINAL = gd.textIndex; gd.textIndex ← tb[segNode].info; TreeOps.ScanList[tb[segNode].son[2], EnterImplicitCDsInOneCodePack]; gd.textIndex ← saveIndex; END; EnterImplicitCDsInOneCodePack: Tree.Scan = BEGIN ProcessOneCD: Tree.Scan = BEGIN cdNode: Tree.Index = TreeOps.GetNode[t]; saveIndex: CARDINAL = gd.textIndex; gd.textIndex ← tb[cdNode].info; SELECT tb[cdNode].name FROM exceptPacks => EnterExceptPacksCD[cdNode]; itemsExceptPacks => EnterItemsExceptPacksCD[cdNode]; exceptPacksItems => EnterExceptPacksItemsCD[cdNode]; ENDCASE; gd.textIndex ← saveIndex; END; cpNode: Tree.Index = TreeOps.GetNode[t]; TreeOps.ScanList[tb[cpNode].son[2], ProcessOneCD]; END; EnterExceptPacksCD: PROC [cdNode: Tree.Index] = BEGIN -- ComponentDesc ::= Component EXCEPT PackList EnterOneImplicitCDModule: PROC [ mti: BcdDefs.MTIndex] RETURNS [stop: BOOL] = BEGIN InsertImplicitCDModuleInPOChain[mti, cdNode, tb[cdNode].son[2]]; RETURN[FALSE]; END; componentSE: SemanticEntry.STIndex = TreeOps.GetSe[tb[cdNode].son[1]]; WITH stb[componentSE] SELECT FROM module => InsertImplicitCDModuleInPOChain[ mti, cdNode, tb[cdNode].son[2]]; config => SourceBcd.EnumerateModulesInConfig[ kind: prototype, configTreeNode: cNode, userProc: EnterOneImplicitCDModule]; ENDCASE; END; InsertImplicitCDModuleInPOChain: PROC [ mti: BcdDefs.MTIndex, cdNode: Tree.Index, packList: Tree.Link] = BEGIN implicitCDIncludesMti: BOOL ← FALSE; CheckCDsOfOnePack: Tree.Scan = BEGIN cpSE: SemanticEntry.STIndex = TreeOps.GetSe[t]; WITH stb[cpSE] SELECT FROM codePack => implicitCDIncludesMti ← DoesImplicitCDInPackIncludeMti[ cpId: hti, cpNode: treeNode, module: mti]; ENDCASE; END; -- check that CDs in PackList that reference module mti are all explicit TreeOps.ScanList[packList, CheckCDsOfOnePack]; IF ~implicitCDIncludesMti THEN InsertInPOChain[mti, cdNode]; END; DoesImplicitCDInPackIncludeMti: PROC [ cpId: SemanticEntry.HTIndex, cpNode: Tree.Index, module: BcdDefs.MTIndex] RETURNS [reply: BOOL] = BEGIN ProcessOneCD: Tree.Scan = BEGIN cdNode: Tree.Index = TreeOps.GetNode[t]; SELECT tb[cdNode].name FROM exceptPacks, itemsExceptPacks, exceptPacksItems => BEGIN -- see if component includes/is module componentSE: SemanticEntry.STIndex = TreeOps.GetSe[tb[cdNode].son[1]]; WITH stb[componentSE] SELECT FROM module => IF mti = module THEN BEGIN Error.ImplicitCDIncludesModule[ error, hti, cpId, module]; reply ← TRUE; END; config => IF SourceBcd.IsModuleInConfig[prototype, module, cNode] THEN BEGIN Error.ImplicitCDIncludesModule[ error, hti, cpId, module]; reply ← TRUE; END; ENDCASE; END; ENDCASE; -- not an implicit component description END; reply ← FALSE; TreeOps.ScanList[tb[cpNode].son[2], ProcessOneCD]; END; EnterItemsExceptPacksCD: PROC [cdNode: Tree.Index] = BEGIN -- ComponentDesc ::= Component [ItemList] EXCEPT PackList EnterOneItem: Tree.Scan = BEGIN EnterOneImplicitCDModule: PROC [ mti: BcdDefs.MTIndex] RETURNS [stop: BOOL] = BEGIN InsertImplicitCDModuleInPOChain[mti, cdNode, tb[cdNode].son[3]]; RETURN[FALSE]; END; itemSE: SemanticEntry.STIndex = TreeOps.GetSe[t]; WITH stb[itemSE] SELECT FROM module => InsertImplicitCDModuleInPOChain[ mti, cdNode, tb[cdNode].son[3]]; config => SourceBcd.EnumerateModulesInConfig[ kind: prototype, configTreeNode: cNode, userProc: EnterOneImplicitCDModule]; ENDCASE; END; componentSE: SemanticEntry.STIndex = TreeOps.GetSe[tb[cdNode].son[1]]; WITH stb[componentSE] SELECT FROM config => TreeOps.ScanList[tb[cdNode].son[2], EnterOneItem]; ENDCASE; END; EnterExceptPacksItemsCD: PROC [cdNode: Tree.Index] = BEGIN -- ComponentDesc ::= Component EXCEPT PackList, [ItemList] componentSE: SemanticEntry.STIndex = TreeOps.GetSe[tb[cdNode].son[1]]; WITH stb[componentSE] SELECT FROM module => InsertImplicitCDModuleInPOChain[ mti, cdNode, tb[cdNode].son[2]]; config => ExcludeImplicitCDItems[ cdNode, tb[cdNode].son[3], tb[cdNode].son[3], cNode]; ENDCASE; END; ExcludeImplicitCDItems: PROC [ cdNode: Tree.Index, packList: Tree.Link, itemList: Tree.Link, configNode: SourceBcd.CTreeIndex] = BEGIN -- enter config's modules that are not (in/equal to) any item EnterModuleIfNotInList: PROC [ module: BcdDefs.MTIndex] RETURNS [stop: BOOL] = BEGIN inAnItem: BOOL; CheckIfModuleInItem: Tree.Test = BEGIN SeeIfModuleFound: PROC [mti: BcdDefs.MTIndex] RETURNS [stop: BOOL] = {IF module = mti THEN inAnItem ← TRUE; RETURN[inAnItem]}; -- item is either a module or a subconfiguration itemSE: SemanticEntry.STIndex = TreeOps.GetSe[t]; WITH stb[itemSE] SELECT FROM module => IF module = mti THEN inAnItem ← TRUE; config => SourceBcd.EnumerateModulesInConfig[ kind: prototype, configTreeNode: cNode, userProc: SeeIfModuleFound]; ENDCASE; RETURN[inAnItem]; -- continue search until found or end of list END; inAnItem ← FALSE; TreeOps.SearchList[itemList, CheckIfModuleInItem]; IF ~inAnItem THEN InsertImplicitCDModuleInPOChain[module, cdNode, packList]; RETURN[FALSE]; END; SourceBcd.EnumerateModulesInConfig[ kind: prototype, configTreeNode: configNode, userProc: EnterModuleIfNotInList]; END; -- ***** Put MAIN OF Component Descriptions in Processing Order Chains ***** EnterRemainingComponentDescs: PROC = { TreeOps.ScanList[gd.root, EnterRemainingCDsInSegments]}; EnterRemainingCDsInSegments: Tree.Scan = { segNode: Tree.Index = TreeOps.GetNode[t]; IF tb[segNode].name = codeSeg THEN EnterRemainingCDsInOneSeg[segNode]}; EnterRemainingCDsInOneSeg: PROC [segNode: Tree.Index] = { saveIndex: CARDINAL = gd.textIndex; gd.textIndex ← tb[segNode].info; TreeOps.ScanList[tb[segNode].son[2], EnterRemainingCDsInOneCodePack]; gd.textIndex ← saveIndex}; EnterRemainingCDsInOneCodePack: Tree.Scan = { ProcessOneCD: Tree.Scan = { cdNode: Tree.Index = TreeOps.GetNode[t]; SELECT tb[cdNode].name FROM mainOfPL, evOfPL, catchOfPL => EnterOneRemainingCD[cdNode]; ENDCASE}; cpNode: Tree.Index = TreeOps.GetNode[t]; TreeOps.ScanList[tb[cpNode].son[2], ProcessOneCD]}; EnterOneRemainingCD: PROC [cdNode: Tree.Index] = { -- ComponentDesc ::= MAIN OF PackList -- ComponentDesc ::= ENTRY VECTOR OF PackList -- ComponentDesc ::= CATCH CODE OF PackList saveIndex: CARDINAL = gd.textIndex; packList: Tree.Link = tb[cdNode].son[1]; EnterModulesOfOneOfSegsPacks: Tree.Scan = { cpNode: Tree.Index = TreeOps.GetNode[t]; InsertModulesOfOnePack[cpNode: cpNode, remainingCdNode: cdNode]}; EnterModulesOfOnePack: Tree.Scan = { cpSE: SemanticEntry.STIndex = TreeOps.GetSe[t]; WITH stb[cpSE] SELECT FROM codePack => InsertModulesOfOnePack[cpNode: treeNode, remainingCdNode: cdNode]; ENDCASE}; gd.textIndex ← tb[cdNode].info; IF TreeOps.ListLength[packList] = 1 THEN { -- packlist might only be name of current code segment firstInList: Tree.Link = TreeOps.ListHead[packList]; firstSE: SemanticEntry.STIndex = TreeOps.GetSe[firstInList]; WITH stb[firstSE] SELECT FROM segment => { segNode: Tree.Index = treeNode; TreeOps.ScanList[tb[segNode].son[2], EnterModulesOfOneOfSegsPacks]; RETURN}; ENDCASE}; TreeOps.ScanList[packList, EnterModulesOfOnePack]; gd.textIndex ← saveIndex}; InsertModulesOfOnePack: PROC [ cpNode: Tree.Index, remainingCdNode: Tree.Index] = { -- enter all modules in a code pack referenced by MAIN/ENTRY VECTOR/CATCH OF InsertAModule: PROC [mti: BcdDefs.MTIndex] RETURNS [BOOL] = { InsertInPOChain[mti, remainingCdNode]; RETURN[FALSE]}; ProcessOneCD: Tree.Scan = { cdNode: Tree.Index = TreeOps.GetNode[t]; SELECT tb[cdNode].name FROM mainOfPL, evOfPL, catchOfPL => NULL; ENDCASE => { componentSE: SemanticEntry.STIndex = TreeOps.GetSe[tb[cdNode].son[1]]; WITH stb[componentSE] SELECT FROM module => IF ~SourceBcd.IsTableCompiled[mti] THEN InsertInPOChain[mti, remainingCdNode]; config => SourceBcd.EnumerateModulesInConfig[ kind: prototype, configTreeNode: cNode, userProc: InsertAModule]; ENDCASE}}; TreeOps.ScanList[tb[cpNode].son[2], ProcessOneCD]}; -- ************ Verify That a Module Appears in Only One Segment ************- VerifyModulesInOneSegment: PROC = { SourceBcd.EnumerateModules[VerifyAModuleInOneSegment]}; VerifyAModuleInOneSegment: PROC [mti: BcdDefs.MTIndex] RETURNS [stop: BOOL] = BEGIN modulesSeg: Tree.Index; CheckOneCDNode: PROC [cdNode: Tree.Index] RETURNS [stop: BOOL] = BEGIN IF modulesSeg = Tree.nullIndex THEN modulesSeg ← tb[cdNode].seg ELSE IF modulesSeg # tb[cdNode].seg THEN BEGIN segId1: SemanticEntry.HTIndex = TreeOps.GetHash[tb[modulesSeg].son[1]]; segId2: SemanticEntry.HTIndex = TreeOps.GetHash[tb[tb[cdNode].seg].son[1]]; Error.ModuleInTwoSegments[error, mti, segId1, segId2]; RETURN[TRUE]; END; RETURN[FALSE]; END; modulesSeg ← Tree.nullIndex; Enumerate[mti, CheckOneCDNode]; RETURN[FALSE]; END; END.