-- ProcessingOrderImpl.mesa  
-- Last edited by Lewis on 31-Dec-80 10:07:15
-- Last edited by Levin on July 6, 1982 4:36 pm

DIRECTORY
  Alloc USING [AddNotify, DropNotify, Handle, Notifier, Words],
  BcdDefs USING [MTRecord, MTIndex, MTNull],
  Error USING [ImplicitCDIncludesModule, ModuleInTwoSegments],
  PackagerDefs USING [
    globalData, packctreetype, packtreetype, packsttype, packpotype],
  PackHeap USING [GetSpace, FreeSpace],
  ProcessingOrder,
  SemanticEntry USING [STIndex, STRecord],
  SourceBcd USING [
    ComponentKind, CTreeIndex, EnumerateModules, EnumerateModulesInConfig,
    IsModuleInConfig, IsTableCompiled, moduleCount, ModuleNum,
    NullModuleNum, ModuleNumForMti],
  SymTabDefs USING [HTIndex],
  Table USING [Base, Limit],
  Tree: FROM "PackTree" USING [Index, Link, NullIndex, root, Scan, Test],
  TreeOps: FROM "PackTreeOps" USING [ListHead, ListLength, ScanList, SearchList];

ProcessingOrderImpl: PROGRAM
    IMPORTS Alloc, Error, PackagerDefs, PackHeap, SourceBcd, Tree, TreeOps
    EXPORTS ProcessingOrder =
  BEGIN OPEN PackagerDefs, ProcessingOrder;

  POerror: PROC = {ERROR FindPOerror};
  FindPOerror: PUBLIC ERROR = CODE;


 -- Parse tree, semantic entry, config tree, and processing order table bases
  table: Alloc.Handle ← NIL;
  tb, stb, ctreeb, pob: Table.Base;

  Notifier: Alloc.Notifier =
    BEGIN
    tb     ← base[PackagerDefs.packtreetype];  
    stb    ← base[PackagerDefs.packsttype];
    ctreeb ← base[PackagerDefs.packctreetype];
    pob    ← base[PackagerDefs.packpotype];
    END;


 -- ********************* Global Data Structures *********************** --

  orderDetermined: BOOLEAN ← FALSE;

  -- Head and tail of chain of PORecords for each module
  POChainHead: LONG DESCRIPTOR FOR ARRAY SourceBcd.ModuleNum OF POIndex;

  POIndex: TYPE = Table.Base RELATIVE POINTER [0..Table.Limit) TO PORecord;
    PONull: POIndex = LAST[POIndex];

  -- 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 =
    BEGIN
    i: SourceBcd.ModuleNum;
    IF SourceBcd.moduleCount # 0 THEN 
      BEGIN
      POChainHead ← DESCRIPTOR[
        PackHeap.GetSpace[SourceBcd.moduleCount*SIZE[POIndex]], SourceBcd.moduleCount];
      FOR i IN [0..SourceBcd.moduleCount) DO 
        POChainHead[i] ← PONull; 
        ENDLOOP;
      END
    ELSE POChainHead ← DESCRIPTOR[NIL, 0];
    END;

  ReleaseChainHeads: PROC = 
    {IF BASE[POChainHead] # NIL THEN PackHeap.FreeSpace[BASE[POChainHead]]};

  InsertInPOChain: PROC [mti: BcdDefs.MTIndex, cdNode: Tree.Index] =
    BEGIN  -- enter component description tree node in mti's p. o. chain
    mNum: SourceBcd.ModuleNum;
    newPO, p, last: POIndex;
    IF mti # BcdDefs.MTNull THEN 
      BEGIN
      mNum ← SourceBcd.ModuleNumForMti[mti];
      IF POChainHead[mNum] = PONull THEN  -- empty chain
	BEGIN 
        newPO ← NewPORecord[];
        pob[newPO] ← PORecord[treeNode: cdNode, link: PONull];
        POChainHead[mNum] ← newPO; 
	END 
      ELSE 
        FOR p ← 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 => 
	      BEGIN
              newPO ← NewPORecord[];
              pob[newPO] ← PORecord[treeNode: cdNode, link: PONull];
	      pob[last].link ← newPO;
	      END;
	  ENDLOOP;
      END;
    END;

  NewPORecord: PROC RETURNS [newPO: POIndex] =
    BEGIN
    newPO ← table.Words[PackagerDefs.packpotype, SIZE[PORecord]];
    pob[newPO] ← PORecord[treeNode: Tree.NullIndex, link: PONull];
    END;


 -- ***************** Module Processing Order Determination ******************

  Determine: PUBLIC PROC =
    BEGIN
    IF orderDetermined THEN POerror[];
    table ← PackagerDefs.globalData.ownTable;
    table.AddNotify[Notifier];
    InitializeChainHeads[];
    WITH Tree.root SELECT FROM
      subtree => 
        BEGIN
        EnterExplicitComponentDescs[];
        EnterImplicitComponentDescs[];
        EnterMainOfComponentDescs[];  -- in fact, these are implicit also
        orderDetermined ← TRUE;
        VerifyModulesInOneSegment[];
        END;
      ENDCASE => POerror[];
    END;

  Destroy: PUBLIC PROC =
    BEGIN
    IF ~orderDetermined THEN POerror[];
    ReleaseChainHeads[];
    table.DropNotify[Notifier];
    orderDetermined ← FALSE;
    END;

  IsEmpty: PUBLIC PROC [mti: BcdDefs.MTIndex] RETURNS [reply: BOOLEAN] =
    BEGIN
    -- 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) ];
    END;

  Enumerate: PUBLIC PROC [
      mti: BcdDefs.MTIndex, 
      userProc: PROC [cdNode: Tree.Index] RETURNS [stop: BOOLEAN]] =
    BEGIN  -- output component description nodes to be processed for mti
    mNum: SourceBcd.ModuleNum = SourceBcd.ModuleNumForMti[mti];
    i: POIndex;
    IF ~orderDetermined THEN POerror[];
    IF mNum = SourceBcd.NullModuleNum THEN POerror[];
    FOR i ← POChainHead[mNum], pob[i].link UNTIL i = PONull DO
      IF userProc[pob[i].treeNode] THEN RETURN;
      ENDLOOP;
    END;


--****** Put Explicit Component Descriptions in Processing Order Chains ******

  EnterExplicitComponentDescs: PROC =
    {TreeOps.ScanList[Tree.root, EnterExplicitCDsInSegments]};

  EnterExplicitCDsInSegments: Tree.Scan =
    BEGIN
    WITH t SELECT FROM
      subtree =>
        BEGIN segNode: Tree.Index = index;
        IF tb[segNode].name = codeSeg THEN EnterExplicitCDsInOneSeg[segNode];
        END;
      ENDCASE => POerror[];
    END;

  EnterExplicitCDsInOneSeg: PROC [segNode: Tree.Index] =
    BEGIN
    saveIndex: CARDINAL = globalData.textIndex;
    globalData.textIndex ← tb[segNode].info;
    TreeOps.ScanList[tb[segNode].son[2], EnterExplicitCDsInOneCodePack];
    globalData.textIndex ← saveIndex;
    END;

  EnterExplicitCDsInOneCodePack: Tree.Scan =
    BEGIN

    ProcessOneCD: Tree.Scan =
      BEGIN
      WITH t SELECT FROM
        subtree =>
          BEGIN cdNode: Tree.Index = index;
          saveIndex: CARDINAL = globalData.textIndex;
          globalData.textIndex ← tb[cdNode].info;
          SELECT tb[cdNode].name FROM
            allComp     => EnterAllCompCD[cdNode];
            compItems   => EnterCompItemsCD[cdNode];
            exceptItems => EnterExceptItemsCD[cdNode];
            ENDCASE;
          globalData.textIndex ← saveIndex;
          END;
        ENDCASE => POerror[];
      END;
  
    WITH t SELECT FROM
      subtree =>
        BEGIN cpNode: Tree.Index = index;
        TreeOps.ScanList[tb[cpNode].son[2], ProcessOneCD];
        END;
      ENDCASE => POerror[];
    END;


  EnterAllCompCD: PROC [cdNode: Tree.Index] =
    BEGIN  -- ComponentDesc ::= Component 
    EnterOneModule: PROC [mti: BcdDefs.MTIndex] RETURNS [stop: BOOLEAN] =
      {InsertInPOChain[mti, cdNode];  RETURN[FALSE]};
  
    WITH tb[cdNode].son[1] SELECT FROM
      symbol => 
        BEGIN componentSE: SemanticEntry.STIndex = index;
	WITH stb[componentSE] SELECT FROM
          module => InsertInPOChain[mti, cdNode]; 
          config => SourceBcd.EnumerateModulesInConfig[
	    kind: prototype, configTreeNode: cNode, userProc: EnterOneModule]; 
          ENDCASE;
        END;
      ENDCASE => POerror[];
    END;


  EnterCompItemsCD: PROC [cdNode: Tree.Index] =
    BEGIN  -- ComponentDesc ::= Component [ItemList]

    EnterOneItem: Tree.Scan =
      BEGIN
      EnterOneModule: PROC [mti: BcdDefs.MTIndex] RETURNS [stop: BOOLEAN] =
        {InsertInPOChain[mti, cdNode];  RETURN[FALSE]};
    
      WITH t SELECT FROM
        symbol =>
          BEGIN itemSE: SemanticEntry.STIndex = index;
	  WITH stb[itemSE] SELECT FROM
            module => InsertInPOChain[mti, cdNode]; 
            config => SourceBcd.EnumerateModulesInConfig[
	      kind: prototype, configTreeNode: cNode, userProc: EnterOneModule];
            ENDCASE;
          END;
        ENDCASE => POerror[];
      END;

    WITH tb[cdNode].son[1] SELECT FROM
      symbol => 
        BEGIN componentSE: SemanticEntry.STIndex = index;
	WITH stb[componentSE] SELECT FROM
          module => InsertInPOChain[mti, cdNode]; 
          config => TreeOps.ScanList[tb[cdNode].son[2], EnterOneItem];
          ENDCASE;
        END;
      ENDCASE => POerror[];
    END;


  EnterExceptItemsCD: PROC [cdNode: Tree.Index] =
    BEGIN  -- ComponentDesc ::= Component EXCEPT [ItemList]
    WITH tb[cdNode].son[1] SELECT FROM
      symbol => 
        BEGIN componentSE: SemanticEntry.STIndex = index;
	WITH stb[componentSE] SELECT FROM
          module => InsertInPOChain[mti, cdNode]; 
          config => ExcludeItems[cdNode, tb[cdNode].son[2], cNode];
          ENDCASE;
        END;
      ENDCASE => POerror[];
    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: BOOLEAN] =
      BEGIN
      inAnItem: BOOLEAN;

      CheckIfModuleInItem: Tree.Test =
        BEGIN 
        SeeIfModuleFound: PROC [mti: BcdDefs.MTIndex] RETURNS [stop: BOOLEAN] =
          {IF module = mti THEN inAnItem ← TRUE;  RETURN[inAnItem]};

        WITH t SELECT FROM
          symbol =>  -- item is either a module or a subconfiguration
            BEGIN itemSE: SemanticEntry.STIndex = index;
    	    WITH stb[itemSE] SELECT FROM
              module => IF module = mti THEN inAnItem ← TRUE;  
              config => SourceBcd.EnumerateModulesInConfig[
	        kind: prototype, configTreeNode: cNode, userProc: SeeIfModuleFound];
    	      ENDCASE;
            END;
          ENDCASE => POerror[];
        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[Tree.root, EnterImplicitCDsInSegments]};

  EnterImplicitCDsInSegments: Tree.Scan =
    BEGIN
    WITH t SELECT FROM
      subtree =>
        BEGIN segNode: Tree.Index = index;
        IF tb[segNode].name = codeSeg THEN EnterImplicitCDsInOneSeg[segNode];
        END;
      ENDCASE => POerror[];
    END;

  EnterImplicitCDsInOneSeg: PROC [segNode: Tree.Index] =
    BEGIN
    saveIndex: CARDINAL = globalData.textIndex;
    globalData.textIndex ← tb[segNode].info;
    TreeOps.ScanList[tb[segNode].son[2], EnterImplicitCDsInOneCodePack];
    globalData.textIndex ← saveIndex;
    END;

  EnterImplicitCDsInOneCodePack: Tree.Scan =
    BEGIN

    ProcessOneCD: Tree.Scan =
      BEGIN
      WITH t SELECT FROM
        subtree =>
          BEGIN cdNode: Tree.Index = index;
          saveIndex: CARDINAL = globalData.textIndex;
          globalData.textIndex ← tb[cdNode].info;
          SELECT tb[cdNode].name FROM
            exceptPacks      => EnterExceptPacksCD[cdNode];
            itemsExceptPacks => EnterItemsExceptPacksCD[cdNode];
            exceptPacksItems => EnterExceptPacksItemsCD[cdNode];
            ENDCASE;
          globalData.textIndex ← saveIndex;
          END;
        ENDCASE => POerror[];
      END;
  
    WITH t SELECT FROM
      subtree =>
        BEGIN cpNode: Tree.Index = index;
        TreeOps.ScanList[tb[cpNode].son[2], ProcessOneCD];
        END;
      ENDCASE => POerror[];
    END;


  EnterExceptPacksCD: PROC [cdNode: Tree.Index] =
    BEGIN  -- ComponentDesc ::= Component EXCEPT PackList

    EnterOneImplicitCDModule: PROC [
        mti: BcdDefs.MTIndex] RETURNS [stop: BOOLEAN] =
      BEGIN
      InsertImplicitCDModuleInPOChain[mti, cdNode, tb[cdNode].son[2]];
      RETURN[FALSE];
      END;

    WITH tb[cdNode].son[1] SELECT FROM
      symbol => 
        BEGIN componentSE: SemanticEntry.STIndex = index;
	WITH stb[componentSE] SELECT FROM
          module => InsertImplicitCDModuleInPOChain[
              mti, cdNode, tb[cdNode].son[2]]; 
          config => SourceBcd.EnumerateModulesInConfig[
              kind: prototype, configTreeNode: cNode, userProc: EnterOneImplicitCDModule]; 
          ENDCASE;
        END;
      ENDCASE => POerror[];
    END;

  InsertImplicitCDModuleInPOChain: PROC [
      mti: BcdDefs.MTIndex, cdNode: Tree.Index, packList: Tree.Link] =
    BEGIN
    implicitCDIncludesMti: BOOLEAN ← FALSE;

    CheckCDsOfOnePack: Tree.Scan =
      BEGIN
      WITH t SELECT FROM
        symbol =>
          BEGIN cpSE: SemanticEntry.STIndex = index;
	  WITH stb[cpSE] SELECT FROM
            codePack => 
	      implicitCDIncludesMti ← DoesImplicitCDInPackIncludeMti[
		cpId: hti, cpNode: treeNode, module: mti];
            ENDCASE;
          END;
        ENDCASE => POerror[];
      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: SymTabDefs.HTIndex, cpNode: Tree.Index, module: BcdDefs.MTIndex]
      RETURNS [reply: BOOLEAN] =
    BEGIN

    ProcessOneCD: Tree.Scan =
      BEGIN
      WITH t SELECT FROM
        subtree =>
          BEGIN cdNode: Tree.Index = index;
          SELECT tb[cdNode].name FROM
	    exceptPacks, itemsExceptPacks, exceptPacksItems =>
	      BEGIN  -- see if component includes/is module 
	      WITH tb[cdNode].son[1] SELECT FROM
                symbol => 
                  BEGIN componentSE: SemanticEntry.STIndex = index;
        	  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 => POerror[];
              END;
            ENDCASE;  -- not an implicit component description
          END;
        ENDCASE => POerror[];
      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: BOOLEAN] =
        BEGIN
        InsertImplicitCDModuleInPOChain[mti, cdNode, tb[cdNode].son[3]];
        RETURN[FALSE];
        END;

      WITH t SELECT FROM
        symbol =>
          BEGIN itemSE: SemanticEntry.STIndex = index;
	  WITH stb[itemSE] SELECT FROM
            module => InsertImplicitCDModuleInPOChain[
                mti, cdNode, tb[cdNode].son[3]]; 
            config => SourceBcd.EnumerateModulesInConfig[
                kind: prototype, configTreeNode: cNode, userProc: EnterOneImplicitCDModule];
            ENDCASE;
          END;
        ENDCASE => POerror[];
      END;

    WITH tb[cdNode].son[1] SELECT FROM
      symbol => 
        BEGIN componentSE: SemanticEntry.STIndex = index;
	WITH stb[componentSE] SELECT FROM
          config => TreeOps.ScanList[tb[cdNode].son[2], EnterOneItem];
          ENDCASE;
        END;
      ENDCASE => POerror[];
    END;


  EnterExceptPacksItemsCD: PROC [cdNode: Tree.Index] =
    BEGIN  -- ComponentDesc ::= Component EXCEPT PackList, [ItemList]
    WITH tb[cdNode].son[1] SELECT FROM
      symbol => 
        BEGIN componentSE: SemanticEntry.STIndex = index;
	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;
      ENDCASE => POerror[];
    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: BOOLEAN] =
      BEGIN
      inAnItem: BOOLEAN;

      CheckIfModuleInItem: Tree.Test =
        BEGIN 
        SeeIfModuleFound: PROC [mti: BcdDefs.MTIndex] RETURNS [stop: BOOLEAN] =
          {IF module = mti THEN inAnItem ← TRUE;  RETURN[inAnItem]};

        WITH t SELECT FROM
          symbol =>  -- item is either a module or a subconfiguration
            BEGIN itemSE: SemanticEntry.STIndex = index;
    	    WITH stb[itemSE] SELECT FROM
              module => IF module = mti THEN inAnItem ← TRUE;  
              config => SourceBcd.EnumerateModulesInConfig[
	        kind: prototype, configTreeNode: cNode, userProc: SeeIfModuleFound];
    	      ENDCASE;
            END;
          ENDCASE => POerror[];
        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 *****

  EnterMainOfComponentDescs: PROC =
    {TreeOps.ScanList[Tree.root, EnterMainOfCDsInSegments]};

  EnterMainOfCDsInSegments: Tree.Scan =
    BEGIN
    WITH t SELECT FROM
      subtree =>
        BEGIN segNode: Tree.Index = index;
        IF tb[segNode].name = codeSeg THEN EnterMainOfCDsInOneSeg[segNode]; 
        END;
      ENDCASE => POerror[];
    END;

  EnterMainOfCDsInOneSeg: PROC [segNode: Tree.Index] =
    BEGIN
    saveIndex: CARDINAL = globalData.textIndex;
    globalData.textIndex ← tb[segNode].info;
    TreeOps.ScanList[tb[segNode].son[2], EnterMainOfCDsInOneCodePack];
    globalData.textIndex ← saveIndex;
    END;

  EnterMainOfCDsInOneCodePack: Tree.Scan =
    BEGIN

    ProcessOneCD: Tree.Scan =
      BEGIN
      WITH t SELECT FROM
        subtree =>
          BEGIN cdNode: Tree.Index = index;
          IF tb[cdNode].name = mainProcs THEN EnterMainOfCD[cdNode];
          END;
        ENDCASE => POerror[];
      END;
  
    WITH t SELECT FROM
      subtree =>
        BEGIN cpNode: Tree.Index = index;
        TreeOps.ScanList[tb[cpNode].son[2], ProcessOneCD];
        END;
      ENDCASE => POerror[];
    END;


  EnterMainOfCD: PROC [cdNode: Tree.Index] =
    BEGIN  -- ComponentDesc ::= MAIN OF PackList
    saveIndex: CARDINAL = globalData.textIndex;
    packList: Tree.Link = tb[cdNode].son[1];
    firstInList: Tree.Link;

    EnterModulesOfOneOfSegsPacks: Tree.Scan =
      BEGIN
      WITH t SELECT FROM
        subtree =>
          BEGIN cpNode: Tree.Index = index;
	  InsertOneMainOfPacksModules[cpNode: cpNode, mainOfCdNode: cdNode];
          END;
        ENDCASE => POerror[];
      END;

    EnterModulesOfOneMainOfPack: Tree.Scan =
      BEGIN
      WITH t SELECT FROM
        symbol =>
          BEGIN cpSE: SemanticEntry.STIndex = index;
	  WITH stb[cpSE] SELECT FROM
            codePack => InsertOneMainOfPacksModules[
		cpNode: treeNode, mainOfCdNode: cdNode];
            ENDCASE;
          END;
        ENDCASE => POerror[];
      END;
  
    globalData.textIndex ← tb[cdNode].info;
    IF TreeOps.ListLength[packList] = 1 THEN
      BEGIN  -- packlist might only be name of current code segment
      firstInList ← TreeOps.ListHead[packList];
      WITH firstInList SELECT FROM
        symbol => 
          BEGIN firstSE: SemanticEntry.STIndex = index;
	  WITH stb[firstSE] SELECT FROM
	    segment =>
	      BEGIN segNode: Tree.Index = treeNode;
	      TreeOps.ScanList[
	        tb[segNode].son[2], EnterModulesOfOneOfSegsPacks];
	      RETURN;
	      END;
	    ENDCASE;
          END;
        ENDCASE => POerror[]; 
      END;
    TreeOps.ScanList[packList, EnterModulesOfOneMainOfPack];
    globalData.textIndex ← saveIndex;
    END;

  InsertOneMainOfPacksModules: PROC [
      cpNode: Tree.Index, mainOfCdNode: Tree.Index] =
    BEGIN  -- enter all modules in a code pack referenced by a MAIN OF

    ProcessOneCD: Tree.Scan =
      BEGIN
      InsertAMainOfPacksModule: PROC [
          mti: BcdDefs.MTIndex] RETURNS [stop: BOOLEAN] =
        {InsertInPOChain[mti, mainOfCdNode];  RETURN[FALSE]};

      WITH t SELECT FROM
        subtree =>
          BEGIN cdNode: Tree.Index = index;
          IF tb[cdNode].name # mainProcs THEN 
	    WITH tb[cdNode].son[1] SELECT FROM
              symbol => 
                BEGIN componentSE: SemanticEntry.STIndex = index;
        	WITH stb[componentSE] SELECT FROM
                  module => 
		      IF ~SourceBcd.IsTableCompiled[mti] THEN
		        InsertInPOChain[mti, mainOfCdNode]; 
                  config => SourceBcd.EnumerateModulesInConfig[
                      kind: prototype, configTreeNode: cNode, userProc: InsertAMainOfPacksModule]; 
                  ENDCASE;
                END;
              ENDCASE => POerror[];
          END;
        ENDCASE => POerror[];
      END;
  
    TreeOps.ScanList[tb[cpNode].son[2], ProcessOneCD];
    END;


-- ************ Verify That a Module Appears in Only One Segment ************-

  VerifyModulesInOneSegment: PROC =
    BEGIN
    SourceBcd.EnumerateModules[VerifyAModuleInOneSegment];
    END;

  VerifyAModuleInOneSegment: PROC [mti: BcdDefs.MTIndex] RETURNS [stop: BOOLEAN] =
    BEGIN
    modulesSeg: Tree.Index;

    CheckOneCDNode: PROC [cdNode: Tree.Index] RETURNS [stop: BOOLEAN] =
      BEGIN
      IF modulesSeg = Tree.NullIndex THEN modulesSeg ← tb[cdNode].seg 
      ELSE IF modulesSeg # tb[cdNode].seg THEN
	BEGIN
	segId1, segId2: SymTabDefs.HTIndex;
	WITH tb[modulesSeg].son[1] SELECT FROM
	  hash => segId1 ← index;
	  ENDCASE => POerror[];
	WITH tb[tb[cdNode].seg].son[1] SELECT FROM
	  hash => segId2 ← index;
	  ENDCASE => POerror[];
	Error.ModuleInTwoSegments[error, mti, segId1, segId2];
        RETURN[TRUE];
	END;
      RETURN[FALSE];
      END;
  
    modulesSeg ← Tree.NullIndex;
    Enumerate[mti, CheckOneCDNode];
    RETURN[FALSE];
    END;

  END.