-- SemanticEntryImpl.mesa -- Last edited by Lewis on 2-Apr-81 10:19:18 -- Last edited by Sweet on September 16, 1980 12:50 PM -- last edited by Levin on July 6, 1982 4:40 pm DIRECTORY Alloc USING [AddNotify, DropNotify, Handle, Notifier, Words], BcdDefs USING [MTIndex, MTNull], Error USING [ Error, ErrorHti, FrameInTwoFramePacks, FrameNotPlaced, TableCompModuleNotIncAsUnit], PackagerDefs USING [ globalData, packctreetype, packtreetype, packsttype], PackHeap USING [GetSpace, FreeSpace], SemanticEntry USING [STIndex, STRecord], SourceBcd USING [ ComponentKind, CTreeIndex, EnumerateModules, EnumerateModulesInConfig, FindModuleOrConfig, IsTableCompiled, LookupId, ModuleNum, moduleCount, ModuleNumForMti, NullCTreeIndex], SymTabDefs USING [HTIndex, HTNull], Table USING [Base], Tree: FROM "PackTree" USING [ Index, Link, Map, Null, NullIndex, root, Scan, Test], TreeOps: FROM "PackTreeOps" USING [ ListLength, ListHead, ListTail, ScanList, SearchList, UpdateList]; SemanticEntryImpl: PROGRAM IMPORTS Alloc, Error, PackagerDefs, PackHeap, SourceBcd, Tree, TreeOps EXPORTS SemanticEntry = BEGIN OPEN PackagerDefs, SemanticEntry; SEerror: PROC = {ERROR BuildSEerror}; BuildSEerror: PUBLIC ERROR = CODE; -- Parse tree, semantic table, and source bcd configuration tree bases table: Alloc.Handle ← NIL; tb, stb, ctreeb: Table.Base; Notifier: Alloc.Notifier = BEGIN tb ← base[PackagerDefs.packtreetype]; stb ← base[PackagerDefs.packsttype]; ctreeb ← base[PackagerDefs.packctreetype]; END; NewSemanticEntry: PROC RETURNS [newSE: STIndex] = BEGIN newSE ← table.Words[PackagerDefs.packsttype, SIZE[STRecord]]; stb[newSE] ← [ hti: SymTabDefs.HTNull, treeNode: Tree.NullIndex, kind: unknown[]]; END; -- *********************** Build semantic entries ************************ anyMergeSegments, anyMergeFramePacks: BOOLEAN; BuildSemanticEntries: PUBLIC PROC = BEGIN table ← PackagerDefs.globalData.ownTable; table.AddNotify[Notifier]; WITH Tree.root SELECT FROM subtree => BEGIN anyMergeSegments ← anyMergeFramePacks ← FALSE; InitializeFrameArray[]; RecordSegAndFramePackIds[]; -- and set anyMergeSegments, anyMergeFramePacks ProcessSegAndFramePacks[]; IF anyMergeSegments THEN ProcessMergeSegments[]; IF anyMergeFramePacks THEN ProcessMergeFramePacks[]; VerifyAllFramesPlaced[]; DestroyFrameArray[]; ReleaseSegAndFramePackIds[]; END; ENDCASE => SEerror[]; table.DropNotify[Notifier]; table ← NIL; END; -- ************* Verify correct placement of global frames ************* -- parse tree nodes of frame packs containing each global frame frameArray: LONG DESCRIPTOR FOR ARRAY SourceBcd.ModuleNum OF Tree.Index; InitializeFrameArray: PROC = BEGIN i: SourceBcd.ModuleNum; IF SourceBcd.moduleCount # 0 THEN BEGIN frameArray ← DESCRIPTOR[ PackHeap.GetSpace[SourceBcd.moduleCount*SIZE[Tree.Index]], SourceBcd.moduleCount]; FOR i IN [0..SourceBcd.moduleCount) DO frameArray[i] ← Tree.NullIndex; ENDLOOP; END ELSE frameArray ← DESCRIPTOR[NIL, 0]; END; DestroyFrameArray: PROC = {IF BASE[frameArray] # NIL THEN PackHeap.FreeSpace[BASE[frameArray]]}; MarkFramePlaced: PROC [mti: BcdDefs.MTIndex, fpNode: Tree.Index] = BEGIN mNum: SourceBcd.ModuleNum ← SourceBcd.ModuleNumForMti[mti]; IF frameArray[mNum] # Tree.NullIndex THEN BEGIN fpId1, fpId2: SymTabDefs.HTIndex; WITH tb[frameArray[mNum]].son[1] SELECT FROM hash => fpId1 ← index; ENDCASE => SEerror[]; WITH tb[fpNode].son[1] SELECT FROM hash => fpId2 ← index; ENDCASE => SEerror[]; Error.FrameInTwoFramePacks[error, mti, fpId1, fpId2]; END ELSE frameArray[mNum] ← fpNode; END; VerifyAllFramesPlaced: PROC = BEGIN VerifyOneFramePlaced: PROC [mti: BcdDefs.MTIndex] RETURNS [stop: BOOLEAN] = BEGIN mNum: SourceBcd.ModuleNum ← SourceBcd.ModuleNumForMti[mti]; IF frameArray[mNum] = Tree.NullIndex THEN Error.FrameNotPlaced[warning, mti]; RETURN[FALSE]; END; SourceBcd.EnumerateModules[VerifyOneFramePlaced]; END; -- ****** Management of segment and frame pack tree node arrays ****** segArray, fpArray: TreeNodeArray; TreeNodeArray: TYPE = LONG DESCRIPTOR FOR ARRAY OF Tree.Index; segCount, fpCount: CARDINAL; currentSeg, currentFP: CARDINAL; RecordSegAndFramePackIds: PROC = BEGIN segCount ← fpCount ← 0; TreeOps.ScanList[Tree.root, CountSegOrFPId]; IF segCount # 0 THEN segArray ← DESCRIPTOR[ PackHeap.GetSpace[segCount*SIZE[Tree.Index]], segCount] ELSE segArray ← DESCRIPTOR[NIL, 0]; IF fpCount # 0 THEN fpArray ← DESCRIPTOR[ PackHeap.GetSpace[fpCount*SIZE[Tree.Index]], fpCount] ELSE fpArray ← DESCRIPTOR[NIL, 0]; currentSeg ← currentFP ← 0; TreeOps.ScanList[Tree.root, NoteSegOrFPId]; END; ReleaseSegAndFramePackIds: PROC = BEGIN IF BASE[segArray] # NIL THEN PackHeap.FreeSpace[BASE[segArray]]; IF BASE[fpArray] # NIL THEN PackHeap.FreeSpace[BASE[fpArray]]; segCount ← fpCount ← 0; END; CountSegOrFPId: Tree.Scan = BEGIN WITH t SELECT FROM subtree => BEGIN node: Tree.Index = index; SELECT tb[node].name FROM codeSeg => segCount ← segCount+1; framePack => fpCount ← fpCount+1; merge => {segCount ← segCount+1; anyMergeSegments ← TRUE}; mergeFP => {fpCount ← fpCount+1; anyMergeFramePacks ← TRUE}; ENDCASE; END; ENDCASE => SEerror[]; END; NoteSegOrFPId: Tree.Scan = BEGIN nodeName: SymTabDefs.HTIndex; i: CARDINAL; saveIndex: CARDINAL = globalData.textIndex; WITH t SELECT FROM subtree => BEGIN node: Tree.Index = index; globalData.textIndex ← tb[node].info; WITH tb[node].son[1] SELECT FROM hash => nodeName ← index; ENDCASE => SEerror[]; SELECT tb[node].name FROM codeSeg, merge => BEGIN FOR i IN [0..currentSeg) DO WITH tb[segArray[i]].son[1] SELECT FROM hash => IF nodeName = index THEN BEGIN Error.ErrorHti[error, "appears twice as a code segment name"L, nodeName]; EXIT; END; ENDCASE => SEerror[]; ENDLOOP; segArray[currentSeg] ← node; currentSeg ← currentSeg+1; END; framePack, mergeFP => BEGIN FOR i IN [0..currentFP) DO WITH tb[fpArray[i]].son[1] SELECT FROM hash => IF nodeName = index THEN BEGIN Error.ErrorHti[error, "appears twice as a frame pack name"L, nodeName]; EXIT; END; ENDCASE => SEerror[]; ENDLOOP; fpArray[currentFP] ← node; currentFP ← currentFP+1; END; ENDCASE; END; ENDCASE => SEerror[]; globalData.textIndex ← saveIndex; END; FindSeg: PROC [ id: SymTabDefs.HTIndex] RETURNS [found: BOOLEAN, segNode: Tree.Index] = BEGIN i: CARDINAL; FOR i IN [0..segCount) DO segNode ← segArray[i]; WITH tb[segNode].son[1] SELECT FROM hash => IF id = index THEN RETURN[TRUE, segNode]; ENDCASE => SEerror[]; ENDLOOP; RETURN[FALSE, Tree.NullIndex]; END; FindFramePack: PROC [ id: SymTabDefs.HTIndex] RETURNS [found: BOOLEAN, fpNode: Tree.Index] = BEGIN i: CARDINAL; FOR i IN [0..fpCount) DO fpNode ← fpArray[i]; WITH tb[fpNode].son[1] SELECT FROM hash => IF id = index THEN RETURN[TRUE, fpNode]; ENDCASE => SEerror[]; ENDLOOP; RETURN[FALSE, Tree.NullIndex]; END; -- ****** Process the identifiers in code segments and frame packs ****** ProcessSegAndFramePacks: PROC = BEGIN ProcessSegOrFP: Tree.Scan = BEGIN WITH t SELECT FROM subtree => BEGIN node: Tree.Index = index; SELECT tb[node].name FROM codeSeg => ProcessOneCodeSeg[node]; framePack => ProcessOneFramePack[node]; ENDCASE; END; ENDCASE => SEerror[]; END; TreeOps.ScanList[Tree.root, ProcessSegOrFP]; END; -- ********************** Process a code segment ********************** currentSegId: SymTabDefs.HTIndex; currentSegNode: Tree.Index; cpArray: TreeNodeArray; -- Segment's code pack tree node array cpCount, currentCP: CARDINAL; ProcessOneCodeSeg: PROC [segNode: Tree.Index] = BEGIN saveIndex: CARDINAL = globalData.textIndex; globalData.textIndex ← tb[segNode].info; currentSegNode ← segNode; WITH tb[segNode].son[1] SELECT FROM hash => currentSegId ← index; ENDCASE => SEerror[]; RecordCodePackIds[segNode]; ProcessCodePacks[segNode]; ReleaseCodePackIds[]; globalData.textIndex ← saveIndex; END; RecordCodePackIds: PROC [segNode: Tree.Index] = BEGIN cpCount ← TreeOps.ListLength[tb[segNode].son[2]]; IF cpCount # 0 THEN cpArray ← DESCRIPTOR[ PackHeap.GetSpace[cpCount*SIZE[Tree.Index]], cpCount] ELSE cpArray ← DESCRIPTOR[NIL, 0]; currentCP ← 0; TreeOps.ScanList[tb[segNode].son[2], NoteCPId]; END; ReleaseCodePackIds: PROC = BEGIN IF BASE[cpArray] # NIL THEN PackHeap.FreeSpace[BASE[cpArray]]; cpCount ← 0; END; NoteCPId: Tree.Scan = BEGIN cpId: SymTabDefs.HTIndex; i: CARDINAL; WITH t SELECT FROM subtree => BEGIN cpNode: Tree.Index = index; SELECT tb[cpNode].name FROM codePack, unnamedCodePack, discardCodePack => BEGIN WITH tb[cpNode].son[1] SELECT FROM hash => cpId ← index; ENDCASE => SEerror[]; FOR i IN [0..currentCP) DO WITH tb[cpArray[i]].son[1] SELECT FROM hash => IF cpId = index THEN BEGIN Error.ErrorHti[error, "appears twice as a code pack name"L, cpId]; EXIT; END; ENDCASE => SEerror[]; ENDLOOP; cpArray[currentCP] ← cpNode; currentCP ← currentCP+1; END; ENDCASE => SEerror[]; END; ENDCASE => SEerror[]; END; FindCodePack: PROC [ id: SymTabDefs.HTIndex] RETURNS [found: BOOLEAN, cpNode: Tree.Index] = BEGIN i: CARDINAL; FOR i IN [0..cpCount) DO cpNode ← cpArray[i]; WITH tb[cpNode].son[1] SELECT FROM hash => IF id = index THEN RETURN[TRUE, cpNode]; ENDCASE => SEerror[]; ENDLOOP; RETURN[FALSE, Tree.NullIndex]; END; ProcessCodePacks: PROC [segNode: Tree.Index] = {TreeOps.ScanList[tb[segNode].son[2], ProcessOneCodePack]}; currentCpNode: Tree.Index; ProcessOneCodePack: Tree.Scan = BEGIN WITH t SELECT FROM subtree => BEGIN currentCpNode ← index; TreeOps.ScanList[tb[currentCpNode].son[2], ProcessOneComponentDesc]; END; ENDCASE => SEerror[]; END; ProcessOneComponentDesc: Tree.Scan = BEGIN saveIndex: CARDINAL = globalData.textIndex; WITH t SELECT FROM subtree => BEGIN cdNode: Tree.Index = index; globalData.textIndex ← tb[cdNode].info; SELECT tb[cdNode].name FROM allComp => ProcessAllComp[cdNode]; compItems => ProcessCompItems[cdNode]; exceptItems => ProcessExceptItems[cdNode]; exceptPacks => ProcessExceptPacks[cdNode]; itemsExceptPacks => ProcessItemsExceptPacks[cdNode]; exceptPacksItems => ProcessExceptPacksItems[cdNode]; mainProcs => ProcessMainProcs[cdNode]; ENDCASE => SEerror[]; tb[cdNode].cp ← currentCpNode; tb[cdNode].seg ← currentSegNode; END; ENDCASE => SEerror[]; globalData.textIndex ← saveIndex; END; ProcessAllComp: PROC [cdNode: Tree.Index] = BEGIN -- ComponentDesc ::= Component tb[cdNode].son[1] ← LookupComponent[tb[cdNode].son[1]]; END; ProcessCompItems: PROC [cdNode: Tree.Index] = BEGIN -- ComponentDesc ::= Component [ItemList] tb[cdNode].son[1] ← LookupComponent[tb[cdNode].son[1]]; WITH tb[cdNode].son[1] SELECT FROM symbol => BEGIN componentSE: STIndex = index; WITH stb[componentSE] SELECT FROM config => IF cNode # SourceBcd.NullCTreeIndex THEN tb[cdNode].son[2] ← LookupComponentItems[cNode, tb[cdNode].son[2]]; module => IF mNode # SourceBcd.NullCTreeIndex AND mti # BcdDefs.MTNull THEN IF SourceBcd.IsTableCompiled[mti] THEN Error.TableCompModuleNotIncAsUnit[error, mti]; ENDCASE; END; ENDCASE => SEerror[]; END; ProcessExceptItems: PROC [cdNode: Tree.Index] = BEGIN -- ComponentDesc ::= Component EXCEPT [ItemList] tb[cdNode].son[1] ← LookupComponent[tb[cdNode].son[1]]; WITH tb[cdNode].son[1] SELECT FROM symbol => BEGIN componentSE: STIndex = index; WITH stb[componentSE] SELECT FROM config => IF cNode # SourceBcd.NullCTreeIndex THEN tb[cdNode].son[2] ← LookupComponentItems[cNode, tb[cdNode].son[2]]; module => IF mNode # SourceBcd.NullCTreeIndex AND mti # BcdDefs.MTNull THEN IF SourceBcd.IsTableCompiled[mti] THEN Error.TableCompModuleNotIncAsUnit[error, mti]; ENDCASE; END; ENDCASE => SEerror[]; END; ProcessExceptPacks: PROC [cdNode: Tree.Index] = BEGIN -- ComponentDesc ::= Component EXCEPT PackList tb[cdNode].son[1] ← LookupComponent[tb[cdNode].son[1]]; WITH tb[cdNode].son[1] SELECT FROM symbol => BEGIN componentSE: STIndex = index; WITH stb[componentSE] SELECT FROM module => IF mNode # SourceBcd.NullCTreeIndex AND mti # BcdDefs.MTNull THEN IF SourceBcd.IsTableCompiled[mti] THEN Error.TableCompModuleNotIncAsUnit[error, mti]; ENDCASE; END; ENDCASE => SEerror[]; tb[cdNode].son[2] ← LookupCodePacks[tb[cdNode].son[2]]; END; ProcessItemsExceptPacks: PROC [cdNode: Tree.Index] = BEGIN -- ComponentDesc ::= Component [ItemList] EXCEPT PackList tb[cdNode].son[1] ← LookupComponent[tb[cdNode].son[1]]; WITH tb[cdNode].son[1] SELECT FROM symbol => BEGIN componentSE: STIndex = index; WITH stb[componentSE] SELECT FROM module => Error.Error[ error, "The component in this kind of component description must not be a module"L]; config => -- process ItemList IF cNode # SourceBcd.NullCTreeIndex THEN tb[cdNode].son[2] ← LookupComponentItems[cNode, tb[cdNode].son[2]]; ENDCASE; END; ENDCASE => SEerror[]; tb[cdNode].son[3] ← LookupCodePacks[tb[cdNode].son[3]]; END; ProcessExceptPacksItems: PROC [cdNode: Tree.Index] = BEGIN -- ComponentDesc ::= Component EXCEPT PackList, [ItemList] tb[cdNode].son[1] ← LookupComponent[tb[cdNode].son[1]]; tb[cdNode].son[2] ← LookupCodePacks[tb[cdNode].son[2]]; WITH tb[cdNode].son[1] SELECT FROM symbol => BEGIN componentSE: STIndex = index; WITH stb[componentSE] SELECT FROM config => IF cNode # SourceBcd.NullCTreeIndex THEN tb[cdNode].son[3] ← LookupComponentItems[cNode, tb[cdNode].son[3]]; module => IF mNode # SourceBcd.NullCTreeIndex AND mti # BcdDefs.MTNull THEN IF SourceBcd.IsTableCompiled[mti] THEN Error.TableCompModuleNotIncAsUnit[error, mti]; ENDCASE; END; ENDCASE => SEerror[]; END; ProcessMainProcs: PROC [cdNode: Tree.Index] = BEGIN -- ComponentDesc ::= MAIN OF PackList packList: Tree.Link = tb[cdNode].son[1]; IF tb[currentCpNode].name = unnamedCodePack THEN Error.Error[ error, "A MAIN OF component description can not be used to specify an unnamed code pack"L]; IF TreeOps.ListLength[packList] = 1 THEN BEGIN -- might be name of current code segment idLink: Tree.Link ← TreeOps.ListHead[packList]; WITH idLink SELECT FROM hash => BEGIN id: SymTabDefs.HTIndex = index; IF id = currentSegId THEN BEGIN segIdSE: STIndex ← NewSemanticEntry[]; stb[segIdSE] ← [ hti: currentSegId, treeNode: currentSegNode, kind: segment[]]; tb[cdNode].son[1] ← Tree.Link[symbol[index: segIdSE]]; RETURN; END; END; ENDCASE => SEerror[]; END; tb[cdNode].son[1] ← LookupCodePacks[packList]; END; LookupComponent: PROC [compList: Tree.Link] RETURNS [seLink: Tree.Link] = BEGIN componentSE: STIndex; WITH compList SELECT FROM subtree => BEGIN node: Tree.Index = index; saveIndex: CARDINAL = globalData.textIndex; globalData.textIndex ← tb[node].info; IF tb[node].name # component THEN SEerror[]; componentSE ← FindComponent[prototype, node]; globalData.textIndex ← saveIndex; END; ENDCASE => SEerror[]; RETURN[Tree.Link[symbol[componentSE]]]; END; LookupComponentItems: PROC [ configNode: SourceBcd.CTreeIndex, itemList: Tree.Link] RETURNS [itemSElist: Tree.Link] = BEGIN LookupOneComponentItem: Tree.Map = BEGIN itemSE: STIndex; WITH t SELECT FROM hash => BEGIN id: SymTabDefs.HTIndex = index; itemSE ← FindConfigItem[prototype, id, configNode]; END; subtree => BEGIN node: Tree.Index = index; IF tb[node].name = main THEN BEGIN Error.Error[error, "MAIN is not directly contained in a configuration"L]; itemSE ← NewSemanticEntry[]; stb[itemSE] ← [hti: SymTabDefs.HTNull, treeNode: Tree.NullIndex, kind: unknown[]]; END ELSE SEerror[]; END; ENDCASE => SEerror[]; RETURN[Tree.Link[symbol[itemSE]]]; END; RETURN[TreeOps.UpdateList[itemList, LookupOneComponentItem]]; END; LookupCodePacks: PROC [idList: Tree.Link] RETURNS [packList: Tree.Link] = {RETURN[TreeOps.UpdateList[idList, LookupOneCodePack]]}; LookupOneCodePack: Tree.Map = BEGIN newSE: STIndex ← NewSemanticEntry[]; cpNode: Tree.Index; found: BOOLEAN; WITH t SELECT FROM hash => BEGIN cpId: SymTabDefs.HTIndex = index; [found, cpNode] ← FindCodePack[cpId]; IF found THEN stb[newSE] ← [hti: cpId, treeNode: cpNode, kind: codePack[]] ELSE BEGIN Error.ErrorHti[error, "is not a code pack in the current segment"L, cpId]; stb[newSE] ← [hti: cpId, treeNode: Tree.NullIndex, kind: unknown[]]; END; RETURN[Tree.Link[symbol[newSE]]]; END; ENDCASE => SEerror[]; END; FindComponent: PROC [ kind: SourceBcd.ComponentKind, compNode: Tree.Index] RETURNS [compSE: STIndex] = BEGIN -- pass id stream (most qualified id first) to FindModuleOrConfig component: SourceBcd.CTreeIndex; idList: Tree.Link = tb[compNode].son[1]; idListLen: CARDINAL = TreeOps.ListLength[idList]; idListTail: Tree.Link = TreeOps.ListTail[idList]; currentIdNo: CARDINAL; ResetIdStream: PROC = {currentIdNo ← idListLen}; FirstQualId: PROC RETURNS [id: SymTabDefs.HTIndex] = BEGIN -- returns the first (i.e. rightmost or most qualified) id WITH idListTail SELECT FROM hash => id ← index; ENDCASE => SEerror[]; END; NextQualId: PROC RETURNS [id: SymTabDefs.HTIndex] = BEGIN -- returns next qualifying configuration id IF (currentIdNo ← currentIdNo-1) < 1 THEN RETURN [SymTabDefs.HTNull]; WITH idList SELECT FROM subtree => BEGIN node: Tree.Index = index; IF tb[node].name = list THEN WITH tb[node].son[currentIdNo] SELECT FROM hash => id ← index; ENDCASE => SEerror[] ELSE SEerror[]; END; ENDCASE => SEerror[]; END; IF idList = Tree.Null THEN SEerror[]; component ← SourceBcd.FindModuleOrConfig[ kind, ResetIdStream, FirstQualId, NextQualId]; compSE ← NewSemanticEntry[]; IF component = SourceBcd.NullCTreeIndex THEN stb[compSE] ← [hti: FirstQualId[], treeNode: compNode, kind: unknown[]] ELSE WITH ctreeb[component].index SELECT FROM config => stb[compSE] ← [ hti: FirstQualId[], treeNode: compNode, kind: config[cti: cti, cNode: component]]; module => stb[compSE] ← [ hti: FirstQualId[], treeNode: compNode, kind: module[mti: mti, mNode: component]]; ENDCASE; RETURN[compSE]; END; FindConfigItem: PROC [ kind: SourceBcd.ComponentKind, id: SymTabDefs.HTIndex, configNode: SourceBcd.CTreeIndex] RETURNS [itemSE: STIndex] = BEGIN -- find the directly contained module or config "id" in configNode item: SourceBcd.CTreeIndex; itemSE ← NewSemanticEntry[]; item ← SourceBcd.LookupId[id, kind]; WHILE item # SourceBcd.NullCTreeIndex DO IF ctreeb[item].father = configNode THEN EXIT; IF kind = instance THEN -- are there any alternatives? item ← ctreeb[item].instancePrev ELSE item ← ctreeb[item].prototypePrev; ENDLOOP; IF item = SourceBcd.NullCTreeIndex THEN BEGIN Error.ErrorHti[error, "is not a directly contained item"L, id]; stb[itemSE] ← [hti: id, treeNode: Tree.NullIndex, kind: unknown[]] END ELSE WITH ctreeb[item].index SELECT FROM config => stb[itemSE] ← [ hti: id, treeNode: Tree.NullIndex, kind: config[cti: cti, cNode: item]]; module => stb[itemSE] ← [ hti: id, treeNode: Tree.NullIndex, kind: module[mti: mti, mNode: item]]; ENDCASE; RETURN[itemSE]; END; -- ********************** Process a frame pack ********************** currentFpNode: Tree.Index; ProcessOneFramePack: PROC [fpNode: Tree.Index] = BEGIN saveIndex: CARDINAL = globalData.textIndex; globalData.textIndex ← tb[fpNode].info; currentFpNode ← fpNode; TreeOps.ScanList[tb[fpNode].son[2], ProcessOneFpCompDesc]; globalData.textIndex ← saveIndex; END; ProcessOneFpCompDesc: Tree.Scan = BEGIN saveIndex: CARDINAL = globalData.textIndex; WITH t SELECT FROM subtree => BEGIN cdNode: Tree.Index = index; globalData.textIndex ← tb[cdNode].info; SELECT tb[cdNode].name FROM allComp => AllFramesOfOneComponent[cdNode]; compItems => FramesOfComponentItems[cdNode]; ENDCASE => Error.Error[ error, "Invalid component description for a frame pack"L]; END; ENDCASE => SEerror[]; globalData.textIndex ← saveIndex; END; AllFramesOfOneComponent: PROC [cdNode: Tree.Index] = BEGIN -- ComponentDesc ::= Component (all global frames of component) tb[cdNode].son[1] ← LookupFpComponent[tb[cdNode].son[1]]; END; FramesOfComponentItems: PROC [cdNode: Tree.Index] = BEGIN -- ComponentDesc ::= Component [ItemList] (frames of component's items) componentSE: STIndex; WITH tb[cdNode].son[1] SELECT FROM -- process frame pack component subtree => BEGIN node: Tree.Index = index; saveIndex: CARDINAL = globalData.textIndex; globalData.textIndex ← tb[node].info; IF tb[node].name # component THEN SEerror[]; componentSE ← FindComponent[instance, node]; tb[cdNode].son[1] ← Tree.Link[symbol[componentSE]]; WITH stb[componentSE] SELECT FROM config => IF cNode # SourceBcd.NullCTreeIndex THEN tb[cdNode].son[2] ← LookupFpComponentItems[ cNode, tb[cdNode].son[2]]; module => Error.Error[ error, "A component description with an itemlist in a frame pack must name a configuration"L]; ENDCASE; globalData.textIndex ← saveIndex; END; ENDCASE => SEerror[]; END; LookupFpComponent: PROC [compList: Tree.Link] RETURNS [seLink: Tree.Link] = BEGIN componentSE: STIndex; MarkOneFramePlaced: PROC [mti: BcdDefs.MTIndex] RETURNS [stop: BOOLEAN] = {MarkFramePlaced[mti, currentFpNode]; RETURN[FALSE]}; WITH compList SELECT FROM -- process frame pack component subtree => BEGIN node: Tree.Index = index; saveIndex: CARDINAL = globalData.textIndex; globalData.textIndex ← tb[node].info; IF tb[node].name # component THEN SEerror[]; componentSE ← FindComponent[instance, node]; WITH stb[componentSE] SELECT FROM module => MarkFramePlaced[mti, currentFpNode]; config => SourceBcd.EnumerateModulesInConfig[ instance, cNode, MarkOneFramePlaced]; ENDCASE; globalData.textIndex ← saveIndex; END; ENDCASE => SEerror[]; RETURN[Tree.Link[symbol[componentSE]]]; END; LookupFpComponentItems: PROC [ compNode: SourceBcd.CTreeIndex, itemList: Tree.Link] RETURNS [itemSElist: Tree.Link] = BEGIN LookupOneFpComponentItem: Tree.Map = BEGIN itemSE: STIndex ← NewSemanticEntry[]; MarkOneFramePlaced: PROC [mti: BcdDefs.MTIndex] RETURNS [stop: BOOLEAN] = {MarkFramePlaced[mti, currentFpNode]; RETURN[FALSE]}; WITH t SELECT FROM hash => BEGIN id: SymTabDefs.HTIndex = index; itemSE ← FindConfigItem[instance, id, compNode]; WITH stb[itemSE] SELECT FROM module => MarkFramePlaced[mti, currentFpNode]; config => SourceBcd.EnumerateModulesInConfig[ instance, cNode, MarkOneFramePlaced]; ENDCASE; END; subtree => BEGIN node: Tree.Index = index; IF tb[node].name = main THEN BEGIN Error.Error[error, "MAIN procedures do not have global frames"L]; stb[itemSE] ← [hti: SymTabDefs.HTNull, treeNode: Tree.NullIndex, kind: unknown[]]; END ELSE SEerror[]; END; ENDCASE => SEerror[]; RETURN[Tree.Link[symbol[itemSE]]]; END; RETURN[TreeOps.UpdateList[itemList, LookupOneFpComponentItem]]; END; -- ********************** Process merged code segments ********************** ProcessMergeSegments: PROC = BEGIN LookForMergeSeg: Tree.Scan = BEGIN WITH t SELECT FROM subtree => BEGIN node: Tree.Index = index; SELECT tb[node].name FROM merge => ProcessOneMergeSeg[node]; ENDCASE; END; ENDCASE => SEerror[]; END; TreeOps.ScanList[Tree.root, LookForMergeSeg]; END; ProcessOneMergeSeg: PROC [mergeNode: Tree.Index] = BEGIN saveIndex: CARDINAL = globalData.textIndex; globalData.textIndex ← tb[mergeNode].info; ProcessIdsOfMergedOldSegs[mergeNode]; RecordCodePackIds[mergeNode]; ProcessMergeCodePacks[mergeNode]; VerifyAllOldCodePacksPlaced[mergeNode]; ReleaseCodePackIds[]; globalData.textIndex ← saveIndex; END; mergedOldSegIdList: Tree.Link; ProcessIdsOfMergedOldSegs: PROC [mergeNode: Tree.Index] = BEGIN mergedOldSegIdList ← tb[mergeNode].son[3] ← TreeOps.UpdateList[ tb[mergeNode].son[3], ProcessIdOfOneOldMergedSeg]; END; ProcessIdOfOneOldMergedSeg: Tree.Map = BEGIN oldSegSE: STIndex ← NewSemanticEntry[]; found: BOOLEAN; oldSegNode: Tree.Index; WITH t SELECT FROM hash => BEGIN oldSegId: SymTabDefs.HTIndex = index; [found, oldSegNode] ← FindSeg[oldSegId]; IF found THEN BEGIN stb[oldSegSE] ← [ hti: oldSegId, treeNode: oldSegNode, kind: segment[]]; tb[oldSegNode].attr2 ← TRUE; -- mark old segment superceded TreeOps.ScanList[tb[oldSegNode].son[2], MarkOldCodePackSuperceded]; END ELSE BEGIN Error.ErrorHti[error, "is not a known segment"L, oldSegId]; stb[oldSegSE] ← [ hti: oldSegId, treeNode: Tree.NullIndex, kind: unknown[]]; END; RETURN[Tree.Link[symbol[oldSegSE]]]; END; ENDCASE => SEerror[]; END; MarkOldCodePackSuperceded: Tree.Scan = BEGIN WITH t SELECT FROM subtree => BEGIN cpNode: Tree.Index = index; SELECT tb[cpNode].name FROM codePack, unnamedCodePack, discardCodePack => BEGIN tb[cpNode].attr2 ← TRUE; -- mark old code pack superceded and tb[cpNode].attr3 ← FALSE; -- not yet placed in new merge segment END; ENDCASE => SEerror[]; END; ENDCASE => SEerror[]; END; ProcessMergeCodePacks: PROC [mergeNode: Tree.Index] = {TreeOps.ScanList[tb[mergeNode].son[2], ProcessOneMergeCodePack]}; ProcessOneMergeCodePack: Tree.Scan = BEGIN WITH t SELECT FROM subtree => BEGIN cpNode: Tree.Index = index; IF tb[cpNode].attr1 THEN BEGIN Error.Error[ error, "A code pack in a merged segment can not contain an EXCEPT [MAIN] clause"L]; END; tb[cpNode].son[2] ← TreeOps.UpdateList[ tb[cpNode].son[2], ProcessOneMergeCompDesc]; END; ENDCASE => SEerror[]; END; ProcessOneMergeCompDesc: Tree.Map = BEGIN saveIndex: CARDINAL = globalData.textIndex; oldCpId: SymTabDefs.HTIndex; oldCpNode: Tree.Index; oldCpSE: STIndex ← NewSemanticEntry[]; WITH t SELECT FROM subtree => BEGIN cdNode: Tree.Index = index; globalData.textIndex ← tb[cdNode].info; SELECT tb[cdNode].name FROM allComp => BEGIN [oldCpId, oldCpNode] ← ProcessMergeComponent[tb[cdNode].son[1]]; stb[oldCpSE] ← [ hti: oldCpId, treeNode: oldCpNode, kind: codePack[]]; END; ENDCASE => BEGIN Error.Error[error, "A component description in a merged code segment may only be a reference to an old code pack"L]; stb[oldCpSE] ← [ hti: SymTabDefs.HTNull, treeNode: Tree.NullIndex, kind: unknown[]]; END; END; ENDCASE => SEerror[]; globalData.textIndex ← saveIndex; RETURN[Tree.Link[symbol[oldCpSE]]]; END; ProcessMergeComponent: PROC [ mergeCompLink: Tree.Link] RETURNS [oldCpId: SymTabDefs.HTIndex, oldCpNode: Tree.Index] = BEGIN oldCpIdLink: Tree.Link; WITH mergeCompLink SELECT FROM subtree => BEGIN compNode: Tree.Index = index; saveIndex: CARDINAL = globalData.textIndex; globalData.textIndex ← tb[compNode].info; IF tb[compNode].name # component THEN SEerror[]; oldCpIdLink ← TreeOps.ListTail[tb[compNode].son[1]]; WITH oldCpIdLink SELECT FROM hash => oldCpId ← index; ENDCASE => SEerror[]; oldCpNode ← FindOldCodePackNode[tb[compNode].son[1]]; IF oldCpNode # Tree.NullIndex THEN IF tb[oldCpNode].attr3 THEN Error.ErrorHti[ error, "was already placed in a merged segment"L, oldCpId] ELSE tb[oldCpNode].attr3 ← TRUE; -- mark placed in merged segment globalData.textIndex ← saveIndex; END; ENDCASE => SEerror[]; END; FindOldCodePackNode: PROC [oldCpIdList: Tree.Link] RETURNS [oldCpNode: Tree.Index] = BEGIN SELECT TreeOps.ListLength[oldCpIdList] FROM = 1 => -- oldCodePackId RETURN[FindUnQualOldCodePackNode[oldCpIdList]]; = 2 => -- oldSegmentId.oldCodePackId RETURN[FindQualOldCodePackNode[oldCpIdList]]; ENDCASE => BEGIN Error.Error[ error, "A component description for a merged code segment must be an optionally qualified old code pack name"L]; RETURN[Tree.NullIndex]; END; END; FindUnQualOldCodePackNode: PROC [oldCpIdList: Tree.Link] RETURNS [oldCpNode: Tree.Index] = BEGIN oldCpIdLink: Tree.Link; oldCpId: SymTabDefs.HTIndex; oldCpFound: BOOLEAN; LookForOldCpIdInOldSeg: Tree.Test = BEGIN oldSegNode: Tree.Index; WITH t SELECT FROM symbol => BEGIN oldSegSE: STIndex = index; WITH stb[oldSegSE] SELECT FROM segment => BEGIN oldSegNode ← treeNode; [oldCpFound, oldCpNode] ← LookupCpInOldSeg[oldCpId, oldSegNode]; END; ENDCASE => SEerror[]; END; ENDCASE => SEerror[]; RETURN[oldCpFound]; -- continue search until found END; oldCpIdLink ← TreeOps.ListTail[oldCpIdList]; WITH oldCpIdLink SELECT FROM hash => oldCpId ← index; ENDCASE => SEerror[]; oldCpFound ← FALSE; oldCpNode ← Tree.NullIndex; TreeOps.SearchList[mergedOldSegIdList, LookForOldCpIdInOldSeg]; IF ~oldCpFound THEN BEGIN Error.ErrorHti[error, "is not a known code pack"L, oldCpId]; RETURN[Tree.NullIndex]; END; END; FindQualOldCodePackNode: PROC [oldCpIdList: Tree.Link] RETURNS [oldCpNode: Tree.Index] = BEGIN oldSegIdLink, oldCpIdLink: Tree.Link; oldSegId, oldCpId: SymTabDefs.HTIndex; oldSegNode: Tree.Index; found: BOOLEAN; oldSegIdLink ← TreeOps.ListHead[oldCpIdList]; WITH oldSegIdLink SELECT FROM hash => oldSegId ← index; ENDCASE => SEerror[]; oldCpIdLink ← TreeOps.ListTail[oldCpIdList]; WITH oldCpIdLink SELECT FROM hash => oldCpId ← index; ENDCASE => SEerror[]; [found, oldSegNode] ← FindSeg[oldSegId]; IF ~found THEN BEGIN Error.ErrorHti[error, "is not a known segment"L, oldSegId]; RETURN[Tree.NullIndex]; END; VerifyInMergedSegIdList[oldSegId]; [found, oldCpNode] ← LookupCpInOldSeg[oldCpId, oldSegNode]; IF ~found THEN BEGIN Error.ErrorHti[error, "is not a known code pack"L, oldCpId]; RETURN[Tree.NullIndex]; END; END; VerifyInMergedSegIdList: PROC [oldSegId: SymTabDefs.HTIndex] = BEGIN inMergedSegIdList: BOOLEAN; LookForOldSegId: Tree.Test = BEGIN WITH t SELECT FROM symbol => BEGIN oldSegSE: STIndex = index; WITH stb[oldSegSE] SELECT FROM segment => IF hti = oldSegId THEN inMergedSegIdList ← TRUE; ENDCASE; END; ENDCASE => SEerror[]; RETURN[inMergedSegIdList]; -- continue search until found END; inMergedSegIdList ← FALSE; TreeOps.SearchList[mergedOldSegIdList, LookForOldSegId]; IF ~inMergedSegIdList THEN Error.ErrorHti[error, "is not a segment being merged"L, oldSegId]; END; LookupCpInOldSeg: PROC [ oldCpId: SymTabDefs.HTIndex, oldSegNode: Tree.Index] RETURNS [found: BOOLEAN, oldCpNode: Tree.Index] = BEGIN LookForOldCpId: Tree.Test = BEGIN WITH t SELECT FROM subtree => BEGIN cpNode: Tree.Index = index; WITH tb[cpNode].son[1] SELECT FROM hash => IF index = oldCpId THEN {found ← TRUE; oldCpNode ← cpNode}; ENDCASE => SEerror[]; END; ENDCASE => SEerror[]; RETURN[found]; -- continue search until found END; found ← FALSE; oldCpNode ← Tree.NullIndex; TreeOps.SearchList[tb[oldSegNode].son[2], LookForOldCpId]; END; VerifyAllOldCodePacksPlaced: PROC [mergeNode: Tree.Index] = BEGIN saveIndex: CARDINAL = globalData.textIndex; globalData.textIndex ← tb[mergeNode].info; TreeOps.ScanList[mergedOldSegIdList, VerifyOneOldSegsCodePacksPlaced]; globalData.textIndex ← saveIndex; END; VerifyOneOldSegsCodePacksPlaced: Tree.Scan = BEGIN oldSegNode: Tree.Index; WITH t SELECT FROM symbol => BEGIN oldSegSE: STIndex = index; WITH stb[oldSegSE] SELECT FROM segment => BEGIN oldSegNode ← treeNode; TreeOps.ScanList[tb[oldSegNode].son[2], VerifyOneOldCodePackPlaced]; END; ENDCASE; END; ENDCASE => SEerror[]; END; VerifyOneOldCodePackPlaced: Tree.Scan = BEGIN WITH t SELECT FROM subtree => BEGIN oldCpNode: Tree.Index = index; SELECT tb[oldCpNode].name FROM codePack, unnamedCodePack, discardCodePack => IF ~tb[oldCpNode].attr3 THEN -- wasn't placed in new merge segment BEGIN WITH tb[oldCpNode].son[1] SELECT FROM hash => BEGIN oldCpId: SymTabDefs.HTIndex ← index; Error.ErrorHti[ error, "was not placed in the merged segment"L, oldCpId]; END; ENDCASE => SEerror[]; END; ENDCASE => SEerror[]; END; ENDCASE => SEerror[]; END; -- ********************** Process merged frame packs ********************** ProcessMergeFramePacks: PROC = BEGIN LookForMergeFP: Tree.Scan = BEGIN WITH t SELECT FROM subtree => BEGIN node: Tree.Index = index; SELECT tb[node].name FROM mergeFP => ProcessOneMergeFP[node]; ENDCASE; END; ENDCASE => SEerror[]; END; TreeOps.ScanList[Tree.root, LookForMergeFP]; END; ProcessOneMergeFP: PROC [mergeFPNode: Tree.Index] = BEGIN saveIndex: CARDINAL = globalData.textIndex; globalData.textIndex ← tb[mergeFPNode].info; ProcessIdsOfMergedOldFPs[mergeFPNode]; globalData.textIndex ← saveIndex; END; mergedOldFPIdList: Tree.Link; ProcessIdsOfMergedOldFPs: PROC [mergeFPNode: Tree.Index] = BEGIN mergedOldFPIdList ← tb[mergeFPNode].son[2] ← TreeOps.UpdateList[ tb[mergeFPNode].son[2], ProcessIdOfOneOldMergedFP]; END; ProcessIdOfOneOldMergedFP: Tree.Map = BEGIN oldFPSE: STIndex ← NewSemanticEntry[]; found: BOOLEAN; oldFPNode: Tree.Index; WITH t SELECT FROM hash => BEGIN oldFPId: SymTabDefs.HTIndex = index; [found, oldFPNode] ← FindFramePack[oldFPId]; IF found THEN BEGIN stb[oldFPSE] ← [ hti: oldFPId, treeNode: oldFPNode, kind: framePack[]]; tb[oldFPNode].attr2 ← TRUE; -- mark old frame pack superceded END ELSE BEGIN Error.ErrorHti[error, "is not a known frame pack"L, oldFPId]; stb[oldFPSE] ← [ hti: oldFPId, treeNode: Tree.NullIndex, kind: unknown[]]; END; RETURN[Tree.Link[symbol[oldFPSE]]]; END; ENDCASE => SEerror[]; END; END.