-------------------------------------------------------------------------------
-- (C) Altran Praxis Limited
-------------------------------------------------------------------------------
--
-- The SPARK toolset is free software; you can redistribute it and/or modify it
-- under terms of the GNU General Public License as published by the Free
-- Software Foundation; either version 3, or (at your option) any later
-- version. The SPARK toolset is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
-- Public License for more details. You should have received a copy of the GNU
-- General Public License distributed with the SPARK toolset; see file
-- COPYING3. If not, go to http://www.gnu.org/licenses for a complete copy of
-- the license.
--
--=============================================================================

with Debug, RelationAlgebra.Debug;
separate (FlowAnalyser)
procedure FlowAnalyse
  (SubprogSym         : in     Dictionary.Symbol;
   StartNode          : in     STree.SyntaxNode;
   EndPosition        : in     LexTokenManager.Token_Position;
   ComponentData      : in out ComponentManager.ComponentData;
   TheHeap            : in out Heap.HeapRecord;
   Table              : in     RefList.HashTable;
   DataFlowErrorFound :    out Boolean)
is
   subtype ExpnCountRange is Natural range 0 .. ExaminerConstants.FlowAnalysisMaxExpnNumber;

   LastNode, Node : STree.SyntaxNode;
   NodeType       : SP_Symbols.SP_Symbol;

   DependencyRelation      : RelationAlgebra.Relation;
   ExpnNumber              : ExpnCountRange; -- Natural;
   S                       : IFA_Stack.Stack;
   InnerExpns              : SeqAlgebra.Seq;
   ReferencedVars          : SeqAlgebra.Seq;
   SeqOfExports            : SeqAlgebra.Seq;
   ExpSeqOfExports         : SeqAlgebra.Seq;
   SeqOfInitVars           : SeqAlgebra.Seq;
   LocalInits              : SeqAlgebra.Seq;
   VarsUsedAsConstants     : SeqAlgebra.Seq;
   SeqOfImports            : SeqAlgebra.Seq;
   ExpSeqOfImports         : SeqAlgebra.Seq;
   DataFlowErrorFoundLocal : Boolean;

   -- ShareableProtectedVars is set of protected own vars that are not streams; these need special handling
   -- in the flow analyser because they are potentially shareable and may cause communication between program threads.
   ShareableProtectedVars : SeqAlgebra.Seq;
   -- Each member of the previous set has an implicitly-declared associated in stream
   InStreamsOfShareableProtectedVars : SeqAlgebra.Seq;
   -- we need to identify protected variables that are referenced somwehere
   ReferencedProtectedVars : SeqAlgebra.Seq;

   subtype ExpnIndexRange is Natural range 1 .. ExaminerConstants.FlowAnalysisMaxExpnNumber;
   type LocnDictionaryType is array (ExpnIndexRange) of STree.SyntaxNode;
   StmtLocations, ExpnLocations : LocnDictionaryType;
   type ExpnKind is (
                     SimpleAssignment, -- was SingleAssignment
                     ComplexAssignment, -- was MultipleAssignment
                     FieldUpdateByProc, -- case used for Inc (R.F) and similar
                     Initialization,
                     ReturnExpn,
                     ForkExpn,
                     ExitExpn,
                     DefaultExitExpn,
                     ControlVarAssignment,
                     ModellingStmt); -- statement for modelling protected state interactions, not traceable to SPARK source
   type KindDictionaryType is array (ExpnIndexRange) of ExpnKind;
   KindDictionary : KindDictionaryType;

   --  ParamDictionary maps expression number to the symbol that is directly
   --  affected by that expression, such as a local variable or an export.
   --  Expresions which do not directly affect a variable or export (e.g. the
   --  controlling expression of an if statement) map to Dictionary.NullSymbol.
   type ParamDictionaryType is array (ExpnIndexRange) of Dictionary.Symbol;
   ParamDictionary : ParamDictionaryType;

   FnResultRepn                                            : constant Natural := 0;
   ZeroStableExpnSeq, OneStableExpnSeq, OtherStableExpnSeq : SeqAlgebra.Seq;

   NullAtom : constant Heap.Atom := Heap.Atom (0);

   Scope : Dictionary.Scopes;

   -------------------------------------------------------------

   procedure PrintStackTop (Msg : in String)
   --# global in SubprogSym;
   --# derives null from Msg,
   --#                   SubprogSym;
   is
      --# hide PrintStackTop
   begin
      Debug.PrintMsg ("-------------------------------------------------------------------------------", True);
      Debug.PrintMsg (Msg, True);
      Debug.Print_Sym (Msg => "For Subprogram ",
                       Sym => SubprogSym);
      Debug.Print_Sym_Seq (Msg      => "DefinedVars     ",
                           Seq      => IFA_Stack.Top (S).DefinedVars,
                           The_Heap => TheHeap);
      Debug.PrintMsg ("----------------------------", True);
      Debug.Print_Sym_Seq (Msg      => "UnPreservedVars ",
                           Seq      => IFA_Stack.Top (S).UnPreservedVars,
                           The_Heap => TheHeap);
      Debug.PrintMsg ("----------------------------", True);
      Debug.Print_Sym_Seq (Msg      => "AllVars         ",
                           Seq      => IFA_Stack.Top (S).AllVars,
                           The_Heap => TheHeap);
      Debug.PrintMsg ("----------------------------", True);

      RelationAlgebra.Debug.Print_Lambda ("Lambda  ", IFA_Stack.Top (S).Lambda, TheHeap);
      Debug.PrintMsg ("----------------------------", True);

      RelationAlgebra.Debug.Print_Mu ("Mu      ", IFA_Stack.Top (S).Mu, TheHeap);
      Debug.PrintMsg ("----------------------------", True);

      -- Theta and Theta~ are both relations from V to E - the same as Lambda,
      -- so we can re-use Print_Lambda here.
      RelationAlgebra.Debug.Print_Lambda ("Theta   ", IFA_Stack.Top (S).Theta, TheHeap);
      Debug.PrintMsg ("----------------------------", True);

      RelationAlgebra.Debug.Print_Lambda ("Theta~  ", IFA_Stack.Top (S).ThetaTilde, TheHeap);
      Debug.PrintMsg ("----------------------------", True);

      RelationAlgebra.Debug.Print_Rho ("Rho ", IFA_Stack.Top (S).Rho, TheHeap);
      Debug.PrintMsg ("-------------------------------------------------------------------------------", True);
   end PrintStackTop;

   -------------------------------------------------------------

   procedure IncrementExpression (X : in out ExpnCountRange)
   --# derives X from *;
   --# pre X <= ExaminerConstants.FlowAnalysisMaxExpnNumber;
   --# post X = X~ + 1;
   is
   begin
      if X = ExaminerConstants.FlowAnalysisMaxExpnNumber then
         SystemErrors.Fatal_Error (Sys_Err => SystemErrors.Flow_Analyser_Expression_Limit,
                                   Msg     => "");
      else
         X := X + 1;
      end if;
   end IncrementExpression;

   -------------------------------------------------------------

   procedure AddSymbol (TheHeap : in out Heap.HeapRecord;
                        Sequ    : in     SeqAlgebra.Seq;
                        Sym     : in     Dictionary.Symbol)
   --# global in out Statistics.TableUsage;
   --# derives Statistics.TableUsage,
   --#         TheHeap               from *,
   --#                                    Sequ,
   --#                                    Sym,
   --#                                    TheHeap;
   is
   begin
      SeqAlgebra.AddMember (TheHeap, Sequ, Natural (Dictionary.SymbolRef (Sym)));
   end AddSymbol;

   -------------------------------------------------------------

   procedure InsertSymbolPair
     (TheHeap    : in out Heap.HeapRecord;
      Rel        : in     RelationAlgebra.Relation;
      Sym1, Sym2 : in     Dictionary.Symbol)
   --# global in out Statistics.TableUsage;
   --# derives Statistics.TableUsage,
   --#         TheHeap               from *,
   --#                                    Rel,
   --#                                    Sym1,
   --#                                    Sym2,
   --#                                    TheHeap;
   is
   begin
      RelationAlgebra.InsertPair (TheHeap, Rel, Natural (Dictionary.SymbolRef (Sym1)), Natural (Dictionary.SymbolRef (Sym2)));
   end InsertSymbolPair;

   -------------------------------------------------------------

   function SymValue (Cell : Heap.Atom) return Dictionary.Symbol
   --# global in TheHeap;
   is
   begin
      return Dictionary.ConvertSymbolRef (ExaminerConstants.RefType (Heap.AValue (TheHeap, Cell)));
   end SymValue;

   -------------------------------------------------------------

   function RepToSym (R : in Natural) return Dictionary.Symbol is
   begin
      return Dictionary.ConvertSymbolRef (ExaminerConstants.RefType (R));
   end RepToSym;

   -------------------------------------------------------------

   -- with the introduction of Ravenscar we need to make sure that Task bodies are analysed like
   -- procedure bodies.  Since task bodies are not procedure as far as the Dictionary is concerned
   -- we add the following functions to relace direct dictionary calls.

   function IsSubprogram (Sym : Dictionary.Symbol) return Boolean
   --# global in Dictionary.Dict;
   is
   begin
      return Dictionary.Is_Subprogram (Sym) or else (Dictionary.IsType (Sym) and then Dictionary.TypeIsTask (Sym));
   end IsSubprogram;

   function IsProcedure (Sym : Dictionary.Symbol) return Boolean
   --# global in Dictionary.Dict;
   is
   begin
      return Dictionary.IsProcedure (Sym) or else (Dictionary.IsType (Sym) and then Dictionary.TypeIsTask (Sym));
   end IsProcedure;

   ---------------------------------------------------------------

   procedure FormSeqOfInitVars
   --# global in     ComponentData;
   --#        in     Dictionary.Dict;
   --#        in     SubprogSym;
   --#        in out Statistics.TableUsage;
   --#        in out TheHeap;
   --#           out SeqOfInitVars;
   --# derives SeqOfInitVars         from TheHeap &
   --#         Statistics.TableUsage,
   --#         TheHeap               from *,
   --#                                    ComponentData,
   --#                                    Dictionary.Dict,
   --#                                    SubprogSym,
   --#                                    TheHeap;
   is
      PackageIterator, OwnVarIterator : Dictionary.Iterator;
   begin
      SeqAlgebra.CreateSeq (TheHeap, SeqOfInitVars);
      if IsSubprogram (SubprogSym) then
         -- we are doing a subprogram which may have embedded packages
         PackageIterator := Dictionary.First_Embedded_Package (Compilation_Unit => SubprogSym);
         while not Dictionary.IsNullIterator (PackageIterator) loop
            OwnVarIterator := Dictionary.FirstInitializedOwnVariable (Dictionary.CurrentSymbol (PackageIterator));
            while not Dictionary.IsNullIterator (OwnVarIterator) loop
               AddSymbol (TheHeap, SeqOfInitVars, Dictionary.CurrentSymbol (OwnVarIterator));
               OwnVarIterator := Dictionary.NextSymbol (OwnVarIterator);
            end loop;
            PackageIterator := Dictionary.NextSymbol (PackageIterator);
         end loop;
         -- no else part, package initializations can't have embedded packs
      end if;
      RefList.ExpandSeq (ComponentData, SeqOfInitVars, TheHeap);
   end FormSeqOfInitVars;

   -------------------------------------------------------------

   procedure FormLocalInits
   --# global in     ComponentData;
   --#        in     Dictionary.Dict;
   --#        in     SubprogSym;
   --#        in out Statistics.TableUsage;
   --#        in out TheHeap;
   --#           out LocalInits;
   --# derives LocalInits            from TheHeap &
   --#         Statistics.TableUsage,
   --#         TheHeap               from *,
   --#                                    ComponentData,
   --#                                    Dictionary.Dict,
   --#                                    SubprogSym,
   --#                                    TheHeap;
   is

      procedure FormSubprogramLocalInits
      --# global in     Dictionary.Dict;
      --#        in     LocalInits;
      --#        in     SubprogSym;
      --#        in out Statistics.TableUsage;
      --#        in out TheHeap;
      --# derives Statistics.TableUsage,
      --#         TheHeap               from *,
      --#                                    Dictionary.Dict,
      --#                                    LocalInits,
      --#                                    SubprogSym,
      --#                                    TheHeap;
      is
         It : Dictionary.Iterator;
      begin
         It := Dictionary.First_Initialized_Variable (Subprogram => SubprogSym);
         while not Dictionary.IsNullIterator (It) loop
            AddSymbol (TheHeap, LocalInits, Dictionary.CurrentSymbol (It));
            It := Dictionary.NextSymbol (It);
         end loop;
      end FormSubprogramLocalInits;

      procedure FormPackageLocalInits (Package_Symbol : Dictionary.Symbol)
      --# global in     Dictionary.Dict;
      --#        in     LocalInits;
      --#        in out Statistics.TableUsage;
      --#        in out TheHeap;
      --# derives Statistics.TableUsage,
      --#         TheHeap               from *,
      --#                                    Dictionary.Dict,
      --#                                    LocalInits,
      --#                                    Package_Symbol,
      --#                                    TheHeap;
      is
         ConstituentList, InitOwnVarList : Dictionary.Iterator;
         InitOwnVarSym, ConstituentSym   : Dictionary.Symbol;
      begin
         InitOwnVarList := Dictionary.FirstInitializedOwnVariable (Package_Symbol);
         while not Dictionary.IsNullIterator (InitOwnVarList) loop
            InitOwnVarSym := Dictionary.CurrentSymbol (InitOwnVarList);
            if Dictionary.IsConcreteOwnVariable (InitOwnVarSym) then
               if Dictionary.VariableIsInitialized (InitOwnVarSym) then
                  -- Local, concrete, and initialized at declaration
                  AddSymbol (TheHeap, LocalInits, InitOwnVarSym);
               end if;
            else
               ConstituentList := Dictionary.FirstConstituent (InitOwnVarSym);
               while not Dictionary.IsNullIterator (ConstituentList) loop
                  ConstituentSym := Dictionary.CurrentSymbol (ConstituentList);
                  if (not Dictionary.IsOwnVariable (ConstituentSym))
                    and then Dictionary.VariableIsInitialized (ConstituentSym) then
                     -- Local refinement constituent initialized at declaration
                     AddSymbol (TheHeap, LocalInits, ConstituentSym);

                  elsif Dictionary.GetConstituentMode (ConstituentSym) /= Dictionary.DefaultMode
                    and then Dictionary.Packages_Are_Equal
                    (Left_Symbol  => Dictionary.GetOwner (ConstituentSym),
                     Right_Symbol => Package_Symbol) then
                     -- Local, external refinement constituent is initialized implicitly
                     AddSymbol (TheHeap, LocalInits, ConstituentSym);

                  end if;

                  -- That's all.  Note that refinement constituents which are own variables of
                  -- _other_ packages (either nested or private child) are never
                  -- considered to be locally initialized here - they are none of our business
                  -- in the context of the analysis of _this_ package body initialization!

                  ConstituentList := Dictionary.NextSymbol (ConstituentList);
               end loop;
            end if;
            InitOwnVarList := Dictionary.NextSymbol (InitOwnVarList);
         end loop;
      end FormPackageLocalInits;

   begin -- FormLocalInits
      SeqAlgebra.CreateSeq (TheHeap, LocalInits);
      if IsSubprogram (SubprogSym) then
         FormSubprogramLocalInits;
      else
         FormPackageLocalInits (Package_Symbol => SubprogSym);
      end if;
      RefList.ExpandSeq (ComponentData, LocalInits, TheHeap);
   end FormLocalInits;

   -------------------------------------------------------------

   procedure ModelLocalInits (Node : in STree.SyntaxNode)
   --# global in     LocalInits;
   --#        in out ExpnNumber;
   --#        in out KindDictionary;
   --#        in out ParamDictionary;
   --#        in out S;
   --#        in out Statistics.TableUsage;
   --#        in out StmtLocations;
   --#        in out TheHeap;
   --# derives ExpnNumber,
   --#         KindDictionary,
   --#         ParamDictionary,
   --#         Statistics.TableUsage,
   --#         TheHeap               from *,
   --#                                    ExpnNumber,
   --#                                    LocalInits,
   --#                                    TheHeap &
   --#         S                     from *,
   --#                                    LocalInits,
   --#                                    TheHeap &
   --#         StmtLocations         from *,
   --#                                    ExpnNumber,
   --#                                    LocalInits,
   --#                                    Node,
   --#                                    TheHeap;
   is
      MemberOfInitVars : SeqAlgebra.MemberOfSeq;
      InitVarRep       : Natural;
      InitVar          : Dictionary.Symbol;
      R                : IFA_Stack.StackMember;
      UndefinedVars    : SeqAlgebra.Seq;
   begin
      MemberOfInitVars := SeqAlgebra.FirstMember (TheHeap, LocalInits);
      if not SeqAlgebra.IsNullMember (MemberOfInitVars) then
         IFA_Stack.EstablishMember (TheHeap, IFA_Stack.Action, R);
         while not SeqAlgebra.IsNullMember (MemberOfInitVars) loop
            InitVarRep := SeqAlgebra.Value_Of_Member (The_Heap => TheHeap,
                                                      M        => MemberOfInitVars);
            InitVar    := Dictionary.ConvertSymbolRef (ExaminerConstants.RefType (InitVarRep));

            IncrementExpression (ExpnNumber);
            StmtLocations (ExpnNumber)   := Node;
            ParamDictionary (ExpnNumber) := InitVar;
            SeqAlgebra.AddMember (TheHeap, R.DefinedVars, InitVarRep);
            SeqAlgebra.AddMember (TheHeap, R.UnPreservedVars, InitVarRep);
            SeqAlgebra.AddMember (TheHeap, R.AllVars, InitVarRep);
            SeqAlgebra.AddMember (TheHeap, R.SeqOfExpns, ExpnNumber);
            RelationAlgebra.InsertPair (TheHeap, R.Mu, ExpnNumber, InitVarRep);
            SeqAlgebra.Complement (TheHeap, R.AllVars, R.DefinedVars, UndefinedVars);
            RelationAlgebra.AddIdentity (TheHeap, R.Rho, UndefinedVars);
            SeqAlgebra.DisposeOfSeq (TheHeap, UndefinedVars);
            KindDictionary (ExpnNumber) := Initialization;
            MemberOfInitVars            := SeqAlgebra.NextMember (TheHeap, MemberOfInitVars);
         end loop;
         IFA_Stack.Push (S, R);
      end if;
   end ModelLocalInits;

   -------------------------------------------------------------

   procedure FormDependencyRelation
   --# global in     CommandLineData.Content;
   --#        in     ComponentData;
   --#        in     Dictionary.Dict;
   --#        in     SubprogSym;
   --#        in out Statistics.TableUsage;
   --#        in out TheHeap;
   --#           out DependencyRelation;
   --#           out ExpSeqOfExports;
   --#           out ExpSeqOfImports;
   --#           out InStreamsOfShareableProtectedVars;
   --#           out ReferencedProtectedVars;
   --#           out SeqOfExports;
   --#           out SeqOfImports;
   --#           out ShareableProtectedVars;
   --# derives DependencyRelation,
   --#         ExpSeqOfExports,
   --#         ExpSeqOfImports,
   --#         InStreamsOfShareableProtectedVars,
   --#         ReferencedProtectedVars,
   --#         SeqOfExports,
   --#         SeqOfImports,
   --#         ShareableProtectedVars            from TheHeap &
   --#         Statistics.TableUsage,
   --#         TheHeap                           from *,
   --#                                                ComponentData,
   --#                                                Dictionary.Dict,
   --#                                                SubprogSym,
   --#                                                TheHeap &
   --#         null                              from CommandLineData.Content;
   is
      Abstraction                            : Dictionary.Abstractions;
      It, ExportIt, ImportIt                 : Dictionary.Iterator;
      ExportVar, RefinedExportVar, ImportVar : Dictionary.Symbol;

      -------------------------------

      procedure AddFunctionImport (Sym : in Dictionary.Symbol)
      --# global in     DependencyRelation;
      --#        in     ExpSeqOfImports;
      --#        in     SeqOfImports;
      --#        in out Statistics.TableUsage;
      --#        in out TheHeap;
      --# derives Statistics.TableUsage,
      --#         TheHeap               from *,
      --#                                    DependencyRelation,
      --#                                    ExpSeqOfImports,
      --#                                    SeqOfImports,
      --#                                    Sym,
      --#                                    TheHeap;
      is
         ImpVarRep : Natural;
      begin
         ImpVarRep := Natural (Dictionary.SymbolRef (Sym));
         SeqAlgebra.AddMember (TheHeap, SeqOfImports, ImpVarRep);
         SeqAlgebra.AddMember (TheHeap, ExpSeqOfImports, ImpVarRep);
         RelationAlgebra.InsertPair (TheHeap, DependencyRelation, ImpVarRep, FnResultRepn);
      end AddFunctionImport;

      -------------------------------

      -- This procedure adds implicit stream effects to the imported and exported
      -- variable sets.  An imported in stream needs also to be made an (implicit)
      -- export and vice versa.  Implemented by adding all streams to both sets; this
      -- is always safe because of earlier wellformation checks.
      -- It also adds the notional in stream associated with each unmoded protected variable
      -- to the list of exports and populates the sets ShareableProtectedVars and InStreamsOfShareableProtectedVars
      procedure AddStreamInteractions (Abstraction : in Dictionary.Abstractions)
      --# global in     Dictionary.Dict;
      --#        in     ExpSeqOfExports;
      --#        in     ExpSeqOfImports;
      --#        in     InStreamsOfShareableProtectedVars;
      --#        in     SeqOfExports;
      --#        in     SeqOfImports;
      --#        in     ShareableProtectedVars;
      --#        in     SubprogSym;
      --#        in out Statistics.TableUsage;
      --#        in out TheHeap;
      --# derives Statistics.TableUsage,
      --#         TheHeap               from *,
      --#                                    Abstraction,
      --#                                    Dictionary.Dict,
      --#                                    ExpSeqOfExports,
      --#                                    ExpSeqOfImports,
      --#                                    InStreamsOfShareableProtectedVars,
      --#                                    SeqOfExports,
      --#                                    SeqOfImports,
      --#                                    ShareableProtectedVars,
      --#                                    SubprogSym,
      --#                                    TheHeap;
      is
         GlobalIt  : Dictionary.Iterator;
         GlobalSym : Dictionary.Symbol;
      begin
         GlobalIt := Dictionary.FirstGlobalVariable (Abstraction, SubprogSym);
         while not Dictionary.IsNullIterator (GlobalIt) loop
            GlobalSym := Dictionary.CurrentSymbol (GlobalIt);
            if Dictionary.GetOwnVariableOrConstituentMode (GlobalSym) /= Dictionary.DefaultMode then
               AddSymbol (TheHeap, SeqOfExports, GlobalSym);
               AddSymbol (TheHeap, SeqOfImports, GlobalSym);
               AddSymbol (TheHeap, ExpSeqOfExports, GlobalSym);
               AddSymbol (TheHeap, ExpSeqOfImports, GlobalSym);
            elsif Dictionary.IsUnmodedProtectedOwnVariable (GlobalSym) then
               AddSymbol (TheHeap, SeqOfExports, Dictionary.GetProtectedImplicitInStream (GlobalSym));
               AddSymbol (TheHeap, ExpSeqOfExports, Dictionary.GetProtectedImplicitInStream (GlobalSym));
               AddSymbol (TheHeap, ShareableProtectedVars, GlobalSym);
               AddSymbol (TheHeap, InStreamsOfShareableProtectedVars, Dictionary.GetProtectedImplicitInStream (GlobalSym));
            end if;
            GlobalIt := Dictionary.NextSymbol (GlobalIt);
         end loop;
      end AddStreamInteractions;

      -------------------------------

      -- Procedure to mark imports of the form "derives null from x,y,z; as imports.
      -- Any that are added by this procedure that are already imports will be ignored
      -- because SeqAlgebra sequences don't accept duplicate entries.
      procedure AddForcedImports (Abstraction : in Dictionary.Abstractions)
      --# global in     Dictionary.Dict;
      --#        in     ExpSeqOfImports;
      --#        in     SeqOfImports;
      --#        in     SubprogSym;
      --#        in out Statistics.TableUsage;
      --#        in out TheHeap;
      --# derives Statistics.TableUsage,
      --#         TheHeap               from *,
      --#                                    Abstraction,
      --#                                    Dictionary.Dict,
      --#                                    ExpSeqOfImports,
      --#                                    SeqOfImports,
      --#                                    SubprogSym,
      --#                                    TheHeap;
      is
         It  : Dictionary.Iterator;
         Sym : Dictionary.Symbol;
      begin
         It := Dictionary.FirstImport (Abstraction, SubprogSym);
         while not Dictionary.IsNullIterator (It) loop
            Sym := Dictionary.CurrentSymbol (It);
            AddSymbol (TheHeap, SeqOfImports, Sym);
            AddSymbol (TheHeap, ExpSeqOfImports, Sym);
            It := Dictionary.NextSymbol (It);
         end loop;
      end AddForcedImports;

      -------------------------------

   begin -- FormDependencyRelation
      SeqAlgebra.CreateSeq (TheHeap, SeqOfExports);
      SeqAlgebra.CreateSeq (TheHeap, ExpSeqOfExports);
      SeqAlgebra.CreateSeq (TheHeap, SeqOfImports);
      SeqAlgebra.CreateSeq (TheHeap, ExpSeqOfImports);
      SeqAlgebra.CreateSeq (TheHeap, ShareableProtectedVars);
      SeqAlgebra.CreateSeq (TheHeap, ReferencedProtectedVars);
      SeqAlgebra.CreateSeq (TheHeap, InStreamsOfShareableProtectedVars);
      RelationAlgebra.CreateRelation (TheHeap, DependencyRelation);
      if IsSubprogram (SubprogSym) then
         Abstraction :=
           Dictionary.GetAbstraction
           (SubprogSym,
            Dictionary.Set_Visibility (The_Visibility => Dictionary.Local,
                                       The_Unit       => SubprogSym));
         if IsProcedure (SubprogSym) then
            ExportIt := Dictionary.FirstExport (Abstraction, SubprogSym);
            while not Dictionary.IsNullIterator (ExportIt) loop
               --# assert Abstraction in Dictionary.Abstractions;
               ExportVar := Dictionary.CurrentSymbol (ExportIt);
               AddSymbol (TheHeap, SeqOfExports, ExportVar);
               AddSymbol (TheHeap, ExpSeqOfExports, ExportVar);
               ImportIt := Dictionary.FirstDependency (Abstraction, SubprogSym, ExportVar);
               while not Dictionary.IsNullIterator (ImportIt) loop
                  --# assert Abstraction in Dictionary.Abstractions;
                  ImportVar := Dictionary.CurrentSymbol (ImportIt);
                  AddSymbol (TheHeap, SeqOfImports, ImportVar);
                  AddSymbol (TheHeap, ExpSeqOfImports, ImportVar);
                  InsertSymbolPair (TheHeap, DependencyRelation, ImportVar, ExportVar);
                  ImportIt := Dictionary.NextSymbol (ImportIt);
               end loop;
               ExportIt := Dictionary.NextSymbol (ExportIt);
            end loop;
            AddStreamInteractions (Abstraction);
            AddForcedImports (Abstraction);
            -- add the data sink NullVariable as an import and an export
            AddSymbol (TheHeap, SeqOfImports, Dictionary.GetNullVariable);
            AddSymbol (TheHeap, ExpSeqOfImports, Dictionary.GetNullVariable);
            AddSymbol (TheHeap, SeqOfExports, Dictionary.GetNullVariable);
            AddSymbol (TheHeap, ExpSeqOfExports, Dictionary.GetNullVariable);

         else
            -- form dependency relation for a function subprogram;
            SeqAlgebra.AddMember (TheHeap, SeqOfExports, FnResultRepn);
            SeqAlgebra.AddMember (TheHeap, ExpSeqOfExports, FnResultRepn);
            -- add the data sink NullVariable as an import
            AddSymbol (TheHeap, SeqOfImports, Dictionary.GetNullVariable);
            AddSymbol (TheHeap, ExpSeqOfImports, Dictionary.GetNullVariable);

            It := Dictionary.FirstSubprogramParameter (SubprogSym);
            while not Dictionary.IsNullIterator (It) loop
               --# assert Abstraction in Dictionary.Abstractions;
               AddFunctionImport (Dictionary.CurrentSymbol (It));
               It := Dictionary.NextSymbol (It);
            end loop;
            It := Dictionary.FirstGlobalVariable (Abstraction, SubprogSym);
            while not Dictionary.IsNullIterator (It) loop
               --# assert Abstraction in Dictionary.Abstractions;
               AddFunctionImport (Dictionary.CurrentSymbol (It));
               It := Dictionary.NextSymbol (It);
            end loop;
            AddStreamInteractions (Abstraction);
         end if;
      else
         -- create "dependency list" for package body initialization
         It := Dictionary.FirstInitializedOwnVariable (SubprogSym);
         while not Dictionary.IsNullIterator (It) loop
            ExportVar := Dictionary.CurrentSymbol (It);
            if Dictionary.Is_Declared (Item => ExportVar) then
               AddSymbol (TheHeap, SeqOfExports, ExportVar);
               AddSymbol (TheHeap, ExpSeqOfExports, ExportVar);
            else -- abstract own var
               ExportIt := Dictionary.FirstConstituent (ExportVar);
               while not Dictionary.IsNullIterator (ExportIt) loop
                  -- exclude refinements to embedded packages
                  RefinedExportVar := Dictionary.CurrentSymbol (ExportIt);
                  if Dictionary.Packages_Are_Equal
                    (Left_Symbol  => Dictionary.GetOwner (RefinedExportVar),
                     Right_Symbol => SubprogSym) then
                     AddSymbol (TheHeap, SeqOfExports, RefinedExportVar);
                     AddSymbol (TheHeap, ExpSeqOfExports, RefinedExportVar);
                  end if;
                  ExportIt := Dictionary.NextSymbol (ExportIt);
               end loop;
            end if;
            It := Dictionary.NextSymbol (It);
         end loop;
      end if;
      RefList.ExpandSeq (ComponentData, ExpSeqOfImports, TheHeap);
      RefList.ExpandSeq (ComponentData, ExpSeqOfExports, TheHeap);

      if CommandLineData.Content.Debug.Rho then
         Debug.Print_Sym (Msg => "Required flow relations for subprogram ",
                          Sym => SubprogSym);
         Debug.Print_Sym_Seq (Msg      => "Exports ",
                              Seq      => SeqOfExports,
                              The_Heap => TheHeap);
         Debug.Print_Sym_Seq (Msg      => "Imports ",
                              Seq      => SeqOfImports,
                              The_Heap => TheHeap);
         RelationAlgebra.Debug.Print_Rho ("Rho ", DependencyRelation, TheHeap);
      end if;

   end FormDependencyRelation;

   -------------------------------------------------------------

   procedure NullStatement
   --# global in out S;
   --#        in out Statistics.TableUsage;
   --#        in out TheHeap;
   --# derives S,
   --#         Statistics.TableUsage,
   --#         TheHeap               from *,
   --#                                    TheHeap;
   is
      R : IFA_Stack.StackMember;
   begin
      IFA_Stack.EstablishMember (TheHeap, IFA_Stack.Action, R);
      IFA_Stack.Push (S, R);
   end NullStatement;

   -------------------------------------------------------------

   procedure CombineSequence
   --# global in out S;
   --#        in out Statistics.TableUsage;
   --#        in out TheHeap;
   --# derives S,
   --#         Statistics.TableUsage,
   --#         TheHeap               from *,
   --#                                    S,
   --#                                    TheHeap;
   is
      A, B, R                                           : IFA_Stack.StackMember;
      NewVars                                           : SeqAlgebra.Seq;
      DefinedVars, UnPreservedVars, AllVars, SeqOfExpns : SeqAlgebra.Seq;
      Lambda, Mu, Rho, Theta, ThetaTilde                : RelationAlgebra.Relation;
   begin
      if IFA_Stack.Top (S).MemberKind = IFA_Stack.Action then
         IFA_Stack.Pop (S, B);
         if not IFA_Stack.IsEmpty (S)
           and then -- only combine if top exists and is action
           IFA_Stack.Top (S).MemberKind = IFA_Stack.Action then
            IFA_Stack.Pop (S, A);
            IFA_Stack.EstablishMember (TheHeap, IFA_Stack.Action, R);
            SeqAlgebra.Union (TheHeap, A.DefinedVars, B.DefinedVars, DefinedVars);
            R.DefinedVars := DefinedVars;
            SeqAlgebra.Union (TheHeap, A.UnPreservedVars, B.UnPreservedVars, UnPreservedVars);
            R.UnPreservedVars := UnPreservedVars;
            SeqAlgebra.Union (TheHeap, A.AllVars, B.AllVars, AllVars);
            R.AllVars := AllVars;
            SeqAlgebra.Union (TheHeap, A.SeqOfExpns, B.SeqOfExpns, SeqOfExpns);
            R.SeqOfExpns := SeqOfExpns;

            SeqAlgebra.Complement (TheHeap, B.AllVars, A.AllVars, NewVars);
            RelationAlgebra.AddIdentity (TheHeap, A.Rho, NewVars);
            SeqAlgebra.DisposeOfSeq (TheHeap, NewVars);
            SeqAlgebra.Complement (TheHeap, A.AllVars, B.AllVars, NewVars);
            RelationAlgebra.AddIdentity (TheHeap, B.Rho, NewVars);
            SeqAlgebra.DisposeOfSeq (TheHeap, NewVars);

            RelationAlgebra.Composition (TheHeap, A.Rho, B.Lambda, Lambda);
            R.Lambda := Lambda;
            RelationAlgebra.AugmentRelation (TheHeap, R.Lambda, A.Lambda);

            RelationAlgebra.Composition (TheHeap, A.Mu, B.Rho, Mu);
            R.Mu := Mu;
            RelationAlgebra.AugmentRelation (TheHeap, R.Mu, B.Mu);
            RelationAlgebra.Composition (TheHeap, A.Rho, B.Rho, Rho);
            R.Rho := Rho;
            RelationAlgebra.RowRemoval (TheHeap, B.Theta, A.UnPreservedVars, Theta);
            R.Theta := Theta;
            RelationAlgebra.AugmentRelation (TheHeap, R.Theta, A.Theta);
            RelationAlgebra.RowRemoval (TheHeap, B.ThetaTilde, A.DefinedVars, ThetaTilde);
            R.ThetaTilde := ThetaTilde;
            RelationAlgebra.AugmentRelation (TheHeap, R.ThetaTilde, A.ThetaTilde);
            IFA_Stack.Push (S, R);
            IFA_Stack.DisposeOfMember (TheHeap, A);
            IFA_Stack.DisposeOfMember (TheHeap, B);
         else
            IFA_Stack.Push (S, B);
         end if;
      end if;
   end CombineSequence;

   -----------------------------------------------------------------
   -- This function returns a reference number for the implicit
   -- in stream associated with a shareable protected variable.
   -- It is used by both Mapping and ConnectProtectedStreams
   function AssociatedStreamRep (TheProtVarRep : Natural) return Natural
   --# global in Dictionary.Dict;
   is
      ProtSym, StreamSym : Dictionary.Symbol;
   begin
      ProtSym   := RepToSym (TheProtVarRep);
      StreamSym := Dictionary.GetProtectedImplicitInStream (ProtSym);
      return Natural (Dictionary.SymbolRef (StreamSym));
   end AssociatedStreamRep;

   -------------------------------------------------------------
   -- This procedure performs a modelling function connected with
   -- potentially shareable (unmoded) protected variables.
   -- For each protected variable P there is a companion in stream
   -- Pin.   Before the start of flow analysis, we need to initialize
   -- the in stream: for each P in set ShareableProtectedVars, we
   -- construct the mapping Pin <-- P.
   -- Between each mapping statement we construct Pin <-- Pin, P.
   -- The following procedure performs the former if WithSelfReference
   -- is False and the latter if it is True.
   procedure ConnectProtectedStreams (Node              : in STree.SyntaxNode;
                                      VarsToMap         : in SeqAlgebra.Seq;
                                      WithSelfReference : in Boolean)
   --# global in     Dictionary.Dict;
   --#        in     ReferencedVars;
   --#        in out ExpnLocations;
   --#        in out ExpnNumber;
   --#        in out KindDictionary;
   --#        in out ParamDictionary;
   --#        in out S;
   --#        in out Statistics.TableUsage;
   --#        in out StmtLocations;
   --#        in out TheHeap;
   --# derives ExpnLocations,
   --#         StmtLocations         from *,
   --#                                    Dictionary.Dict,
   --#                                    ExpnNumber,
   --#                                    Node,
   --#                                    ReferencedVars,
   --#                                    TheHeap,
   --#                                    VarsToMap,
   --#                                    WithSelfReference &
   --#         ExpnNumber,
   --#         KindDictionary,
   --#         ParamDictionary,
   --#         Statistics.TableUsage,
   --#         TheHeap               from *,
   --#                                    Dictionary.Dict,
   --#                                    ExpnNumber,
   --#                                    ReferencedVars,
   --#                                    TheHeap,
   --#                                    VarsToMap,
   --#                                    WithSelfReference &
   --#         S                     from *,
   --#                                    TheHeap;
   is
      ProtVarMem            : SeqAlgebra.MemberOfSeq;
      ProtVarRep, StreamRep : Natural;
      R                     : IFA_Stack.StackMember;

      procedure AddOneMapping (StreamRep, ProtVarRep : in Natural;
                               WithSelfReference     : in Boolean)
      --# global in     Node;
      --#        in     R;
      --#        in     ReferencedVars;
      --#        in out ExpnLocations;
      --#        in out ExpnNumber;
      --#        in out KindDictionary;
      --#        in out ParamDictionary;
      --#        in out Statistics.TableUsage;
      --#        in out StmtLocations;
      --#        in out TheHeap;
      --# derives ExpnLocations,
      --#         StmtLocations         from *,
      --#                                    ExpnNumber,
      --#                                    Node &
      --#         ExpnNumber,
      --#         KindDictionary        from *,
      --#                                    ExpnNumber &
      --#         ParamDictionary       from *,
      --#                                    ExpnNumber,
      --#                                    StreamRep &
      --#         Statistics.TableUsage,
      --#         TheHeap               from *,
      --#                                    ExpnNumber,
      --#                                    ProtVarRep,
      --#                                    R,
      --#                                    ReferencedVars,
      --#                                    StreamRep,
      --#                                    TheHeap,
      --#                                    WithSelfReference;

      is
         UndefinedVars : SeqAlgebra.Seq;
      begin
         IncrementExpression (ExpnNumber);

         StmtLocations (ExpnNumber) := Node;
         ExpnLocations (ExpnNumber) := Node;

         -- Rather unintuitively, the export is the IN stream associated with the PO
         ParamDictionary (ExpnNumber) := RepToSym (StreamRep);

         -- make Pin an export
         SeqAlgebra.AddMember (TheHeap, R.DefinedVars, StreamRep);
         SeqAlgebra.AddMember (TheHeap, R.UnPreservedVars, StreamRep);
         SeqAlgebra.AddMember (TheHeap, R.AllVars, StreamRep);
         SeqAlgebra.AddMember (TheHeap, R.SeqOfExpns, ExpnNumber);
         RelationAlgebra.InsertPair (TheHeap, R.Mu, ExpnNumber, StreamRep);

         -- make P an import
         SeqAlgebra.AddMember (TheHeap, ReferencedVars, ProtVarRep);
         SeqAlgebra.AddMember (TheHeap, R.AllVars, ProtVarRep);
         RelationAlgebra.InsertPair (TheHeap, R.Lambda, ProtVarRep, ExpnNumber);
         RelationAlgebra.InsertPair (TheHeap, R.Rho, ProtVarRep, StreamRep);
         RelationAlgebra.InsertPair (TheHeap, R.Theta, ProtVarRep, ExpnNumber);
         RelationAlgebra.InsertPair (TheHeap, R.ThetaTilde, ProtVarRep, ExpnNumber);

         -- conditionally make Pin an import
         if WithSelfReference then
            SeqAlgebra.AddMember (TheHeap, ReferencedVars, StreamRep);
            RelationAlgebra.InsertPair (TheHeap, R.Lambda, StreamRep, ExpnNumber);
            RelationAlgebra.InsertPair (TheHeap, R.Rho, StreamRep, StreamRep);
            RelationAlgebra.InsertPair (TheHeap, R.Theta, StreamRep, ExpnNumber);
            RelationAlgebra.InsertPair (TheHeap, R.ThetaTilde, StreamRep, ExpnNumber);
         end if;

         SeqAlgebra.Complement (TheHeap, R.AllVars, R.DefinedVars, UndefinedVars);
         RelationAlgebra.AddIdentity (TheHeap, R.Rho, UndefinedVars);
         SeqAlgebra.DisposeOfSeq (TheHeap, UndefinedVars);

         -- mark statement as being for modelling purposes only and not associated with
         -- a user source statement.  No errors are reported for these kinds of statement
         KindDictionary (ExpnNumber) := ModellingStmt;
      end AddOneMapping;

   begin -- ConnectProtectedStreams
      IFA_Stack.EstablishMember (TheHeap, IFA_Stack.Action, R);
      ProtVarMem := SeqAlgebra.FirstMember (TheHeap, VarsToMap);
      while not SeqAlgebra.IsNullMember (ProtVarMem) loop
         ProtVarRep := SeqAlgebra.Value_Of_Member (The_Heap => TheHeap,
                                                   M        => ProtVarMem);
         StreamRep  := AssociatedStreamRep (ProtVarRep);
         AddOneMapping (StreamRep, ProtVarRep, WithSelfReference);

         ProtVarMem := SeqAlgebra.NextMember (TheHeap, ProtVarMem);
      end loop;
      IFA_Stack.Push (S, R);
   end ConnectProtectedStreams;

   -------------------------------------------------------------
   -- The Rho and other sets/relations for the sequence of statements
   -- will have substituted the implicit in stream P__in for each
   -- referenced protected variable P.  This procedure initializes
   -- each P__in by constructing the mapping P__in <-- P
   procedure InitializeProtectedStreams (Node : in STree.SyntaxNode)
   --# global in     Dictionary.Dict;
   --#        in     ReferencedProtectedVars;
   --#        in     ReferencedVars;
   --#        in out ExpnLocations;
   --#        in out ExpnNumber;
   --#        in out KindDictionary;
   --#        in out ParamDictionary;
   --#        in out S;
   --#        in out Statistics.TableUsage;
   --#        in out StmtLocations;
   --#        in out TheHeap;
   --# derives ExpnLocations,
   --#         StmtLocations         from *,
   --#                                    Dictionary.Dict,
   --#                                    ExpnNumber,
   --#                                    Node,
   --#                                    ReferencedProtectedVars,
   --#                                    ReferencedVars,
   --#                                    TheHeap &
   --#         ExpnNumber,
   --#         KindDictionary,
   --#         ParamDictionary,
   --#         S                     from *,
   --#                                    Dictionary.Dict,
   --#                                    ExpnNumber,
   --#                                    ReferencedProtectedVars,
   --#                                    ReferencedVars,
   --#                                    TheHeap &
   --#         Statistics.TableUsage,
   --#         TheHeap               from *,
   --#                                    Dictionary.Dict,
   --#                                    ExpnNumber,
   --#                                    ReferencedProtectedVars,
   --#                                    ReferencedVars,
   --#                                    S,
   --#                                    TheHeap;
   is
      TempStackTop : IFA_Stack.StackMember;
   begin
      if not SeqAlgebra.IsEmptySeq (TheHeap, ReferencedProtectedVars) then
         IFA_Stack.Pop (S, TempStackTop);
         -- Then build the relation for initializing the streams
         ConnectProtectedStreams (Node              => Node,
                                  VarsToMap         => ReferencedProtectedVars,
                                  WithSelfReference => False);
         -- Restore stack
         IFA_Stack.Push (S, TempStackTop);
         -- and combine the intializations in
         CombineSequence;
      end if;
   end InitializeProtectedStreams;

   -------------------------------------------------------------

   procedure Mapping (Node : in STree.SyntaxNode)
   -- This procedure constructs the flow relations for a mapping statement.
   --# global in     ComponentData;
   --#        in     Dictionary.Dict;
   --#        in     ReferencedProtectedVars;
   --#        in     ReferencedVars;
   --#        in     ShareableProtectedVars;
   --#        in     STree.Table;
   --#        in     Table;
   --#        in out ExpnLocations;
   --#        in out ExpnNumber;
   --#        in out KindDictionary;
   --#        in out ParamDictionary;
   --#        in out S;
   --#        in out Statistics.TableUsage;
   --#        in out StmtLocations;
   --#        in out TheHeap;
   --# derives ExpnLocations,
   --#         ExpnNumber,
   --#         KindDictionary,
   --#         ParamDictionary,
   --#         S,
   --#         StmtLocations         from *,
   --#                                    ComponentData,
   --#                                    Dictionary.Dict,
   --#                                    ExpnNumber,
   --#                                    Node,
   --#                                    ParamDictionary,
   --#                                    ReferencedProtectedVars,
   --#                                    ReferencedVars,
   --#                                    ShareableProtectedVars,
   --#                                    STree.Table,
   --#                                    Table,
   --#                                    TheHeap &
   --#         Statistics.TableUsage,
   --#         TheHeap               from *,
   --#                                    ComponentData,
   --#                                    Dictionary.Dict,
   --#                                    ExpnNumber,
   --#                                    Node,
   --#                                    ParamDictionary,
   --#                                    ReferencedProtectedVars,
   --#                                    ReferencedVars,
   --#                                    S,
   --#                                    ShareableProtectedVars,
   --#                                    STree.Table,
   --#                                    Table,
   --#                                    TheHeap;
   is
      ExportAtom                 : Heap.Atom;
      DepList                    : SeqAlgebra.Seq;
      ExpVarRep, FirstExpression : Natural;

      NmbrOfExpns            : ExpnCountRange;
      R                      : IFA_Stack.StackMember;
      UndefinedVars          : SeqAlgebra.Seq;
      AssignedExpressionNode : STree.SyntaxNode;
      AssignedSym            : Dictionary.Symbol := Dictionary.NullSymbol;
      ExportSet              : SeqAlgebra.Seq; -- set of all 'exports' of this statement
      AssignmentKind         : ExpnKind;
      -- this set gets populated with all the protected vars Pin that need a mapping Pin <- Pin adding
      ProtectedSelfReferenceToAdd : SeqAlgebra.Seq;
      -- this set is the set ofthings we need to add Pin <= Pin, P to.
      ProtectedUpdatesToConnect : SeqAlgebra.Seq;
      ProtVarMem                : SeqAlgebra.MemberOfSeq;
      ProtVarRep                : Natural;

      procedure SubstituteProtectedVars (Imports : in SeqAlgebra.Seq)
      --# global in     Dictionary.Dict;
      --#        in     ProtectedSelfReferenceToAdd;
      --#        in     ReferencedProtectedVars;
      --#        in     ShareableProtectedVars;
      --#        in out Statistics.TableUsage;
      --#        in out TheHeap;
      --# derives Statistics.TableUsage,
      --#         TheHeap               from *,
      --#                                    Dictionary.Dict,
      --#                                    Imports,
      --#                                    ProtectedSelfReferenceToAdd,
      --#                                    ReferencedProtectedVars,
      --#                                    ShareableProtectedVars,
      --#                                    TheHeap;
      is
         ProtectedImports : SeqAlgebra.Seq;
         ProtMem          : SeqAlgebra.MemberOfSeq;
         ProtRep          : Natural;
      begin
         SeqAlgebra.Intersection (TheHeap, Imports, ShareableProtectedVars,
                                  -- to get
                                  ProtectedImports);
         SeqAlgebra.Reduction (TheHeap, Imports, ProtectedImports);
         -- Imports now only contain things that AREN'T shareable protected vars and
         -- ProtectedImports contains a list of that ARE
         -- Now we insert the associated in stream for each member of ProtectedImports into Imports
         ProtMem := SeqAlgebra.FirstMember (TheHeap, ProtectedImports);
         while not SeqAlgebra.IsNullMember (ProtMem) loop
            ProtRep := SeqAlgebra.Value_Of_Member (The_Heap => TheHeap,
                                                   M        => ProtMem);
            SeqAlgebra.AddMember (TheHeap, Imports, AssociatedStreamRep (ProtRep));
            -- and in the set of all referenced protected vars
            SeqAlgebra.AddMember (TheHeap, ReferencedProtectedVars, ProtRep);
            -- and we add the stream to the set of things that require a self-reference in mapping
            SeqAlgebra.AddMember (TheHeap, ProtectedSelfReferenceToAdd, AssociatedStreamRep (ProtRep));
            ProtMem := SeqAlgebra.NextMember (TheHeap, ProtMem);
         end loop;
         SeqAlgebra.DisposeOfSeq (TheHeap, ProtectedImports);
      end SubstituteProtectedVars;

      ------------------------------------------------------

      procedure ProcedureAssignmentKind (ExNum          : in     ExpnIndexRange;
                                         AssignmentKind :    out ExpnKind)
      --# global in     ComponentData;
      --#        in     Dictionary.Dict;
      --#        in     ExportSet;
      --#        in     ParamDictionary;
      --#        in out Statistics.TableUsage;
      --#        in out TheHeap;
      --# derives AssignmentKind        from ComponentData,
      --#                                    Dictionary.Dict,
      --#                                    ExNum,
      --#                                    ExportSet,
      --#                                    ParamDictionary,
      --#                                    TheHeap &
      --#         Statistics.TableUsage,
      --#         TheHeap               from *,
      --#                                    ComponentData,
      --#                                    Dictionary.Dict,
      --#                                    ExNum,
      --#                                    ParamDictionary,
      --#                                    TheHeap;
      is
         ExportSiblings : SeqAlgebra.Seq;
         CurrentSibling : SeqAlgebra.MemberOfSeq;
      begin
         AssignmentKind := ComplexAssignment;
         if Dictionary.IsSubcomponent (ParamDictionary (ExNum)) then
            ComponentManager.GetLeaves
              (TheHeap,
               ComponentData,
               ComponentManager.GetRoot
                 (ComponentData,
                  ComponentManager.GetComponentNode (ComponentData, ParamDictionary (ExNum))),
               -- to get
               ExportSiblings);
            CurrentSibling := SeqAlgebra.FirstMember (TheHeap, ExportSiblings);
            while not SeqAlgebra.IsNullMember (CurrentSibling) loop
               if not SeqAlgebra.IsMember
                 (TheHeap,
                  ExportSet,
                  SeqAlgebra.Value_Of_Member (The_Heap => TheHeap,
                                              M        => CurrentSibling)) then
                  AssignmentKind := FieldUpdateByProc;
                  exit;
               end if;

               CurrentSibling := SeqAlgebra.NextMember (TheHeap, CurrentSibling);
            end loop;
         end if;
      end ProcedureAssignmentKind;

   begin -- Mapping
      SeqAlgebra.CreateSeq (TheHeap, ExportSet);
      SeqAlgebra.CreateSeq (TheHeap, ProtectedSelfReferenceToAdd);
      IFA_Stack.EstablishMember (TheHeap, IFA_Stack.Action, R);
      NmbrOfExpns := 0;
      RefList.FirstExport (Table, TheHeap, Node,
                           -- to get
                           ExportAtom);
      while ExportAtom /= NullAtom loop
         --# assert NmbrOfExpns in ExpnCountRange and
         --#   ExportAtom in Heap.Atom;
         IncrementExpression (ExpnNumber);

         IncrementExpression (NmbrOfExpns);
         StmtLocations (ExpnNumber)   := Node;
         ParamDictionary (ExpnNumber) := SymValue (ExportAtom);
         AssignedSym                  := SymValue (ExportAtom);
         ExpVarRep                    := Heap.AValue (TheHeap, ExportAtom);
         SeqAlgebra.AddMember (TheHeap, ExportSet, ExpVarRep);
         SeqAlgebra.AddMember (TheHeap, R.DefinedVars, ExpVarRep);
         SeqAlgebra.AddMember (TheHeap, R.UnPreservedVars, ExpVarRep);
         SeqAlgebra.AddMember (TheHeap, R.AllVars, ExpVarRep);
         SeqAlgebra.AddMember (TheHeap, R.SeqOfExpns, ExpnNumber);
         RelationAlgebra.InsertPair (TheHeap, R.Mu, ExpnNumber, ExpVarRep);
         DepList := RefList.DependencyList (TheHeap, ExportAtom);

         -- Where DepList contains references to potentially shareable
         -- protected variables (indicated by membership of ShareableProtectedVars)
         -- then we need to replace each such P with its associated implicit in stream Pin
         SubstituteProtectedVars (DepList);
         -- After the above call, set ProtectedSelfReferenceToAdd contains all the
         -- Pin have been substituted so we can add self-dependencies on them below

         -- new loop-free version using suitable rel & seq algebra calls
         SeqAlgebra.AugmentSeq (TheHeap, ReferencedVars, DepList);
         SeqAlgebra.AugmentSeq (TheHeap, R.AllVars, DepList);
         RelationAlgebra.AddCol (TheHeap, R.Lambda, ExpnNumber, DepList);
         RelationAlgebra.AddCol (TheHeap, R.Rho, ExpVarRep, DepList);
         -- In the two following statements, ordered pairs in Theta and ThetaTilde
         -- associated with a mapping statement are all attributed to the first
         -- of its expressions, to avoid replication of SPARK error messages.
         FirstExpression := (ExpnNumber - NmbrOfExpns) + 1;
         RelationAlgebra.AddCol (TheHeap, R.Theta, FirstExpression, DepList);
         RelationAlgebra.AddCol (TheHeap, R.ThetaTilde, FirstExpression, DepList);
         ExportAtom := RefList.NextExport (TheHeap, ExportAtom);
      end loop;

      -- We have now modelled all the explicit mappings obtained from the RefList for
      -- the statement in question (with any protected imports replaced by their
      -- associated implicit in stream.  For each of these streams, we now need to add
      -- a self reference Pin <- Pin
      ProtVarMem := SeqAlgebra.FirstMember (TheHeap, ProtectedSelfReferenceToAdd);
      while not SeqAlgebra.IsNullMember (ProtVarMem) loop
         --# assert NmbrOfExpns in ExpnCountRange;
         ProtVarRep := SeqAlgebra.Value_Of_Member (The_Heap => TheHeap,
                                                   M        => ProtVarMem);
         -- ProtVarRep contains one instance of a Pin
         IncrementExpression (ExpnNumber);
         IncrementExpression (NmbrOfExpns);
         StmtLocations (ExpnNumber)   := Node;
         ParamDictionary (ExpnNumber) := RepToSym (ProtVarRep);
         AssignedSym                  := RepToSym (ProtVarRep);
         -- make Pin an export
         SeqAlgebra.AddMember (TheHeap, ExportSet, ProtVarRep);
         SeqAlgebra.AddMember (TheHeap, R.DefinedVars, ProtVarRep);
         SeqAlgebra.AddMember (TheHeap, R.UnPreservedVars, ProtVarRep);
         SeqAlgebra.AddMember (TheHeap, R.AllVars, ProtVarRep);
         SeqAlgebra.AddMember (TheHeap, R.SeqOfExpns, ExpnNumber);
         RelationAlgebra.InsertPair (TheHeap, R.Mu, ExpnNumber, ProtVarRep);
         -- make Pin an import
         SeqAlgebra.AddMember (TheHeap, ReferencedVars, ProtVarRep);
         RelationAlgebra.InsertPair (TheHeap, R.Lambda, ProtVarRep, ExpnNumber);
         RelationAlgebra.InsertPair (TheHeap, R.Rho, ProtVarRep, ProtVarRep);
         RelationAlgebra.InsertPair (TheHeap, R.Theta, ProtVarRep, ExpnNumber);
         RelationAlgebra.InsertPair (TheHeap, R.ThetaTilde, ProtVarRep, ExpnNumber);

         ProtVarMem := SeqAlgebra.NextMember (TheHeap, ProtVarMem);
      end loop;

      -- after this mapping statement, we will add a modelling statement (of the fomr Pin <- Pin, P) for
      -- protected state that has been defined by the mapping
      SeqAlgebra.Intersection (TheHeap, R.DefinedVars, ShareableProtectedVars,
                               -- to get
                               ProtectedUpdatesToConnect);

      SeqAlgebra.Complement (TheHeap, R.AllVars, R.DefinedVars, UndefinedVars);
      RelationAlgebra.AddIdentity (TheHeap, R.Rho, UndefinedVars);
      SeqAlgebra.DisposeOfSeq (TheHeap, UndefinedVars);
      IFA_Stack.Push (S, R);

      -- tests to distinguish between a simple assignment statement
      -- where we want to report error on expression and procedure call which
      -- is potentially a multiple assignment.  Note however that a procedure
      -- call with a single export still wants to report error on statement not
      -- expression.  Also, if assigned variable is an array we must report on
      -- the statement in case it is an index that is undefined.
      AssignedExpressionNode := STree.Next_Sibling (Current_Node => STree.Child_Node (Current_Node => Node));

      if STree.Syntax_Node_Type (Node => AssignedExpressionNode) = SP_Symbols.expression then
         -- assignment statement not procedure call
         if NmbrOfExpns = 1 then
            -- single assignment, could be scalar, array aggregate or unexpanded record aggregate
            if Dictionary.TypeIsArray (Dictionary.GetType (AssignedSym)) then
               -- single assignment to array regarded as a complex assignment
               KindDictionary (ExpnNumber) := ComplexAssignment;
            else -- assignment to scalar or unexpanded record
               ExpnLocations (ExpnNumber)  := AssignedExpressionNode;
               KindDictionary (ExpnNumber) := SimpleAssignment;
            end if;

         else -- multiple expressions, must be expanded record aggregate
            for ExpnCounter in ExpnCountRange range (ExpnNumber - NmbrOfExpns) + 1 .. ExpnNumber loop
               ProcedureAssignmentKind (ExpnCounter,
                                        -- to get
                                        AssignmentKind);
               KindDictionary (ExpnCounter) := AssignmentKind;
            end loop;
         end if;

      else -- procedure call - for loop works even in single export case
         for ExpnCounter in ExpnCountRange range (ExpnNumber - NmbrOfExpns) + 1 .. ExpnNumber loop
            ProcedureAssignmentKind (ExpnCounter,
                                     -- to get
                                     AssignmentKind);
            KindDictionary (ExpnCounter) := AssignmentKind;
         end loop;
      end if;
      SeqAlgebra.DisposeOfSeq (TheHeap, ExportSet);
      SeqAlgebra.DisposeOfSeq (TheHeap, ProtectedSelfReferenceToAdd);

      -- Add in modelling statement Pin <- Pin, P;
      ConnectProtectedStreams (Node              => Node,
                               VarsToMap         => ProtectedUpdatesToConnect,
                               WithSelfReference => True);
      CombineSequence; -- connect it to the original mapping that was top of stack

      -- new top of stack is the combined effect of the Mapping and the protected state update model
      SeqAlgebra.DisposeOfSeq (TheHeap, ProtectedUpdatesToConnect);
   end Mapping;

   -----------------------------------------------------------------

   procedure ProcessExpression (Node, StmtNode : in STree.SyntaxNode;
                                R              : in IFA_Stack.StackMember)
   --# global in     ReferencedVars;
   --#        in     Table;
   --#        in out ExpnLocations;
   --#        in out ExpnNumber;
   --#        in out KindDictionary;
   --#        in out ParamDictionary;
   --#        in out Statistics.TableUsage;
   --#        in out StmtLocations;
   --#        in out TheHeap;
   --# derives ExpnLocations         from *,
   --#                                    ExpnNumber,
   --#                                    Node &
   --#         ExpnNumber,
   --#         ParamDictionary       from *,
   --#                                    ExpnNumber &
   --#         KindDictionary        from *,
   --#                                    ExpnNumber,
   --#                                    R &
   --#         Statistics.TableUsage,
   --#         TheHeap               from *,
   --#                                    ExpnNumber,
   --#                                    Node,
   --#                                    R,
   --#                                    ReferencedVars,
   --#                                    Table,
   --#                                    TheHeap &
   --#         StmtLocations         from *,
   --#                                    ExpnNumber,
   --#                                    StmtNode;
   is
      ImportList : SeqAlgebra.Seq;
   begin
      IncrementExpression (ExpnNumber);
      ExpnLocations (ExpnNumber) := Node;
      StmtLocations (ExpnNumber) := StmtNode;

      --  The expression being processed controls a compound expression,
      --  or an implicit or explicit loop exit, so is not directly connected
      --  to any variable or export, so...
      ParamDictionary (ExpnNumber) := Dictionary.NullSymbol;

      case R.MemberKind is
         when IFA_Stack.IfNode | IFA_Stack.ElsifNode | IFA_Stack.CaseNode =>
            KindDictionary (ExpnNumber) := ForkExpn;
         when IFA_Stack.ExitNode =>
            KindDictionary (ExpnNumber) := ExitExpn;
         when IFA_Stack.DefaultExitNode                             --898
           =>
            KindDictionary (ExpnNumber) := DefaultExitExpn;         --898
         when others =>
            null;
      end case;
      SeqAlgebra.AddMember (TheHeap, R.SeqOfExpns, ExpnNumber);
      RefList.ReferencedVarList (Table, TheHeap, Node,
                                 -- to get
                                 ImportList);

      SeqAlgebra.AugmentSeq (TheHeap, ReferencedVars, ImportList);
      SeqAlgebra.AugmentSeq (TheHeap, R.AllVars, ImportList);
   end ProcessExpression;

   -----------------------------------------------------------------

   procedure StartIf
   -- This procedure constructs the stack member for a condition node of an
   -- if_statement.
   --# global in     Node;
   --#        in     ReferencedVars;
   --#        in     Table;
   --#        in out ExpnLocations;
   --#        in out ExpnNumber;
   --#        in out KindDictionary;
   --#        in out ParamDictionary;
   --#        in out S;
   --#        in out Statistics.TableUsage;
   --#        in out StmtLocations;
   --#        in out TheHeap;
   --# derives ExpnLocations,
   --#         StmtLocations         from *,
   --#                                    ExpnNumber,
   --#                                    Node &
   --#         ExpnNumber,
   --#         ParamDictionary       from *,
   --#                                    ExpnNumber &
   --#         KindDictionary        from *,
   --#                                    ExpnNumber,
   --#                                    TheHeap &
   --#         S                     from *,
   --#                                    TheHeap &
   --#         Statistics.TableUsage,
   --#         TheHeap               from *,
   --#                                    ExpnNumber,
   --#                                    Node,
   --#                                    ReferencedVars,
   --#                                    Table,
   --#                                    TheHeap;
   is
      R : IFA_Stack.StackMember;
   begin
      IFA_Stack.EstablishMember (TheHeap, IFA_Stack.IfNode, R);
      ProcessExpression (Node, Node, R);
      IFA_Stack.Push (S, R);
   end StartIf;

   -----------------------------------------------------------------

   procedure StartElsIf
   -- This procedure constructs the stack member for a condition node of an
   -- elsif clause.
   --# global in     Node;
   --#        in     ReferencedVars;
   --#        in     Table;
   --#        in out ExpnLocations;
   --#        in out ExpnNumber;
   --#        in out KindDictionary;
   --#        in out ParamDictionary;
   --#        in out S;
   --#        in out Statistics.TableUsage;
   --#        in out StmtLocations;
   --#        in out TheHeap;
   --# derives ExpnLocations,
   --#         StmtLocations         from *,
   --#                                    ExpnNumber,
   --#                                    Node &
   --#         ExpnNumber,
   --#         ParamDictionary       from *,
   --#                                    ExpnNumber &
   --#         KindDictionary        from *,
   --#                                    ExpnNumber,
   --#                                    TheHeap &
   --#         S                     from *,
   --#                                    TheHeap &
   --#         Statistics.TableUsage,
   --#         TheHeap               from *,
   --#                                    ExpnNumber,
   --#                                    Node,
   --#                                    ReferencedVars,
   --#                                    Table,
   --#                                    TheHeap;
   is
      R : IFA_Stack.StackMember;
   begin
      IFA_Stack.EstablishMember (TheHeap, IFA_Stack.ElsifNode, R);
      ProcessExpression (Node, Node, R);
      IFA_Stack.Push (S, R);
   end StartElsIf;

   -----------------------------------------------------------------

   procedure StartCase
   -- This procedure constructs the stack member for the expression node of a
   -- case_statement.
   --# global in     Node;
   --#        in     ReferencedVars;
   --#        in     Table;
   --#        in out ExpnLocations;
   --#        in out ExpnNumber;
   --#        in out KindDictionary;
   --#        in out ParamDictionary;
   --#        in out S;
   --#        in out Statistics.TableUsage;
   --#        in out StmtLocations;
   --#        in out TheHeap;
   --# derives ExpnLocations,
   --#         StmtLocations         from *,
   --#                                    ExpnNumber,
   --#                                    Node &
   --#         ExpnNumber,
   --#         ParamDictionary       from *,
   --#                                    ExpnNumber &
   --#         KindDictionary        from *,
   --#                                    ExpnNumber,
   --#                                    TheHeap &
   --#         S                     from *,
   --#                                    TheHeap &
   --#         Statistics.TableUsage,
   --#         TheHeap               from *,
   --#                                    ExpnNumber,
   --#                                    Node,
   --#                                    ReferencedVars,
   --#                                    Table,
   --#                                    TheHeap;
   is
      R : IFA_Stack.StackMember;
   begin
      IFA_Stack.EstablishMember (TheHeap, IFA_Stack.CaseNode, R);
      ProcessExpression (Node, Node, R);
      IFA_Stack.Push (S, R);
   end StartCase;

   -----------------------------------------------------------------

   procedure StartLoop
   --# global in     ComponentData;
   --#        in     Dictionary.Dict;
   --#        in     Node;
   --#        in     ReferencedProtectedVars;
   --#        in     ReferencedVars;
   --#        in     ShareableProtectedVars;
   --#        in     STree.Table;
   --#        in     Table;
   --#        in out ExpnLocations;
   --#        in out ExpnNumber;
   --#        in out KindDictionary;
   --#        in out ParamDictionary;
   --#        in out S;
   --#        in out Statistics.TableUsage;
   --#        in out StmtLocations;
   --#        in out TheHeap;
   --# derives ExpnLocations,
   --#         ExpnNumber,
   --#         KindDictionary,
   --#         ParamDictionary,
   --#         S,
   --#         StmtLocations         from *,
   --#                                    ComponentData,
   --#                                    Dictionary.Dict,
   --#                                    ExpnNumber,
   --#                                    Node,
   --#                                    ParamDictionary,
   --#                                    ReferencedProtectedVars,
   --#                                    ReferencedVars,
   --#                                    ShareableProtectedVars,
   --#                                    STree.Table,
   --#                                    Table,
   --#                                    TheHeap &
   --#         Statistics.TableUsage,
   --#         TheHeap               from *,
   --#                                    ComponentData,
   --#                                    Dictionary.Dict,
   --#                                    ExpnNumber,
   --#                                    Node,
   --#                                    ParamDictionary,
   --#                                    ReferencedProtectedVars,
   --#                                    ReferencedVars,
   --#                                    S,
   --#                                    ShareableProtectedVars,
   --#                                    STree.Table,
   --#                                    Table,
   --#                                    TheHeap;
   is
      LocalNode : STree.SyntaxNode;

      procedure PushLoopHead
      --# global in out S;
      --#        in out Statistics.TableUsage;
      --#        in out TheHeap;
      --# derives S,
      --#         Statistics.TableUsage,
      --#         TheHeap               from *,
      --#                                    TheHeap;
      is
         R : IFA_Stack.StackMember;
      begin
         IFA_Stack.EstablishMember (TheHeap, IFA_Stack.LoopHead, R);
         IFA_Stack.Push (S, R);
      end PushLoopHead;

      -----------------------------------------------------------------

      procedure StartWhileLoop
      --# global in     LocalNode;
      --#        in     ReferencedVars;
      --#        in     Table;
      --#        in out ExpnLocations;
      --#        in out ExpnNumber;
      --#        in out KindDictionary;
      --#        in out ParamDictionary;
      --#        in out S;
      --#        in out Statistics.TableUsage;
      --#        in out StmtLocations;
      --#        in out TheHeap;
      --# derives ExpnLocations,
      --#         StmtLocations         from *,
      --#                                    ExpnNumber,
      --#                                    LocalNode &
      --#         ExpnNumber,
      --#         ParamDictionary       from *,
      --#                                    ExpnNumber &
      --#         KindDictionary        from *,
      --#                                    ExpnNumber,
      --#                                    TheHeap &
      --#         S                     from *,
      --#                                    TheHeap &
      --#         Statistics.TableUsage,
      --#         TheHeap               from *,
      --#                                    ExpnNumber,
      --#                                    LocalNode,
      --#                                    ReferencedVars,
      --#                                    Table,
      --#                                    TheHeap;
      is
         R1, R2 : IFA_Stack.StackMember;
      begin
         IFA_Stack.EstablishMember (TheHeap, IFA_Stack.ExitNode, R1);
         IFA_Stack.EstablishMember (TheHeap, IFA_Stack.ExitBranch, R2);
         PushLoopHead;
         ProcessExpression (LocalNode, LocalNode, R1);
         IFA_Stack.Push (S, R1);
         IFA_Stack.Push (S, R2);
      end StartWhileLoop;

      -----------------------------------------------------------------

      procedure StartForLoop
      --# global in     ComponentData;
      --#        in     Dictionary.Dict;
      --#        in     LocalNode;
      --#        in     ReferencedProtectedVars;
      --#        in     ReferencedVars;
      --#        in     ShareableProtectedVars;
      --#        in     STree.Table;
      --#        in     Table;
      --#        in out ExpnLocations;
      --#        in out ExpnNumber;
      --#        in out KindDictionary;
      --#        in out ParamDictionary;
      --#        in out S;
      --#        in out Statistics.TableUsage;
      --#        in out StmtLocations;
      --#        in out TheHeap;
      --# derives ExpnLocations,
      --#         ExpnNumber,
      --#         KindDictionary,
      --#         ParamDictionary,
      --#         S,
      --#         StmtLocations         from *,
      --#                                    ComponentData,
      --#                                    Dictionary.Dict,
      --#                                    ExpnNumber,
      --#                                    LocalNode,
      --#                                    ParamDictionary,
      --#                                    ReferencedProtectedVars,
      --#                                    ReferencedVars,
      --#                                    ShareableProtectedVars,
      --#                                    STree.Table,
      --#                                    Table,
      --#                                    TheHeap &
      --#         Statistics.TableUsage,
      --#         TheHeap               from *,
      --#                                    ComponentData,
      --#                                    Dictionary.Dict,
      --#                                    ExpnNumber,
      --#                                    LocalNode,
      --#                                    ParamDictionary,
      --#                                    ReferencedProtectedVars,
      --#                                    ReferencedVars,
      --#                                    S,
      --#                                    ShareableProtectedVars,
      --#                                    STree.Table,
      --#                                    Table,
      --#                                    TheHeap;
      is
         R1, R2, R3    : IFA_Stack.StackMember;
         ControlVarRep : Natural;
         ExportAtom    : Heap.Atom;
      begin
         -- LocalNode is loop_parameter_specification;
         -- Establish initialization of control variable;

         -- Establish test for termination;
         -- moved lower and made conditional
         -- IFA_Stack.EstablishMember (TheHeap,
         --                               IFA_Stack.ExitNode,
         --                               R1);
         -- IFA_Stack.EstablishMember (TheHeap,
         --                               IFA_Stack.ExitBranch,
         --                               R2);

         -- Establish model of updating of control variable;
         IFA_Stack.EstablishMember (TheHeap, IFA_Stack.Action, R3);
         Mapping (LocalNode);
         KindDictionary (ExpnNumber) := ControlVarAssignment;
         PushLoopHead;
         RefList.FirstExport (Table, TheHeap, LocalNode,
                              -- to get
                              ExportAtom);
         ControlVarRep := Heap.AValue (TheHeap, ExportAtom);

         -- ChHeck to see whether loop must be enetered or might be bypassed
         if not Dictionary.LoopParameterHasStaticRange (RepToSym (ControlVarRep)) then
            -- We have a loop that may be bypassed because it's range might be empty so
            -- we need to set up an exit at the top of the loop.
            IFA_Stack.EstablishMember (TheHeap, IFA_Stack.ExitNode, R1);
            IFA_Stack.EstablishMember (TheHeap, IFA_Stack.ExitBranch, R2);
            IncrementExpression (ExpnNumber);
            ExpnLocations (ExpnNumber)  := LocalNode;
            StmtLocations (ExpnNumber)  := STree.Parent_Node (Current_Node => LocalNode);
            KindDictionary (ExpnNumber) := ExitExpn;
            SeqAlgebra.AddMember (TheHeap, R1.SeqOfExpns, ExpnNumber);
            SeqAlgebra.AddMember (TheHeap, ReferencedVars, ControlVarRep);
            SeqAlgebra.AddMember (TheHeap, R1.AllVars, ControlVarRep);
            IFA_Stack.Push (S, R1);
            IFA_Stack.Push (S, R2);
         end if;

         IncrementExpression (ExpnNumber);
         StmtLocations (ExpnNumber) := LocalNode;
         SeqAlgebra.AddMember (TheHeap, R3.DefinedVars, ControlVarRep);
         SeqAlgebra.AddMember (TheHeap, R3.UnPreservedVars, ControlVarRep);
         SeqAlgebra.AddMember (TheHeap, R3.AllVars, ControlVarRep);
         SeqAlgebra.AddMember (TheHeap, R3.SeqOfExpns, ExpnNumber);
         RelationAlgebra.InsertPair (TheHeap, R3.Mu, ExpnNumber, ControlVarRep);
         SeqAlgebra.AddMember (TheHeap, ReferencedVars, ControlVarRep);
         RelationAlgebra.InsertPair (TheHeap, R3.Lambda, ControlVarRep, ExpnNumber);
         RelationAlgebra.InsertPair (TheHeap, R3.Rho, ControlVarRep, ControlVarRep);
         RelationAlgebra.InsertPair (TheHeap, R3.Theta, ControlVarRep, ExpnNumber);
         RelationAlgebra.InsertPair (TheHeap, R3.ThetaTilde, ControlVarRep, ExpnNumber);
         IFA_Stack.Push (S, R3);
         KindDictionary (ExpnNumber) := ControlVarAssignment;
         --# accept Flow, 601, ExpnNumber, S, "Spurious coupling expected" &
         --#        Flow, 601, StmtLocations, S, "Spurious coupling expected" &
         --#        Flow, 601, ExpnLocations, S, "Spurious coupling expected" &
         --#        Flow, 601, KindDictionary, S, "Spurious coupling expected";
      end StartForLoop; -- ignore 4 spurious couplings with S

   begin -- StartLoop

      -- advance to iteration_scheme;
      LocalNode := STree.Child_Node (Current_Node => Node);
      if LocalNode = STree.NullNode then
         -- loop does not have an iteration_scheme;
         PushLoopHead;
      else
         -- localnode is of type iteration_scheme;
         LocalNode := STree.Child_Node (Current_Node => LocalNode);
         case STree.Syntax_Node_Type (Node => LocalNode) is
            when SP_Symbols.condition =>
               StartWhileLoop;
            when SP_Symbols.loop_parameter_specification =>
               StartForLoop;
            when others =>
               null;
         end case;
      end if;
   end StartLoop;

   -----------------------------------------------------------------

   procedure ModelExit
   --# global in     Node;
   --#        in     ReferencedVars;
   --#        in     STree.Table;
   --#        in     Table;
   --#        in out ExpnLocations;
   --#        in out ExpnNumber;
   --#        in out KindDictionary;
   --#        in out ParamDictionary;
   --#        in out S;
   --#        in out Statistics.TableUsage;
   --#        in out StmtLocations;
   --#        in out TheHeap;
   --# derives ExpnLocations,
   --#         ExpnNumber,
   --#         ParamDictionary       from *,
   --#                                    ExpnNumber,
   --#                                    Node &
   --#         KindDictionary        from *,
   --#                                    ExpnNumber,
   --#                                    Node,
   --#                                    TheHeap &
   --#         S                     from *,
   --#                                    Node,
   --#                                    TheHeap &
   --#         Statistics.TableUsage,
   --#         TheHeap               from *,
   --#                                    ExpnNumber,
   --#                                    Node,
   --#                                    ReferencedVars,
   --#                                    Table,
   --#                                    TheHeap &
   --#         StmtLocations         from *,
   --#                                    ExpnNumber,
   --#                                    Node,
   --#                                    STree.Table;
   is
      R1, R2 : IFA_Stack.StackMember;
   begin
      IFA_Stack.EstablishMember (TheHeap, IFA_Stack.ExitNode, R1);
      IFA_Stack.EstablishMember (TheHeap, IFA_Stack.ExitBranch, R2);
      if Node /= STree.NullNode then
         ProcessExpression (Node, STree.Parent_Node (Current_Node => Node), R1);
         IFA_Stack.Push (S, R1);
         IFA_Stack.Push (S, R2);
      else
         IFA_Stack.Push (S, R1);
      end if;
   end ModelExit;

   -----------------------------------------------------------------

   -- This procedure handles two things:
   -- (1) For a plain loop with no exits it ass an "exit when false" at the end
   -- (2) For a FOR loop which must have been entered it adds an exit, dependent on
   --     the loop counter at the end (so that the body of the loop is always executed
   --     at least once.
   -- In all other cases it models a null statement.
   procedure ModelDefaultExitOrFinalForLoopExit
   --# global in     Dictionary.Dict;
   --#        in     Node;
   --#        in     ReferencedVars;
   --#        in     STree.Table;
   --#        in     Table;
   --#        in out ExpnLocations;
   --#        in out ExpnNumber;
   --#        in out KindDictionary;
   --#        in out ParamDictionary;
   --#        in out S;
   --#        in out Statistics.TableUsage;
   --#        in out StmtLocations;
   --#        in out TheHeap;
   --# derives ExpnLocations,
   --#         ExpnNumber,
   --#         KindDictionary,
   --#         StmtLocations         from *,
   --#                                    Dictionary.Dict,
   --#                                    ExpnNumber,
   --#                                    Node,
   --#                                    STree.Table,
   --#                                    Table,
   --#                                    TheHeap &
   --#         ParamDictionary       from *,
   --#                                    Dictionary.Dict,
   --#                                    ExpnNumber,
   --#                                    Node,
   --#                                    STree.Table &
   --#         S                     from *,
   --#                                    Dictionary.Dict,
   --#                                    Node,
   --#                                    STree.Table,
   --#                                    Table,
   --#                                    TheHeap &
   --#         Statistics.TableUsage,
   --#         TheHeap               from *,
   --#                                    Dictionary.Dict,
   --#                                    ExpnNumber,
   --#                                    Node,
   --#                                    ReferencedVars,
   --#                                    STree.Table,
   --#                                    Table,
   --#                                    TheHeap;
   --# pre STree.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.end_of_loop;
   is
      R1, R2      : IFA_Stack.StackMember;
      LoopCounter : Dictionary.Symbol;

      function IsAForLoop return Boolean
      --# global in Node;
      --#        in STree.Table;
      is
      begin
         -- look for a loop_parameter_specification node to see if we are in a for loop
         return STree.Syntax_Node_Type (Node => STree.LoopParameterSpecFromEndOfLoop (Node)) =
           SP_Symbols.loop_parameter_specification;
      end IsAForLoop;

      function GetLoopCounter return  Dictionary.Symbol
      --# global in Node;
      --#        in STree.Table;
      --#        in Table;
      --#        in TheHeap;
      is
         LoopParamNode : STree.SyntaxNode;
         ExportAtom    : Heap.Atom;
      begin
         -- Move to loop_parameter_specificatio node
         LoopParamNode := STree.LoopParameterSpecFromEndOfLoop (Node);

         -- the loop counter is modelled by wffs as being updated here so is an export of this node
         RefList.FirstExport (Table, TheHeap, LoopParamNode,
                              -- to get
                              ExportAtom);
         -- convert to a symbol and return
         return SymValue (ExportAtom);
      end GetLoopCounter;

      procedure ModelFinalForLoopExit
      --# global in     LoopCounter;
      --#        in     Node;
      --#        in     ReferencedVars;
      --#        in     STree.Table;
      --#        in out ExpnLocations;
      --#        in out ExpnNumber;
      --#        in out KindDictionary;
      --#        in out S;
      --#        in out Statistics.TableUsage;
      --#        in out StmtLocations;
      --#        in out TheHeap;
      --# derives ExpnLocations         from *,
      --#                                    ExpnNumber,
      --#                                    Node &
      --#         ExpnNumber,
      --#         KindDictionary        from *,
      --#                                    ExpnNumber &
      --#         S                     from *,
      --#                                    TheHeap &
      --#         Statistics.TableUsage,
      --#         TheHeap               from *,
      --#                                    ExpnNumber,
      --#                                    LoopCounter,
      --#                                    ReferencedVars,
      --#                                    TheHeap &
      --#         StmtLocations         from *,
      --#                                    ExpnNumber,
      --#                                    Node,
      --#                                    STree.Table;
      --# pre IsAForLoop  (Node, STree.Table);
      is
         R1, R2 : IFA_Stack.StackMember;
      begin
         -- Establish test for termination;
         IFA_Stack.EstablishMember (TheHeap, IFA_Stack.ExitNode, R1);
         IFA_Stack.EstablishMember (TheHeap, IFA_Stack.ExitBranch, R2);
         IncrementExpression (ExpnNumber);
         ExpnLocations (ExpnNumber)  := Node;
         StmtLocations (ExpnNumber)  := STree.Parent_Node (Current_Node => Node);
         KindDictionary (ExpnNumber) := ExitExpn;
         SeqAlgebra.AddMember (TheHeap, R1.SeqOfExpns, ExpnNumber);
         -- exit depends on loop counter
         AddSymbol (TheHeap, ReferencedVars, LoopCounter);
         AddSymbol (TheHeap, R1.AllVars, LoopCounter);
         IFA_Stack.Push (S, R1);
         IFA_Stack.Push (S, R2);
      end ModelFinalForLoopExit;

   begin -- ModelDefaultExitOrFinalForLoopExit
      if Dictionary.IsPredefinedBooleanType (STree.NodeSymbol (Node)) then
         -- A Boolean type symbol placed in this not by WalkStatements.wf_loop_param indicates
         -- that the loop is a plain loop, with no iteration scheme and no exit statement.
         -- In this case we patch in a "exit when false" exit statement at the bottom of the loop
         -- to give a syntactic exit path so that the loop can be flow analysed correctly.
         IFA_Stack.EstablishMember (TheHeap, IFA_Stack.DefaultExitNode, R1);
         IFA_Stack.EstablishMember (TheHeap, IFA_Stack.ExitBranch, R2);

         ProcessExpression (Node, Node, R1);
         IFA_Stack.Push (S, R1);
         IFA_Stack.Push (S, R2);

      elsif IsAForLoop then
         -- We have two kinds of for loop to deal with.  A for loop that may be bypassed because
         -- its counter range may be empty will already have had an exit statement modeled at its
         -- head by StartForLoop.  In the case where the loop counter has a static range that we
         -- know to be non-empty then this exit will not have been placed (to avoid analysis
         -- of the semantcially infeasible path round the loop) so we need to add an exit at the bottom
         -- of the loop.
         -- The following IF statement covers these two cases.
         LoopCounter := GetLoopCounter;
         if Dictionary.LoopParameterHasStaticRange (LoopCounter) then
            ModelFinalForLoopExit;

         else
            -- it's a for loop that may be bypassed, an exit already exists at the top
            -- so just place a null statement here
            IFA_Stack.EstablishMember (TheHeap, IFA_Stack.Action, R1);
            IFA_Stack.Push (S, R1);
         end if;

      else
         -- It's a plain (not a for) loop, but it already has (a) user-supplied exit statement(s).
         -- there are already proper exits so just model a null statement
         IFA_Stack.EstablishMember (TheHeap, IFA_Stack.Action, R1);
         IFA_Stack.Push (S, R1);
      end if;
   end ModelDefaultExitOrFinalForLoopExit;
   --898 end

   -----------------------------------------------------------------

   procedure Join
   --# global in out S;
   --#        in out Statistics.TableUsage;
   --#        in out TheHeap;
   --# derives S,
   --#         Statistics.TableUsage,
   --#         TheHeap               from *,
   --#                                    S,
   --#                                    TheHeap;
   is
      A, B, R                            : IFA_Stack.StackMember;
      Finished                           : Boolean;
      PreservedVars                      : SeqAlgebra.Seq;
      ExpnNmbr                           : Natural;
      DefinedVars, UnPreservedVars       : SeqAlgebra.Seq;
      Lambda, Mu, Rho, Theta, ThetaTilde : RelationAlgebra.Relation;
   begin
      if IFA_Stack.Top (S).MemberKind = IFA_Stack.ExitNode then
         IFA_Stack.Pop (S, A);
         if IFA_Stack.Top (S).MemberKind = IFA_Stack.Action then
            IFA_Stack.DisposeOfMember (TheHeap, A);
            IFA_Stack.Pop (S, A);
         end if;
         A.MemberKind := IFA_Stack.ExitBranch;
         IFA_Stack.Pop (S, B);
         B.MemberKind := IFA_Stack.ExitNode;
         IFA_Stack.Push (S, B);
         IFA_Stack.Push (S, A);
      else
         Finished := False;
         while not Finished loop
            IFA_Stack.Pop (S, A);
            IFA_Stack.Pop (S, B);
            IFA_Stack.Pop (S, R);
            Finished := (R.MemberKind = IFA_Stack.IfNode);
            ExpnNmbr := SeqAlgebra.Value_Of_Member (The_Heap => TheHeap,
                                                    M        => SeqAlgebra.FirstMember (TheHeap, R.SeqOfExpns));
            SeqAlgebra.AugmentSeq (TheHeap, R.SeqOfExpns, A.SeqOfExpns);
            SeqAlgebra.AugmentSeq (TheHeap, R.SeqOfExpns, B.SeqOfExpns);
            R.MemberKind := IFA_Stack.Action;
            SeqAlgebra.Union (TheHeap, A.DefinedVars, B.DefinedVars, DefinedVars);
            R.DefinedVars := DefinedVars;
            SeqAlgebra.Intersection (TheHeap, A.UnPreservedVars, B.UnPreservedVars, UnPreservedVars);
            R.UnPreservedVars := UnPreservedVars;
            RelationAlgebra.CartesianProduct (TheHeap, R.AllVars, R.DefinedVars, Rho);
            R.Rho := Rho;
            RelationAlgebra.Sum (TheHeap, A.Lambda, B.Lambda, Lambda);
            R.Lambda := Lambda;
            RelationAlgebra.AddCol (TheHeap, R.Lambda, ExpnNmbr, R.AllVars);
            RelationAlgebra.Sum (TheHeap, A.Theta, B.Theta, Theta);
            R.Theta := Theta;
            RelationAlgebra.AddCol (TheHeap, R.Theta, ExpnNmbr, R.AllVars);
            RelationAlgebra.Sum (TheHeap, A.ThetaTilde, B.ThetaTilde, ThetaTilde);
            R.ThetaTilde := ThetaTilde;
            RelationAlgebra.AddCol (TheHeap, R.ThetaTilde, ExpnNmbr, R.AllVars);
            RelationAlgebra.Sum (TheHeap, A.Mu, B.Mu, Mu);
            R.Mu := Mu;
            RelationAlgebra.AddRow (TheHeap, R.Mu, ExpnNmbr, R.DefinedVars);
            RelationAlgebra.AugmentRelation (TheHeap, R.Rho, A.Rho);
            RelationAlgebra.AugmentRelation (TheHeap, R.Rho, B.Rho);
            SeqAlgebra.AugmentSeq (TheHeap, R.AllVars, A.AllVars);
            SeqAlgebra.AugmentSeq (TheHeap, R.AllVars, B.AllVars);
            SeqAlgebra.Complement (TheHeap, R.AllVars, R.UnPreservedVars, PreservedVars);
            RelationAlgebra.AddIdentity (TheHeap, R.Rho, PreservedVars);
            SeqAlgebra.DisposeOfSeq (TheHeap, PreservedVars);
            IFA_Stack.DisposeOfMember (TheHeap, A);
            IFA_Stack.DisposeOfMember (TheHeap, B);
            IFA_Stack.Push (S, R);
         end loop;
      end if;
   end Join;

   -----------------------------------------------------------------

   procedure CombineCases
   --# global in out S;
   --#        in out Statistics.TableUsage;
   --#        in out TheHeap;
   --# derives S,
   --#         Statistics.TableUsage,
   --#         TheHeap               from *,
   --#                                    S,
   --#                                    TheHeap;
   is
      UnPreservedVars, TempVarSeq : SeqAlgebra.Seq;
      ExpnNmbr                    : Natural;
      Product                     : RelationAlgebra.Relation;
      A, R                        : IFA_Stack.StackMember;
   begin
      IFA_Stack.Pop (S, R);
      loop
         IFA_Stack.Pop (S, A);
         SeqAlgebra.AugmentSeq (TheHeap, R.AllVars, A.AllVars);
         SeqAlgebra.AugmentSeq (TheHeap, R.SeqOfExpns, A.SeqOfExpns);
         exit when A.MemberKind = IFA_Stack.CaseNode;
         SeqAlgebra.AugmentSeq (TheHeap, R.DefinedVars, A.DefinedVars);
         -- replace R.UnPreservedVars by its intersection with A.UnPreservedVars;
         SeqAlgebra.Intersection (TheHeap, R.UnPreservedVars, A.UnPreservedVars, TempVarSeq);
         SeqAlgebra.DisposeOfSeq (TheHeap, R.UnPreservedVars);
         SeqAlgebra.CreateSeq (TheHeap, UnPreservedVars);
         R.UnPreservedVars := UnPreservedVars;
         SeqAlgebra.AugmentSeq (TheHeap, R.UnPreservedVars, TempVarSeq);
         SeqAlgebra.DisposeOfSeq (TheHeap, TempVarSeq);
         -- end of replacement;
         RelationAlgebra.AugmentRelation (TheHeap, R.Lambda, A.Lambda);
         RelationAlgebra.AugmentRelation (TheHeap, R.Theta, A.Theta);
         RelationAlgebra.AugmentRelation (TheHeap, R.ThetaTilde, A.ThetaTilde);
         RelationAlgebra.AugmentRelation (TheHeap, R.Mu, A.Mu);
         RelationAlgebra.AugmentRelation (TheHeap, R.Rho, A.Rho);
         IFA_Stack.DisposeOfMember (TheHeap, A);
      end loop;
      SeqAlgebra.Complement (TheHeap, R.AllVars, R.UnPreservedVars, TempVarSeq);
      RelationAlgebra.AddIdentity (TheHeap, R.Rho, TempVarSeq);
      SeqAlgebra.DisposeOfSeq (TheHeap, TempVarSeq);
      ExpnNmbr := SeqAlgebra.Value_Of_Member (The_Heap => TheHeap,
                                              M        => SeqAlgebra.FirstMember (TheHeap, A.SeqOfExpns));
      RelationAlgebra.AddCol (TheHeap, R.Lambda, ExpnNmbr, A.AllVars);
      RelationAlgebra.AddCol (TheHeap, R.Theta, ExpnNmbr, A.AllVars);
      RelationAlgebra.AddCol (TheHeap, R.ThetaTilde, ExpnNmbr, A.AllVars);
      RelationAlgebra.AddRow (TheHeap, R.Mu, ExpnNmbr, R.DefinedVars);
      RelationAlgebra.CartesianProduct (TheHeap, A.AllVars, R.DefinedVars, Product);
      IFA_Stack.DisposeOfMember (TheHeap, A);
      RelationAlgebra.AugmentRelation (TheHeap, R.Rho, Product);
      RelationAlgebra.DisposeOfRelation (TheHeap, Product);
      IFA_Stack.Push (S, R);
   end CombineCases;

   -----------------------------------------------------------------

   procedure CloseLoop
   --# global in     InnerExpns;
   --#        in     KindDictionary;
   --#        in     OneStableExpnSeq;
   --#        in     OtherStableExpnSeq;
   --#        in     ZeroStableExpnSeq;
   --#        in out S;
   --#        in out Statistics.TableUsage;
   --#        in out TheHeap;
   --# derives S                     from *,
   --#                                    TheHeap &
   --#         Statistics.TableUsage,
   --#         TheHeap               from *,
   --#                                    InnerExpns,
   --#                                    KindDictionary,
   --#                                    OneStableExpnSeq,
   --#                                    OtherStableExpnSeq,
   --#                                    S,
   --#                                    TheHeap,
   --#                                    ZeroStableExpnSeq;
   is
      ExpnNmbr                                              : Natural;
      ExpnsInBody, ExpnsInExits, BodyVars, NewVars, TempSeq : SeqAlgebra.Seq;
      FirstExitFound                                        : Boolean;
      BodyLambda, Closure, RhoProducts, TempRelation, TopMu : RelationAlgebra.Relation;
      A, R                                                  : IFA_Stack.StackMember;
      AuxiliaryStack                                        : IFA_Stack.Stack;
      UnPreservedVars, SeqOfExpns                           : SeqAlgebra.Seq;
      Rho, Theta, ThetaTilde, Lambda                        : RelationAlgebra.Relation;

      procedure StabilityTest
      --# global in     BodyLambda;
      --#        in     BodyVars;
      --#        in     ExpnsInBody;
      --#        in     InnerExpns;
      --#        in     KindDictionary;
      --#        in     OneStableExpnSeq;
      --#        in     OtherStableExpnSeq;
      --#        in     ZeroStableExpnSeq;
      --#        in out RhoProducts;
      --#        in out Statistics.TableUsage;
      --#        in out TheHeap;
      --# derives RhoProducts           from TheHeap &
      --#         Statistics.TableUsage,
      --#         TheHeap               from *,
      --#                                    BodyLambda,
      --#                                    BodyVars,
      --#                                    ExpnsInBody,
      --#                                    InnerExpns,
      --#                                    KindDictionary,
      --#                                    OneStableExpnSeq,
      --#                                    OtherStableExpnSeq,
      --#                                    RhoProducts,
      --#                                    TheHeap,
      --#                                    ZeroStableExpnSeq;
      is
         subtype VarNmbrRange is Natural range 1 .. ExaminerConstants.FlowAnalysisMaxVarNumber;
         type IndegreeType is array (VarNmbrRange) of Natural;
         Indegree : IndegreeType;
         type StabilityIndexType is array (VarNmbrRange) of Natural;
         StabilityIndex                                                            : StabilityIndexType;
         LambdaCol, ReducedCol, TestSeq, PendingVarSeq, StableVarSeq, SuccessorSeq : SeqAlgebra.Seq;
         M, N                                                                      : SeqAlgebra.MemberOfSeq;
         MemberNmbr, ValueOfM, ValueOfN, MaxVarIndex, ExpnIndex                    : Natural;
         NmbrOfM, NmbrOfN                                                          : VarNmbrRange;

         ----------------------------------------------

         function max (X, Y : Natural) return Natural is
            Result : Natural;
         begin
            case X > Y is
               when True =>
                  Result := X;
               when False =>
                  Result := Y;
            end case;
            return Result;
         end max;

         ----------------------------------------------

         procedure IncNumber (X : in out Natural)
         --# derives X from *;
         --# post X = X~ + 1 and X <= ExaminerConstants.FlowAnalysisMaxVarNumber;
         is
         begin
            if X >= ExaminerConstants.FlowAnalysisMaxVarNumber then
               SystemErrors.Fatal_Error (Sys_Err => SystemErrors.Too_Many_Flow_Analyser_Expressions,
                                         Msg     => "");
            end if;
            X := X + 1;
         end IncNumber;

         ----------------------------------------------

      begin -- StabilityTest
         SeqAlgebra.CreateSeq (TheHeap, PendingVarSeq);
         SeqAlgebra.CreateSeq (TheHeap, StableVarSeq);
         RelationAlgebra.ExtractSubRelation (TheHeap, RhoProducts, BodyVars);
         M          := SeqAlgebra.FirstMember (TheHeap, BodyVars);
         MemberNmbr := 0;
         while not SeqAlgebra.IsNullMember (M) loop
            --# assert MemberNmbr in Natural;
            ValueOfM := SeqAlgebra.Value_Of_Member (The_Heap => TheHeap,
                                                    M        => M);
            IncNumber (MemberNmbr);
            --# accept Flow, 23, StabilityIndex, "Expect flow error on 1st write to array";
            StabilityIndex (MemberNmbr) := 0;
            --# end accept;
            --# accept Flow, 23, Indegree, "Expect flow error on 1st write to array";
            Indegree (MemberNmbr) := RelationAlgebra.ColumnCount (TheHeap, RhoProducts, ValueOfM);
            --# end accept;

            if Indegree (MemberNmbr) = 0 then
               SeqAlgebra.AddMember (TheHeap, PendingVarSeq, ValueOfM);
               SeqAlgebra.AddMember (TheHeap, StableVarSeq, ValueOfM);
            end if;
            M := SeqAlgebra.NextMember (TheHeap, M);
         end loop;
         while not SeqAlgebra.IsNullMember (SeqAlgebra.FirstMember (TheHeap, PendingVarSeq)) loop
            M        := SeqAlgebra.FirstMember (TheHeap, PendingVarSeq);
            ValueOfM := SeqAlgebra.Value_Of_Member (The_Heap => TheHeap,
                                                    M        => M);
            SeqAlgebra.RemoveMember (TheHeap, PendingVarSeq, ValueOfM);
            RelationAlgebra.RowExtraction (TheHeap, RhoProducts, ValueOfM, SuccessorSeq);
            NmbrOfM := SeqAlgebra.MemberIndex (TheHeap, BodyVars, ValueOfM);
            N       := SeqAlgebra.FirstMember (TheHeap, SuccessorSeq);
            while not SeqAlgebra.IsNullMember (N) loop
               ValueOfN := SeqAlgebra.Value_Of_Member (The_Heap => TheHeap,
                                                       M        => N);
               NmbrOfN  := SeqAlgebra.MemberIndex (TheHeap, BodyVars, ValueOfN);

               --# accept Flow, 504, Indegree, "Expect flow error";
               Indegree (NmbrOfN) := Indegree (NmbrOfN) - 1;
               --# end accept;

               --# accept Flow, 504, StabilityIndex, "Expect flow error";
               StabilityIndex (NmbrOfN) := max (StabilityIndex (NmbrOfN), StabilityIndex (NmbrOfM) + 1);
               --# end accept;

               if Indegree (NmbrOfN) = 0 then
                  SeqAlgebra.AddMember (TheHeap, PendingVarSeq, ValueOfN);
                  SeqAlgebra.AddMember (TheHeap, StableVarSeq, ValueOfN);
               end if;
               N := SeqAlgebra.NextMember (TheHeap, N);
            end loop;
            SeqAlgebra.DisposeOfSeq (TheHeap, SuccessorSeq);
         end loop;
         SeqAlgebra.DisposeOfSeq (TheHeap, PendingVarSeq);

         M := SeqAlgebra.FirstMember (TheHeap, ExpnsInBody);
         while not SeqAlgebra.IsNullMember (M) loop
            ValueOfM := SeqAlgebra.Value_Of_Member (The_Heap => TheHeap,
                                                    M        => M);
            if not SeqAlgebra.IsMember (TheHeap, InnerExpns, ValueOfM) then
               SeqAlgebra.AddMember (TheHeap, InnerExpns, ValueOfM);
               if (KindDictionary (ValueOfM) = ExitExpn) or
                 --(KindDictionary (ValueOfM) = DefaultExitExpn) or --898
                 (KindDictionary (ValueOfM) = ForkExpn) then
                  RelationAlgebra.ColExtraction (TheHeap, BodyLambda, ValueOfM, LambdaCol);
                  SeqAlgebra.Intersection (TheHeap, LambdaCol, BodyVars, ReducedCol);
                  SeqAlgebra.DisposeOfSeq (TheHeap, LambdaCol);
                  SeqAlgebra.Complement (TheHeap, ReducedCol, StableVarSeq, TestSeq);
                  if SeqAlgebra.IsEmptySeq (TheHeap, TestSeq) then
                     if SeqAlgebra.IsEmptySeq (TheHeap, ReducedCol) then
                        ExpnIndex := 0;
                     else
                        MaxVarIndex := 0;
                        N           := SeqAlgebra.FirstMember (TheHeap, ReducedCol);

                        while not SeqAlgebra.IsNullMember (N) loop

                           --# accept Flow, 501, StabilityIndex, "Expect flow error";
                           MaxVarIndex :=
                             max
                             (MaxVarIndex,
                              StabilityIndex (SeqAlgebra.MemberIndex
                                                (TheHeap,
                                                 BodyVars,
                                                 SeqAlgebra.Value_Of_Member (The_Heap => TheHeap,
                                                                             M        => N))));
                           --# end accept;

                           N := SeqAlgebra.NextMember (TheHeap, N);
                        end loop;
                        ExpnIndex := MaxVarIndex + 1;
                     end if;
                     if ExpnIndex = 0 then
                        SeqAlgebra.AddMember (TheHeap, ZeroStableExpnSeq, ValueOfM);
                     elsif ExpnIndex = 1 then
                        SeqAlgebra.AddMember (TheHeap, OneStableExpnSeq, ValueOfM);
                     else
                        SeqAlgebra.AddMember (TheHeap, OtherStableExpnSeq, ValueOfM);
                     end if;
                  end if;
                  SeqAlgebra.DisposeOfSeq (TheHeap, ReducedCol);
                  SeqAlgebra.DisposeOfSeq (TheHeap, TestSeq);
               end if;
            end if;
            M := SeqAlgebra.NextMember (TheHeap, M);
         end loop;
         SeqAlgebra.DisposeOfSeq (TheHeap, StableVarSeq);
         --# accept Flow, 602, Statistics.TableUsage, Indegree, "expect 4 warnings from array DF anomolies" &
         --#        Flow, 602, Statistics.TableUsage, StabilityIndex, "expect 4 warnings from array DF anomolies" &
         --#        Flow, 602, TheHeap, Indegree, "expect 4 warnings from array DF anomolies" &
         --#        Flow, 602, TheHeap, StabilityIndex, "expect 4 warnings from array DF anomolies";
      end StabilityTest;

      --------------------------------------------------------------

   begin -- CloseLoop
      IFA_Stack.EstablishMember (TheHeap, IFA_Stack.Action, R);
      SeqAlgebra.CreateSeq (TheHeap, BodyVars);
      SeqAlgebra.CreateSeq (TheHeap, ExpnsInBody);
      SeqAlgebra.CreateSeq (TheHeap, ExpnsInExits);
      IFA_Stack.ClearStack (AuxiliaryStack);
      FirstExitFound := False;
      IFA_Stack.Pop (S, A);
      while A.MemberKind /= IFA_Stack.LoopHead loop
         SeqAlgebra.AugmentSeq (TheHeap, R.AllVars, A.AllVars);
         case A.MemberKind is
            when IFA_Stack.Action =>
               SeqAlgebra.AugmentSeq (TheHeap, BodyVars, A.DefinedVars);
               SeqAlgebra.AugmentSeq (TheHeap, R.DefinedVars, A.DefinedVars);
               SeqAlgebra.AugmentSeq (TheHeap, ExpnsInBody, A.SeqOfExpns);
               SeqAlgebra.AugmentSeq (TheHeap, R.UnPreservedVars, A.UnPreservedVars);
            when IFA_Stack.ExitBranch =>
               SeqAlgebra.AugmentSeq (TheHeap, R.DefinedVars, A.DefinedVars);
               SeqAlgebra.AugmentSeq (TheHeap, ExpnsInExits, A.SeqOfExpns);
               if FirstExitFound then
                  TempSeq := R.UnPreservedVars;
                  SeqAlgebra.Intersection (TheHeap, TempSeq, A.UnPreservedVars, UnPreservedVars);
                  R.UnPreservedVars := UnPreservedVars;
                  SeqAlgebra.DisposeOfSeq (TheHeap, TempSeq);
               else
                  FirstExitFound := True;
                  SeqAlgebra.DisposeOfSeq (TheHeap, R.UnPreservedVars);
                  SeqAlgebra.CreateSeq (TheHeap, UnPreservedVars);
                  R.UnPreservedVars := UnPreservedVars;
                  SeqAlgebra.AugmentSeq (TheHeap, R.UnPreservedVars, A.UnPreservedVars);
               end if;
            when IFA_Stack.ExitNode =>
               SeqAlgebra.AugmentSeq (TheHeap, ExpnsInBody, A.SeqOfExpns);
            when others =>
               null;
         end case;
         IFA_Stack.Push (AuxiliaryStack, A);
         IFA_Stack.Pop (S, A);
      end loop;
      IFA_Stack.Push (AuxiliaryStack, A);
      SeqAlgebra.Union (TheHeap, ExpnsInBody, ExpnsInExits, SeqOfExpns);
      R.SeqOfExpns := SeqOfExpns;

      -- Restore stack S.
      while not IFA_Stack.IsEmpty (AuxiliaryStack) loop
         IFA_Stack.Pop (AuxiliaryStack, A);
         IFA_Stack.Push (S, A);
      end loop;

      -- Construct Lambda, Rho, Theta and ThetaTilde relations.
      RelationAlgebra.CreateRelation (TheHeap, BodyLambda);
      RelationAlgebra.CreateRelation (TheHeap, RhoProducts);
      RelationAlgebra.AddIdentity (TheHeap, RhoProducts, R.AllVars);

      IFA_Stack.Pop (S, A);
      while A.MemberKind /= IFA_Stack.LoopHead loop
         case A.MemberKind is
            when IFA_Stack.Action =>
               SeqAlgebra.Complement (TheHeap, R.AllVars, A.AllVars, NewVars);
               RelationAlgebra.AddIdentity (TheHeap, A.Rho, NewVars);
               SeqAlgebra.DisposeOfSeq (TheHeap, NewVars);
               RelationAlgebra.Composition (TheHeap, A.Rho, BodyLambda, TempRelation);
               RelationAlgebra.DisposeOfRelation (TheHeap, BodyLambda);
               RelationAlgebra.Sum (TheHeap, A.Lambda, TempRelation, BodyLambda);
               RelationAlgebra.DisposeOfRelation (TheHeap, TempRelation);
               TempRelation := R.Rho;
               RelationAlgebra.Composition (TheHeap, A.Rho, R.Rho, Rho);
               R.Rho     := Rho;
               A.RhoProd := RhoProducts;
               RelationAlgebra.Composition (TheHeap, A.Rho, RhoProducts, Rho);
               RhoProducts := Rho;
               RelationAlgebra.DisposeOfRelation (TheHeap, A.Rho);
               A.Rho := TempRelation;
               RelationAlgebra.RowRemoval (TheHeap, R.Theta, A.UnPreservedVars, TempRelation);
               RelationAlgebra.DisposeOfRelation (TheHeap, R.Theta);
               RelationAlgebra.Sum (TheHeap, A.Theta, TempRelation, Theta);
               R.Theta := Theta;
               RelationAlgebra.DisposeOfRelation (TheHeap, TempRelation);
               RelationAlgebra.RowRemoval (TheHeap, R.ThetaTilde, A.DefinedVars, TempRelation);
               RelationAlgebra.DisposeOfRelation (TheHeap, R.ThetaTilde);
               RelationAlgebra.Sum (TheHeap, A.ThetaTilde, TempRelation, ThetaTilde);
               R.ThetaTilde := ThetaTilde;
               RelationAlgebra.DisposeOfRelation (TheHeap, TempRelation);
            when IFA_Stack.ExitBranch =>
               SeqAlgebra.Complement (TheHeap, R.AllVars, A.AllVars, NewVars);
               RelationAlgebra.AddIdentity (TheHeap, A.Rho, NewVars);
               SeqAlgebra.DisposeOfSeq (TheHeap, NewVars);
               RelationAlgebra.AugmentRelation (TheHeap, R.Rho, A.Rho);
               RelationAlgebra.AugmentRelation (TheHeap, BodyLambda, A.Lambda);
               RelationAlgebra.AugmentRelation (TheHeap, R.Theta, A.Theta);
               RelationAlgebra.AugmentRelation (TheHeap, R.ThetaTilde, A.ThetaTilde);
            when IFA_Stack.ExitNode =>
               ExpnNmbr := SeqAlgebra.Value_Of_Member (The_Heap => TheHeap,
                                                       M        => SeqAlgebra.FirstMember (TheHeap, A.SeqOfExpns));
               RelationAlgebra.AddCol (TheHeap, BodyLambda, ExpnNmbr, A.AllVars);
               RelationAlgebra.AddCol (TheHeap, R.Theta, ExpnNmbr, A.AllVars);
               RelationAlgebra.AddCol (TheHeap, R.ThetaTilde, ExpnNmbr, A.AllVars);
               RelationAlgebra.CartesianProduct (TheHeap, A.AllVars, R.DefinedVars, TempRelation);
               RelationAlgebra.AugmentRelation (TheHeap, R.Rho, TempRelation);
               RelationAlgebra.DisposeOfRelation (TheHeap, TempRelation);
            when others =>
               null;
         end case;
         IFA_Stack.Push (AuxiliaryStack, A);
         IFA_Stack.Pop (S, A);
      end loop;
      IFA_Stack.Push (AuxiliaryStack, A);
      RelationAlgebra.CreateRelation (TheHeap, Closure);
      RelationAlgebra.AugmentRelation (TheHeap, Closure, RhoProducts);
      RelationAlgebra.CloseRelation (TheHeap, Closure);
      RelationAlgebra.AddIdentity (TheHeap, Closure, R.AllVars);
      RelationAlgebra.Composition (TheHeap, Closure, BodyLambda, Lambda);
      R.Lambda := Lambda;
      RelationAlgebra.Composition (TheHeap, Closure, R.Rho, TempRelation);
      RelationAlgebra.DisposeOfRelation (TheHeap, Closure);
      RelationAlgebra.DisposeOfRelation (TheHeap, R.Rho);
      R.Rho := TempRelation;
      -- Restore stack S.
      while not IFA_Stack.IsEmpty (AuxiliaryStack) loop
         IFA_Stack.Pop (AuxiliaryStack, A);
         IFA_Stack.Push (S, A);
      end loop;
      -- Construct Mu relation.
      IFA_Stack.Pop (S, A);
      while A.MemberKind /= IFA_Stack.LoopHead loop
         case A.MemberKind is
            when IFA_Stack.Action =>
               RelationAlgebra.Composition (TheHeap, A.RhoProd, R.Rho, TempRelation);
               RelationAlgebra.AugmentRelation (TheHeap, TempRelation, A.Rho);
               RelationAlgebra.Composition (TheHeap, A.Mu, TempRelation, TopMu);
               RelationAlgebra.DisposeOfRelation (TheHeap, TempRelation);
               RelationAlgebra.AugmentRelation (TheHeap, R.Mu, TopMu);
               RelationAlgebra.DisposeOfRelation (TheHeap, TopMu);
            when IFA_Stack.ExitBranch =>
               RelationAlgebra.AugmentRelation (TheHeap, R.Mu, A.Mu);
            when IFA_Stack.ExitNode =>
               ExpnNmbr := SeqAlgebra.Value_Of_Member (The_Heap => TheHeap,
                                                       M        => SeqAlgebra.FirstMember (TheHeap, A.SeqOfExpns));
               RelationAlgebra.AddRow (TheHeap, R.Mu, ExpnNmbr, R.DefinedVars);
            when others =>
               null;
         end case;
         IFA_Stack.DisposeOfMember (TheHeap, A);
         IFA_Stack.Pop (S, A);
      end loop;
      IFA_Stack.DisposeOfMember (TheHeap, A);
      IFA_Stack.Push (S, R);
      SeqAlgebra.DisposeOfSeq (TheHeap, ExpnsInExits);
      StabilityTest;
      SeqAlgebra.DisposeOfSeq (TheHeap, ExpnsInBody);
      SeqAlgebra.DisposeOfSeq (TheHeap, BodyVars);
      RelationAlgebra.DisposeOfRelation (TheHeap, BodyLambda);
      RelationAlgebra.DisposeOfRelation (TheHeap, RhoProducts);
   end CloseLoop;

   -----------------------------------------------------------------

   procedure ReturnExpression
   --# global in     Node;
   --#        in     ReferencedVars;
   --#        in     STree.Table;
   --#        in     Table;
   --#        in out ExpnLocations;
   --#        in out ExpnNumber;
   --#        in out KindDictionary;
   --#        in out S;
   --#        in out Statistics.TableUsage;
   --#        in out TheHeap;
   --# derives ExpnLocations         from *,
   --#                                    ExpnNumber,
   --#                                    Node &
   --#         ExpnNumber,
   --#         KindDictionary        from *,
   --#                                    ExpnNumber &
   --#         S                     from *,
   --#                                    TheHeap &
   --#         Statistics.TableUsage,
   --#         TheHeap               from *,
   --#                                    ExpnNumber,
   --#                                    Node,
   --#                                    ReferencedVars,
   --#                                    STree.Table,
   --#                                    Table,
   --#                                    TheHeap;
   is
      ImportList    : SeqAlgebra.Seq;
      R             : IFA_Stack.StackMember;
      UndefinedVars : SeqAlgebra.Seq;
   begin
      IFA_Stack.EstablishMember (TheHeap, IFA_Stack.Action, R);
      SeqAlgebra.AddMember (TheHeap, R.DefinedVars, FnResultRepn);
      SeqAlgebra.AddMember (TheHeap, R.UnPreservedVars, FnResultRepn);
      SeqAlgebra.AddMember (TheHeap, R.AllVars, FnResultRepn);
      IncrementExpression (ExpnNumber);
      ExpnLocations (ExpnNumber)  := Node;
      KindDictionary (ExpnNumber) := ReturnExpn;
      SeqAlgebra.AddMember (TheHeap, R.SeqOfExpns, ExpnNumber);
      RelationAlgebra.InsertPair (TheHeap, R.Mu, ExpnNumber, FnResultRepn);
      RefList.ReferencedVarList (Table, TheHeap, STree.Parent_Node (Current_Node => Node),
                                 -- to get
                                 ImportList);
      SeqAlgebra.AugmentSeq (TheHeap, ReferencedVars, ImportList);
      SeqAlgebra.AugmentSeq (TheHeap, R.AllVars, ImportList);
      RelationAlgebra.AddCol (TheHeap, R.Lambda, ExpnNumber, ImportList);
      RelationAlgebra.AddCol (TheHeap, R.Rho, FnResultRepn, ImportList);
      RelationAlgebra.AddCol (TheHeap, R.Theta, ExpnNumber, ImportList);
      RelationAlgebra.AddCol (TheHeap, R.ThetaTilde, ExpnNumber, ImportList);
      SeqAlgebra.Complement (TheHeap, R.AllVars, R.DefinedVars, UndefinedVars);
      RelationAlgebra.AddIdentity (TheHeap, R.Rho, UndefinedVars);
      SeqAlgebra.DisposeOfSeq (TheHeap, UndefinedVars);
      IFA_Stack.Push (S, R);
   end ReturnExpression;

   --------------------------------------------------------------------------

   procedure CheckVarsUsedAsConsts
   --# global in     Dictionary.Dict;
   --#        in     LocalInits;
   --#        in     S;
   --#        in     SubprogSym;
   --#        in     VarsUsedAsConstants;
   --#        in out Statistics.TableUsage;
   --#        in out TheHeap;
   --# derives Statistics.TableUsage,
   --#         TheHeap               from *,
   --#                                    Dictionary.Dict,
   --#                                    LocalInits,
   --#                                    S,
   --#                                    SubprogSym,
   --#                                    TheHeap,
   --#                                    VarsUsedAsConstants;
   is
      MemberOfInitVars : SeqAlgebra.MemberOfSeq;
      InitVarRep       : Natural;
   begin
      if IsSubprogram (SubprogSym) then
         MemberOfInitVars := SeqAlgebra.FirstMember (TheHeap, LocalInits);
         while not SeqAlgebra.IsNullMember (MemberOfInitVars) loop
            InitVarRep := SeqAlgebra.Value_Of_Member (The_Heap => TheHeap,
                                                      M        => MemberOfInitVars);
            if not SeqAlgebra.IsMember (TheHeap, IFA_Stack.Top (S).DefinedVars, InitVarRep) then
               SeqAlgebra.AddMember (TheHeap, VarsUsedAsConstants, InitVarRep);
            end if;
            MemberOfInitVars := SeqAlgebra.NextMember (TheHeap, MemberOfInitVars);
         end loop;
      end if;
   end CheckVarsUsedAsConsts;

   --------------------------------------------------------------------------

   procedure AnalyseRelations
   --# global in     CommandLineData.Content;
   --#        in     DependencyRelation;
   --#        in     Dictionary.Dict;
   --#        in     EndPosition;
   --#        in     ExpnLocations;
   --#        in     ExpSeqOfExports;
   --#        in     ExpSeqOfImports;
   --#        in     InnerExpns;
   --#        in     InStreamsOfShareableProtectedVars;
   --#        in     KindDictionary;
   --#        in     LexTokenManager.State;
   --#        in     OneStableExpnSeq;
   --#        in     OtherStableExpnSeq;
   --#        in     ParamDictionary;
   --#        in     ReferencedVars;
   --#        in     S;
   --#        in     Scope;
   --#        in     SeqOfExports;
   --#        in     SeqOfImports;
   --#        in     SeqOfInitVars;
   --#        in     StmtLocations;
   --#        in     STree.Table;
   --#        in     SubprogSym;
   --#        in     VarsUsedAsConstants;
   --#        in     ZeroStableExpnSeq;
   --#        in out ComponentData;
   --#        in out DataFlowErrorFoundLocal;
   --#        in out ErrorHandler.Error_Context;
   --#        in out SPARK_IO.File_Sys;
   --#        in out Statistics.TableUsage;
   --#        in out TheHeap;
   --# derives ComponentData,
   --#         Statistics.TableUsage,
   --#         TheHeap                    from *,
   --#                                         ComponentData,
   --#                                         DependencyRelation,
   --#                                         Dictionary.Dict,
   --#                                         EndPosition,
   --#                                         ExpnLocations,
   --#                                         ExpSeqOfExports,
   --#                                         ExpSeqOfImports,
   --#                                         InnerExpns,
   --#                                         InStreamsOfShareableProtectedVars,
   --#                                         KindDictionary,
   --#                                         ParamDictionary,
   --#                                         ReferencedVars,
   --#                                         S,
   --#                                         SeqOfExports,
   --#                                         SeqOfImports,
   --#                                         SeqOfInitVars,
   --#                                         StmtLocations,
   --#                                         STree.Table,
   --#                                         SubprogSym,
   --#                                         TheHeap,
   --#                                         VarsUsedAsConstants &
   --#         DataFlowErrorFoundLocal    from *,
   --#                                         ComponentData,
   --#                                         Dictionary.Dict,
   --#                                         EndPosition,
   --#                                         ExpnLocations,
   --#                                         ExpSeqOfExports,
   --#                                         ExpSeqOfImports,
   --#                                         InnerExpns,
   --#                                         KindDictionary,
   --#                                         ParamDictionary,
   --#                                         S,
   --#                                         SeqOfInitVars,
   --#                                         StmtLocations,
   --#                                         STree.Table,
   --#                                         SubprogSym,
   --#                                         TheHeap &
   --#         ErrorHandler.Error_Context,
   --#         SPARK_IO.File_Sys          from CommandLineData.Content,
   --#                                         ComponentData,
   --#                                         DependencyRelation,
   --#                                         Dictionary.Dict,
   --#                                         EndPosition,
   --#                                         ErrorHandler.Error_Context,
   --#                                         ExpnLocations,
   --#                                         ExpSeqOfExports,
   --#                                         ExpSeqOfImports,
   --#                                         InnerExpns,
   --#                                         InStreamsOfShareableProtectedVars,
   --#                                         KindDictionary,
   --#                                         LexTokenManager.State,
   --#                                         OneStableExpnSeq,
   --#                                         OtherStableExpnSeq,
   --#                                         ParamDictionary,
   --#                                         ReferencedVars,
   --#                                         S,
   --#                                         Scope,
   --#                                         SeqOfExports,
   --#                                         SeqOfImports,
   --#                                         SeqOfInitVars,
   --#                                         SPARK_IO.File_Sys,
   --#                                         StmtLocations,
   --#                                         STree.Table,
   --#                                         SubprogSym,
   --#                                         TheHeap,
   --#                                         VarsUsedAsConstants,
   --#                                         ZeroStableExpnSeq;
      is separate;

begin -- FlowAnalyse
   Scope := Dictionary.Set_Visibility (The_Visibility => Dictionary.Local,
                                       The_Unit       => SubprogSym);
   RefList.ExpandToComponentEntities (ComponentData, Table, TheHeap);
   FormSeqOfInitVars;
   FormLocalInits;
   FormDependencyRelation;
   SeqAlgebra.CreateSeq (TheHeap, ReferencedVars);
   SeqAlgebra.CreateSeq (TheHeap, InnerExpns);
   SeqAlgebra.CreateSeq (TheHeap, ZeroStableExpnSeq);
   SeqAlgebra.CreateSeq (TheHeap, OneStableExpnSeq);
   SeqAlgebra.CreateSeq (TheHeap, OtherStableExpnSeq);
   SeqAlgebra.CreateSeq (TheHeap, VarsUsedAsConstants);
   IFA_Stack.ClearStack (S);
   DataFlowErrorFoundLocal := False;
   ExpnNumber              := 0;
   Node                    := StartNode;

   -- ANALYSIS ONLY
   -- The following initializations are not needed but were inserted
   --     temporarily to ensure that expected flow errors were not masking
   --     any other possible errors.  The initializations do not form part
   --     of the delivered code.
   -- KindDictionary  := KindDictionaryType'(others => SimpleAssignment);
   -- ParamDictionary := ParamDictionaryType'(others => Dictionary.NullSymbol);
   -- ExpnLocations   := LocnDictionaryType'(others => STree.NullNode);
   -- StmtLocations   := LocnDictionaryType'(others => STree.NullNode);

   --# accept Flow, 23, StmtLocations, "Partial but effective array init." &
   --#        Flow, 23, KindDictionary, "Partial but effective array init." &
   --#        Flow, 23, ParamDictionary, "Partial but effective array init.";
   ModelLocalInits (Node);
   --# end accept;

   loop -- Down Loop --
      LastNode := Node;
      NodeType := STree.Syntax_Node_Type (Node => Node);

      --# accept Flow, 23, ExpnLocations, "Expect err owing to partial but effective array init.";
      case NodeType is
         when SP_Symbols.sequence_of_statements |
           SP_Symbols.statement              |
           SP_Symbols.simple_statement       |
           SP_Symbols.compound_statement     |
           SP_Symbols.elsif_part             |
           SP_Symbols.alternatives           |
           SP_Symbols.others_part            |
           SP_Symbols.loop_statement         =>
            Node := STree.Child_Node (Current_Node => Node);
         when SP_Symbols.simple_name =>
            Node := STree.NullNode;
         when SP_Symbols.proof_statement | SP_Symbols.justification_statement | SP_Symbols.apragma | SP_Symbols.null_statement =>
            NullStatement;
            Node := STree.NullNode;
         when SP_Symbols.assignment_statement | SP_Symbols.procedure_call_statement | SP_Symbols.delay_statement =>
            Mapping (Node);
            Node := STree.NullNode;
         when SP_Symbols.if_statement =>
            Node     := STree.Child_Node (Current_Node => Node);
            LastNode := Node;
            StartIf; -- Expect err owing to partial but effective array init.
            Node := STree.NullNode;
         when SP_Symbols.condition =>
            StartElsIf; -- Expect err owing to partial but effective array init.
            Node := STree.NullNode;
         when SP_Symbols.else_part =>
            Node := STree.Child_Node (Current_Node => Node);
            if Node = STree.NullNode and then IFA_Stack.Top (S).MemberKind /= IFA_Stack.ExitNode then
               NullStatement;
            end if;
         when SP_Symbols.case_statement =>
            Node     := STree.Child_Node (Current_Node => Node);
            LastNode := Node;
            StartCase; -- Expect err owing to partial but effective array init.
            Node := STree.NullNode;
         when SP_Symbols.case_statement_alternative =>
            Node := STree.Child_Node (Current_Node => Node);
            Node := STree.Next_Sibling (Current_Node => Node);
         when SP_Symbols.return_statement =>
            Node := STree.Child_Node (Current_Node => Node);
            ReturnExpression; -- Expect err owing to partial but effective array init.
            Node := STree.NullNode;
         when SP_Symbols.loop_statement_opt =>
            StartLoop; -- Expect err owing to partial but effective array init.
            Node := STree.NullNode;
         when SP_Symbols.exit_statement =>
            Node := STree.Child_Node (Current_Node => Node);
            Node := STree.Next_Sibling (Current_Node => Node);

            if STree.Syntax_Node_Type (Node => Node) = SP_Symbols.simple_name then
               -- Exit statement has a label, which we must skip
               -- to get to the condition.
               Node := STree.Next_Sibling (Current_Node => Node);
            end if;

            ModelExit; -- Expect err owing to partial but effective array init.
            Node := STree.NullNode;

         when SP_Symbols.end_of_loop =>
            ModelDefaultExitOrFinalForLoopExit;   -- Expect err owing to partial but effective array init.
            Node := STree.NullNode;

         when SP_Symbols.sequence_of_labels | SP_Symbols.label =>
            Node := STree.NullNode;

         when others =>
            Node := STree.NullNode;
            SystemErrors.Fatal_Error
              (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
               Msg     => "FlowAnalyse: Unexpected node kind in main tree");
      end case;
      --# end accept;

      -- Up Loop --------------------------
      if Node = STree.NullNode and then LastNode /= StartNode then
         loop
            Node := STree.Next_Sibling (Current_Node => LastNode);
            exit when Node /= STree.NullNode;
            Node := STree.Parent_Node (Current_Node => LastNode);
            exit when Node = STree.NullNode or else Node = StartNode;
            NodeType := STree.Syntax_Node_Type (Node => Node);
            case NodeType is
               when SP_Symbols.statement =>
                  if STree.Child_Node (Current_Node => STree.Parent_Node (Current_Node => Node)) /= Node then
                     CombineSequence;
                  end if;
               when SP_Symbols.if_statement =>
                  Join;
               when SP_Symbols.case_statement =>
                  CombineCases;
               when SP_Symbols.loop_statement =>
                  CloseLoop;
                  if ((STree.Child_Node (Current_Node => STree.Child_Node (Current_Node => Node)) /= STree.NullNode)
                      and then (STree.Syntax_Node_Type
                                  (Node => STree.Child_Node
                                     (Current_Node =>
                                        STree.Child_Node (Current_Node => STree.Child_Node (Current_Node => Node)))) =
                                  SP_Symbols.loop_parameter_specification))
                    or else ((STree.Child_Node
                                (Current_Node => STree.Next_Sibling (Current_Node => STree.Child_Node (Current_Node => Node))) /=
                                STree.NullNode)
                             and then (STree.Syntax_Node_Type
                                         (Node => STree.Child_Node
                                            (Current_Node =>
                                               STree.Child_Node
                                               (Current_Node => STree.Next_Sibling
                                                  (Current_Node => STree.Child_Node (Current_Node => Node))))) =
                                         SP_Symbols.loop_parameter_specification)) then
                     CombineSequence;
                  end if;

               when others =>
                  null;
            end case;
            LastNode := Node;
         end loop; -- Up
      end if;
      exit when Node = STree.NullNode or else Node = StartNode;
   end loop; -- Down

   -- combine in local variable initializations if there are any
   if not SeqAlgebra.IsEmptySeq (TheHeap, LocalInits) then
      CheckVarsUsedAsConsts;
      CombineSequence;
   end if;

   -- For every protected variable P that has been referenced somewhere, we need to
   -- set up an initialization of the associated protected stream thus : P--in <-- P.
   --# accept Flow, 10, ExpnNumber, "Final assignment to ExpnNumber not used" &
   --#        Flow, 504, ExpnLocations, "Partial but effective array init.";
   InitializeProtectedStreams (Node);
   --# end accept;

   if CommandLineData.Content.Debug.Rho then
      PrintStackTop ("Calculated flow relations before AnalyseRelations");
   end if;

   AnalyseRelations; -- Expect err owing to partial but effective array init.
   IFA_Stack.DisposeOfMember (TheHeap, IFA_Stack.Top (S));
   SeqAlgebra.DisposeOfSeq (TheHeap, ReferencedVars);
   SeqAlgebra.DisposeOfSeq (TheHeap, InnerExpns);
   SeqAlgebra.DisposeOfSeq (TheHeap, ZeroStableExpnSeq);
   SeqAlgebra.DisposeOfSeq (TheHeap, OneStableExpnSeq);
   SeqAlgebra.DisposeOfSeq (TheHeap, OtherStableExpnSeq);
   SeqAlgebra.DisposeOfSeq (TheHeap, SeqOfImports);
   SeqAlgebra.DisposeOfSeq (TheHeap, SeqOfInitVars);
   SeqAlgebra.DisposeOfSeq (TheHeap, LocalInits);
   SeqAlgebra.DisposeOfSeq (TheHeap, VarsUsedAsConstants);
   SeqAlgebra.DisposeOfSeq (TheHeap, SeqOfExports);
   SeqAlgebra.DisposeOfSeq (TheHeap, ExpSeqOfImports); -- added during 1215 but not really part of it
   SeqAlgebra.DisposeOfSeq (TheHeap, ExpSeqOfExports); -- added during 1215 but not really part of it
   SeqAlgebra.DisposeOfSeq (TheHeap, ShareableProtectedVars);
   SeqAlgebra.DisposeOfSeq (TheHeap, ReferencedProtectedVars);
   SeqAlgebra.DisposeOfSeq (TheHeap, InStreamsOfShareableProtectedVars);
   RelationAlgebra.DisposeOfRelation (TheHeap, DependencyRelation);

   -- signal presence of DFEs for use by VCG
   DataFlowErrorFound := DataFlowErrorFoundLocal;
   --# accept Flow, 602, Statistics.TableUsage, StmtLocations, "Partial but effective array init." &
   --#        Flow, 602, Statistics.TableUsage, ExpnLocations, "Partial but effective array init." &
   --#        Flow, 602, Statistics.TableUsage, KindDictionary, "Partial but effective array init." &
   --#        Flow, 602, Statistics.TableUsage, ParamDictionary, "Partial but effective array init." &
   --#        Flow, 602, ErrorHandler.Error_Context, StmtLocations, "Partial but effective array init." &
   --#        Flow, 602, ErrorHandler.Error_Context, ExpnLocations, "Partial but effective array init." &
   --#        Flow, 602, ErrorHandler.Error_Context, KindDictionary, "Partial but effective array init." &
   --#        Flow, 602, ErrorHandler.Error_Context, ParamDictionary, "Partial but effective array init." &
   --#        Flow, 602, ComponentData, StmtLocations, "Partial but effective array init." &
   --#        Flow, 602, ComponentData, ExpnLocations, "Partial but effective array init." &
   --#        Flow, 602, ComponentData, KindDictionary, "Partial but effective array init." &
   --#        Flow, 602, ComponentData, ParamDictionary, "Partial but effective array init." &
   --#        Flow, 602, TheHeap, StmtLocations, "Partial but effective array init." &
   --#        Flow, 602, TheHeap, ExpnLocations, "Partial but effective array init." &
   --#        Flow, 602, TheHeap, KindDictionary, "Partial but effective array init." &
   --#        Flow, 602, TheHeap, ParamDictionary, "Partial but effective array init." &
   --#        Flow, 602, DataFlowErrorFound, StmtLocations, "Partial but effective array init." &
   --#        Flow, 602, DataFlowErrorFound, ExpnLocations, "Partial but effective array init." &
   --#        Flow, 602, DataFlowErrorFound, KindDictionary, "Partial but effective array init." &
   --#        Flow, 602, DataFlowErrorFound, ParamDictionary, "Partial but effective array init." &
   --#        Flow, 602, SPARK_IO.File_Sys, StmtLocations, "Partial but effective array init." &
   --#        Flow, 602, SPARK_IO.File_Sys, ExpnLocations, "Partial but effective array init." &
   --#        Flow, 602, SPARK_IO.File_Sys, KindDictionary, "Partial but effective array init." &
   --#        Flow, 602, SPARK_IO.File_Sys, ParamDictionary, "Partial but effective array init.";
end FlowAnalyse;
