-------------------------------------------------------------------------------
-- (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_Common;
with Sparklalr_Goto;
with Sparklalr_Memory;
with Sparklalr_Parser;
with Symbols_Dump;

package body Sparklalr_Patab
--# own State is Patab,
--#              Pat_Seg_Count,
--#              State_Table;
is

   type Patab_Elem is record
      Nact            : Integer;
      Other_Act       : Boolean;
      Check_Other_Act : Boolean;
   end record;
   type Patab_T is array (Sparklalr_Common.State_Range) of Patab_Elem;

   type State_Index_Pair is record
      Lower, Upper : Integer;
   end record;
   type State_Index is array (Sparklalr_Common.State_Range) of State_Index_Pair;

   Patab         : Patab_T;
   State_Table   : State_Index;
   Pat_Seg_Count : Integer;

   procedure Initialise
   --# global out Patab;
   --#        out Pat_Seg_Count;
   --#        out State_Table;
   --# derives Patab,
   --#         Pat_Seg_Count,
   --#         State_Table   from ;
   is
   begin
      Patab         := Patab_T'(others => Patab_Elem'(Nact            => 0,
                                                      Other_Act       => False,
                                                      Check_Other_Act => False));
      State_Table   := State_Index'(others => State_Index_Pair'(Lower => 0,
                                                                Upper => 0));
      Pat_Seg_Count := 0;
      for I in Sparklalr_Common.State_Range loop
         Patab (I).Nact := I;
      end loop;
   end Initialise;

   procedure Pa_Out (F : in out SPARK.Ada.Text_IO.File_Type)
   --# global in     Sparklalr_Memory.Prod_Sum;
   --#        in     Sparklalr_Memory.Stat_No;
   --#        in     Symbols_Dump.State;
   --#        in out Patab;
   --#        in out SPARK.Ada.Text_IO.The_Standard_Output;
   --#        in out Sparklalr_Parser.State;
   --#        in out State_Table;
   --# derives F                                     from *,
   --#                                                    Patab,
   --#                                                    Sparklalr_Memory.Prod_Sum,
   --#                                                    Sparklalr_Memory.Stat_No,
   --#                                                    Sparklalr_Parser.State,
   --#                                                    State_Table,
   --#                                                    Symbols_Dump.State &
   --#         Patab,
   --#         Sparklalr_Parser.State                from *,
   --#                                                    Patab,
   --#                                                    Sparklalr_Memory.Stat_No &
   --#         SPARK.Ada.Text_IO.The_Standard_Output from *,
   --#                                                    Patab,
   --#                                                    Sparklalr_Memory.Prod_Sum,
   --#                                                    Sparklalr_Memory.Stat_No,
   --#                                                    Sparklalr_Parser.State,
   --#                                                    Symbols_Dump.State &
   --#         State_Table                           from *,
   --#                                                    Patab,
   --#                                                    Sparklalr_Memory.Stat_No,
   --#                                                    Sparklalr_Parser.State;
   is

      procedure Aux_Pat_Out (F : in out SPARK.Ada.Text_IO.File_Type)
      --# global in     Sparklalr_Memory.Prod_Sum;
      --#        in     Sparklalr_Memory.Stat_No;
      --#        in     Symbols_Dump.State;
      --#        in out Patab;
      --#        in out SPARK.Ada.Text_IO.The_Standard_Output;
      --#        in out Sparklalr_Parser.State;
      --#        in out State_Table;
      --# derives F,
      --#         SPARK.Ada.Text_IO.The_Standard_Output from *,
      --#                                                    Patab,
      --#                                                    Sparklalr_Memory.Prod_Sum,
      --#                                                    Sparklalr_Memory.Stat_No,
      --#                                                    Sparklalr_Parser.State,
      --#                                                    Symbols_Dump.State &
      --#         Patab,
      --#         Sparklalr_Parser.State                from *,
      --#                                                    Patab,
      --#                                                    Sparklalr_Memory.Stat_No &
      --#         State_Table                           from *,
      --#                                                    Patab,
      --#                                                    Sparklalr_Memory.Stat_No,
      --#                                                    Sparklalr_Parser.State;
      is
         J                : Integer;
         Other_Acts_There : Boolean;
         Curr_Pat_Index   : Integer;
      begin
         Curr_Pat_Index   := 1;
         Other_Acts_There := False;
         SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                          Item => "  Parse_Action_Table : constant Aux_PAT := Aux_PAT'(");
         SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                          Item => "-- STATE INDEX");
         for I in Integer range 1 .. Sparklalr_Memory.Get_Stat_No loop
            if not Patab (I).Other_Act then
               if I > 1 then
                  SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                                   Item => ",");
               end if;
               State_Table (I).Lower := Curr_Pat_Index;
               SPARK.Ada.Text_IO.Put_File (File => F,
                                           Item => "----- ");
               SPARK_Ada_Integer_Text_IO.Put_File (File  => F,
                                                   Item  => I,
                                                   Width => 1,
                                                   Base  => 10);
               SPARK.Ada.Text_IO.New_Line_File (File    => F,
                                                Spacing => 1);
               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 => " => ");
               Sparklalr_Parser.Action_Gen_Pa_Out (F, I, Curr_Pat_Index);
               State_Table (I).Upper := Curr_Pat_Index - 1;
               Other_Acts_There      := True;
            end if;
         end loop;
         for I in Integer range 1 .. Sparklalr_Memory.Get_Stat_No loop
            if Patab (I).Check_Other_Act then
               if Other_Acts_There then
                  SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                                   Item => ",");
               else
                  Other_Acts_There := True;
               end if;
               J := I;
               SPARK.Ada.Text_IO.Put_File (File => F,
                                           Item => "----- ");
               SPARK_Ada_Integer_Text_IO.Put_File (File  => F,
                                                   Item  => J,
                                                   Width => 1,
                                                   Base  => 10);
               SPARK.Ada.Text_IO.New_Line_File (File    => F,
                                                Spacing => 1);
               loop
                  J                         := Patab (J).Nact;
                  Patab (J).Check_Other_Act := False;
                  SPARK.Ada.Text_IO.Put_File (File => F,
                                              Item => "----- ");
                  SPARK_Ada_Integer_Text_IO.Put_File (File  => F,
                                                      Item  => J,
                                                      Width => 1,
                                                      Base  => 10);
                  SPARK.Ada.Text_IO.New_Line_File (File    => F,
                                                   Spacing => 1);
                  exit when Patab (J).Nact = J;
               end loop;
            end if;
            if Patab (I).Other_Act then
               J                     := I;
               State_Table (I).Lower := Curr_Pat_Index;
               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 => " => ");
               Sparklalr_Parser.Action_Gen_Pa_Out (F, J, Curr_Pat_Index);
               State_Table (I).Upper := Curr_Pat_Index - 1;
               loop
                  J                   := Patab (J).Nact;
                  Patab (J).Other_Act := False;
                  State_Table (J)     := State_Table (I);
                  exit when Patab (J).Nact = J;
               end loop;
            end if;
         end loop;
         SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                          Item => ");");
      end Aux_Pat_Out;

      procedure Main_Pat_Out (F : in out SPARK.Ada.Text_IO.File_Type)
      --# global in Sparklalr_Memory.Stat_No;
      --#        in State_Table;
      --# derives F from *,
      --#                Sparklalr_Memory.Stat_No,
      --#                State_Table;
      is
      begin
         SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                          Item => "  State_Table : constant Main_PAT := Main_PAT'(");
         SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                          Item => "-- STATE");
         for State_Var in Integer range 1 .. Sparklalr_Memory.Get_Stat_No - 1 loop
            SPARK_Ada_Integer_Text_IO.Put_File (File  => F,
                                                Item  => State_Var,
                                                Width => 5,
                                                Base  => 10);
            SPARK.Ada.Text_IO.Put_File (File => F,
                                        Item => " => PAT_Index_Pair'(");
            SPARK_Ada_Integer_Text_IO.Put_File (File  => F,
                                                Item  => State_Table (State_Var).Lower,
                                                Width => 1,
                                                Base  => 10);
            SPARK.Ada.Text_IO.Put_File (File => F,
                                        Item => ", ");
            SPARK_Ada_Integer_Text_IO.Put_File (File  => F,
                                                Item  => State_Table (State_Var).Upper,
                                                Width => 1,
                                                Base  => 10);
            SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                             Item => "),");
         end loop;
         SPARK_Ada_Integer_Text_IO.Put_File (File  => F,
                                             Item  => Sparklalr_Memory.Get_Stat_No,
                                             Width => 5,
                                             Base  => 10);
         SPARK.Ada.Text_IO.Put_File (File => F,
                                     Item => " => PAT_Index_Pair'(");
         SPARK_Ada_Integer_Text_IO.Put_File
           (File  => F,
            Item  => State_Table (Sparklalr_Memory.Get_Stat_No).Lower,
            Width => 1,
            Base  => 10);
         SPARK.Ada.Text_IO.Put_File (File => F,
                                     Item => ", ");
         SPARK_Ada_Integer_Text_IO.Put_File
           (File  => F,
            Item  => State_Table (Sparklalr_Memory.Get_Stat_No).Upper,
            Width => 1,
            Base  => 10);
         SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                          Item => "));");
      end Main_Pat_Out;

   begin -- Pa_Out
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => "   Default : constant SP_Symbols.SP_Terminal := SP_Symbols.SPDEFAULT;");
      SPARK.Ada.Text_IO.New_Line_File (File    => F,
                                       Spacing => 1);
      SPARK.Ada.Text_IO.Put_File (File => F,
                                  Item => "   No_Of_PAT_Entries : constant Positive := ");
      SPARK_Ada_Integer_Text_IO.Put_File (File  => F,
                                          Item  => Sparklalr_Parser.Get_Pat_Count,
                                          Width => 1,
                                          Base  => 10);
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => ";");
      SPARK.Ada.Text_IO.New_Line_File (File    => F,
                                       Spacing => 1);
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => "   type PAT_Index is range 1 .. No_Of_PAT_Entries;");
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => "   type Sym_Action_Pair is record");
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => "      Term_Sym     : SP_Symbols.SP_Terminal;");
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => "      Parse_Action : SP_Parse_Act;");
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => "   end record;");
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => "   pragma PACK(Sym_Action_Pair);");
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => "   type Aux_PAT is array (PAT_Index) of Sym_Action_Pair;");
      SPARK.Ada.Text_IO.New_Line_File (File    => F,
                                       Spacing => 1);
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => "   type PAT_Index_Pair is record");
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => "      Lower, Upper : PAT_Index;");
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => "   end record;");
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => "   pragma PACK(PAT_Index_Pair);");
      SPARK.Ada.Text_IO.Put_Line_File
        (File => F,
         Item => "   type Main_PAT is array (SP_Productions.Valid_States) of PAT_Index_Pair;");
      SPARK.Ada.Text_IO.New_Line_File (File    => F,
                                       Spacing => 1);
      Aux_Pat_Out (F);
      SPARK.Ada.Text_IO.New_Line_File (File    => F,
                                       Spacing => 1);
      Main_Pat_Out (F);
   end Pa_Out;

   procedure Pa_Out_Sp (F : in out SPARK.Ada.Text_IO.File_Type)
   --# global in     Sparklalr_Memory.Max_Right;
   --#        in     Sparklalr_Memory.Prod_Sum;
   --#        in     Sparklalr_Memory.Stat_No;
   --#        in     Symbols_Dump.State;
   --#        in out Patab;
   --#        in out SPARK.Ada.Text_IO.The_Standard_Output;
   --#        in out Sparklalr_Parser.State;
   --#        in out State_Table;
   --# derives F                                     from *,
   --#                                                    Patab,
   --#                                                    Sparklalr_Memory.Max_Right,
   --#                                                    Sparklalr_Memory.Prod_Sum,
   --#                                                    Sparklalr_Memory.Stat_No,
   --#                                                    Sparklalr_Parser.State,
   --#                                                    State_Table,
   --#                                                    Symbols_Dump.State &
   --#         Patab,
   --#         Sparklalr_Parser.State                from *,
   --#                                                    Patab,
   --#                                                    Sparklalr_Memory.Stat_No &
   --#         SPARK.Ada.Text_IO.The_Standard_Output from *,
   --#                                                    Patab,
   --#                                                    Sparklalr_Memory.Prod_Sum,
   --#                                                    Sparklalr_Memory.Stat_No,
   --#                                                    Sparklalr_Parser.State,
   --#                                                    Symbols_Dump.State &
   --#         State_Table                           from *,
   --#                                                    Patab,
   --#                                                    Sparklalr_Memory.Stat_No,
   --#                                                    Sparklalr_Parser.State;
   is

      Max_Right_Power2, Packed_Symact_Max, Terminal_Count_P2, Non_Terminal_Count_P2, State_Count_P2, Prod_Count_P2, Pat_Index_P2 :
        Integer;

      procedure Aux_Pat_Out (F : in out SPARK.Ada.Text_IO.File_Type)
      --# global in     Sparklalr_Memory.Prod_Sum;
      --#        in     Sparklalr_Memory.Stat_No;
      --#        in     Symbols_Dump.State;
      --#        in out Patab;
      --#        in out SPARK.Ada.Text_IO.The_Standard_Output;
      --#        in out Sparklalr_Parser.State;
      --#        in out State_Table;
      --# derives F,
      --#         SPARK.Ada.Text_IO.The_Standard_Output from *,
      --#                                                    Patab,
      --#                                                    Sparklalr_Memory.Prod_Sum,
      --#                                                    Sparklalr_Memory.Stat_No,
      --#                                                    Sparklalr_Parser.State,
      --#                                                    Symbols_Dump.State &
      --#         Patab,
      --#         Sparklalr_Parser.State                from *,
      --#                                                    Patab,
      --#                                                    Sparklalr_Memory.Stat_No &
      --#         State_Table                           from *,
      --#                                                    Patab,
      --#                                                    Sparklalr_Memory.Stat_No,
      --#                                                    Sparklalr_Parser.State;
      is
         J                : Integer;
         Other_Acts_There : Boolean;
         Curr_Pat_Index   : Integer;
      begin
         Curr_Pat_Index   := 1;
         Other_Acts_There := False;
         SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                          Item => "   Parse_Action_Table : constant Aux_PAT := Aux_PAT'(");
         SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                          Item => "-- STATE INDEX");
         for I in Integer range 1 .. Sparklalr_Memory.Get_Stat_No loop
            if not Patab (I).Other_Act then
               if I > 1 then
                  SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                                   Item => ",");
               end if;
               State_Table (I).Lower := Curr_Pat_Index;
               SPARK.Ada.Text_IO.Put_File (File => F,
                                           Item => "----- ");
               SPARK_Ada_Integer_Text_IO.Put_File (File  => F,
                                                   Item  => I,
                                                   Width => 1,
                                                   Base  => 10);
               SPARK.Ada.Text_IO.New_Line_File (File    => F,
                                                Spacing => 1);
               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 => " => ");
               Sparklalr_Parser.Action_Gen_Pa_Out_Sp (F, I, Curr_Pat_Index);
               State_Table (I).Upper := Curr_Pat_Index - 1;
               Other_Acts_There      := True;
            end if;
         end loop;
         for I in Integer range 1 .. Sparklalr_Memory.Get_Stat_No loop
            if Patab (I).Check_Other_Act then
               if Other_Acts_There then
                  SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                                   Item => ",");
               else
                  Other_Acts_There := True;
               end if;
               J := I;
               SPARK.Ada.Text_IO.Put_File (File => F,
                                           Item => "----- ");
               SPARK_Ada_Integer_Text_IO.Put_File (File  => F,
                                                   Item  => J,
                                                   Width => 1,
                                                   Base  => 10);
               SPARK.Ada.Text_IO.New_Line_File (File    => F,
                                                Spacing => 1);
               loop
                  J                         := Patab (J).Nact;
                  Patab (J).Check_Other_Act := False;
                  SPARK.Ada.Text_IO.Put_File (File => F,
                                              Item => "----- ");
                  SPARK_Ada_Integer_Text_IO.Put_File (File  => F,
                                                      Item  => J,
                                                      Width => 1,
                                                      Base  => 10);
                  SPARK.Ada.Text_IO.New_Line_File (File    => F,
                                                   Spacing => 1);
                  exit when Patab (J).Nact = J;
               end loop;
            end if;
            if Patab (I).Other_Act then
               J                     := I;
               State_Table (I).Lower := Curr_Pat_Index;
               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 => " => ");
               Sparklalr_Parser.Action_Gen_Pa_Out_Sp (F, J, Curr_Pat_Index);
               State_Table (I).Upper := Curr_Pat_Index - 1;
               loop
                  J                   := Patab (J).Nact;
                  Patab (J).Other_Act := False;
                  State_Table (J)     := State_Table (I);
                  exit when Patab (J).Nact = J;
               end loop;
            end if;
         end loop;
         SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                          Item => ");");
      end Aux_Pat_Out;

      procedure Main_Pat_Out (F : in out SPARK.Ada.Text_IO.File_Type)
      --# global in Sparklalr_Memory.Stat_No;
      --#        in State_Table;
      --# derives F from *,
      --#                Sparklalr_Memory.Stat_No,
      --#                State_Table;
      is
      begin
         SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                          Item => "   State_Table : constant Main_PAT := Main_PAT'(");
         SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                          Item => "-- STATE");
         for State_Var in Integer range 1 .. Sparklalr_Memory.Get_Stat_No - 1 loop
            SPARK_Ada_Integer_Text_IO.Put_File (File  => F,
                                                Item  => State_Var,
                                                Width => 5,
                                                Base  => 10);
            SPARK.Ada.Text_IO.Put_File (File => F,
                                        Item => " => Lower_PAT_Index * ");
            SPARK_Ada_Integer_Text_IO.Put_File (File  => F,
                                                Item  => State_Table (State_Var).Lower,
                                                Width => 1,
                                                Base  => 10);
            SPARK.Ada.Text_IO.Put_File (File => F,
                                        Item => " + Upper_PAT_Index * ");
            SPARK_Ada_Integer_Text_IO.Put_File (File  => F,
                                                Item  => State_Table (State_Var).Upper,
                                                Width => 1,
                                                Base  => 10);
            SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                             Item => ",");
         end loop;
         SPARK_Ada_Integer_Text_IO.Put_File (File  => F,
                                             Item  => Sparklalr_Memory.Get_Stat_No,
                                             Width => 5,
                                             Base  => 10);
         SPARK.Ada.Text_IO.Put_File (File => F,
                                     Item => " => Lower_PAT_Index * ");
         SPARK_Ada_Integer_Text_IO.Put_File
           (File  => F,
            Item  => State_Table (Sparklalr_Memory.Get_Stat_No).Lower,
            Width => 1,
            Base  => 10);
         SPARK.Ada.Text_IO.Put_File (File => F,
                                     Item => " + Upper_PAT_Index * ");
         SPARK_Ada_Integer_Text_IO.Put_File
           (File  => F,
            Item  => State_Table (Sparklalr_Memory.Get_Stat_No).Upper,
            Width => 1,
            Base  => 10);
         SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                          Item => ");");
      end Main_Pat_Out;

   begin -- Pa_Out_Sp
      Terminal_Count_P2 := 0;
      while 2 ** Terminal_Count_P2 <= Symbols_Dump.Get_Nterms loop
         Terminal_Count_P2 := Terminal_Count_P2 + 1;
      end loop;
      Non_Terminal_Count_P2 := 0;
      while 2 ** Non_Terminal_Count_P2 <= Symbols_Dump.Get_Nnon_Terms loop
         Non_Terminal_Count_P2 := Non_Terminal_Count_P2 + 1;
      end loop;
      State_Count_P2 := 0;
      while 2 ** State_Count_P2 <= Sparklalr_Memory.Get_Stat_No loop
         State_Count_P2 := State_Count_P2 + 1;
      end loop;
      Prod_Count_P2    := 0;
      Max_Right_Power2 := 0;
      while 2 ** Max_Right_Power2 <= Sparklalr_Memory.Get_Max_Right loop
         Max_Right_Power2 := Max_Right_Power2 + 1;
      end loop;
      if ((2 + Terminal_Count_P2) + State_Count_P2) >
        ((((2 + Terminal_Count_P2) + Non_Terminal_Count_P2) + Max_Right_Power2) + Prod_Count_P2) then
         Packed_Symact_Max := (2 + Terminal_Count_P2) + State_Count_P2;
      else
         Packed_Symact_Max := (((2 + Terminal_Count_P2) + Non_Terminal_Count_P2) + Max_Right_Power2) + Prod_Count_P2;
      end if;
      Pat_Index_P2 := 0;
      while 2 ** Pat_Index_P2 <= Sparklalr_Parser.Get_Pat_Count loop
         Pat_Index_P2 := Pat_Index_P2 + 1;
      end loop;
      SPARK.Ada.Text_IO.New_Line_File (File    => F,
                                       Spacing => 1);
      SPARK.Ada.Text_IO.Put_File (File => F,
                                  Item => "   No_Of_PAT_Entries : constant Positive := ");
      SPARK_Ada_Integer_Text_IO.Put_File (File  => F,
                                          Item  => Sparklalr_Parser.Get_Pat_Count,
                                          Width => 1,
                                          Base  => 10);
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => ";");
      SPARK.Ada.Text_IO.New_Line_File (File    => F,
                                       Spacing => 1);
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => "   type PAT_Index is range 1 .. No_Of_PAT_Entries;");
      SPARK.Ada.Text_IO.Put_File (File => F,
                                  Item => "   type Packed_Sym_Action_Pair is range 0 .. 2**");
      SPARK_Ada_Integer_Text_IO.Put_File (File  => F,
                                          Item  => Packed_Symact_Max,
                                          Width => 1,
                                          Base  => 10);
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => "-1;");
      SPARK.Ada.Text_IO.New_Line_File (File    => F,
                                       Spacing => 1);
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => "   Act_Lim      : constant Packed_Sym_Action_Pair := 2**2;");
      SPARK.Ada.Text_IO.Put_File (File => F,
                                  Item => "   Term_Sym_Lim : constant Packed_Sym_Action_Pair := 2**");
      SPARK_Ada_Integer_Text_IO.Put_File (File  => F,
                                          Item  => Terminal_Count_P2,
                                          Width => 1,
                                          Base  => 10);
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => ";");
      SPARK.Ada.Text_IO.Put_File (File => F,
                                  Item => "   State_Lim    : constant Packed_Sym_Action_Pair := 2**");
      SPARK_Ada_Integer_Text_IO.Put_File (File  => F,
                                          Item  => State_Count_P2,
                                          Width => 1,
                                          Base  => 10);
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => ";");
      SPARK.Ada.Text_IO.Put_File (File => F,
                                  Item => "   Symbol_Lim   : constant Packed_Sym_Action_Pair := 2**");
      SPARK_Ada_Integer_Text_IO.Put_File (File  => F,
                                          Item  => Non_Terminal_Count_P2,
                                          Width => 1,
                                          Base  => 10);
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => ";");
      SPARK.Ada.Text_IO.Put_File (File => F,
                                  Item => "   Red_By_Lim   : constant Packed_Sym_Action_Pair := 2**");
      SPARK_Ada_Integer_Text_IO.Put_File (File  => F,
                                          Item  => Max_Right_Power2,
                                          Width => 1,
                                          Base  => 10);
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => ";");
      SPARK.Ada.Text_IO.Put_File (File => F,
                                  Item => "   Prod_No_Lim  : constant Packed_Sym_Action_Pair := 2**");
      SPARK_Ada_Integer_Text_IO.Put_File (File  => F,
                                          Item  => Prod_Count_P2,
                                          Width => 1,
                                          Base  => 10);
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => ";");
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => "   pragma Unreferenced (Prod_No_Lim);");
      SPARK.Ada.Text_IO.New_Line_File (File    => F,
                                       Spacing => 1);
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => "   Term_Sym : constant Packed_Sym_Action_Pair := 1;");
      SPARK.Ada.Text_IO.Put_Line_File
        (File => F,
         Item => "   Act      : constant Packed_Sym_Action_Pair := Term_Sym * Term_Sym_Lim;");
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => "   State    : constant Packed_Sym_Action_Pair := Act * Act_Lim;");
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => "   Symbol   : constant Packed_Sym_Action_Pair := Act * Act_Lim;");
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => "   Red_By   : constant Packed_Sym_Action_Pair := Symbol * Symbol_Lim;");
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => "   Prod_No  : constant Packed_Sym_Action_Pair := 0;");
      SPARK.Ada.Text_IO.New_Line_File (File    => F,
                                       Spacing => 1);
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => "   First_Non_Terminal : constant Packed_Sym_Action_Pair :=");
      SPARK.Ada.Text_IO.Put_Line_File
        (File => F,
         Item => "     SP_Symbols.SP_Non_Terminal'Pos (SP_Symbols.SP_Non_Terminal'First);");
      SPARK.Ada.Text_IO.New_Line_File (File    => F,
                                       Spacing => 1);
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => "   type Aux_PAT is array (PAT_Index) of Packed_Sym_Action_Pair;");
      SPARK.Ada.Text_IO.New_Line_File (File    => F,
                                       Spacing => 1);
      SPARK.Ada.Text_IO.Put_File (File => F,
                                  Item => "   Default    : constant Packed_Sym_Action_Pair :=");
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => " SP_Symbols.SP_Terminal'Pos (SP_Symbols.SPDEFAULT);");
      SPARK.Ada.Text_IO.Put_File (File => F,
                                  Item => "   Error_Act  : constant Packed_Sym_Action_Pair :=");
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => " Act * SP_Action_Kind'Pos (Error);");
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => "   pragma Unreferenced (Error_Act);");
      SPARK.Ada.Text_IO.Put_File (File => F,
                                  Item => "   Shift_Act  : constant Packed_Sym_Action_Pair :=");
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => " Act * SP_Action_Kind'Pos (Shift);");
      SPARK.Ada.Text_IO.Put_File (File => F,
                                  Item => "   Reduce_Act : constant Packed_Sym_Action_Pair :=");
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => " Act * SP_Action_Kind'Pos (Reduce);");
      SPARK.Ada.Text_IO.Put_File (File => F,
                                  Item => "   Accept_Act : constant Packed_Sym_Action_Pair :=");
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => " Act * SP_Action_Kind'Pos (Accpt);");
      SPARK.Ada.Text_IO.New_Line_File (File    => F,
                                       Spacing => 1);
      SPARK.Ada.Text_IO.Put_File (File => F,
                                  Item => "   type Packed_PAT_Index_Pair is range 0 .. 2**");
      SPARK_Ada_Integer_Text_IO.Put_File (File  => F,
                                          Item  => 2 * Pat_Index_P2,
                                          Width => 1,
                                          Base  => 10);
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => "-1;");
      SPARK.Ada.Text_IO.Put_File (File => F,
                                  Item => "   PAT_Index_Size  : constant Packed_PAT_Index_Pair := 2**");
      SPARK_Ada_Integer_Text_IO.Put_File (File  => F,
                                          Item  => Pat_Index_P2,
                                          Width => 1,
                                          Base  => 10);
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => ";");
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => "   Lower_PAT_Index : constant Packed_PAT_Index_Pair := 1;");
      SPARK.Ada.Text_IO.Put_Line_File
        (File => F,
         Item => "   Upper_PAT_Index : constant Packed_PAT_Index_Pair := PAT_Index_Size;");
      SPARK.Ada.Text_IO.Put_File (File => F,
                                  Item => "   type Main_PAT is array (SP_Productions.Valid_States)");
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => " of Packed_PAT_Index_Pair;");
      SPARK.Ada.Text_IO.New_Line_File (File    => F,
                                       Spacing => 1);
      Aux_Pat_Out (F);
      SPARK.Ada.Text_IO.New_Line_File (File    => F,
                                       Spacing => 1);
      Main_Pat_Out (F);
   end Pa_Out_Sp;

   -- These procedures calculate the SPARK parser table sizes prior to output
   procedure Calc_Table_Sizes
   --# global in     Sparklalr_Memory.Stat_No;
   --#        in     Symbols_Dump.State;
   --#        in out Patab;
   --#        in out Sparklalr_Goto.State;
   --#        in out Sparklalr_Parser.State;
   --#           out Pat_Seg_Count;
   --# derives Patab,
   --#         Sparklalr_Parser.State from *,
   --#                                     Patab,
   --#                                     Sparklalr_Memory.Stat_No &
   --#         Pat_Seg_Count          from Patab,
   --#                                     Sparklalr_Memory.Stat_No,
   --#                                     Sparklalr_Parser.State &
   --#         Sparklalr_Goto.State   from *,
   --#                                     Symbols_Dump.State;
   is
      J, Seg_Count : Integer;
   begin
      Pat_Seg_Count := 0;
      Sparklalr_Parser.Init_Pat_Count;
      for I in Integer range 1 .. Sparklalr_Memory.Get_Stat_No loop
         Seg_Count := Sparklalr_Parser.Get_Pat_Count;
         if not Patab (I).Check_Other_Act then
            Sparklalr_Parser.Action_Gen (I);
         end if;
         if Sparklalr_Parser.Get_Pat_Count - Seg_Count > Pat_Seg_Count then
            Pat_Seg_Count := Sparklalr_Parser.Get_Pat_Count - Seg_Count;
         end if;
      end loop;
      for I in Integer range 1 .. Sparklalr_Memory.Get_Stat_No loop
         Seg_Count := Sparklalr_Parser.Get_Pat_Count;
         if Patab (I).Check_Other_Act then
            J := I;
            Sparklalr_Parser.Action_Gen (J);
            loop
               J                         := Patab (J).Nact;
               Patab (J).Check_Other_Act := False;
               exit when Patab (J).Nact = J;
            end loop;
         end if;
         if Sparklalr_Parser.Get_Pat_Count - Seg_Count > Pat_Seg_Count then
            Pat_Seg_Count := Sparklalr_Parser.Get_Pat_Count - Seg_Count;
         end if;
      end loop;
      for I in Integer range 1 .. Sparklalr_Memory.Get_Stat_No loop
         Patab (I).Check_Other_Act := Patab (I).Other_Act;
      end loop;
      for I in Integer range 2 .. Symbols_Dump.Get_Nnon_Terms loop
         Sparklalr_Goto.Go_Out (I);
      end loop;
   end Calc_Table_Sizes;

   procedure Optimise
   -- SET UP THE PATAB DATA STRUCTURE
   -- SO THAT OPTIMISATION OF THE PASCAL PARSING ACTION FUNCTION IS
   -- CARRIED OUT
   --# global in     Command_Line_Options.State;
   --#        in     Sparklalr_Memory.Stat_No;
   --#        in     Sparklalr_Parser.State;
   --#        in out Patab;
   --#        in out SPARK.Ada.Text_IO.The_Standard_Output;
   --# derives Patab                                 from *,
   --#                                                    Sparklalr_Memory.Stat_No,
   --#                                                    Sparklalr_Parser.State &
   --#         SPARK.Ada.Text_IO.The_Standard_Output from *,
   --#                                                    Command_Line_Options.State,
   --#                                                    Patab,
   --#                                                    Sparklalr_Memory.Stat_No,
   --#                                                    Sparklalr_Parser.State;
   is
      I : Integer;
   begin
      for Istart in Integer range 1 .. Sparklalr_Memory.Get_Stat_No loop
         I := Istart;
         if not Patab (I).Other_Act then
            for J in Integer range I + 1 .. Sparklalr_Memory.Get_Stat_No loop
               if Patab (J).Nact = J then
                  if Sparklalr_Parser.Action_Equal (Sparklalr_Parser.Get_Pa_List (I), Sparklalr_Parser.Get_Pa_List (J)) then
                     --# accept F, 41, "Stable expression here expected and OK";
                     if Command_Line_Options.Get_Debug_Level (6) then
                        SPARK.Ada.Text_IO.Put_Output (Item => " MERGING ACTIONS ");
                        SPARK_Ada_Integer_Text_IO.Put_Output (Item  => I,
                                                              Width => 3,
                                                              Base  => 10);
                        SPARK.Ada.Text_IO.Put_Output (Item => " AND ");
                        SPARK_Ada_Integer_Text_IO.Put_Output (Item  => J,
                                                              Width => 3,
                                                              Base  => 10);
                        SPARK.Ada.Text_IO.New_Line_Output (Spacing => 1);
                     end if;
                     --# end accept;
                     Patab (I).Other_Act       := True;
                     Patab (I).Check_Other_Act := True;
                     Patab (I).Nact            := J;
                     Patab (J).Other_Act       := True;
                     Patab (J).Check_Other_Act := True;
                     I                         := J;
                  end if;
               end if;
            end loop;
         end if;
      end loop;
   end Optimise;

   procedure Opt_Stats (Std_Out : in     Boolean;
                        F       : in out SPARK.Ada.Text_IO.File_Type)
   --# global in     Patab;
   --#        in     Sparklalr_Memory.Stat_No;
   --#        in out SPARK.Ada.Text_IO.The_Standard_Output;
   --# derives F,
   --#         SPARK.Ada.Text_IO.The_Standard_Output from *,
   --#                                                    Patab,
   --#                                                    Sparklalr_Memory.Stat_No,
   --#                                                    Std_Out;
   is
      J : Integer;
   begin
      J := 0;
      for I in Integer range 1 .. Sparklalr_Memory.Get_Stat_No loop
         if Patab (I).Other_Act then
            J := J + 1;
         end if;
      end loop;
      Sparklalr_Common.Put_Integer_File_Output (Std_Out => Std_Out,
                                                File    => F,
                                                Item    => J,
                                                Width   => 6);
      Sparklalr_Common.Put_Line_File_Output
        (Std_Out => Std_Out,
         File    => F,
         Item    => " PARSING ACTIONS OPTIMISED BY CASE LABEL MERGE");
   end Opt_Stats;

   function Get_Pat_Seg_Count return Integer
   --# global in Pat_Seg_Count;
   is
   begin
      return Pat_Seg_Count;
   end Get_Pat_Seg_Count;

end Sparklalr_Patab;
