-------------------------------------------------------------------------------
-- (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_Level;
with Sparklalr_Memory;
with Sparklalr_Memory.Dump;
with Sparklalr_Parser;
with Sparklalr_Patab;
with Symbols_Dump;

use type Sparklalr_Common.Action_Type;

package body Sparklalr_Conflict
--# own State is List_Of_Conflicts,
--#              Rconflict_Array;
is

   type Tconflict is (Shred, Redred);

   Rconflict_Table_Size : constant := 100;

   subtype Ptr_Conflict is Natural range 0 .. Rconflict_Table_Size;
   subtype Rconflict_Array_Range is Positive range 1 .. Rconflict_Table_Size;
   type Rconflict is record
      Ctype                           : Tconflict;
      Cstate, Cterm, Resolved, C1, C2 : Integer;
      Lnk                             : Ptr_Conflict;
   end record;
   type Rconflict_Array_Array_T is array (Rconflict_Array_Range) of Rconflict;
   type Rconflict_Array_T is record
      The_Array : Rconflict_Array_Array_T;
      Top       : Ptr_Conflict;
   end record;

   Rconflict_Array   : Rconflict_Array_T;
   List_Of_Conflicts : Ptr_Conflict;

   procedure Initialise
   --# global out List_Of_Conflicts;
   --#        out Rconflict_Array;
   --# derives List_Of_Conflicts,
   --#         Rconflict_Array   from ;
   is
   begin
      Rconflict_Array   :=
        Rconflict_Array_T'
        (The_Array => Rconflict_Array_Array_T'(others => Rconflict'(Ctype    => Shred,
                                                                    Cstate   => 0,
                                                                    Cterm    => 0,
                                                                    Resolved => 0,
                                                                    C1       => 0,
                                                                    C2       => 0,
                                                                    Lnk      => 0)),
         Top       => 0);
      List_Of_Conflicts := 0;
   end Initialise;

   procedure Print_Conflicts (F : in out SPARK.Ada.Text_IO.File_Type)
   --# global in     List_Of_Conflicts;
   --#        in     Rconflict_Array;
   --#        in     Sparklalr_Memory.Dump.State;
   --#        in     Sparklalr_Memory.Stat_No;
   --#        in     Sparklalr_Parser.State;
   --#        in     Symbols_Dump.State;
   --#        in out SPARK.Ada.Text_IO.The_Standard_Output;
   --# derives F,
   --#         SPARK.Ada.Text_IO.The_Standard_Output from *,
   --#                                                    List_Of_Conflicts,
   --#                                                    Rconflict_Array,
   --#                                                    Sparklalr_Memory.Dump.State,
   --#                                                    Sparklalr_Memory.Stat_No,
   --#                                                    Sparklalr_Parser.State,
   --#                                                    Symbols_Dump.State;
   is
      Pc   : Ptr_Conflict;
      Posn : Integer;
      S, T : Sparklalr_Memory.Dump.Pt_Memory;
      More : Boolean;
   begin
      if List_Of_Conflicts /= 0 then
         Posn := 1;
         for Nstate in Integer range 1 .. Sparklalr_Memory.Get_Stat_No loop
            Pc   := List_Of_Conflicts;
            More := Rconflict_Array.The_Array (Pc).Cstate /= Nstate;
            while More loop
               Pc := Rconflict_Array.The_Array (Pc).Lnk;
               if Pc /= 0 then
                  More := Rconflict_Array.The_Array (Pc).Cstate /= Nstate;
               else
                  More := False;
               end if;
            end loop;
            if Pc /= 0 then
               More := True;
               SPARK.Ada.Text_IO.New_Line_File (File    => F,
                                                Spacing => 1);
               SPARK.Ada.Text_IO.Put_File (File => F,
                                           Item => " STATE ");
               SPARK_Ada_Integer_Text_IO.Put_File (File  => F,
                                                   Item  => Nstate,
                                                   Width => 4,
                                                   Base  => 10);
               SPARK.Ada.Text_IO.New_Line_File (File    => F,
                                                Spacing => 1);
               S := Sparklalr_Memory.Dump.Get_State (Nstate);
               T := Sparklalr_Memory.Dump.Get_State (Nstate + 1);
               Sparklalr_Memory.Dump.Dump_Items (F, S, T);
               SPARK.Ada.Text_IO.New_Line_File (File    => F,
                                                Spacing => 1);
               Sparklalr_Parser.Dump_Actions (F, Nstate);
               SPARK.Ada.Text_IO.New_Line_File (File    => F,
                                                Spacing => 1);
               while More loop
                  case Rconflict_Array.The_Array (Pc).Ctype is
                     when Shred =>
                        SPARK.Ada.Text_IO.Put_File (File => F,
                                                    Item => " ** SHIFT ");
                        SPARK_Ada_Integer_Text_IO.Put_File
                          (File  => F,
                           Item  => Rconflict_Array.The_Array (Pc).C1,
                           Width => 1,
                           Base  => 10);
                        SPARK.Ada.Text_IO.Put_File (File => F,
                                                    Item => "/REDUCE ");
                        SPARK_Ada_Integer_Text_IO.Put_File
                          (File  => F,
                           Item  => Rconflict_Array.The_Array (Pc).C2,
                           Width => 1,
                           Base  => 10);
                     when Redred =>
                        SPARK.Ada.Text_IO.Put_File (File => F,
                                                    Item => " ** REDUCE ");
                        SPARK_Ada_Integer_Text_IO.Put_File
                          (File  => F,
                           Item  => Rconflict_Array.The_Array (Pc).C1,
                           Width => 1,
                           Base  => 10);
                        SPARK.Ada.Text_IO.Put_File (File => F,
                                                    Item => "/REDUCE ");
                        SPARK_Ada_Integer_Text_IO.Put_File
                          (File  => F,
                           Item  => Rconflict_Array.The_Array (Pc).C2,
                           Width => 1,
                           Base  => 10);
                  end case;
                  SPARK.Ada.Text_IO.Put_File (File => F,
                                              Item => " CONFLICT ON TERMINAL ");
                  Posn := Posn + 43;
                  --# accept F, 10, Posn, "Ineffective assignment here expected and OK";
                  Symbols_Dump.Print_Sym (F, Rconflict_Array.The_Array (Pc).Cterm, Posn, 10, False);
                  --# end accept;

                  SPARK.Ada.Text_IO.New_Line_File (File    => F,
                                                   Spacing => 1);

                  --# accept W, 303, "when others here covers all cases";
                  case Rconflict_Array.The_Array (Pc).Resolved is
                     when 1 =>
                        SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                                         Item => " SHIFT SELECTED");
                     when 2 =>
                        SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                                         Item => " REDUCE SELECTED");
                     when 3 =>
                        SPARK.Ada.Text_IO.Put_File (File => F,
                                                    Item => " REDUCE ");
                        SPARK_Ada_Integer_Text_IO.Put_File
                          (File  => F,
                           Item  => Rconflict_Array.The_Array (Pc).C2,
                           Width => 1,
                           Base  => 10);
                        SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                                         Item => " SELECTED ");
                     when 4 =>
                        SPARK.Ada.Text_IO.Put_File (File => F,
                                                    Item => " REDUCE ");
                        SPARK_Ada_Integer_Text_IO.Put_File
                          (File  => F,
                           Item  => Rconflict_Array.The_Array (Pc).C1,
                           Width => 1,
                           Base  => 10);
                        SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                                         Item => " SELECTED ");
                     when 5 =>
                        SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                                         Item => " ***ERROR*** BINARY CONFLICT - ERROR INSERTED ");
                     when others =>
                        null;
                  end case;
                  --# end accept;

                  Posn := 1;
                  Pc   := Rconflict_Array.The_Array (Pc).Lnk;
                  if Pc /= 0 then
                     More := Rconflict_Array.The_Array (Pc).Cstate = Nstate;
                  else
                     More := False;
                  end if;
               end loop;
            end if;
         end loop;
      end if;
   end Print_Conflicts;

   procedure Conflict_Stats (Std_Out : in     Boolean;
                             F       : in out SPARK.Ada.Text_IO.File_Type)
   --# global in     List_Of_Conflicts;
   --#        in     Rconflict_Array;
   --#        in out SPARK.Ada.Text_IO.The_Standard_Output;
   --# derives F,
   --#         SPARK.Ada.Text_IO.The_Standard_Output from *,
   --#                                                    List_Of_Conflicts,
   --#                                                    Rconflict_Array,
   --#                                                    Std_Out;
   is
      Sr_Count, Rr_Count : Integer;
      P                  : Ptr_Conflict;
   begin
      Sr_Count := 0;
      Rr_Count := 0;
      P        := List_Of_Conflicts;
      while P /= 0 loop
         if Rconflict_Array.The_Array (P).Ctype = Shred then
            Sr_Count := Sr_Count + 1;
         else
            Rr_Count := Rr_Count + 1;
         end if;
         P := Rconflict_Array.The_Array (P).Lnk;
      end loop;
      Sparklalr_Common.New_Line_File_Output (Std_Out => Std_Out,
                                             File    => F);
      Sparklalr_Common.Put_Integer_File_Output (Std_Out => Std_Out,
                                                File    => F,
                                                Item    => Sr_Count,
                                                Width   => 6);
      Sparklalr_Common.Put_Line_File_Output (Std_Out => Std_Out,
                                             File    => F,
                                             Item    => " SHIFT/REDUCE CONFLICTS");
      Sparklalr_Common.Put_Integer_File_Output (Std_Out => Std_Out,
                                                File    => F,
                                                Item    => Rr_Count,
                                                Width   => 6);
      Sparklalr_Common.Put_Line_File_Output (Std_Out => Std_Out,
                                             File    => F,
                                             Item    => " REDUCE/REDUCE CONFLICTS");
      Sparklalr_Common.New_Line_File_Output (Std_Out => Std_Out,
                                             File    => F);
   end Conflict_Stats;

   procedure Dump_Conflicts (F      : in out SPARK.Ada.Text_IO.File_Type;
                             Nstate : in     Integer)
   --# global in     List_Of_Conflicts;
   --#        in     Rconflict_Array;
   --#        in     Symbols_Dump.State;
   --#        in out SPARK.Ada.Text_IO.The_Standard_Output;
   --# derives F,
   --#         SPARK.Ada.Text_IO.The_Standard_Output from *,
   --#                                                    List_Of_Conflicts,
   --#                                                    Nstate,
   --#                                                    Rconflict_Array,
   --#                                                    Symbols_Dump.State;
   is
      Dummy : Ptr_Conflict;
      Posn  : Integer;

      function Cflct (Init_Cflct : in Ptr_Conflict) return Ptr_Conflict
      --# global in Nstate;
      --#        in Rconflict_Array;
      is
         P     : Ptr_Conflict;
         Found : Boolean;
      begin
         Found := False;
         P     := Init_Cflct;
         while (P /= 0) and then not Found loop
            if Rconflict_Array.The_Array (P).Cstate = Nstate then
               Found := True;
            else
               P := Rconflict_Array.The_Array (P).Lnk;
            end if;
         end loop;
         return P;
      end Cflct;

   begin -- Dump_Conflicts
      Posn  := 1;
      Dummy := Cflct (List_Of_Conflicts);
      while Dummy /= 0 loop
         case Rconflict_Array.The_Array (Dummy).Ctype is
            when Shred =>
               SPARK.Ada.Text_IO.Put_File (File => F,
                                           Item => " ** SHIFT ");
               SPARK_Ada_Integer_Text_IO.Put_File
                 (File  => F,
                  Item  => Rconflict_Array.The_Array (Dummy).C1,
                  Width => 1,
                  Base  => 10);
               SPARK.Ada.Text_IO.Put_File (File => F,
                                           Item => "/REDUCE ");
               SPARK_Ada_Integer_Text_IO.Put_File
                 (File  => F,
                  Item  => Rconflict_Array.The_Array (Dummy).C2,
                  Width => 1,
                  Base  => 10);
            when Redred =>
               SPARK.Ada.Text_IO.Put_File (File => F,
                                           Item => " ** REDUCE ");
               SPARK_Ada_Integer_Text_IO.Put_File
                 (File  => F,
                  Item  => Rconflict_Array.The_Array (Dummy).C1,
                  Width => 1,
                  Base  => 10);
               SPARK.Ada.Text_IO.Put_File (File => F,
                                           Item => "/REDUCE ");
               SPARK_Ada_Integer_Text_IO.Put_File
                 (File  => F,
                  Item  => Rconflict_Array.The_Array (Dummy).C2,
                  Width => 1,
                  Base  => 10);
         end case;
         SPARK.Ada.Text_IO.Put_File (File => F,
                                     Item => " CONFLICT ON TERMINAL ");
         Posn := Posn + 43;
         --# accept F, 10, Posn, "Ineffective assignment here expected and OK";
         Symbols_Dump.Print_Sym (F, Rconflict_Array.The_Array (Dummy).Cterm, Posn, 10, False);
         --# end accept;
         SPARK.Ada.Text_IO.New_Line_File (File    => F,
                                          Spacing => 1);

         --# accept W, 303, "when others here covers all cases";
         case Rconflict_Array.The_Array (Dummy).Resolved is
            when 1 =>
               SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                                Item => " SHIFT SELECTED");
            when 2 =>
               SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                                Item => " REDUCE SELECTED");
            when 3 =>
               SPARK.Ada.Text_IO.Put_File (File => F,
                                           Item => " REDUCE ");
               SPARK_Ada_Integer_Text_IO.Put_File
                 (File  => F,
                  Item  => Rconflict_Array.The_Array (Dummy).C2,
                  Width => 1,
                  Base  => 10);
               SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                                Item => " SELECTED ");
            when 4 =>
               SPARK.Ada.Text_IO.Put_File (File => F,
                                           Item => " REDUCE ");
               SPARK_Ada_Integer_Text_IO.Put_File
                 (File  => F,
                  Item  => Rconflict_Array.The_Array (Dummy).C1,
                  Width => 1,
                  Base  => 10);
               SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                                Item => " SELECTED ");
            when 5 =>
               SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                                Item => " ***ERROR*** BINARY CONFLICT - ERROR INSERTED ");
            when others =>
               null;
         end case;
         --# end accept;

         Posn  := 1;
         Dummy := Cflct (Rconflict_Array.The_Array (Dummy).Lnk);
      end loop;
   end Dump_Conflicts;

   procedure Parse_Action_Generation (F : in out SPARK.Ada.Text_IO.File_Type)
   -- PARSEACTIONGENERATION GENERATES THE REDUCES IN THE
   -- PARSING ACTION TABLE

   --# global in     Command_Line_Options.State;
   --#        in     Sparklalr_Level.State;
   --#        in     Sparklalr_Memory.Stat_No;
   --#        in     Symbols_Dump.State;
   --#        in out List_Of_Conflicts;
   --#        in out Rconflict_Array;
   --#        in out SPARK.Ada.Text_IO.The_Standard_Output;
   --#        in out Sparklalr_Memory.Dump.State;
   --#        in out Sparklalr_Parser.State;
   --#        in out Sparklalr_Patab.State;
   --# derives F,
   --#         Sparklalr_Memory.Dump.State,
   --#         Sparklalr_Parser.State,
   --#         Sparklalr_Patab.State                 from *,
   --#                                                    Command_Line_Options.State,
   --#                                                    Sparklalr_Level.State,
   --#                                                    Sparklalr_Memory.Dump.State,
   --#                                                    Sparklalr_Memory.Stat_No,
   --#                                                    Sparklalr_Parser.State,
   --#                                                    Symbols_Dump.State &
   --#         List_Of_Conflicts,
   --#         Rconflict_Array                       from Command_Line_Options.State,
   --#                                                    List_Of_Conflicts,
   --#                                                    Rconflict_Array,
   --#                                                    Sparklalr_Level.State,
   --#                                                    Sparklalr_Memory.Dump.State,
   --#                                                    Sparklalr_Memory.Stat_No,
   --#                                                    Sparklalr_Parser.State,
   --#                                                    Symbols_Dump.State &
   --#         SPARK.Ada.Text_IO.The_Standard_Output from *,
   --#                                                    Command_Line_Options.State,
   --#                                                    Sparklalr_Level.State,
   --#                                                    Sparklalr_Memory.Dump.State,
   --#                                                    Sparklalr_Memory.Stat_No,
   --#                                                    Sparklalr_Parser.State,
   --#                                                    Sparklalr_Patab.State,
   --#                                                    Symbols_Dump.State;
   is

      S, T                                 : Sparklalr_Memory.Dump.Pt_Memory;
      C                                    : Integer;
      Result_Pa_Search1, Result_Pa_Search2 : Integer;
      Pl                                   : Sparklalr_Parser.Pt_Pa_Rec;

      procedure Pa_Gen
        (F                       : in out SPARK.Ada.Text_IO.File_Type;
         Sr                      : in     Sparklalr_Common.Action_Type;
         State_Index, Term_Index : in     Integer;
         S                       : in     Sparklalr_Memory.Dump.Pt_Memory;
         C                       : in     Integer)
      -- ADD ENTRIES INTO PARSING ACTION TABLE RESOLVING
      -- ANY RESULTING CONFLICTS

      --# global in     Command_Line_Options.State;
      --#        in     Sparklalr_Level.State;
      --#        in     Sparklalr_Memory.Stat_No;
      --#        in     Symbols_Dump.State;
      --#        in out List_Of_Conflicts;
      --#        in out Rconflict_Array;
      --#        in out SPARK.Ada.Text_IO.The_Standard_Output;
      --#        in out Sparklalr_Memory.Dump.State;
      --#        in out Sparklalr_Parser.State;
      --# derives F                                     from *,
      --#                                                    C,
      --#                                                    Command_Line_Options.State,
      --#                                                    Sparklalr_Level.State,
      --#                                                    Sparklalr_Parser.State,
      --#                                                    Sr,
      --#                                                    State_Index,
      --#                                                    Symbols_Dump.State,
      --#                                                    Term_Index &
      --#         List_Of_Conflicts,
      --#         Rconflict_Array                       from C,
      --#                                                    List_Of_Conflicts,
      --#                                                    Rconflict_Array,
      --#                                                    Sparklalr_Level.State,
      --#                                                    Sparklalr_Parser.State,
      --#                                                    Sr,
      --#                                                    State_Index,
      --#                                                    Term_Index &
      --#         SPARK.Ada.Text_IO.The_Standard_Output from *,
      --#                                                    C,
      --#                                                    Command_Line_Options.State,
      --#                                                    S,
      --#                                                    Sparklalr_Level.State,
      --#                                                    Sparklalr_Memory.Dump.State,
      --#                                                    Sparklalr_Memory.Stat_No,
      --#                                                    Sparklalr_Parser.State,
      --#                                                    Sr,
      --#                                                    State_Index,
      --#                                                    Symbols_Dump.State,
      --#                                                    Term_Index &
      --#         Sparklalr_Memory.Dump.State           from *,
      --#                                                    S,
      --#                                                    Sparklalr_Parser.State,
      --#                                                    Sr,
      --#                                                    State_Index,
      --#                                                    Term_Index &
      --#         Sparklalr_Parser.State                from *,
      --#                                                    C,
      --#                                                    S,
      --#                                                    Sparklalr_Level.State,
      --#                                                    Sparklalr_Memory.Dump.State,
      --#                                                    Sparklalr_Memory.Stat_No,
      --#                                                    Sr,
      --#                                                    State_Index,
      --#                                                    Term_Index;
      is

         Result_Pa_Search, Result_New_State : Integer;
         Pl                                 : Sparklalr_Parser.Pt_Pa_Rec;

         -- -- Automatic resolution of conflicts is not acceptable with SPARKLALR --
         procedure Resolve_Conflict
           (F                       : in out SPARK.Ada.Text_IO.File_Type;
            Sr                      : in     Sparklalr_Common.Action_Type;
            State_Index, Term_Index : in     Integer;
            C                       : in     Integer)
         -- RESOLUTION OF ANY GRAMMAR AMBIGUITIES USING
         -- THE PRECEDENCE INFORMATION

         --# global in     Command_Line_Options.State;
         --#        in     Sparklalr_Level.State;
         --#        in     Symbols_Dump.State;
         --#        in out List_Of_Conflicts;
         --#        in out Rconflict_Array;
         --#        in out SPARK.Ada.Text_IO.The_Standard_Output;
         --#        in out Sparklalr_Parser.State;
         --# derives F,
         --#         SPARK.Ada.Text_IO.The_Standard_Output from *,
         --#                                                    C,
         --#                                                    Command_Line_Options.State,
         --#                                                    Sparklalr_Level.State,
         --#                                                    Sparklalr_Parser.State,
         --#                                                    Sr,
         --#                                                    State_Index,
         --#                                                    Symbols_Dump.State,
         --#                                                    Term_Index &
         --#         List_Of_Conflicts,
         --#         Rconflict_Array                       from C,
         --#                                                    List_Of_Conflicts,
         --#                                                    Rconflict_Array,
         --#                                                    Sparklalr_Level.State,
         --#                                                    Sparklalr_Parser.State,
         --#                                                    Sr,
         --#                                                    State_Index,
         --#                                                    Term_Index &
         --#         Sparklalr_Parser.State                from *,
         --#                                                    C,
         --#                                                    Sparklalr_Level.State,
         --#                                                    Sr,
         --#                                                    State_Index,
         --#                                                    Term_Index;
         is

            Result_Pa_Search : Integer;
            Pl               : Sparklalr_Parser.Pt_Pa_Rec;

            procedure Rslv
              (F                       : in out SPARK.Ada.Text_IO.File_Type;
               Sr                      : in     Tconflict;
               A, B                    : in     Integer;
               State_Index, Term_Index : in     Integer)
            -- RSLV USES PRECEDENCE TO PHYSICALLY ALTER THE
            -- PARSING ACTION TABLE TO OVERCOME ANY AMBIGUITY CONFLICTS.

            --# global in     Command_Line_Options.State;
            --#        in     Sparklalr_Level.State;
            --#        in     Symbols_Dump.State;
            --#        in out List_Of_Conflicts;
            --#        in out Rconflict_Array;
            --#        in out SPARK.Ada.Text_IO.The_Standard_Output;
            --#        in out Sparklalr_Parser.State;
            --# derives F,
            --#         SPARK.Ada.Text_IO.The_Standard_Output from *,
            --#                                                    A,
            --#                                                    B,
            --#                                                    Command_Line_Options.State,
            --#                                                    Sparklalr_Level.State,
            --#                                                    Sr,
            --#                                                    State_Index,
            --#                                                    Symbols_Dump.State,
            --#                                                    Term_Index &
            --#         List_Of_Conflicts                     from *,
            --#                                                    A,
            --#                                                    B,
            --#                                                    Rconflict_Array,
            --#                                                    Sparklalr_Level.State,
            --#                                                    Sr,
            --#                                                    Term_Index &
            --#         Rconflict_Array                       from *,
            --#                                                    A,
            --#                                                    B,
            --#                                                    List_Of_Conflicts,
            --#                                                    Sparklalr_Level.State,
            --#                                                    Sr,
            --#                                                    State_Index,
            --#                                                    Term_Index &
            --#         Sparklalr_Parser.State                from *,
            --#                                                    A,
            --#                                                    B,
            --#                                                    Sparklalr_Level.State,
            --#                                                    Sr,
            --#                                                    State_Index,
            --#                                                    Term_Index;
            is

               Err_Code          : constant := -1;
               Report            : Boolean;
               Result_Precedence : Integer;
               Conflict          : Ptr_Conflict;

               procedure Report_Conflict
                 (F                       : in out SPARK.Ada.Text_IO.File_Type;
                  State_Index, Term_Index : in     Integer;
                  S                       : in     Tconflict;
                  Conflict                :    out Ptr_Conflict)
               -- REPORTCONFLICT REPORTS A PARSING ACTION CONFLICT THAT MAY
               -- ARISE DUE TO AMBIGUITIES PRESENT IN THE INPUT GRAMMAR.
               -- FIRSTLY, THE APPROPRIATE MESSAGE IS SENT TO THE DAYFILE.
               -- THE CONFLICT IS ALSO STORED FOR FUTURE REFERENCE IN A
               -- LINKED LIST DATA STRUCTURE WHICH STORES INFORMATION
               -- SUCH AS CONFLICT TYPE, TERMINAL INVOLVED, AND RELEVANT SHIFTS OR
               -- REDUCTIONS .

               --# global in out List_Of_Conflicts;
               --#        in out Rconflict_Array;
               --#        in out SPARK.Ada.Text_IO.The_Standard_Output;
               --# derives Conflict,
               --#         List_Of_Conflicts                     from Rconflict_Array &
               --#         F,
               --#         SPARK.Ada.Text_IO.The_Standard_Output from *,
               --#                                                    S,
               --#                                                    State_Index &
               --#         Rconflict_Array                       from *,
               --#                                                    List_Of_Conflicts,
               --#                                                    S,
               --#                                                    State_Index,
               --#                                                    Term_Index;
               is
               begin
                  Rconflict_Array.Top := Rconflict_Array.Top + 1;
                  Conflict            := Rconflict_Array.Top;
                  SPARK.Ada.Text_IO.Put_Output (Item => "STATE ");
                  SPARK_Ada_Integer_Text_IO.Put_Output (Item  => State_Index,
                                                        Width => 1,
                                                        Base  => 10);
                  SPARK.Ada.Text_IO.Put_Output (Item => ": ");
                  SPARK.Ada.Text_IO.Put_File (File => F,
                                              Item => "STATE ");
                  SPARK_Ada_Integer_Text_IO.Put_File (File  => F,
                                                      Item  => State_Index,
                                                      Width => 1,
                                                      Base  => 10);
                  SPARK.Ada.Text_IO.Put_File (File => F,
                                              Item => ": ");
                  case S is
                     when Shred =>
                        SPARK.Ada.Text_IO.Put_Line_Output (Item => "* SHIFT/REDUCE CONFLICT");
                        SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                                         Item => "* SHIFT/REDUCE CONFLICT");
                     when Redred =>
                        SPARK.Ada.Text_IO.Put_Line_Output (Item => "* REDUCE/REDUCE CONFLICT");
                        SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                                         Item => "* REDUCE/REDUCE CONFLICT");
                  end case;
                  Rconflict_Array.The_Array (Conflict) :=
                    Rconflict'
                    (Lnk      => List_Of_Conflicts,
                     Cstate   => State_Index,
                     Cterm    => Term_Index,
                     Ctype    => S,
                     Resolved => 0,
                     C1       => 0,
                     C2       => 0);
                  List_Of_Conflicts                    := Conflict;
               end Report_Conflict;

            begin -- Rslv
               Conflict := 0;
               Sparklalr_Level.Precedence (Sr = Shred, A, B, Term_Index, Report, Result_Precedence);
               if Report then
                  Report_Conflict (F, State_Index, Term_Index, Sr, Conflict);
               end if;

               --# accept W, 303, "when others here covers all cases";
               case Result_Precedence is
                  when 1 =>
                     if Report then
                        Rconflict_Array.The_Array (Conflict).Resolved := 1;
                     end if;
                     Sparklalr_Parser.Pa_Insert
                       (F           => F,
                        State_Index => State_Index,
                        Term_Index  => Term_Index,
                        Insertion   => Sparklalr_Common.Code (Sparklalr_Common.Shift, B));
                  when 2 =>
                     if Report then
                        Rconflict_Array.The_Array (Conflict).Resolved := 2;
                     end if;
                     Sparklalr_Parser.Pa_Insert
                       (F           => F,
                        State_Index => State_Index,
                        Term_Index  => Term_Index,
                        Insertion   => Sparklalr_Common.Code (Sparklalr_Common.Reduce, A));
                  when 3 =>
                     if Report then
                        Rconflict_Array.The_Array (Conflict).Resolved := 3;
                     end if;
                  when 4 =>
                     if Report then
                        Rconflict_Array.The_Array (Conflict).Resolved := 3;
                     end if;
                     Sparklalr_Parser.Pa_Insert
                       (F           => F,
                        State_Index => State_Index,
                        Term_Index  => Term_Index,
                        Insertion   => Sparklalr_Common.Code (Sparklalr_Common.Reduce, B));
                  when 5 =>
                     if Report then
                        Rconflict_Array.The_Array (Conflict).Resolved := 5;
                     end if;
                     Sparklalr_Parser.Pa_Insert
                       (F           => F,
                        State_Index => State_Index,
                        Term_Index  => Term_Index,
                        Insertion   => Err_Code);
                  when others =>
                     null;
               end case;
               --# end accept;

               if Report then
                  Rconflict_Array.The_Array (Conflict).C1 := B;
                  Rconflict_Array.The_Array (Conflict).C2 := A;
               end if;
            end Rslv;

         begin -- Resolve_Conflict
            if Sr = Sparklalr_Common.Shift then
               -- SHIFT - REDUCE CONFLICT
               --# accept F, 10, Pl, "Ineffective assignment here expected and OK";
               Sparklalr_Parser.Pa_Search (State_Index, Term_Index, Result_Pa_Search, Pl);
               --# end accept;
               Rslv (F, Shred, Sparklalr_Common.Decode (Result_Pa_Search), Term_Index, State_Index, Term_Index);
            else
               --# accept F, 10, Pl, "Ineffective assignment here expected and OK";
               Sparklalr_Parser.Pa_Search (State_Index, Term_Index, Result_Pa_Search, Pl);
               --# end accept;
               if Result_Pa_Search <= Sparklalr_Common.Prod_Lim then
                  -- REDUCE - REDUCE CONFLICT
                  --# accept F, 10, Pl, "Ineffective assignment here expected and OK";
                  Sparklalr_Parser.Pa_Search (State_Index, Term_Index, Result_Pa_Search, Pl);
                  --# end accept;
                  Rslv (F, Redred, Sparklalr_Common.Decode (Result_Pa_Search), -C, State_Index, Term_Index);
               else
                  -- SHIFT - REDUCE CONFLICT
                  --# accept F, 10, Pl, "Ineffective assignment here expected and OK";
                  Sparklalr_Parser.Pa_Search (State_Index, Term_Index, Result_Pa_Search, Pl);
                  --# end accept;
                  Rslv (F, Shred, -C, Sparklalr_Common.Decode (Result_Pa_Search), State_Index, Term_Index);
               end if;
            end if;
            --# accept F, 33, Pl, "Pl is unused OK";
         end Resolve_Conflict;

      begin -- Pa_Gen

         --# accept F, 10, Pl, "Ineffective assignment here expected and OK";
         Sparklalr_Parser.Pa_Search (State_Index, Term_Index, Result_Pa_Search, Pl);
         --# end accept;
         if Result_Pa_Search /= 0 then
            Resolve_Conflict (F, Sr, State_Index, Term_Index, C);
         else
            if Sr = Sparklalr_Common.Shift then
               Sparklalr_Memory.Dump.New_State (S, Result_New_State);
               Sparklalr_Parser.Pa_Insert
                 (F           => F,
                  State_Index => State_Index,
                  Term_Index  => Term_Index,
                  Insertion   => Sparklalr_Common.Code (Sr, Result_New_State));
            else
               Sparklalr_Parser.Pa_Insert (F           => F,
                                           State_Index => State_Index,
                                           Term_Index  => Term_Index,
                                           Insertion   => -C);
            end if;
         end if;
         --# accept F, 33, Pl, "Pl is unused OK";
      end Pa_Gen;

   begin -- Parse_Action_Generation
      for I in Integer range 1 .. Sparklalr_Memory.Get_Stat_No loop
         S := Sparklalr_Memory.Dump.Get_State (I);
         T := Sparklalr_Memory.Dump.Get_State (I + 1);
         while S /= T loop
            C := Sparklalr_Memory.Dump.Get_Contents (Sparklalr_Memory.Dump.Get_Dot (Sparklalr_Memory.Dump.Get_Item (S)));
            if C < 0 then
               for J in Integer range 0 .. Symbols_Dump.Get_Nterms loop
                  if Sparklalr_Memory.Dump.Get_Lh_Lset (Sparklalr_Memory.Dump.Get_Item (S), J) then
                     Pa_Gen (F, Sparklalr_Common.Reduce, I, J, S, C);
                  end if;
               end loop;
            else
               if C = 0 then -- SPEND
                  C := -1;
                  Pa_Gen (F, Sparklalr_Common.Reduce, I, 0, S, C);
                  --# accept F, 41, "Stable expression here expected and OK";
                  if Command_Line_Options.Get_Multi_Comp then
                     for Term_Sym in Integer range 2 .. Symbols_Dump.Get_Nterms loop
                        -- Not SPEND or SPDEFAULT
                        --# accept F, 10, Pl, "Ineffective assignment here expected and OK";
                        Sparklalr_Parser.Pa_Search (1, Term_Sym, Result_Pa_Search1, Pl);
                        Sparklalr_Parser.Pa_Search (I, Term_Sym, Result_Pa_Search2, Pl);
                        --# end accept;
                        if (Result_Pa_Search1 /= 0) and then (Result_Pa_Search2 = 0) then
                           Pa_Gen (F, Sparklalr_Common.Reduce, I, Term_Sym, S, C);
                        end if;
                     end loop;
                  end if;
                  --# end accept;
               end if;
            end if;
            S := Sparklalr_Memory.Dump.Get_Next (S);
         end loop;
      end loop;
      Sparklalr_Patab.Optimise;
      --# accept F, 33, Pl, "Pl is unused OK";
   end Parse_Action_Generation;

end Sparklalr_Conflict;
