-------------------------------------------------------------------------------
-- (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_Memory.Dump;
with Symbols_Dump;

package body Sparklalr_Memory.Left_Corner
--# own State is Left_Corners,
--#              Left_Corner_Count;
is

   -- ---- These types are used in the generation of the SPARK parser Tables ----
   type Left_Corner_Entry is record
      Lower, Upper        : Integer;
      Left_Corner_Symbols : Sparklalr_Memory.Symbol_Set_T;
      Other_Symbol        : Boolean;
      Base_Symbol         : Sparklalr_Common.Non_Term_Range;
   end record;
   type Left_Corner_Tab is array (Sparklalr_Common.Non_Term_Range) of Left_Corner_Entry;

   Left_Corner_Count : Integer;
   Left_Corners      : Left_Corner_Tab;

   procedure Count_Left_Corners
   --# global in     Symbols_Dump.State;
   --#        in out Left_Corners;
   --#        in out Left_Corner_Count;
   --# derives Left_Corners,
   --#         Left_Corner_Count from Left_Corners,
   --#                                Left_Corner_Count,
   --#                                Symbols_Dump.State;
   is
   begin
      for Nt in Integer range 1 .. Symbols_Dump.Get_Nnon_Terms loop
         if Left_Corners (Nt).Base_Symbol /= Nt then
            Left_Corners (Nt).Lower := Left_Corners (Left_Corners (Nt).Base_Symbol).Lower;
            Left_Corners (Nt).Upper := Left_Corners (Left_Corners (Nt).Base_Symbol).Upper;
         else
            Left_Corners (Nt).Lower := Left_Corner_Count;
            for Sym in Integer range 0 .. Symbols_Dump.Get_Nterms loop
               if Sparklalr_Memory.Get_Symbol_Set (Left_Corners (Nt).Left_Corner_Symbols, Sym) then
                  Left_Corner_Count := Left_Corner_Count + 1;
               end if;
            end loop;
            for Sym in Integer range Sparklalr_Common.Nt_Base + 1 .. Sparklalr_Common.Nt_Base + Symbols_Dump.Get_Nnon_Terms loop
               if Sparklalr_Memory.Get_Symbol_Set (Left_Corners (Nt).Left_Corner_Symbols, Sym) then
                  Left_Corner_Count := Left_Corner_Count + 1;
               end if;
            end loop;
            Left_Corners (Nt).Upper := Left_Corner_Count - 1;
         end if;
      end loop;
   end Count_Left_Corners;

   procedure Gen_Left_Corner
   --# global in     Dump.State;
   --#        in     Symbols_Dump.State;
   --#           out Left_Corners;
   --#           out Left_Corner_Count;
   --# derives Left_Corners      from Dump.State,
   --#                                Symbols_Dump.State &
   --#         Left_Corner_Count from ;
   is

      C                         : Sparklalr_Common.Sym_Range;
      S, T                      : Dump.Pt_Memory;
      Not_Closed, Element_Added : Boolean;
      B                         : Sparklalr_Memory.Symbol_Set_T;

      procedure Merge_Left_Corner_Groups
      --# global in     Symbols_Dump.State;
      --#        in out Left_Corners;
      --# derives Left_Corners from *,
      --#                           Symbols_Dump.State;
      is
         Sym      : Sparklalr_Common.Sym_Range;
         The_Same : Boolean;
      begin
         if Symbols_Dump.Get_Nnon_Terms > 0 then
            for Nt1 in Integer range 1 .. Symbols_Dump.Get_Nnon_Terms loop
               if Nt1 - 1 > 0 then
                  for Nt2 in Integer range 1 .. Nt1 - 1 loop
                     if Left_Corners (Nt2).Base_Symbol = Nt2 then
                        The_Same := True;
                        Sym      := 0;
                        while The_Same and then (Sym <= Symbols_Dump.Get_Nterms) loop
                           The_Same := Sparklalr_Memory.Get_Symbol_Set (Left_Corners (Nt1).Left_Corner_Symbols, Sym) =
                             Sparklalr_Memory.Get_Symbol_Set (Left_Corners (Nt2).Left_Corner_Symbols, Sym);
                           Sym      := Sym + 1;
                        end loop;
                        Sym := 1;
                        while The_Same and then (Sym <= Symbols_Dump.Get_Nnon_Terms) loop
                           The_Same :=
                             Sparklalr_Memory.Get_Symbol_Set
                             (Left_Corners (Nt1).Left_Corner_Symbols,
                              Sym + Sparklalr_Common.Nt_Base) =
                             Sparklalr_Memory.Get_Symbol_Set
                             (Left_Corners (Nt2).Left_Corner_Symbols,
                              Sym + Sparklalr_Common.Nt_Base);
                           Sym      := Sym + 1;
                        end loop;
                        if The_Same then
                           Left_Corners (Nt2).Other_Symbol := True;
                           Left_Corners (Nt1).Base_Symbol  := Nt2;
                        end if;
                     end if;
                  end loop;
               end if;
            end loop;
         end if;
      end Merge_Left_Corner_Groups;

   begin
      Left_Corner_Count := 1;
      Left_Corners      :=
        Left_Corner_Tab'
        (others => Left_Corner_Entry'(Lower               => 0,
                                      Upper               => 0,
                                      Left_Corner_Symbols => Sparklalr_Memory.Symbol_Set_T'(others => False),
                                      Other_Symbol        => False,
                                      Base_Symbol         => 1));
      for Nt in Integer range 1 .. Symbols_Dump.Get_Nnon_Terms loop
         for Sym_Set_El in Sparklalr_Common.Sym_Range loop
            Left_Corners (Nt).Left_Corner_Symbols (Sym_Set_El) := False;
         end loop;
         Left_Corners (Nt).Other_Symbol := False;
         Left_Corners (Nt).Base_Symbol  := Nt;
      end loop;
      -- Form closure of LeftCorner
      Not_Closed := True;
      while Not_Closed loop
         Not_Closed := False;
         for Nt in Integer range 1 .. Symbols_Dump.Get_Nnon_Terms loop
            S := Dump.Get_Ntrdn (Nt);
            T := Dump.Get_Ntrdn (Nt + 1);
            while S /= T loop
               if Dump.Get_Contents (Dump.Get_Next (Dump.Get_Mem_Pt (S))) >= 0 then
                  C := Dump.Get_Contents (Dump.Get_Next (Dump.Get_Mem_Pt (S)));
                  if not Sparklalr_Memory.Get_Symbol_Set (Left_Corners (Nt).Left_Corner_Symbols, C) then
                     Left_Corners (Nt).Left_Corner_Symbols (C) := True;
                     Not_Closed                                := True;
                  end if;
                  if C > Sparklalr_Common.Nt_Base then
                     B := Left_Corners (C - Sparklalr_Common.Nt_Base).Left_Corner_Symbols;
                     Sparklalr_Memory.Set_Union (Left_Corners (Nt).Left_Corner_Symbols, B, Element_Added);
                     Not_Closed := Not_Closed or else Element_Added;
                  end if;
               end if;
               S := Dump.Get_Next (S);
            end loop;
         end loop;
      end loop;
      Merge_Left_Corner_Groups;
   end Gen_Left_Corner;

   procedure Out_Left_Corner (F : in out SPARK.Ada.Text_IO.File_Type)
   --# global in     Command_Line_Options.State;
   --#        in     Dump.State;
   --#        in     Left_Corners;
   --#        in     Left_Corner_Count;
   --#        in     Symbols_Dump.State;
   --#        in out SPARK.Ada.Text_IO.The_Standard_Output;
   --# derives F                                     from *,
   --#                                                    Command_Line_Options.State,
   --#                                                    Dump.State,
   --#                                                    Left_Corners,
   --#                                                    Left_Corner_Count,
   --#                                                    Symbols_Dump.State &
   --#         SPARK.Ada.Text_IO.The_Standard_Output from *,
   --#                                                    Command_Line_Options.State,
   --#                                                    Left_Corners,
   --#                                                    Symbols_Dump.State;
   is
      Pos, Index, Left_Corners_P2 : Integer;
      Comma_Required              : Boolean;
   begin
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => "with SP_Symbols;");
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => "use type SP_Symbols.SP_Symbol;");
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => "--# inherit SP_Symbols;");
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => "package SP_Relations is");
      SPARK.Ada.Text_IO.New_Line_File (File    => F,
                                       Spacing => 1);
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => "   function SP_Left_Corner (Parent : SP_Symbols.SP_Symbol;");
      SPARK.Ada.Text_IO.Put_Line_File
        (File => F,
         Item => "                            Child  : SP_Symbols.SP_Symbol) return Boolean;");
      SPARK.Ada.Text_IO.New_Line_File (File    => F,
                                       Spacing => 1);
      SPARK.Ada.Text_IO.Put_Line_File
        (File => F,
         Item => "   function SP_Terminal_Like (Sym : SP_Symbols.SP_Symbol) return Boolean;");
      SPARK.Ada.Text_IO.New_Line_File (File    => F,
                                       Spacing => 1);
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => "end SP_Relations;");
      SPARK.Ada.Text_IO.New_Line_File (File    => F,
                                       Spacing => 1);
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => "package body SP_Relations is");
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => "   --# hide SP_Relations;");
      SPARK.Ada.Text_IO.New_Line_File (File    => F,
                                       Spacing => 1);
      SPARK.Ada.Text_IO.Put_File (File => F,
                                  Item => "   No_Of_Left_Corners : constant Natural := ");
      SPARK_Ada_Integer_Text_IO.Put_File (File  => F,
                                          Item  => Left_Corner_Count - 1,
                                          Width => 1,
                                          Base  => 10);
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => ";");
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => "   type Left_Corner_Range is range 1 .. No_Of_Left_Corners;");
      SPARK.Ada.Text_IO.Put_Line_File
        (File => F,
         Item => "   type Left_Corner_Rel is array (Left_Corner_Range) of SP_Symbols.SP_Symbol;");
      SPARK.Ada.Text_IO.New_Line_File (File    => F,
                                       Spacing => 1);
      if Command_Line_Options.Get_Self_Pack then
         Left_Corners_P2 := 0;
         while 2 ** Left_Corners_P2 <= Left_Corner_Count - 1 loop
            Left_Corners_P2 := Left_Corners_P2 + 1;
         end loop;
         SPARK.Ada.Text_IO.Put_File (File => F,
                                     Item => "   type Relation_Entry is range 0 .. 2**");
         SPARK_Ada_Integer_Text_IO.Put_File (File  => F,
                                             Item  => 2 * Left_Corners_P2 + 1,
                                             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 => "   Term_Like_Lim : constant Relation_Entry := 2;");
         SPARK.Ada.Text_IO.Put_File (File => F,
                                     Item => "   Low_Lim       : constant Relation_Entry := 2**");
         SPARK_Ada_Integer_Text_IO.Put_File (File  => F,
                                             Item  => Left_Corners_P2,
                                             Width => 1,
                                             Base  => 10);
         SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                          Item => ";");
         SPARK.Ada.Text_IO.Put_File (File => F,
                                     Item => "   High_Lim      : constant Relation_Entry := 2**");
         SPARK_Ada_Integer_Text_IO.Put_File (File  => F,
                                             Item  => Left_Corners_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 => "   Terminal_Like : constant Relation_Entry := 1;");
         SPARK.Ada.Text_IO.Put_Line_File
           (File => F,
            Item => "   Low           : constant Relation_Entry := Terminal_Like * Term_Like_Lim;");
         SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                          Item => "   High          : constant Relation_Entry := Low * Low_Lim;");
      else
         SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                          Item => "   type Relation_Entry is record");
         SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                          Item => "      Terminal_Like : Boolean;");
         SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                          Item => "      Low, High     : Left_Corner_Range;");
         SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                          Item => "   end record;");
      end if;
      SPARK.Ada.Text_IO.Put_Line_File
        (File => F,
         Item => "   type Relation_Table is array (SP_Symbols.SP_Non_Terminal) of Relation_Entry;");
      SPARK.Ada.Text_IO.New_Line_File (File    => F,
                                       Spacing => 1);
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => "   Left_Corner : constant Left_Corner_Rel := Left_Corner_Rel'(");
      Comma_Required := False;
      Index          := 1;
      for Nt in Integer range 1 .. Symbols_Dump.Get_Nnon_Terms loop
         if Left_Corners (Nt).Base_Symbol = Nt then
            if Left_Corners (Nt).Other_Symbol then
               for Subordinate in Integer range Nt + 1 .. Symbols_Dump.Get_Nnon_Terms loop
                  if Left_Corners (Subordinate).Base_Symbol = Nt then
                     if Comma_Required then
                        SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                                         Item => ",");
                     end if;
                     Comma_Required := False;
                     Sparklalr_Common.Put_N_Chars (Std_Out => False,
                                                   F       => F,
                                                   C       => ' ',
                                                   N       => 3);
                     SPARK.Ada.Text_IO.Put_File (File => F,
                                                 Item => "-- ");
                     Pos := 7;
                     --# accept F, 10, Pos, "Ineffective assignment here expected and OK";
                     Sparklalr_Common.Print2
                       (F,
                        Sparklalr_Common.Sp_Symbol_Str,
                        Symbols_Dump.Get_Nterm_Set (Subordinate),
                        Pos,
                        7,
                        False);
                     --# end accept;
                     SPARK.Ada.Text_IO.New_Line_File (File    => F,
                                                      Spacing => 1);
                  end if;
               end loop;
            end if;
            if Comma_Required then
               SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                                Item => ",");
            end if;
            Comma_Required := False;
            Sparklalr_Common.Put_N_Chars (Std_Out => False,
                                          F       => F,
                                          C       => ' ',
                                          N       => 3);
            SPARK.Ada.Text_IO.Put_File (File => F,
                                        Item => "-- ");
            Pos := 7;
            --# accept F, 10, Pos, "Ineffective assignment here expected and OK";
            Sparklalr_Common.Print2 (F, Sparklalr_Common.Sp_Symbol_Str, Symbols_Dump.Get_Nterm_Set (Nt), Pos, 7, False);
            --# end accept;
            SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                             Item => " =>");
            for Sym in Integer range 0 .. Symbols_Dump.Get_Nterms loop
               if Sparklalr_Memory.Get_Symbol_Set (Left_Corners (Nt).Left_Corner_Symbols, Sym) then
                  if Comma_Required then
                     SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                                      Item => ",");
                  else
                     Comma_Required := True;
                  end if;
                  SPARK_Ada_Integer_Text_IO.Put_File (File  => F,
                                                      Item  => Index,
                                                      Width => 5,
                                                      Base  => 10);
                  SPARK.Ada.Text_IO.Put_File (File => F,
                                              Item => " => ");
                  Pos := 10;
                  --# accept F, 10, Pos, "Ineffective assignment here expected and OK";
                  Symbols_Dump.Print_String_Sym (F, Sparklalr_Common.Sp_Symbol_Str, Sym, Pos, 10, False);
                  --# end accept;
                  Index := Index + 1;
               end if;
            end loop;
            for Sym in Integer range Sparklalr_Common.Nt_Base + 1 .. Sparklalr_Common.Nt_Base + Symbols_Dump.Get_Nnon_Terms loop
               if Sparklalr_Memory.Get_Symbol_Set (Left_Corners (Nt).Left_Corner_Symbols, Sym) then
                  if Comma_Required then
                     SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                                      Item => ",");
                  else
                     Comma_Required := True;
                  end if;
                  SPARK_Ada_Integer_Text_IO.Put_File (File  => F,
                                                      Item  => Index,
                                                      Width => 5,
                                                      Base  => 10);
                  SPARK.Ada.Text_IO.Put_File (File => F,
                                              Item => " => ");
                  Pos := 10;
                  --# accept F, 10, Pos, "Ineffective assignment here expected and OK";
                  Symbols_Dump.Print_String_Sym (F, Sparklalr_Common.Sp_Symbol_Str, Sym, Pos, 10, False);
                  --# end accept;
                  Index := Index + 1;
               end if;
            end loop;
         end if;
      end loop;
      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 => "   Rel_Tab : constant Relation_Table := Relation_Table'(");
      if Command_Line_Options.Get_Self_Pack then
         for Nt in Integer range 1 .. Symbols_Dump.Get_Nnon_Terms - 1 loop
            Sparklalr_Common.Put_N_Chars (Std_Out => False,
                                          F       => F,
                                          C       => ' ',
                                          N       => 4);
            Pos := 4;
            --# accept F, 10, Pos, "Ineffective assignment here expected and OK";
            Sparklalr_Common.Print2 (F, Sparklalr_Common.Sp_Symbol_Str, Symbols_Dump.Get_Nterm_Set (Nt), Pos, 4, False);
            --# end accept;
            SPARK.Ada.Text_IO.Put_File (File => F,
                                        Item => " => ");
            if Dump.Get_Terminal_Like (Nt + Sparklalr_Common.Nt_Base) then
               SPARK.Ada.Text_IO.Put_File (File => F,
                                           Item => "Terminal_Like * Boolean'Pos (True) + ");
            else
               SPARK.Ada.Text_IO.Put_File (File => F,
                                           Item => "Terminal_Like * Boolean'Pos (False) + ");
            end if;
            SPARK.Ada.Text_IO.Put_File (File => F,
                                        Item => "Low*");
            SPARK_Ada_Integer_Text_IO.Put_File (File  => F,
                                                Item  => Left_Corners (Nt).Lower,
                                                Width => 1,
                                                Base  => 10);
            SPARK.Ada.Text_IO.Put_File (File => F,
                                        Item => " + ");
            SPARK.Ada.Text_IO.Put_File (File => F,
                                        Item => "High*");
            SPARK_Ada_Integer_Text_IO.Put_File (File  => F,
                                                Item  => Left_Corners (Nt).Upper,
                                                Width => 1,
                                                Base  => 10);
            SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                             Item => ",");
         end loop;
         Sparklalr_Common.Put_N_Chars (Std_Out => False,
                                       F       => F,
                                       C       => ' ',
                                       N       => 4);
         Pos := 4;
         --# accept F, 10, Pos, "Ineffective assignment here expected and OK";
         Sparklalr_Common.Print2
           (F,
            Sparklalr_Common.Sp_Symbol_Str,
            Symbols_Dump.Get_Nterm_Set (Symbols_Dump.Get_Nnon_Terms),
            Pos,
            4,
            False);
         --# end accept;
         SPARK.Ada.Text_IO.Put_File (File => F,
                                     Item => " => ");
         if Dump.Get_Terminal_Like (Symbols_Dump.Get_Nnon_Terms + Sparklalr_Common.Nt_Base) then
            SPARK.Ada.Text_IO.Put_File (File => F,
                                        Item => "Terminal_Like * Boolean'Pos (True) + ");
         else
            SPARK.Ada.Text_IO.Put_File (File => F,
                                        Item => "Terminal_Like * Boolean'Pos (False) + ");
         end if;
         SPARK.Ada.Text_IO.Put_File (File => F,
                                     Item => "Low*");
         SPARK_Ada_Integer_Text_IO.Put_File
           (File  => F,
            Item  => Left_Corners (Symbols_Dump.Get_Nnon_Terms).Lower,
            Width => 1,
            Base  => 10);
         SPARK.Ada.Text_IO.Put_File (File => F,
                                     Item => " + ");
         SPARK.Ada.Text_IO.Put_File (File => F,
                                     Item => "High*");
         SPARK_Ada_Integer_Text_IO.Put_File
           (File  => F,
            Item  => Left_Corners (Symbols_Dump.Get_Nnon_Terms).Upper,
            Width => 1,
            Base  => 10);
         SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                          Item => ");");
      else
         for Nt in Integer range 1 .. Symbols_Dump.Get_Nnon_Terms - 1 loop
            Sparklalr_Common.Put_N_Chars (Std_Out => False,
                                          F       => F,
                                          C       => ' ',
                                          N       => 4);
            Pos := 4;
            --# accept F, 10, Pos, "Ineffective assignment here expected and OK";
            Sparklalr_Common.Print2 (F, Sparklalr_Common.Sp_Symbol_Str, Symbols_Dump.Get_Nterm_Set (Nt), Pos, 4, False);
            --# end accept;
            SPARK.Ada.Text_IO.Put_File (File => F,
                                        Item => " => Relation_Entry'(");
            if Dump.Get_Terminal_Like (Nt + Sparklalr_Common.Nt_Base) then
               SPARK.Ada.Text_IO.Put_File (File => F,
                                           Item => "True, ");
            else
               SPARK.Ada.Text_IO.Put_File (File => F,
                                           Item => "False, ");
            end if;
            SPARK_Ada_Integer_Text_IO.Put_File (File  => F,
                                                Item  => Left_Corners (Nt).Lower,
                                                Width => 1,
                                                Base  => 10);
            SPARK.Ada.Text_IO.Put_File (File => F,
                                        Item => ", ");
            SPARK_Ada_Integer_Text_IO.Put_File (File  => F,
                                                Item  => Left_Corners (Nt).Upper,
                                                Width => 1,
                                                Base  => 10);
            SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                             Item => "),");
         end loop;
         Sparklalr_Common.Put_N_Chars (Std_Out => False,
                                       F       => F,
                                       C       => ' ',
                                       N       => 4);
         Pos := 4;
         --# accept F, 10, Pos, "Ineffective assignment here expected and OK";
         Sparklalr_Common.Print2
           (F,
            Sparklalr_Common.Sp_Symbol_Str,
            Symbols_Dump.Get_Nterm_Set (Symbols_Dump.Get_Nnon_Terms),
            Pos,
            4,
            False);
         --# end accept;
         SPARK.Ada.Text_IO.Put_File (File => F,
                                     Item => " => Relation_Entry'(");
         if Dump.Get_Terminal_Like (Symbols_Dump.Get_Nnon_Terms + Sparklalr_Common.Nt_Base) then
            SPARK.Ada.Text_IO.Put_File (File => F,
                                        Item => "True, ");
         else
            SPARK.Ada.Text_IO.Put_File (File => F,
                                        Item => "False, ");
         end if;
         SPARK_Ada_Integer_Text_IO.Put_File
           (File  => F,
            Item  => Left_Corners (Symbols_Dump.Get_Nnon_Terms).Lower,
            Width => 1,
            Base  => 10);
         SPARK.Ada.Text_IO.Put_File (File => F,
                                     Item => ", ");
         SPARK_Ada_Integer_Text_IO.Put_File
           (File  => F,
            Item  => Left_Corners (Symbols_Dump.Get_Nnon_Terms).Upper,
            Width => 1,
            Base  => 10);
         SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                          Item => "));");
      end if;
      SPARK.Ada.Text_IO.New_Line_File (File    => F,
                                       Spacing => 1);
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => "   function SP_Left_Corner (Parent : SP_Symbols.SP_Symbol;");
      SPARK.Ada.Text_IO.Put_File (File => F,
                                  Item => "                            Child  : SP_Symbols.SP_Symbol)");
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => " return Boolean is separate;");
      SPARK.Ada.Text_IO.New_Line_File (File    => F,
                                       Spacing => 1);
      SPARK.Ada.Text_IO.Put_File (File => F,
                                  Item => "   function SP_Terminal_Like (Sym : SP_Symbols.SP_Symbol)");
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => " return Boolean is separate;");
      SPARK.Ada.Text_IO.New_Line_File (File    => F,
                                       Spacing => 1);
      SPARK.Ada.Text_IO.Put_Line_File (File => F,
                                       Item => "end SP_Relations;");
   end Out_Left_Corner;

end Sparklalr_Memory.Left_Corner;
