-------------------------------------------------------------------------------
-- (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 Command_Line_Options;
with SPARK_Ada_Integer_Text_IO;
with Sparklalr_Goto;
with Sparklalr_Memory;
with Symbols_Dump;

use type Sparklalr_Goto.Next_T;

package body Sparklalr_Parser
--# own State is Pat_Count,
--#              Pa_Array,
--#              Pa_Count,
--#              Pa_List,
--#              Reduce_State,
--#              Unique_Reduce_State;
is

   subtype Pa_Array_Range is Positive range 1 .. Pa_Table_Size;
   type Pa_Rec is record
      Index     : Sparklalr_Common.Term_Range;
      The_Entry : Sparklalr_Common.Short_Int;
      Pa_Next   : Pt_Pa_Rec;
   end record;
   type Pa_Array_Array_T is array (Pa_Array_Range) of Pa_Rec;
   type Pa_Array_T is record
      The_Array : Pa_Array_Array_T;
      Top       : Pt_Pa_Rec;
   end record;

   type State_Set is array (Sparklalr_Common.State_Range) of Boolean;
   type Pa_List_T is array (Sparklalr_Common.State_Range) of Pt_Pa_Rec; -- PARSING ACTION TABLE

   Pa_List             : Pa_List_T;
   Reduce_State        : State_Set;
   Unique_Reduce_State : State_Set;
   Pa_Count            : Integer;
   Pat_Count           : Integer;
   Pa_Array            : Pa_Array_T;

   -- Local procedures/functions
   procedure Sort_Pa (Head : in out Pt_Pa_Rec)
   --# global in out Pa_Array;
   --# derives Head,
   --#         Pa_Array from Head,
   --#                       Pa_Array;
   is
      P, Pnext, Q : Pt_Pa_Rec;
      Found       : Boolean;
   begin
      if Head /= 0 then
         P                                 := Pa_Array.The_Array (Head).Pa_Next;
         Pa_Array.The_Array (Head).Pa_Next := 0;
      else
         P := 0;
      end if;
      while P /= 0 loop
         Pnext := Pa_Array.The_Array (P).Pa_Next;
         if Pa_Array.The_Array (P).The_Entry >= Pa_Array.The_Array (Head).The_Entry then
            Pa_Array.The_Array (P).Pa_Next := Head;
            Head                           := P;
         else
            Q     := Head;
            Found := False;
            loop
               if Pa_Array.The_Array (Q).Pa_Next /= 0 then
                  if Pa_Array.The_Array (P).The_Entry >= Pa_Array.The_Array (Pa_Array.The_Array (Q).Pa_Next).The_Entry then
                     Found := True;
                  else
                     Q := Pa_Array.The_Array (Q).Pa_Next;
                  end if;
               else
                  Found := True;
               end if;
               exit when Found;
            end loop;
            Pa_Array.The_Array (P).Pa_Next := Pa_Array.The_Array (Q).Pa_Next;
            Pa_Array.The_Array (Q).Pa_Next := P;
         end if;
         P := Pnext;
      end loop;
   end Sort_Pa;
   -- End local procedures/functions

   procedure Init_Pa_List
   --# global out Pa_List;
   --# derives Pa_List from ;
   is
   begin
      Pa_List := Pa_List_T'(others => 0);
   end Init_Pa_List;

   procedure Init_Pat_Count
   --# global out Pat_Count;
   --# derives Pat_Count from ;
   is
   begin
      Pat_Count := 0;
   end Init_Pat_Count;

   procedure Initialise
   --# global out Pat_Count;
   --#        out Pa_Array;
   --#        out Pa_Count;
   --#        out Pa_List;
   --#        out Reduce_State;
   --#        out Unique_Reduce_State;
   --# derives Pat_Count,
   --#         Pa_Array,
   --#         Pa_Count,
   --#         Pa_List,
   --#         Reduce_State,
   --#         Unique_Reduce_State from ;
   is
   begin
      Init_Pa_List;
      Init_Pat_Count;
      Reduce_State        := State_Set'(others => False);
      Unique_Reduce_State := State_Set'(others => False);
      Pa_Count            := 0;
      Pa_Array            :=
        Pa_Array_T'(The_Array => Pa_Array_Array_T'(others => Pa_Rec'(Index     => 0,
                                                                     The_Entry => 0,
                                                                     Pa_Next   => 0)),
                    Top       => 0);
   end Initialise;

   procedure Gen_State_Info
   --# global in     Pa_Array;
   --#        in     Pa_List;
   --#        in     Sparklalr_Memory.Stat_No;
   --#        in out Reduce_State;
   --#        in out Unique_Reduce_State;
   --# derives Reduce_State,
   --#         Unique_Reduce_State from *,
   --#                                  Pa_Array,
   --#                                  Pa_List,
   --#                                  Sparklalr_Memory.Stat_No;
   is
      Ptr, List_Start  : Pt_Pa_Rec;
      Is_Unique_Reduce : Boolean;
   begin
      for ST in Integer range 1 .. Sparklalr_Memory.Get_Stat_No loop
         Ptr              := Pa_List (ST);
         List_Start       := Ptr;
         Is_Unique_Reduce := True;
         while Ptr /= 0 loop
            if (Pa_Array.The_Array (Ptr).The_Entry > Sparklalr_Common.Prod_Lim)
              or else (Pa_Array.The_Array (Ptr).The_Entry = 1) then
               Is_Unique_Reduce := False;
            else
               Reduce_State (ST) := True;
               Is_Unique_Reduce  := Is_Unique_Reduce
                 and then (Pa_Array.The_Array (Ptr).The_Entry = Pa_Array.The_Array (List_Start).The_Entry);
            end if;
            Ptr := Pa_Array.The_Array (Ptr).Pa_Next;
         end loop;
         if Is_Unique_Reduce then
            Unique_Reduce_State (ST) := True;
         end if;
      end loop;
   end Gen_State_Info;

   procedure Pa_Search (State_Index, Term_Index : in     Integer;
                        Result                  :    out Integer;
                        Pl                      :    out Pt_Pa_Rec)
   --# global in Pa_Array;
   --#        in Pa_List;
   --# derives Pl,
   --#         Result from Pa_Array,
   --#                     Pa_List,
   --#                     State_Index,
   --#                     Term_Index;
   is
      Found : Boolean;
      Plist : Pt_Pa_Rec;
   begin
      Result := 0;
      Pl     := 0;
      Found  := False;
      Plist  := Pa_List (State_Index);
      while (Plist /= 0) and then not Found loop
         if Pa_Array.The_Array (Plist).Index = Term_Index then
            Pl     := Plist;
            Result := Pa_Array.The_Array (Plist).The_Entry;
            Found  := True;
         else
            Plist := Pa_Array.The_Array (Plist).Pa_Next;
         end if;
      end loop;
   end Pa_Search;

   procedure Pa_Insert (F                                  : in out SPARK.Ada.Text_IO.File_Type;
                        State_Index, Term_Index, Insertion : in     Integer)
   -- INSERTS A NEW ENTRY INTO THE PARSING ACTION TABLE
   --# global in     Command_Line_Options.State;
   --#        in     Symbols_Dump.State;
   --#        in out Pa_Array;
   --#        in out Pa_Count;
   --#        in out Pa_List;
   --#        in out SPARK.Ada.Text_IO.The_Standard_Output;
   --# derives F                                     from *,
   --#                                                    Command_Line_Options.State,
   --#                                                    Symbols_Dump.State,
   --#                                                    Term_Index &
   --#         Pa_Array                              from *,
   --#                                                    Insertion,
   --#                                                    Pa_List,
   --#                                                    State_Index,
   --#                                                    Term_Index &
   --#         Pa_Count                              from * &
   --#         Pa_List                               from *,
   --#                                                    Pa_Array,
   --#                                                    State_Index,
   --#                                                    Term_Index &
   --#         SPARK.Ada.Text_IO.The_Standard_Output from *,
   --#                                                    Command_Line_Options.State,
   --#                                                    Insertion,
   --#                                                    State_Index,
   --#                                                    Symbols_Dump.State,
   --#                                                    Term_Index;
   is
      Posn             : Integer;
      Result_Pa_Search : Integer;
      Pl               : Pt_Pa_Rec;
   begin
      if Command_Line_Options.Get_Debug_Level (6) then
         SPARK.Ada.Text_IO.Put_Output (Item => " PA(STATE=");
         SPARK_Ada_Integer_Text_IO.Put_Output (Item  => State_Index,
                                               Width => 3,
                                               Base  => 10);
         SPARK.Ada.Text_IO.Put_Output (Item => ",TERMINAL=");
         Posn := 23;
         --# accept F, 10, Posn, "Ineffective assigment to Posn here expected and OK";
         Sparklalr_Common.Print
           (Std_Out => True,
            F       => F,
            String1 => Symbols_Dump.Get_Term_Set (Term_Index),
            Posn    => Posn,
            Tab     => 23,
            Comm    => False);
         --# end accept;
         SPARK.Ada.Text_IO.Put_Output (Item => ") = ");
         SPARK_Ada_Integer_Text_IO.Put_Output (Item  => Insertion,
                                               Width => 3,
                                               Base  => 10);
         SPARK.Ada.Text_IO.New_Line_Output (Spacing => 1);
      end if;
      Pa_Count := Pa_Count + 1;
      Pa_Search (State_Index, Term_Index, Result_Pa_Search, Pl);
      if Result_Pa_Search /= 0 then
         Pa_Array.The_Array (Pl).The_Entry := Insertion;
      else
         Pa_Array.Top                      := Pa_Array.Top + 1;
         Pa_Array.The_Array (Pa_Array.Top) :=
           Pa_Rec'(Index     => Term_Index,
                   The_Entry => Insertion,
                   Pa_Next   => Pa_List (State_Index));
         Pa_List (State_Index)             := Pa_Array.Top;
      end if;
   end Pa_Insert;

   function Action_Equal (Act1, Act2 : in Pt_Pa_Rec) return Boolean
   --# global in Pa_Array;
   is
      Found    : Boolean;
      A2       : Pt_Pa_Rec;
      C1, C2   : Integer;
      Act1_Tmp : Pt_Pa_Rec;

      function Eq_Pa_Size (A1, A2 : in Pt_Pa_Rec) return Boolean
      --# global in Pa_Array;
      is
         A1_Tmp : Pt_Pa_Rec;
         A2_Tmp : Pt_Pa_Rec;
      begin
         A1_Tmp := A1;
         A2_Tmp := A2;
         while (A1_Tmp /= 0) and then (A2_Tmp /= 0) loop
            A1_Tmp := Pa_Array.The_Array (A1_Tmp).Pa_Next;
            A2_Tmp := Pa_Array.The_Array (A2_Tmp).Pa_Next;
         end loop;
         return A1_Tmp = A2_Tmp;
      end Eq_Pa_Size;

   begin
      Act1_Tmp := Act1;
      Found    := False;
      if Eq_Pa_Size (Act1_Tmp, Act2) then
         while Act1_Tmp /= 0 loop
            C1    := Pa_Array.The_Array (Act1_Tmp).Index;
            C2    := Pa_Array.The_Array (Act1_Tmp).The_Entry;
            A2    := Act2;
            Found := False;
            while (A2 /= 0) and then not Found loop
               if Pa_Array.The_Array (A2).Index = C1 then
                  if Pa_Array.The_Array (A2).The_Entry = C2 then
                     Found := True;
                  else
                     A2 := 0;
                  end if;
               else
                  A2 := Pa_Array.The_Array (A2).Pa_Next;
               end if;
            end loop;
            if Found then
               Act1_Tmp := Pa_Array.The_Array (Act1_Tmp).Pa_Next;
            else
               Act1_Tmp := 0;
            end if;
         end loop;
      end if;
      return Found;
   end Action_Equal;

   procedure Pa_Stats (Std_Out : in     Boolean;
                       F       : in out SPARK.Ada.Text_IO.File_Type)
   --# global in     Pa_Count;
   --#        in out SPARK.Ada.Text_IO.The_Standard_Output;
   --# derives F,
   --#         SPARK.Ada.Text_IO.The_Standard_Output from *,
   --#                                                    Pa_Count,
   --#                                                    Std_Out;
   is
   begin
      Sparklalr_Common.Put_Integer_File_Output (Std_Out => Std_Out,
                                                File    => F,
                                                Item    => Pa_Count,
                                                Width   => 6);
      Sparklalr_Common.Put_Line_File_Output (Std_Out => Std_Out,
                                             File    => F,
                                             Item    => " PARSING ACTIONS GENERATED");
   end Pa_Stats;

   procedure Dump_Actions (F      : in out SPARK.Ada.Text_IO.File_Type;
                           Nstate : in     Integer)
   --# global in     Pa_Array;
   --#        in     Pa_List;
   --#        in     Symbols_Dump.State;
   --#        in out SPARK.Ada.Text_IO.The_Standard_Output;
   --# derives F,
   --#         SPARK.Ada.Text_IO.The_Standard_Output from *,
   --#                                                    Nstate,
   --#                                                    Pa_Array,
   --#                                                    Pa_List,
   --#                                                    Symbols_Dump.State;
   is
      Pl               : Pt_Pa_Rec;
      J                : Integer;
      Posn             : Integer;
      Result_Pa_Search : Integer;
   begin
      Posn := 1;
      for I in Integer range 0 .. Symbols_Dump.Get_Nterms loop
         --# accept F, 10, Pl, "Ineffective assigment to Pl here expected and OK";
         Pa_Search (Nstate, I, Result_Pa_Search, Pl);
         --# end accept;
         if Result_Pa_Search /= 0 then
            Sparklalr_Common.Put_N_Chars (Std_Out => False,
                                          F       => F,
                                          C       => ' ',
                                          N       => 4);
            Posn := Posn + 4;
            --# accept F, 10, Posn, "Ineffective assigment to Posn here expected and OK";
            Sparklalr_Common.Print
              (Std_Out => False,
               F       => F,
               String1 => Symbols_Dump.Get_Term_Set (I),
               Posn    => Posn,
               Tab     => 4,
               Comm    => False);
            --# end accept;
            --# accept F, 10, Pl, "Ineffective assigment to Pl here expected and OK";
            Pa_Search (Nstate, I, J, Pl);
            --# end accept;
            if J > Sparklalr_Common.Prod_Lim then
               SPARK.Ada.Text_IO.Put_File (File => F,
                                           Item => " SHIFT ");
               SPARK_Ada_Integer_Text_IO.Put_File (File  => F,
                                                   Item  => J - Sparklalr_Common.Prod_Lim,
                                                   Width => 4,
                                                   Base  => 10);
            else
               if (J = 1) or else (J = -1) then
                  if J = 1 then
                     SPARK.Ada.Text_IO.Put_File (File => F,
                                                 Item => " ACCEPT ");
                  else
                     SPARK.Ada.Text_IO.Put_File (File => F,
                                                 Item => " ERROR ");
                  end if;
               else
                  SPARK.Ada.Text_IO.Put_File (File => F,
                                              Item => " REDUCE ");
                  SPARK_Ada_Integer_Text_IO.Put_File (File  => F,
                                                      Item  => J,
                                                      Width => 4,
                                                      Base  => 10);
               end if;
            end if;
            SPARK.Ada.Text_IO.New_Line_File (File    => F,
                                             Spacing => 1);
            Posn := 1;
         end if;
      end loop;
      --# accept F, 33, Pl, "Pl is unused OK";
   end Dump_Actions;

   procedure Action_Gen (State_Var : in Integer)
   --# global in     Unique_Reduce_State;
   --#        in out Pat_Count;
   --#        in out Pa_Array;
   --#        in out Pa_List;
   --# derives Pat_Count from *,
   --#                        Pa_Array,
   --#                        Pa_List,
   --#                        State_Var,
   --#                        Unique_Reduce_State &
   --#         Pa_Array,
   --#         Pa_List   from Pa_Array,
   --#                        Pa_List,
   --#                        State_Var;
   is

      Curr_Entry : Integer;
      Red_Count  : Sparklalr_Common.Production_Count;
      Exit_Flag  : Boolean;
      P          : Pt_Pa_Rec;
      Next       : Sparklalr_Goto.Next_T;
      First_Var  : Sparklalr_Common.Term_Range;

      procedure Write_Cond (Next      : in Sparklalr_Goto.Next_T;
                            First_Var : in Sparklalr_Common.Term_Range)
      --# global in out Pat_Count;
      --# derives Pat_Count from *,
      --#                        First_Var,
      --#                        Next;
      is
         T        : Sparklalr_Common.Term_Range;
         Next_Tmp : Sparklalr_Goto.Next_T;
      begin
         Next_Tmp  := Next;
         Pat_Count := Pat_Count + 1;
         if Next_Tmp /= Sparklalr_Goto.Next_False_Const then
            T := First_Var;
            loop
               T := T + 1;
               if Sparklalr_Goto.Get_Next (Next_Tmp, T) then
                  Pat_Count := Pat_Count + 1;
                  Sparklalr_Goto.Set_Next (Next_Tmp, T, False);
               end if;
               exit when Next_Tmp = Sparklalr_Goto.Next_False_Const;
            end loop;
         end if;
      end Write_Cond;

   begin
      Sort_Pa (Pa_List (State_Var));
      P := Pa_List (State_Var);
      while P /= 0 loop
         Curr_Entry := Pa_Array.The_Array (P).The_Entry;
         First_Var  := Pa_Array.The_Array (P).Index;
         Next       := Sparklalr_Goto.Next_False_Const;
         Exit_Flag  := False;
         Red_Count  := 0;
         loop
            P := Pa_Array.The_Array (P).Pa_Next;
            if P /= 0 then
               if Pa_Array.The_Array (P).The_Entry = Curr_Entry then
                  if Pa_Array.The_Array (P).Index < First_Var then
                     Sparklalr_Goto.Set_Next (Next, First_Var, True);
                     First_Var := Pa_Array.The_Array (P).Index;
                  else
                     Sparklalr_Goto.Set_Next (Next, Pa_Array.The_Array (P).Index, True);
                  end if;
               else
                  Exit_Flag := True;
               end if;
            else
               Exit_Flag := True;
            end if;
            exit when Exit_Flag;
         end loop;
         if Curr_Entry >= 0 then
            if Curr_Entry <= Sparklalr_Common.Prod_Lim then
               Red_Count := Red_Count + 1;
            end if;
            if (Red_Count = 1) and then (P = 0) and then Unique_Reduce_State (State_Var) then
               Pat_Count := Pat_Count + 1;
            else
               Write_Cond (Next, First_Var);
            end if;
         end if;
      end loop;
   end Action_Gen;

   procedure Action_Gen_Pa_Out (F              : in out SPARK.Ada.Text_IO.File_Type;
                                State_Var      : in     Integer;
                                Curr_Pat_Index : in out Integer)
   --# global in     Sparklalr_Memory.Prod_Sum;
   --#        in     Symbols_Dump.State;
   --#        in     Unique_Reduce_State;
   --#        in out Pa_Array;
   --#        in out Pa_List;
   --#        in out SPARK.Ada.Text_IO.The_Standard_Output;
   --# derives Curr_Pat_Index                        from *,
   --#                                                    Pa_Array,
   --#                                                    Pa_List,
   --#                                                    State_Var,
   --#                                                    Unique_Reduce_State &
   --#         F                                     from *,
   --#                                                    Curr_Pat_Index,
   --#                                                    Pa_Array,
   --#                                                    Pa_List,
   --#                                                    Sparklalr_Memory.Prod_Sum,
   --#                                                    State_Var,
   --#                                                    Symbols_Dump.State,
   --#                                                    Unique_Reduce_State &
   --#         Pa_Array,
   --#         Pa_List                               from Pa_Array,
   --#                                                    Pa_List,
   --#                                                    State_Var &
   --#         SPARK.Ada.Text_IO.The_Standard_Output from *,
   --#                                                    Pa_Array,
   --#                                                    Pa_List,
   --#                                                    Sparklalr_Memory.Prod_Sum,
   --#                                                    State_Var,
   --#                                                    Symbols_Dump.State,
   --#                                                    Unique_Reduce_State;
   is

      Red_Count  : Sparklalr_Common.Production_Count;
      Exit_Flag  : Boolean;
      P          : Pt_Pa_Rec;
      Next       : Sparklalr_Goto.Next_T;
      First_Var  : Sparklalr_Common.Term_Range;
      Curr_Entry : Integer;

      procedure Write_Act (F          : in out SPARK.Ada.Text_IO.File_Type;
                           Curr_Entry : in     Integer)
      --# global in     Sparklalr_Memory.Prod_Sum;
      --#        in     Symbols_Dump.State;
      --#        in out SPARK.Ada.Text_IO.The_Standard_Output;
      --# derives F,
      --#         SPARK.Ada.Text_IO.The_Standard_Output from *,
      --#                                                    Curr_Entry,
      --#                                                    Sparklalr_Memory.Prod_Sum,
      --#                                                    Symbols_Dump.State;
      is
         Posn : Integer;
      begin
         Posn := 22;
         if Curr_Entry /= 1 then -- ACCEPT
            if Curr_Entry > Sparklalr_Common.Prod_Lim then
               SPARK.Ada.Text_IO.Put_File (File => F,
                                           Item => ", SP_Parse_Act'(Shift, ");
               SPARK_Ada_Integer_Text_IO.Put_File
                 (File  => F,
                  Item  => Curr_Entry - Sparklalr_Common.Prod_Lim,
                  Width => 1,
                  Base  => 10);
               SPARK.Ada.Text_IO.Put_File (File => F,
                                           Item => ", No_Sym, No_Red, No_Prod)");
            else
               SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                                Item => ", SP_Parse_Act'(Reduce, SP_Productions.No_State, ");
               Sparklalr_Common.Put_N_Chars (Std_Out => False,
                                             F       => F,
                                             C       => ' ',
                                             N       => 22);
               --# accept F, 10, Posn, "Ineffective assigment to Posn here expected and OK";
               Symbols_Dump.Print_String_Sym
                 (F,
                  Sparklalr_Common.Sp_Symbol_Str,
                  Sparklalr_Memory.Get_Prod_Sum (Curr_Entry, 1) + Sparklalr_Common.Nt_Base,
                  Posn,
                  22,
                  False);
               --# end accept;
               SPARK.Ada.Text_IO.New_Line_File (File    => F,
                                                Spacing => 1);
               Sparklalr_Common.Put_N_Chars (Std_Out => False,
                                             F       => F,
                                             C       => ' ',
                                             N       => 22);
               SPARK.Ada.Text_IO.Put_File (File => F,
                                           Item => ", ");
               SPARK_Ada_Integer_Text_IO.Put_File
                 (File  => F,
                  Item  => Sparklalr_Memory.Get_Prod_Sum (Curr_Entry, 2),
                  Width => 1,
                  Base  => 10);
               SPARK.Ada.Text_IO.Put_File (File => F,
                                           Item => ", ");
               SPARK_Ada_Integer_Text_IO.Put_File (File  => F,
                                                   Item  => Curr_Entry,
                                                   Width => 1,
                                                   Base  => 10);
               SPARK.Ada.Text_IO.Put_Character_File (File => F,
                                                     Item => ')');
            end if;
         else
            SPARK.Ada.Text_IO.Put_File (File => F,
                                        Item => ", Accept_Action");
         end if;
      end Write_Act;

      procedure Write_Cond
        (F              : in out SPARK.Ada.Text_IO.File_Type;
         Next           : in     Sparklalr_Goto.Next_T;
         First_Var      : in     Sparklalr_Common.Term_Range;
         Curr_Entry     : in     Integer;
         Curr_Pat_Index : in out Integer)
      --# global in     Sparklalr_Memory.Prod_Sum;
      --#        in     Symbols_Dump.State;
      --#        in out SPARK.Ada.Text_IO.The_Standard_Output;
      --# derives Curr_Pat_Index                        from *,
      --#                                                    First_Var,
      --#                                                    Next &
      --#         F                                     from *,
      --#                                                    Curr_Entry,
      --#                                                    Curr_Pat_Index,
      --#                                                    First_Var,
      --#                                                    Next,
      --#                                                    Sparklalr_Memory.Prod_Sum,
      --#                                                    Symbols_Dump.State &
      --#         SPARK.Ada.Text_IO.The_Standard_Output from *,
      --#                                                    Curr_Entry,
      --#                                                    First_Var,
      --#                                                    Next,
      --#                                                    Sparklalr_Memory.Prod_Sum,
      --#                                                    Symbols_Dump.State;
      is
         T        : Sparklalr_Common.Term_Range;
         Posn     : Integer;
         Next_Tmp : Sparklalr_Goto.Next_T;
      begin
         SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                          Item => "                         Sym_Action_Pair'(");
         Next_Tmp       := Next;
         Curr_Pat_Index := Curr_Pat_Index + 1;
         Posn           := 21;
         if Next_Tmp = Sparklalr_Goto.Next_False_Const then
            --# accept F, 10, Posn, "Ineffective assigment to Posn here expected and OK";
            Sparklalr_Common.Print2 (F, Sparklalr_Common.Sp_Symbol_Str, Symbols_Dump.Get_Term_Set (First_Var), Posn, 21, False);
            --# end accept;
            Write_Act (F, Curr_Entry);
            SPARK.Ada.Text_IO.Put_Character_File (File => F,
                                                  Item => ')');
         else
            --# accept F, 10, Posn, "Ineffective assigment to Posn here expected and OK";
            Sparklalr_Common.Print2 (F, Sparklalr_Common.Sp_Symbol_Str, Symbols_Dump.Get_Term_Set (First_Var), Posn, 21, False);
            --# end accept;
            Write_Act (F, Curr_Entry);
            SPARK.Ada.Text_IO.Put_Character_File (File => F,
                                                  Item => ')');
            T := First_Var;
            loop
               T := T + 1;
               if Sparklalr_Goto.Get_Next (Next_Tmp, T) then
                  SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                                   Item => ",");
                  SPARK_Ada_Integer_Text_IO.Put_File (File  => F,
                                                      Item  => Curr_Pat_Index,
                                                      Width => 5,
                                                      Base  => 10);
                  SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                                   Item => "                      => Sym_Action_Pair'(");
                  Curr_Pat_Index := Curr_Pat_Index + 1;
                  Posn           := 21;
                  --# accept F, 10, Posn, "Ineffective assigment to Posn here expected and OK";
                  Sparklalr_Common.Print2 (F, Sparklalr_Common.Sp_Symbol_Str, Symbols_Dump.Get_Term_Set (T), Posn, 13, False);
                  --# end accept;
                  Write_Act (F, Curr_Entry);
                  SPARK.Ada.Text_IO.Put_Character_File (File => F,
                                                        Item => ')');
                  Sparklalr_Goto.Set_Next (Next_Tmp, T, False);
               end if;
               exit when Next_Tmp = Sparklalr_Goto.Next_False_Const;
            end loop;
         end if;
      end Write_Cond;

   begin -- Action_Gen_Pa_Out
      Sort_Pa (Pa_List (State_Var));
      P := Pa_List (State_Var);
      while P /= 0 loop
         Curr_Entry := Pa_Array.The_Array (P).The_Entry;
         First_Var  := Pa_Array.The_Array (P).Index;
         Next       := Sparklalr_Goto.Next_False_Const;
         Exit_Flag  := False;
         Red_Count  := 0;
         loop
            P := Pa_Array.The_Array (P).Pa_Next;
            if P /= 0 then
               if Pa_Array.The_Array (P).The_Entry = Curr_Entry then
                  if Pa_Array.The_Array (P).Index < First_Var then
                     Sparklalr_Goto.Set_Next (Next, First_Var, True);
                     First_Var := Pa_Array.The_Array (P).Index;
                  else
                     Sparklalr_Goto.Set_Next (Next, Pa_Array.The_Array (P).Index, True);
                  end if;
               else
                  Exit_Flag := True;
               end if;
            else
               Exit_Flag := True;
            end if;
            exit when Exit_Flag;
         end loop;
         if Curr_Entry >= 0 then
            if Curr_Entry <= Sparklalr_Common.Prod_Lim then
               Red_Count := Red_Count + 1;
            end if;
            if (Red_Count = 1) and then (P = 0) and then Unique_Reduce_State (State_Var) then
               SPARK.Ada.Text_IO.Put_File (File => F,
                                           Item => "Sym_Action_Pair'(Default");
               Curr_Pat_Index := Curr_Pat_Index + 1;
               Write_Act (F, Curr_Entry);
               SPARK.Ada.Text_IO.Put_Character_File (File => F,
                                                     Item => ')');
            else
               if P = 0 then
                  Write_Cond (F, Next, First_Var, Curr_Entry, Curr_Pat_Index);
               else
                  Write_Cond (F, Next, First_Var, Curr_Entry, Curr_Pat_Index);
                  SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                                   Item => ",");
                  SPARK_Ada_Integer_Text_IO.Put_File (File  => F,
                                                      Item  => Curr_Pat_Index,
                                                      Width => 5,
                                                      Base  => 10);
                  SPARK.Ada.Text_IO.Put_File (File => F,
                                              Item => " => ");
               end if;
            end if;
         end if;
      end loop;
   end Action_Gen_Pa_Out;

   procedure Action_Gen_Pa_Out_Sp
     (F              : in out SPARK.Ada.Text_IO.File_Type;
      State_Var      : in     Integer;
      Curr_Pat_Index : in out Integer)
   --# global in     Sparklalr_Memory.Prod_Sum;
   --#        in     Symbols_Dump.State;
   --#        in     Unique_Reduce_State;
   --#        in out Pa_Array;
   --#        in out Pa_List;
   --#        in out SPARK.Ada.Text_IO.The_Standard_Output;
   --# derives Curr_Pat_Index                        from *,
   --#                                                    Pa_Array,
   --#                                                    Pa_List,
   --#                                                    State_Var,
   --#                                                    Unique_Reduce_State &
   --#         F                                     from *,
   --#                                                    Curr_Pat_Index,
   --#                                                    Pa_Array,
   --#                                                    Pa_List,
   --#                                                    Sparklalr_Memory.Prod_Sum,
   --#                                                    State_Var,
   --#                                                    Symbols_Dump.State,
   --#                                                    Unique_Reduce_State &
   --#         Pa_Array,
   --#         Pa_List                               from Pa_Array,
   --#                                                    Pa_List,
   --#                                                    State_Var &
   --#         SPARK.Ada.Text_IO.The_Standard_Output from *,
   --#                                                    Pa_Array,
   --#                                                    Pa_List,
   --#                                                    Sparklalr_Memory.Prod_Sum,
   --#                                                    State_Var,
   --#                                                    Symbols_Dump.State,
   --#                                                    Unique_Reduce_State;
   is

      Red_Count  : Sparklalr_Common.Production_Count;
      Exit_Flag  : Boolean;
      P          : Pt_Pa_Rec;
      Posn       : Integer;
      Next       : Sparklalr_Goto.Next_T;
      First_Var  : Sparklalr_Common.Term_Range;
      Curr_Entry : Integer;

      procedure Write_Act
        (F          : in out SPARK.Ada.Text_IO.File_Type;
         Posn       : in out Integer;
         Tab        : in     Integer;
         Curr_Entry : in     Integer)
      --# global in     Sparklalr_Memory.Prod_Sum;
      --#        in     Symbols_Dump.State;
      --#        in out SPARK.Ada.Text_IO.The_Standard_Output;
      --# derives F,
      --#         Posn,
      --#         SPARK.Ada.Text_IO.The_Standard_Output from *,
      --#                                                    Curr_Entry,
      --#                                                    Posn,
      --#                                                    Sparklalr_Memory.Prod_Sum,
      --#                                                    Symbols_Dump.State,
      --#                                                    Tab;
      is
      begin
         if Curr_Entry /= 1 then -- ACCEPT
            if Curr_Entry > Sparklalr_Common.Prod_Lim then
               SPARK.Ada.Text_IO.Put_File (File => F,
                                           Item => " + (Shift_Act + State * ");
               SPARK_Ada_Integer_Text_IO.Put_File
                 (File  => F,
                  Item  => Curr_Entry - Sparklalr_Common.Prod_Lim,
                  Width => 1,
                  Base  => 10);
               SPARK.Ada.Text_IO.Put_Character_File (File => F,
                                                     Item => ')');
            else
               SPARK.Ada.Text_IO.Put_File (File => F,
                                           Item => " + (Reduce_Act + ((Symbol * (SP_Symbols.SP_Non_Terminal'Pos (");
               Posn := Posn + 72;
               Symbols_Dump.Print_String_Sym
                 (F,
                  Sparklalr_Common.Sp_Symbol_Str,
                  Sparklalr_Memory.Get_Prod_Sum (Curr_Entry, 1) + Sparklalr_Common.Nt_Base,
                  Posn,
                  Tab,
                  False);
               SPARK.Ada.Text_IO.Put_File (File => F,
                                           Item => ") - First_Non_Terminal) + Red_By * ");
               SPARK_Ada_Integer_Text_IO.Put_File
                 (File  => F,
                  Item  => Sparklalr_Memory.Get_Prod_Sum (Curr_Entry, 2),
                  Width => 1,
                  Base  => 10);
               SPARK.Ada.Text_IO.Put_File (File => F,
                                           Item => ") + Prod_No * ");
               SPARK_Ada_Integer_Text_IO.Put_File (File  => F,
                                                   Item  => Curr_Entry,
                                                   Width => 1,
                                                   Base  => 10);
               SPARK.Ada.Text_IO.Put_File (File => F,
                                           Item => "))");
               Posn := Posn + 32;
            end if;
         else
            SPARK.Ada.Text_IO.Put_File (File => F,
                                        Item => " + Accept_Act");
            Posn := Posn + 12;
         end if;
      end Write_Act;

      procedure Write_Cond
        (F              : in out SPARK.Ada.Text_IO.File_Type;
         Next           : in     Sparklalr_Goto.Next_T;
         First_Var      : in     Sparklalr_Common.Term_Range;
         Curr_Entry     : in     Integer;
         Curr_Pat_Index : in out Integer)
      --# global in     Sparklalr_Memory.Prod_Sum;
      --#        in     Symbols_Dump.State;
      --#        in out SPARK.Ada.Text_IO.The_Standard_Output;
      --# derives Curr_Pat_Index                        from *,
      --#                                                    First_Var,
      --#                                                    Next &
      --#         F                                     from *,
      --#                                                    Curr_Entry,
      --#                                                    Curr_Pat_Index,
      --#                                                    First_Var,
      --#                                                    Next,
      --#                                                    Sparklalr_Memory.Prod_Sum,
      --#                                                    Symbols_Dump.State &
      --#         SPARK.Ada.Text_IO.The_Standard_Output from *,
      --#                                                    Curr_Entry,
      --#                                                    First_Var,
      --#                                                    Next,
      --#                                                    Sparklalr_Memory.Prod_Sum,
      --#                                                    Symbols_Dump.State;
      is
         T        : Sparklalr_Common.Term_Range;
         Posn     : Integer;
         Next_Tmp : Sparklalr_Goto.Next_T;
      begin
         Next_Tmp       := Next;
         Curr_Pat_Index := Curr_Pat_Index + 1;
         if Next_Tmp = Sparklalr_Goto.Next_False_Const then
            SPARK.Ada.Text_IO.Put_File (File => F,
                                        Item => "SP_Symbols.SP_Terminal'Pos (");
            Posn := 36;
            Sparklalr_Common.Print2 (F, Sparklalr_Common.Sp_Symbol_Str, Symbols_Dump.Get_Term_Set (First_Var), Posn, 10, False);
            SPARK.Ada.Text_IO.Put_Character_File (File => F,
                                                  Item => ')');
            Posn := Posn + 1;
            --# accept F, 10, Posn, "Ineffective assigment to Posn here expected and OK";
            Write_Act (F, Posn, 10, Curr_Entry);
            --# end accept;
         else
            SPARK.Ada.Text_IO.Put_File (File => F,
                                        Item => "SP_Symbols.SP_Terminal'Pos (");
            Posn := 26;
            Sparklalr_Common.Print2 (F, Sparklalr_Common.Sp_Symbol_Str, Symbols_Dump.Get_Term_Set (First_Var), Posn, 10, False);
            SPARK.Ada.Text_IO.Put_Character_File (File => F,
                                                  Item => ')');
            Posn := Posn + 1;
            --# accept F, 10, Posn, "Ineffective assigment to Posn here expected and OK";
            Write_Act (F, Posn, 10, Curr_Entry);
            --# end accept;
            T := First_Var;
            loop
               T := T + 1;
               if Sparklalr_Goto.Get_Next (Next_Tmp, T) then
                  SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                                   Item => ",");
                  SPARK_Ada_Integer_Text_IO.Put_File (File  => F,
                                                      Item  => Curr_Pat_Index,
                                                      Width => 5,
                                                      Base  => 10);
                  SPARK.Ada.Text_IO.Put_File (File => F,
                                              Item => " => ");
                  Curr_Pat_Index := Curr_Pat_Index + 1;
                  SPARK.Ada.Text_IO.Put_File (File => F,
                                              Item => "SP_Symbols.SP_Terminal'Pos (");
                  Posn := 26;
                  Sparklalr_Common.Print2 (F, Sparklalr_Common.Sp_Symbol_Str, Symbols_Dump.Get_Term_Set (T), Posn, 10, False);
                  SPARK.Ada.Text_IO.Put_Character_File (File => F,
                                                        Item => ')');
                  Posn := Posn + 1;
                  --# accept F, 10, Posn, "Ineffective assigment to Posn here expected and OK";
                  Write_Act (F, Posn, 10, Curr_Entry);
                  --# end accept;
                  Sparklalr_Goto.Set_Next (Next_Tmp, T, False);
               end if;
               exit when Next_Tmp = Sparklalr_Goto.Next_False_Const;
            end loop;
         end if;
      end Write_Cond;

   begin -- Action_Gen_Pa_Out_Sp
      Sort_Pa (Pa_List (State_Var));
      Posn := 0;
      P    := Pa_List (State_Var);
      while P /= 0 loop
         Curr_Entry := Pa_Array.The_Array (P).The_Entry;
         First_Var  := Pa_Array.The_Array (P).Index;
         Next       := Sparklalr_Goto.Next_False_Const;
         Exit_Flag  := False;
         Red_Count  := 0;
         loop
            P := Pa_Array.The_Array (P).Pa_Next;
            if P /= 0 then
               if Pa_Array.The_Array (P).The_Entry = Curr_Entry then
                  if Pa_Array.The_Array (P).Index < First_Var then
                     Sparklalr_Goto.Set_Next (Next, First_Var, True);
                     First_Var := Pa_Array.The_Array (P).Index;
                  else
                     Sparklalr_Goto.Set_Next (Next, Pa_Array.The_Array (P).Index, True);
                  end if;
               else
                  Exit_Flag := True;
               end if;
            else
               Exit_Flag := True;
            end if;
            exit when Exit_Flag;
         end loop;
         if Curr_Entry >= 0 then
            if Curr_Entry <= Sparklalr_Common.Prod_Lim then
               Red_Count := Red_Count + 1;
            end if;
            if (Red_Count = 1) and then (P = 0) and then Unique_Reduce_State (State_Var) then
               SPARK.Ada.Text_IO.Put_File (File => F,
                                           Item => "Default");
               Curr_Pat_Index := Curr_Pat_Index + 1;
               Write_Act (F, Posn, 10, Curr_Entry);
            else
               if P = 0 then
                  Write_Cond (F, Next, First_Var, Curr_Entry, Curr_Pat_Index);
               else
                  Write_Cond (F, Next, First_Var, Curr_Entry, Curr_Pat_Index);
                  SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                                   Item => ",");
                  SPARK_Ada_Integer_Text_IO.Put_File (File  => F,
                                                      Item  => Curr_Pat_Index,
                                                      Width => 5,
                                                      Base  => 10);
                  SPARK.Ada.Text_IO.Put_File (File => F,
                                              Item => " => ");
               end if;
            end if;
         end if;
      end loop;
   end Action_Gen_Pa_Out_Sp;

   function Get_Reduce_State (S : in Sparklalr_Common.State_Range) return Boolean
   --# global in Reduce_State;
   is
   begin
      return Reduce_State (S);
   end Get_Reduce_State;

   function Get_Pat_Count return Integer
   --# global in Pat_Count;
   is
   begin
      return Pat_Count;
   end Get_Pat_Count;

   function Get_Pa_List (I : in Sparklalr_Common.State_Range) return Pt_Pa_Rec
   --# global in Pa_List;
   is
   begin
      return Pa_List (I);
   end Get_Pa_List;

end Sparklalr_Parser;
