-------------------------------------------------------------------------------
-- (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 AdjustFDL_RWs;
with CommandLineData;
with DAG_IO;
with Debug;
with E_Strings;
with Lists;
with Maths;
with Symbol_Set;

separate (Declarations.OutputDeclarations)
procedure PrintDeclarations
  (Heap           : in out Cells.Heap_Record;
   File           : in     SPARK_IO.File_Type;
   Rule_File      : in     SPARK_IO.File_Type;
   Needed_Symbols : in     Cells.Cell;
   Scope          : in     Dictionary.Scopes;
   Write_Rules    : in     Boolean;
   End_Position   : in     LexTokenManager.Token_Position)
is
   Sym          : Dictionary.Symbol;
   Declare_List : Cells.Cell;
   Indent       : constant Integer := 3;
   Max_Column   : constant Integer := 78;

   -- Type_List records types that require proof rules to be
   -- generated for them.  Prior to Examiner 7p2d08, only scalar
   -- type were added to this list, since these were the only
   -- types that could have replacement rules generated for them.
   -- Following 7p2d08, this list now records all types to allow
   -- for replacement rules for 'Size of non-scalar types.
   L_Heap           : Lists.List_Heap;
   Type_List        : Lists.List;
   Rule_Family_Name : E_Strings.T;
   Rule_Counter     : Natural;
   Max_Rank         : Cells.Cell_Rank;

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

   procedure Debug_Rank_Sym (Msg : in String;
                             Sym : in Dictionary.Symbol)
   --# derives null from Msg,
   --#                   Sym;
   is
      --# hide Debug_Rank_Sym;
   begin
      if CommandLineData.Content.Debug.FDL_Ranking then
         Debug.Print_Sym (Msg => Msg,
                          Sym => Sym);
      end if;
   end Debug_Rank_Sym;

   procedure Debug_Rank_Int (Msg : in String;
                             N   : in Integer)
   --# derives null from Msg,
   --#                   N;
   is
      --# hide Debug_Rank_Int;
   begin
      if CommandLineData.Content.Debug.FDL_Ranking then
         Debug.PrintInt (Msg, N);
      end if;
   end Debug_Rank_Int;

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

   function Get_Name (Sym   : Dictionary.Symbol;
                      Scope : Dictionary.Scopes) return E_Strings.T
   --# global in CommandLineData.Content;
   --#        in Dictionary.Dict;
   --#        in LexTokenManager.State;
   is
      Prefix      : E_Strings.T;
      Simple_Name : E_Strings.T;
      Result      : E_Strings.T;
   begin
      -- if VCs are generated from code with semantic errors in type declarations then
      -- null symbols etc. might get as far as here and cause an internal error.  The first if
      -- provides protection against this.
      if Dictionary.Is_Null_Symbol (Sym) then
         Result := E_Strings.Copy_String (Str => "unexpected_null_symbol");
      elsif Dictionary.IsTypeMark (Sym) and then Dictionary.IsUnknownTypeMark (Sym) then
         Result := E_Strings.Copy_String (Str => "unknown_type");
      else
         if Dictionary.IsRecordComponent (Sym) then
            Prefix := E_Strings.Empty_String;
         else
            Prefix := Dictionary.GetAnyPrefixNeeded (Sym       => Sym,
                                                     Scope     => Scope,
                                                     Separator => "__");
         end if;
         Simple_Name := Dictionary.GenerateSimpleName (Item      => Sym,
                                                       Separator => "__");

         if E_Strings.Get_Length (E_Str => Prefix) > 0 then
            Result := Prefix;
            E_Strings.Append_String (E_Str => Result,
                                     Str   => "__");
            E_Strings.Append_Examiner_String (E_Str1 => Result,
                                              E_Str2 => Simple_Name);
         else
            if not E_Strings.Is_Empty (E_Str => CommandLineData.Content.FDL_Mangle) then
               AdjustFDL_RWs.Possibly_Adjust (E_Str  => Simple_Name,
                                              Prefix => CommandLineData.Content.FDL_Mangle);
            end if;
            Result := Simple_Name;
         end if;
         Result := E_Strings.Lower_Case (E_Str => Result);
      end if;
      return Result;
   end Get_Name;

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

   -- Print Sym, without wrapping or white-space
   procedure Print_Symbol_No_Wrap (File  : in SPARK_IO.File_Type;
                                   Scope : in Dictionary.Scopes;
                                   Sym   : in Dictionary.Symbol)
   --# global in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     LexTokenManager.State;
   --#        in out SPARK_IO.File_Sys;
   --# derives SPARK_IO.File_Sys from *,
   --#                                CommandLineData.Content,
   --#                                Dictionary.Dict,
   --#                                File,
   --#                                LexTokenManager.State,
   --#                                Scope,
   --#                                Sym;
   is
   begin
      E_Strings.Put_String (File  => File,
                            E_Str => Get_Name (Sym   => Sym,
                                               Scope => Scope));
   end Print_Symbol_No_Wrap;

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

   -- Print Name, possibly wrapping and indenting to the next line
   procedure Print_Name (File : in SPARK_IO.File_Type;
                         Name : in E_Strings.T)
   --# global in out SPARK_IO.File_Sys;
   --# derives SPARK_IO.File_Sys from *,
   --#                                File,
   --#                                Name;
   is
   begin
      if SPARK_IO.Col (File) /= Indent
        and then (((SPARK_IO.Col (File) + E_Strings.Get_Length (E_Str => Name)) + 12) > Max_Column) then
         SPARK_IO.New_Line (File, 1);
         SPARK_IO.Set_Col (File, 2 * Indent);
      end if;

      E_Strings.Put_String (File  => File,
                            E_Str => Name);
   end Print_Name;

   ----------------------------------------------------------------------
   -- Print Sym, possibly wrapping and indenting to the next line
   procedure Print_Symbol (File  : in SPARK_IO.File_Type;
                           Scope : in Dictionary.Scopes;
                           Sym   : in Dictionary.Symbol)
   --# global in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     LexTokenManager.State;
   --#        in out SPARK_IO.File_Sys;
   --# derives SPARK_IO.File_Sys from *,
   --#                                CommandLineData.Content,
   --#                                Dictionary.Dict,
   --#                                File,
   --#                                LexTokenManager.State,
   --#                                Scope,
   --#                                Sym;
   is
      Name : E_Strings.T;
   begin
      Name := Get_Name (Sym   => Sym,
                        Scope => Scope);
      Print_Name (File, Name);
   end Print_Symbol;

   -- Print Sym in upper-case, possibly wrapping and indenting to the next line
   procedure Print_Symbol_Upper_Case (File  : in SPARK_IO.File_Type;
                                      Scope : in Dictionary.Scopes;
                                      Sym   : in Dictionary.Symbol)
   --# global in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     LexTokenManager.State;
   --#        in out SPARK_IO.File_Sys;
   --# derives SPARK_IO.File_Sys from *,
   --#                                CommandLineData.Content,
   --#                                Dictionary.Dict,
   --#                                File,
   --#                                LexTokenManager.State,
   --#                                Scope,
   --#                                Sym;
   is
      Name : E_Strings.T;
   begin
      Name := Get_Name (Sym   => Sym,
                        Scope => Scope);
      Name := E_Strings.Upper_Case (Name);
      Print_Name (File, Name);
   end Print_Symbol_Upper_Case;

   ----------------------------------------------------------------------
   procedure Print_Symbol_Type
     (File      : in SPARK_IO.File_Type;
      Scope     : in Dictionary.Scopes;
      Sub_Type  : in Boolean;
      Component : in Boolean;
      Sym       : in Dictionary.Symbol)
   --# global in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     LexTokenManager.State;
   --#        in out SPARK_IO.File_Sys;
   --# derives SPARK_IO.File_Sys from *,
   --#                                CommandLineData.Content,
   --#                                Component,
   --#                                Dictionary.Dict,
   --#                                File,
   --#                                LexTokenManager.State,
   --#                                Scope,
   --#                                Sub_Type,
   --#                                Sym;
   is

      Type_Sym : Dictionary.Symbol;

      ----------------------------------------------------------------------
      -- Function to calculate the required type symbol to be printed for a
      -- given symbol. Consider making this global and using it prior to all
      -- calls to Print_Symbol_Type (except when printing arrays and records)
      -- thus eliminating the need for the 'Component' flag.
      ----------------------------------------------------------------------
      function Get_Type_Sym (Sym   : in Dictionary.Symbol;
                             Scope : in Dictionary.Scopes) return Dictionary.Symbol
      --# global in Dictionary.Dict;
      is
         Type_Sym : Dictionary.Symbol;
      begin
         if Dictionary.IsTypeMark (Sym) and not Dictionary.IsSubtype (Sym) then
            Type_Sym := Dictionary.GetRootType (Sym);
         elsif Dictionary.Is_Variable (Sym) and then Dictionary.IsOwnVariable (Sym) then
            Type_Sym := Dictionary.GetRootType (Dictionary.GetOwnVariableTypeHere (OwnVariable => Sym,
                                                                                   Scope       => Scope));
         else
            Type_Sym := Dictionary.GetRootType (Dictionary.GetType (Sym));
         end if;

         return Type_Sym;

      end Get_Type_Sym;

   begin -- Print_Symbol_Type

      -- Sym is the symbol whose type is to be printed, and Type_Sym is the symbol of its (sub)type
      if Component then
         Type_Sym := Sym; -- When printing record component, array index or element types the Type_Sym is the Sym.
      else
         Type_Sym := Get_Type_Sym (Sym, Scope);
      end if;

      -- Print out the type symbol if possible, or just the basic type of integer, character, real or
      -- boolean otherwise. Note that the Simplifier cannot currently handle transitivity in subtype
      -- declarations, eg if we say "type t = integer; type st = t; type a = array[st] of ..." then the
      -- Simplifier rejects VCs that index into array 'a' using type st. Hence the flag Sub_Type is
      -- used to avoid this behaviour and print "type st = integer" in such cases. It may be possible to
      -- remove this flag in future if the Simplifier is modified to handle subtypes transitively. See
      -- discussion under [K401-011].
      if (Dictionary.TypeIsInteger (Type_Sym) or else Dictionary.TypeIsModular (Type_Sym))
        and then not Dictionary.IsPrivateType (Type_Sym, Scope)
        and then (Dictionary.IsUniversalIntegerType (Type_Sym) or Sub_Type) then
         SPARK_IO.Put_String (File, "integer", 0);
      elsif Dictionary.TypeIsCharacter (Type_Sym) then
         SPARK_IO.Put_String (File, "character", 0);
      elsif Dictionary.TypeIsReal (Type_Sym) then
         SPARK_IO.Put_String (File, "real", 0);
      elsif Dictionary.TypeIsBoolean (Type_Sym) then
         SPARK_IO.Put_String (File, "boolean", 0);
      else
         Print_Symbol (File  => File,
                       Scope => Scope,
                       Sym   => Type_Sym);
      end if;
   end Print_Symbol_Type;

   ----------------------------------------------------------------------
   -- routines to print rules go here because they need to be seen by
   -- Print_Constant_Declaration and they use Print_Symbol
   ----------------------------------------------------------------------

   procedure Print_Rule_Name (Rule_File : in SPARK_IO.File_Type)
   --# global in     Rule_Family_Name;
   --#        in out Rule_Counter;
   --#        in out SPARK_IO.File_Sys;
   --# derives Rule_Counter      from * &
   --#         SPARK_IO.File_Sys from *,
   --#                                Rule_Counter,
   --#                                Rule_Family_Name,
   --#                                Rule_File;
   is
   begin
      Rule_Counter := Rule_Counter + 1;
      E_Strings.Put_String (File  => Rule_File,
                            E_Str => Rule_Family_Name);
      SPARK_IO.Put_Char (Rule_File, '(');
      SPARK_IO.Put_Integer (Rule_File, Rule_Counter, 0, 10);
      SPARK_IO.Put_String (Rule_File, "): ", 0);
   end Print_Rule_Name;

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

   procedure End_A_Rule (Rule_File : in SPARK_IO.File_Type)
   --# global in out SPARK_IO.File_Sys;
   --# derives SPARK_IO.File_Sys from *,
   --#                                Rule_File;
   is
   begin
      SPARK_IO.Put_String (Rule_File, ".", 0);
      SPARK_IO.New_Line (Rule_File, 1);
   end End_A_Rule;

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

   function Get_Value
     (Store_Val : LexTokenManager.Lex_String;
      Type_Mark : Dictionary.Symbol;
      Scope     : Dictionary.Scopes)
     return      E_Strings.T
   --# global in CommandLineData.Content;
   --#        in Dictionary.Dict;
   --#        in LexTokenManager.State;
   is
      Str : E_Strings.T;
   begin

      if LexTokenManager.Lex_String_Case_Insensitive_Compare (Lex_Str1 => Store_Val,
                                                              Lex_Str2 => LexTokenManager.True_Token) =
        LexTokenManager.Str_Eq then
         Str := E_Strings.Copy_String (Str => "true");
      elsif LexTokenManager.Lex_String_Case_Insensitive_Compare (Lex_Str1 => Store_Val,
                                                                 Lex_Str2 => LexTokenManager.False_Token) =
        LexTokenManager.Str_Eq then
         Str := E_Strings.Copy_String (Str => "false");
      elsif Dictionary.TypeIsNumeric (Type_Mark) or else Dictionary.TypeIsCharacter (Type_Mark) then
         Str := Maths.ValueToString (Maths.ValueRep (Store_Val));
      else
         Str := Get_Name (Sym   => Dictionary.GetEnumerationLiteral (Type_Mark, Store_Val),
                          Scope => Scope);
      end if;
      return Str;
   end Get_Value;

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

   procedure Print_Replacement_Rule
     (Rule_File : in SPARK_IO.File_Type;
      Store_Val : in LexTokenManager.Lex_String;
      Type_Mark : in Dictionary.Symbol;
      Scope     : in Dictionary.Scopes)
   --# global in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     LexTokenManager.State;
   --#        in out SPARK_IO.File_Sys;
   --# derives SPARK_IO.File_Sys from *,
   --#                                CommandLineData.Content,
   --#                                Dictionary.Dict,
   --#                                LexTokenManager.State,
   --#                                Rule_File,
   --#                                Scope,
   --#                                Store_Val,
   --#                                Type_Mark;
   is
   begin
      SPARK_IO.Put_String (Rule_File, " may_be_replaced_by ", 0);
      E_Strings.Put_String
        (File  => Rule_File,
         E_Str => Get_Value (Store_Val => Store_Val,
                             Type_Mark => Type_Mark,
                             Scope     => Scope));
      End_A_Rule (Rule_File => Rule_File);
   end Print_Replacement_Rule;

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

   procedure PrintRuleHeader (Write_Rules : in Boolean;
                              Rule_File   : in SPARK_IO.File_Type)
   --# global in     Dictionary.Dict;
   --#        in     LexTokenManager.State;
   --#        in     Scope;
   --#        in out L_Heap;
   --#        in out SPARK_IO.File_Sys;
   --#           out Rule_Counter;
   --#           out Rule_Family_Name;
   --#           out Type_List;
   --# derives L_Heap,
   --#         Type_List         from L_Heap &
   --#         Rule_Counter      from  &
   --#         Rule_Family_Name  from Dictionary.Dict,
   --#                                LexTokenManager.State,
   --#                                Scope &
   --#         SPARK_IO.File_Sys from *,
   --#                                Dictionary.Dict,
   --#                                LexTokenManager.State,
   --#                                Rule_File,
   --#                                Scope,
   --#                                Write_Rules;
      is separate;

   ----------------------------------------------
   procedure PrintTypeRules (Write_Rules : in Boolean;
                             Rule_File   : in SPARK_IO.File_Type)
   --# global in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     LexTokenManager.State;
   --#        in     Rule_Family_Name;
   --#        in     Scope;
   --#        in out L_Heap;
   --#        in out Rule_Counter;
   --#        in out SPARK_IO.File_Sys;
   --#        in out Type_List;
   --# derives L_Heap,
   --#         Type_List         from LexTokenManager.State,
   --#                                L_Heap,
   --#                                Type_List,
   --#                                Write_Rules &
   --#         Rule_Counter      from *,
   --#                                Dictionary.Dict,
   --#                                LexTokenManager.State,
   --#                                L_Heap,
   --#                                Scope,
   --#                                Type_List,
   --#                                Write_Rules &
   --#         SPARK_IO.File_Sys from *,
   --#                                CommandLineData.Content,
   --#                                Dictionary.Dict,
   --#                                LexTokenManager.State,
   --#                                L_Heap,
   --#                                Rule_Counter,
   --#                                Rule_Family_Name,
   --#                                Rule_File,
   --#                                Scope,
   --#                                Type_List,
   --#                                Write_Rules;
      is separate;

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

   procedure PrintConstantRules
     (Write_Rules  : in Boolean;
      Sym          : in Dictionary.Symbol;
      Rule_File    : in SPARK_IO.File_Type;
      Scope        : in Dictionary.Scopes;
      End_Position : in LexTokenManager.Token_Position)
   --# global in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     LexTokenManager.State;
   --#        in     Rule_Family_Name;
   --#        in out ErrorHandler.Error_Context;
   --#        in out Rule_Counter;
   --#        in out SPARK_IO.File_Sys;
   --# derives ErrorHandler.Error_Context,
   --#         SPARK_IO.File_Sys          from CommandLineData.Content,
   --#                                         Dictionary.Dict,
   --#                                         End_Position,
   --#                                         ErrorHandler.Error_Context,
   --#                                         LexTokenManager.State,
   --#                                         Rule_Counter,
   --#                                         Rule_Family_Name,
   --#                                         Rule_File,
   --#                                         Scope,
   --#                                         SPARK_IO.File_Sys,
   --#                                         Sym,
   --#                                         Write_Rules &
   --#         Rule_Counter               from *,
   --#                                         CommandLineData.Content,
   --#                                         Dictionary.Dict,
   --#                                         LexTokenManager.State,
   --#                                         Scope,
   --#                                         Sym,
   --#                                         Write_Rules;
      is separate;

   procedure PrintConstantReplacementRule
     (Write_Rules : in Boolean;
      Sym         : in Dictionary.Symbol;
      DAG         : in Cells.Cell;
      Rule_File   : in SPARK_IO.File_Type;
      Scope       : in Dictionary.Scopes)
   --# global in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     LexTokenManager.State;
   --#        in     Rule_Family_Name;
   --#        in out Heap;
   --#        in out Rule_Counter;
   --#        in out SPARK_IO.File_Sys;
   --#        in out Statistics.TableUsage;
   --# derives Heap,
   --#         Statistics.TableUsage from *,
   --#                                    DAG,
   --#                                    Heap,
   --#                                    Write_Rules &
   --#         Rule_Counter          from *,
   --#                                    Write_Rules &
   --#         SPARK_IO.File_Sys     from *,
   --#                                    CommandLineData.Content,
   --#                                    DAG,
   --#                                    Dictionary.Dict,
   --#                                    Heap,
   --#                                    LexTokenManager.State,
   --#                                    Rule_Counter,
   --#                                    Rule_Family_Name,
   --#                                    Rule_File,
   --#                                    Scope,
   --#                                    Sym,
   --#                                    Write_Rules;
   is
   begin
      if Write_Rules then
         Print_Rule_Name (Rule_File => Rule_File);
         Print_Symbol (File  => Rule_File,
                       Scope => Scope,
                       Sym   => Sym);
         SPARK_IO.Put_String (Rule_File, " may_be_replaced_by ", 0);
         DAG_IO.PrintDag (Heap, Rule_File, DAG, Scope, DAG_IO.Default_Wrap_Limit);
         End_A_Rule (Rule_File => Rule_File);
      end if;
   end PrintConstantReplacementRule;

   ----------------------------------------------------------------------
   -- Produces FDL rules that are common to ALL Examiner-generated rule
   -- files.
   procedure PrintStandardRules (Write_Rules : in Boolean;
                                 Rule_File   : in SPARK_IO.File_Type)

   --# global in     Rule_Family_Name;
   --#        in out Rule_Counter;
   --#        in out SPARK_IO.File_Sys;
   --# derives Rule_Counter      from *,
   --#                                Write_Rules &
   --#         SPARK_IO.File_Sys from *,
   --#                                Rule_Counter,
   --#                                Rule_Family_Name,
   --#                                Rule_File,
   --#                                Write_Rules;
   is
      --# hide PrintStandardRules;
      pragma Unreferenced (Write_Rules);
      pragma Unreferenced (Rule_File);
   begin
      -- Currently, there are no such standard rules.
      -- This used to produce rules for Character'Pos and 'Val, but
      -- these are no longer needed following CFR 1804.
      -- We leave the contract of this unit as-was, though, in case
      -- of future re-instatement of this procedure.
      null;
   end PrintStandardRules;

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

   procedure Print_Declaration_Head (File  : in SPARK_IO.File_Type;
                                     Scope : in Dictionary.Scopes)
   --# global in     Dictionary.Dict;
   --#        in     LexTokenManager.State;
   --#        in out SPARK_IO.File_Sys;
   --# derives SPARK_IO.File_Sys from *,
   --#                                Dictionary.Dict,
   --#                                File,
   --#                                LexTokenManager.State,
   --#                                Scope;
   is
      Subprog_Sym : Dictionary.Symbol;
   begin
      -- Note that in the declarations header, we always print the
      -- _simple_ name of the subprogram, so it always matches the name
      -- output as the prefix of each VC generated by Graph.PrintVCs
      Subprog_Sym := Dictionary.GetRegion (Scope);
      SPARK_IO.Put_String (File, "title ", 0);
      if Dictionary.IsFunction (Subprog_Sym) then
         SPARK_IO.Put_String (File, "function ", 0);
      elsif Dictionary.IsProcedure (Subprog_Sym) then
         SPARK_IO.Put_String (File, "procedure ", 0);
      elsif Dictionary.IsTaskType (Subprog_Sym) then
         SPARK_IO.Put_String (File, "task_type ", 0);
      else
         null;
      end if;
      E_Strings.Put_String
        (File  => File,
         E_Str => E_Strings.Lower_Case
           (E_Str => LexTokenManager.Lex_String_To_String (Lex_Str => Dictionary.GetSimpleName (Subprog_Sym))));
      SPARK_IO.Put_Char (File, ';');
      SPARK_IO.New_Line (File, 2);
   end Print_Declaration_Head;

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

   function Find_Own_Var_Matching_This_Type (Sym   : Dictionary.Symbol;
                                             Scope : Dictionary.Scopes) return Dictionary.Symbol
   --# global in Dictionary.Dict;
   is
      It              : Dictionary.Iterator;
      Result          : Dictionary.Symbol := Dictionary.NullSymbol;
      Current_Own_Var : Dictionary.Symbol;
   begin
      It := Dictionary.FirstOwnVariable (Dictionary.GetEnclosingPackage (Scope));
      while not Dictionary.IsNullIterator (It) loop
         Current_Own_Var := Dictionary.CurrentSymbol (It);
         if Dictionary.Types_Are_Equal
           (Left_Symbol        => Dictionary.GetType (Current_Own_Var),
            Right_Symbol       => Sym,
            Full_Range_Subtype => False) then
            Result := Current_Own_Var;
            exit;
         end if;
         It := Dictionary.NextSymbol (It);
      end loop;
      return Result;
   end Find_Own_Var_Matching_This_Type;

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

   procedure Print_Declaration (File  : in SPARK_IO.File_Type;
                                Scope : in Dictionary.Scopes;
                                Sym   : in Dictionary.Symbol)
   --# global in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     LexTokenManager.State;
   --#        in     Needed_Symbols;
   --#        in     Rule_Family_Name;
   --#        in     Rule_File;
   --#        in out Heap;
   --#        in out Rule_Counter;
   --#        in out SPARK_IO.File_Sys;
   --#        in out Statistics.TableUsage;
   --# derives Heap                  from *,
   --#                                    Dictionary.Dict,
   --#                                    Scope,
   --#                                    Sym &
   --#         Rule_Counter          from *,
   --#                                    Dictionary.Dict,
   --#                                    Heap,
   --#                                    Needed_Symbols,
   --#                                    Sym &
   --#         SPARK_IO.File_Sys     from *,
   --#                                    CommandLineData.Content,
   --#                                    Dictionary.Dict,
   --#                                    File,
   --#                                    Heap,
   --#                                    LexTokenManager.State,
   --#                                    Needed_Symbols,
   --#                                    Rule_Counter,
   --#                                    Rule_Family_Name,
   --#                                    Rule_File,
   --#                                    Scope,
   --#                                    Sym &
   --#         Statistics.TableUsage from *,
   --#                                    Dictionary.Dict,
   --#                                    Heap,
   --#                                    Needed_Symbols,
   --#                                    Scope,
   --#                                    Sym;
   is

      procedure Print_Variable_Declaration
        (File  : in SPARK_IO.File_Type;
         Scope : in Dictionary.Scopes;
         Sym   : in Dictionary.Symbol)
      --# global in     CommandLineData.Content;
      --#        in     Dictionary.Dict;
      --#        in     LexTokenManager.State;
      --#        in out SPARK_IO.File_Sys;
      --# derives SPARK_IO.File_Sys from *,
      --#                                CommandLineData.Content,
      --#                                Dictionary.Dict,
      --#                                File,
      --#                                LexTokenManager.State,
      --#                                Scope,
      --#                                Sym;
      is
      begin
         SPARK_IO.Set_Col (File, Indent);
         SPARK_IO.Put_String (File, "var ", 0);
         Print_Symbol (File  => File,
                       Scope => Scope,
                       Sym   => Sym);
         SPARK_IO.Put_String (File, " : ", 0);
         Print_Symbol_Type (File      => File,
                            Scope     => Scope,
                            Sub_Type  => False,
                            Component => False,
                            Sym       => Sym);
         SPARK_IO.Put_Line (File, ";", 0);
      end Print_Variable_Declaration;

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

      procedure Print_Constant_Declaration
        (File  : in SPARK_IO.File_Type;
         Scope : in Dictionary.Scopes;
         Sym   : in Dictionary.Symbol)
      --# global in     CommandLineData.Content;
      --#        in     Dictionary.Dict;
      --#        in     LexTokenManager.State;
      --#        in out SPARK_IO.File_Sys;
      --# derives SPARK_IO.File_Sys from *,
      --#                                CommandLineData.Content,
      --#                                Dictionary.Dict,
      --#                                File,
      --#                                LexTokenManager.State,
      --#                                Scope,
      --#                                Sym;
      is
      begin
         if not Dictionary.IsEnumerationLiteral (Sym) then
            SPARK_IO.Set_Col (File, Indent);
            SPARK_IO.Put_String (File, "const ", 0);
            Print_Symbol (File  => File,
                          Scope => Scope,
                          Sym   => Sym);
            SPARK_IO.Put_String (File, " : ", 0);
            Print_Symbol_Type (File      => File,
                               Scope     => Scope,
                               Sub_Type  => False,
                               Component => False,
                               Sym       => Sym);
            SPARK_IO.Put_String (File, " = pending", 0);
            SPARK_IO.Put_Line (File, ";", 0);
         end if;
      end Print_Constant_Declaration;

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

      procedure Print_Type_Declaration (File  : in SPARK_IO.File_Type;
                                        Scope : in Dictionary.Scopes;
                                        Sym   : in Dictionary.Symbol)
      --# global in     CommandLineData.Content;
      --#        in     Dictionary.Dict;
      --#        in     LexTokenManager.State;
      --#        in out SPARK_IO.File_Sys;
      --# derives SPARK_IO.File_Sys from *,
      --#                                CommandLineData.Content,
      --#                                Dictionary.Dict,
      --#                                File,
      --#                                LexTokenManager.State,
      --#                                Scope,
      --#                                Sym;
      is

         Typ : Dictionary.Symbol;

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

         procedure Print_Private_Type (File  : in SPARK_IO.File_Type;
                                       Scope : in Dictionary.Scopes;
                                       Sym   : in Dictionary.Symbol)
         --# global in     CommandLineData.Content;
         --#        in     Dictionary.Dict;
         --#        in     LexTokenManager.State;
         --#        in out SPARK_IO.File_Sys;
         --# derives SPARK_IO.File_Sys from *,
         --#                                CommandLineData.Content,
         --#                                Dictionary.Dict,
         --#                                File,
         --#                                LexTokenManager.State,
         --#                                Scope,
         --#                                Sym;
         is
         begin
            SPARK_IO.Set_Col (File, Indent);
            SPARK_IO.Put_String (File, "type ", 0);
            Print_Symbol (File  => File,
                          Scope => Scope,
                          Sym   => Sym);
            SPARK_IO.Put_Line (File, " = pending;", 0);
         end Print_Private_Type;

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

         -- Same as Print_Private_Type for now, but kept separate in case we
         -- implement further support for proof of protected types
         -- in future.
         procedure Print_Protected_Type (File  : in SPARK_IO.File_Type;
                                         Scope : in Dictionary.Scopes;
                                         Sym   : in Dictionary.Symbol)
         --# global in     CommandLineData.Content;
         --#        in     Dictionary.Dict;
         --#        in     LexTokenManager.State;
         --#        in out SPARK_IO.File_Sys;
         --# derives SPARK_IO.File_Sys from *,
         --#                                CommandLineData.Content,
         --#                                Dictionary.Dict,
         --#                                File,
         --#                                LexTokenManager.State,
         --#                                Scope,
         --#                                Sym;
         is
         begin
            SPARK_IO.Set_Col (File, Indent);
            SPARK_IO.Put_String (File, "type ", 0);
            Print_Symbol (File  => File,
                          Scope => Scope,
                          Sym   => Sym);
            SPARK_IO.Put_Line (File, " = pending;", 0);
         end Print_Protected_Type;

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

         -- Same as Print_Private_Type for now, but kept separate for clarity
         procedure Print_Incomplete_Type
           (File  : in SPARK_IO.File_Type;
            Scope : in Dictionary.Scopes;
            Sym   : in Dictionary.Symbol)
         --# global in     CommandLineData.Content;
         --#        in     Dictionary.Dict;
         --#        in     LexTokenManager.State;
         --#        in out SPARK_IO.File_Sys;
         --# derives SPARK_IO.File_Sys from *,
         --#                                CommandLineData.Content,
         --#                                Dictionary.Dict,
         --#                                File,
         --#                                LexTokenManager.State,
         --#                                Scope,
         --#                                Sym;
         is
         begin
            SPARK_IO.Set_Col (File, Indent);
            SPARK_IO.Put_String (File, "type ", 0);
            Print_Symbol (File  => File,
                          Scope => Scope,
                          Sym   => Sym);
            SPARK_IO.Put_Line (File, " = pending;", 0);
         end Print_Incomplete_Type;

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

         procedure Print_Sub_Type (File  : in SPARK_IO.File_Type;
                                   Scope : in Dictionary.Scopes;
                                   Sym   : in Dictionary.Symbol)
         --# global in     CommandLineData.Content;
         --#        in     Dictionary.Dict;
         --#        in     LexTokenManager.State;
         --#        in out SPARK_IO.File_Sys;
         --# derives SPARK_IO.File_Sys from *,
         --#                                CommandLineData.Content,
         --#                                Dictionary.Dict,
         --#                                File,
         --#                                LexTokenManager.State,
         --#                                Scope,
         --#                                Sym;
         is
         begin
            SPARK_IO.Set_Col (File, Indent);
            SPARK_IO.Put_String (File, "type ", 0);
            Print_Symbol (File  => File,
                          Scope => Scope,
                          Sym   => Sym);
            SPARK_IO.Put_String (File, " = ", 0);
            Print_Symbol_Type (File      => File,
                               Scope     => Scope,
                               Sub_Type  => True,
                               Component => False,
                               Sym       => Sym);
            SPARK_IO.Put_Line (File, ";", 0);
         end Print_Sub_Type;

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

         procedure Print_Time_Type (File  : in SPARK_IO.File_Type;
                                    Scope : in Dictionary.Scopes;
                                    Sym   : in Dictionary.Symbol)
         --# global in     CommandLineData.Content;
         --#        in     Dictionary.Dict;
         --#        in     LexTokenManager.State;
         --#        in out SPARK_IO.File_Sys;
         --# derives SPARK_IO.File_Sys from *,
         --#                                CommandLineData.Content,
         --#                                Dictionary.Dict,
         --#                                File,
         --#                                LexTokenManager.State,
         --#                                Scope,
         --#                                Sym;
         is
         begin
            -- Ada95 LRM D.8 (27) says that time types (and their
            -- operators) behave as if they were integers.
            SPARK_IO.Set_Col (File, Indent);
            SPARK_IO.Put_String (File, "type ", 0);
            Print_Symbol (File  => File,
                          Scope => Scope,
                          Sym   => Sym);
            SPARK_IO.Put_Line (File, " = integer;", 0);
         end Print_Time_Type;

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

         procedure Print_Enumerated_Type
           (File  : in SPARK_IO.File_Type;
            Scope : in Dictionary.Scopes;
            Sym   : in Dictionary.Symbol)
         --# global in     CommandLineData.Content;
         --#        in     Dictionary.Dict;
         --#        in     LexTokenManager.State;
         --#        in out SPARK_IO.File_Sys;
         --# derives SPARK_IO.File_Sys from *,
         --#                                CommandLineData.Content,
         --#                                Dictionary.Dict,
         --#                                File,
         --#                                LexTokenManager.State,
         --#                                Scope,
         --#                                Sym;
         is
            EnumIt    : Dictionary.Iterator;
            First_One : Boolean;
         begin
            SPARK_IO.Set_Col (File, Indent);
            SPARK_IO.Put_String (File, "type ", 0);
            Print_Symbol (File  => File,
                          Scope => Scope,
                          Sym   => Sym);
            SPARK_IO.Put_String (File, " = ", 0);
            SPARK_IO.Put_Char (File, '(');
            if Dictionary.TypeIsGeneric (Sym) then
               -- we can't print the actual enumeration literals because there aren't any
               -- so we synthesise some to tell the proof tools this is an enumeration
               -- the synthetic literals will never appear in VCs and can't be used

               -- format is type T = (generic__t__lower, generic__t__upper);

               SPARK_IO.Put_String (File, "generic__", 0);
               Print_Symbol_No_Wrap (File  => File,
                                     Scope => Scope,
                                     Sym   => Sym);
               SPARK_IO.Put_String (File, "__lower, ", 0);
               SPARK_IO.Put_String (File, "generic__", 0);
               Print_Symbol_No_Wrap (File  => File,
                                     Scope => Scope,
                                     Sym   => Sym);
               SPARK_IO.Put_String (File, "__upper", 0);
            else
               -- not generic, get literals from Dictionary
               First_One := True;
               EnumIt    := Dictionary.FirstEnumerationLiteral (Sym);
               while not Dictionary.IsNullIterator (EnumIt) loop
                  if First_One then
                     First_One := False;
                  else
                     SPARK_IO.Put_String (File, ", ", 0);
                  end if;
                  Print_Symbol (File  => File,
                                Scope => Scope,
                                Sym   => Dictionary.CurrentSymbol (EnumIt));
                  EnumIt := Dictionary.NextSymbol (EnumIt);
               end loop;
            end if;
            SPARK_IO.Put_Char (File, ')');
            SPARK_IO.Put_Line (File, ";", 0);
         end Print_Enumerated_Type;

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

         procedure Print_Character_Type (File : in SPARK_IO.File_Type)
         --# global in out SPARK_IO.File_Sys;
         --# derives SPARK_IO.File_Sys from *,
         --#                                File;
         is
         begin
            SPARK_IO.Set_Col (File, Indent);
            SPARK_IO.Put_Line (File, "type character = integer;", 0);
         end Print_Character_Type;

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

         procedure Print_Record_Type
           (File               : in SPARK_IO.File_Type;
            Scope              : in Dictionary.Scopes;
            Sym                : in Dictionary.Symbol;
            Has_Private_Fields : in Boolean)
         --# global in     CommandLineData.Content;
         --#        in     Dictionary.Dict;
         --#        in     LexTokenManager.State;
         --#        in out SPARK_IO.File_Sys;
         --# derives SPARK_IO.File_Sys from *,
         --#                                CommandLineData.Content,
         --#                                Dictionary.Dict,
         --#                                File,
         --#                                Has_Private_Fields,
         --#                                LexTokenManager.State,
         --#                                Scope,
         --#                                Sym;
         is
            Component_It  : Dictionary.Iterator;
            First_One     : Boolean;
            Component_Sym : Dictionary.Symbol;
         begin
            -- If the root of an extended record is a null record then we don't want a declaration.
            if Dictionary.RecordHasSomeFields (Sym) then
               SPARK_IO.Set_Col (File, Indent);
               SPARK_IO.Put_String (File, "type ", 0);
               Print_Symbol (File  => File,
                             Scope => Scope,
                             Sym   => Sym);
               SPARK_IO.Put_String (File, " = ", 0);
               SPARK_IO.Put_Line (File, "record", 0);

               if Has_Private_Fields then
                  -- just declare inherit field
                  SPARK_IO.Set_Col (File, 3 * Indent);
                  SPARK_IO.Put_String (File, "inherit : ", 0);
                  Print_Symbol_Type
                    (File      => File,
                     Scope     => Scope,
                     Sub_Type  => False,
                     Component => False,
                     Sym       => Dictionary.GetRootOfExtendedType (Sym));

               else
                  -- declare all fields
                  Component_It := Dictionary.FirstRecordComponent (Sym);

                  -- If all ancestors of an extended record are null records then we don't want
                  -- a declaration of an Inherit field referencing first of them.
                  if Dictionary.TypeIsExtendedTagged (Sym) and then Dictionary.NoFieldsBelowThisRecord (Sym) then
                     --skip inherit field
                     Component_It := Dictionary.NextSymbol (Component_It);
                  end if;

                  First_One := True;
                  while not Dictionary.IsNullIterator (Component_It) loop
                     if First_One then
                        First_One := False;
                     else
                        SPARK_IO.Put_Line (File, ";", 0);
                     end if;
                     SPARK_IO.Set_Col (File, 3 * Indent);
                     Print_Symbol_No_Wrap (File  => File,
                                           Scope => Scope,
                                           Sym   => Dictionary.CurrentSymbol (Component_It));
                     SPARK_IO.Put_String (File, " : ", 0);

                     Component_Sym := Dictionary.GetType (Dictionary.CurrentSymbol (Component_It));
                     if Dictionary.Is_Constrained_Array_Type_Mark (Component_Sym, Scope)
                       or else (Dictionary.TypeIsRecord (Component_Sym) and then Dictionary.IsSubtype (Component_Sym)) then
                        -- If the record component type is a constrained subtype of an unconstrained
                        -- array then print the unconstrained array type. It may be possible to enhance
                        -- this in future and print the constrained subtype here but there are two
                        -- issues that would need to be addressed:
                        -- a. Making the Simplifier deal with transitivity of subtypes properly.
                        -- b. When printing out the rules for functions that take unconstrained arrays
                        --    as parameters, the Examiner would need to print out a version of the
                        --    function that took the constrained array as a parameter, or the Simplifier
                        --    would need to be modified to understand that a constrained subtype can be
                        --    passed to such a function in place of the unconstrained type.
                        -- The same applies to record subtypes.
                        Print_Symbol_Type
                          (File      => File,
                           Scope     => Scope,
                           Sub_Type  => False,
                           Component => True,
                           Sym       => Dictionary.GetRootType (Component_Sym));
                     else
                        -- The normal case is to print the type of the record component.
                        Print_Symbol_Type
                          (File      => File,
                           Scope     => Scope,
                           Sub_Type  => False,
                           Component => True,
                           Sym       => Component_Sym);
                     end if;
                     Component_It := Dictionary.NextSymbol (Component_It);
                  end loop;
               end if;

               SPARK_IO.New_Line (File, 1);
               SPARK_IO.Set_Col (File, 2 * Indent);
               SPARK_IO.Put_String (File, "end", 0);
               SPARK_IO.Put_Line (File, ";", 0);
            end if;
         end Print_Record_Type;

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

         procedure Print_Array_Type (File  : in SPARK_IO.File_Type;
                                     Scope : in Dictionary.Scopes;
                                     Sym   : in Dictionary.Symbol)
         --# global in     CommandLineData.Content;
         --#        in     Dictionary.Dict;
         --#        in     LexTokenManager.State;
         --#        in out SPARK_IO.File_Sys;
         --# derives SPARK_IO.File_Sys from *,
         --#                                CommandLineData.Content,
         --#                                Dictionary.Dict,
         --#                                File,
         --#                                LexTokenManager.State,
         --#                                Scope,
         --#                                Sym;
         is
            Index_It      : Dictionary.Iterator;
            First_One     : Boolean;
            Component_Sym : Dictionary.Symbol;
         begin
            SPARK_IO.Set_Col (File, Indent);
            SPARK_IO.Put_String (File, "type ", 0);
            Print_Symbol (File  => File,
                          Scope => Scope,
                          Sym   => Sym);
            SPARK_IO.Put_String (File, " = ", 0);
            SPARK_IO.Put_String (File, "array [", 0);
            Index_It  := Dictionary.FirstArrayIndex (Sym);
            First_One := True;
            while not Dictionary.IsNullIterator (Index_It) loop
               if First_One then
                  First_One := False;
               else
                  SPARK_IO.Put_String (File, ",", 0);
               end if;
               Print_Symbol_Type
                 (File      => File,
                  Scope     => Scope,
                  Sub_Type  => False,
                  Component => True,
                  Sym       => Dictionary.CurrentSymbol (Index_It));
               Index_It := Dictionary.NextSymbol (Index_It);
            end loop;
            SPARK_IO.Put_String (File, "] of ", 0);

            Component_Sym := Dictionary.GetArrayComponent (Sym);
            if Dictionary.Is_Constrained_Array_Type_Mark (Component_Sym, Scope)
              or else (Dictionary.TypeIsRecord (Component_Sym) and then Dictionary.IsSubtype (Component_Sym)) then
               -- If the array component type is a constrained subtype of an unconstrained
               -- array then print the unconstrained array type. It may be possible to enhance
               -- this in future and print the constrained subtype here but there are two
               -- issues that would need to be addressed:
               -- a. Making the Simplifier deal with transitivity of subtypes properly.
               -- b. When printing out the rules for functions that take unconstrained arrays
               --    as parameters, the Examiner would need to print out a version of the
               --    function that took the constrained array as a parameter, or the Simplifier
               --    would need to be modified to understand that a constrained subtype can be
               --    passed to such a function in place of the unconstrained type.
               -- The same applies to record subtypes.
               Print_Symbol_Type
                 (File      => File,
                  Scope     => Scope,
                  Sub_Type  => False,
                  Component => True,
                  Sym       => Dictionary.GetRootType (Component_Sym));
            else
               -- The normal case is to print the type of the array component.
               Print_Symbol_Type (File      => File,
                                  Scope     => Scope,
                                  Sub_Type  => False,
                                  Component => True,
                                  Sym       => Component_Sym);
            end if;
            SPARK_IO.Put_Line (File, ";", 0);

            -- Wherever type String is declared, we also produce a
            -- declaration of a deferred constant that represents the
            -- Null String literal ""
            if Dictionary.IsPredefinedStringType (Sym) then
               SPARK_IO.Set_Col (File, Indent);
               SPARK_IO.Put_String (File, "const ", 0);
               SPARK_IO.Put_String (File, DAG_IO.Null_String_Literal_Name, 0);
               SPARK_IO.Put_Line (File, " : string = pending;", 0);
            end if;

         end Print_Array_Type;

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

         -- Procedure to print abstract types: either "pending"
         -- or and FDL record declaration is printed depending on scope
         procedure Print_Abstract_Type (File  : in SPARK_IO.File_Type;
                                        Scope : in Dictionary.Scopes;
                                        Sym   : in Dictionary.Symbol)
         --# global in     CommandLineData.Content;
         --#        in     Dictionary.Dict;
         --#        in     LexTokenManager.State;
         --#        in out SPARK_IO.File_Sys;
         --# derives SPARK_IO.File_Sys from *,
         --#                                CommandLineData.Content,
         --#                                Dictionary.Dict,
         --#                                File,
         --#                                LexTokenManager.State,
         --#                                Scope,
         --#                                Sym;
         is

            Own_Var_Sym : Dictionary.Symbol;

            procedure Print_Refinement_Record
              (File  : in SPARK_IO.File_Type;
               Scope : in Dictionary.Scopes;
               Sym   : in Dictionary.Symbol)
            --# global in     CommandLineData.Content;
            --#        in     Dictionary.Dict;
            --#        in     LexTokenManager.State;
            --#        in out SPARK_IO.File_Sys;
            --# derives SPARK_IO.File_Sys from *,
            --#                                CommandLineData.Content,
            --#                                Dictionary.Dict,
            --#                                File,
            --#                                LexTokenManager.State,
            --#                                Scope,
            --#                                Sym;
            is
               Component_It : Dictionary.Iterator;
               First_One    : Boolean;
            begin
               SPARK_IO.Set_Col (File, Indent);
               SPARK_IO.Put_String (File, "type ", 0);
               Print_Symbol (File  => File,
                             Scope => Scope,
                             Sym   => Dictionary.GetType (Sym));
               SPARK_IO.Put_String (File, " = ", 0);
               SPARK_IO.Put_Line (File, "record", 0);
               Component_It := Dictionary.FirstConstituent (Sym);
               First_One    := True;
               while not Dictionary.IsNullIterator (Component_It) loop
                  if First_One then
                     First_One := False;
                  else
                     SPARK_IO.Put_Line (File, ";", 0);
                  end if;
                  SPARK_IO.Set_Col (File, 3 * Indent);
                  Print_Symbol (File  => File,
                                Scope => Scope,
                                Sym   => Dictionary.CurrentSymbol (Component_It));
                  SPARK_IO.Put_String (File, " : ", 0);
                  Print_Symbol_Type
                    (File      => File,
                     Scope     => Scope,
                     Sub_Type  => False,
                     Component => False,
                     Sym       => Dictionary.CurrentSymbol (Component_It));
                  Component_It := Dictionary.NextSymbol (Component_It);
               end loop;
               SPARK_IO.New_Line (File, 1);
               SPARK_IO.Set_Col (File, 2 * Indent);
               SPARK_IO.Put_String (File, "end", 0);
               SPARK_IO.Put_Line (File, ";", 0);
            end Print_Refinement_Record;

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

         begin  --Print_Abstract_Type
            Own_Var_Sym := Find_Own_Var_Matching_This_Type (Sym   => Sym,
                                                            Scope => Scope);
            if IsLocalOwnVariableWithRefinement (Own_Var_Sym, Scope) then
               Print_Refinement_Record (File  => File,
                                        Scope => Scope,
                                        Sym   => Own_Var_Sym);
            else
               SPARK_IO.Set_Col (File, Indent);
               SPARK_IO.Put_String (File, "type ", 0);
               Print_Symbol (File  => File,
                             Scope => Scope,
                             Sym   => Sym);
               SPARK_IO.Put_Line (File, " = pending;", 0);
            end if;
         end Print_Abstract_Type;

      begin -- Print_Type_Declaration

         -- Time types are private from the point of view of the
         -- type system, but need special handling in FDL so that
         -- their relational and arithmetic operators are well-defined,
         -- so we deal with them first.
         if Dictionary.IsPredefinedTimeType (Sym) or else Dictionary.IsPredefinedTimeSpanType (Sym) then
            Print_Time_Type (File  => File,
                             Scope => Scope,
                             Sym   => Sym);

         elsif Dictionary.IsPrivateType (Sym, Scope) and then not Dictionary.TypeIsExtendedTagged (Sym) then
            Print_Private_Type (File  => File,
                                Scope => Scope,
                                Sym   => Sym);

         elsif Dictionary.TypeIsAbstractProof (Sym) then
            Print_Abstract_Type (File  => File,
                                 Scope => Scope,
                                 Sym   => Sym);

         elsif Dictionary.IsSubtype (Sym)
           and then not Dictionary.TypeIsRecord (Dictionary.GetRootType (Sym))
           and then not Dictionary.TypeIsArray (Dictionary.GetRootType (Sym)) then
            -- Subtypes are those which actually appear in
            -- the VC, since only base types are ever added
            -- by generatesuccessors. These can only occur in attributes
            -- so we want the actual type not the base type.
            -- For record subtypes (which are always full range in SPARK) don't
            -- print the subtype as the root type is always used in FDL.
            -- Similarly for array subtypes (which are either full range, or are
            -- constrained subtypes of unconstrained arrays) don't print subtype
            -- because the root type is always used in FDL.
            Print_Sub_Type (File  => File,
                            Scope => Scope,
                            Sym   => Sym);

         elsif Dictionary.TypeIsIncompleteHere (Sym, Scope) and then not Dictionary.TypeIsExtendedTagged (Sym) then
            Print_Incomplete_Type (File  => File,
                                   Scope => Scope,
                                   Sym   => Sym);

         elsif Dictionary.IsParameterConstraint (Sym) then
            -- subprogram parameter constraint symbols are used to communicate information about
            -- unconstrained array formal parameters.  They behave as subtypes for VC declaration purposes
            Print_Sub_Type (File  => File,
                            Scope => Scope,
                            Sym   => Sym);

         else
            Typ := Dictionary.GetRootType (Sym);

            if Dictionary.TypeIsCharacter (Typ) then
               Print_Character_Type (File => File);

            elsif Dictionary.IsPredefinedIntegerType (Typ) or
              Dictionary.IsPredefinedFloatType (Typ) or
              Dictionary.TypeIsBoolean (Typ) then
               -- No action, since "integer", "real" and "boolean" are
               -- predefined in FDL
               null;

            elsif Dictionary.TypeIsEnumeration (Typ) then
               Print_Enumerated_Type (File  => File,
                                      Scope => Scope,
                                      Sym   => Typ);

            elsif (Dictionary.TypeIsRecord (Typ) or Dictionary.TypeIsExtendedTagged (Sym)) then
               if Dictionary.IsSubtype (Sym) then
                  -- Don't print out record subtypes. We always use the root type in FDL, and
                  -- that will be printed separately.
                  null;
               else
                  Print_Record_Type
                    (File               => File,
                     Scope              => Scope,
                     Sym                => Typ,
                     Has_Private_Fields => Dictionary.IsPrivateType (Sym, Scope));
               end if;

            elsif Dictionary.TypeIsArray (Typ) then
               if Dictionary.IsSubtype (Sym) then
                  -- Don't print out array subtypes. We always use the root type in FDL, and
                  -- that will be printed separately.
                  null;
               else
                  Print_Array_Type (File  => File,
                                    Scope => Scope,
                                    Sym   => Typ);
               end if;

            elsif Dictionary.TypeIsInteger (Typ) or Dictionary.TypeIsReal (Typ) or Dictionary.TypeIsModular (Typ) then

               Print_Sub_Type (File  => File,
                               Scope => Scope,
                               Sym   => Typ);

            elsif Dictionary.IsProtectedType (Typ) then
               -- Protected types need at least a "pending" declaration in FDL,
               -- so that later proof functions and variables make sense.
               Print_Protected_Type (File  => File,
                                     Scope => Scope,
                                     Sym   => Typ);

            else
               Debug_Rank_Sym (Msg => "Print_Type_Declaration does not know how to deal with ",
                               Sym => Typ);
               SystemErrors.Fatal_Error
                 (Sys_Err => SystemErrors.Assertion_Failure,
                  Msg     => "Unknown type in Print_Type_Declaration");
            end if;
         end if;
      end Print_Type_Declaration;

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

      procedure Print_Procedure_Declaration
        (File  : in SPARK_IO.File_Type;
         Scope : in Dictionary.Scopes;
         Sym   : in Dictionary.Symbol)
      --# global in     CommandLineData.Content;
      --#        in     Dictionary.Dict;
      --#        in     LexTokenManager.State;
      --#        in out Heap;
      --#        in out SPARK_IO.File_Sys;
      --#        in out Statistics.TableUsage;
      --# derives Heap,
      --#         Statistics.TableUsage from *,
      --#                                    Dictionary.Dict,
      --#                                    Heap,
      --#                                    Scope,
      --#                                    Sym &
      --#         SPARK_IO.File_Sys     from *,
      --#                                    CommandLineData.Content,
      --#                                    Dictionary.Dict,
      --#                                    File,
      --#                                    Heap,
      --#                                    LexTokenManager.State,
      --#                                    Scope,
      --#                                    Sym;
      is
         Exp_It, Imp_It         : Dictionary.Iterator;
         First_One              : Boolean;
         Abstraction            : Dictionary.Abstractions;
         Export_Sym, Import_Sym : Dictionary.Symbol;

         -- These stacks are needed to revsers order of both exports and imports
         Import_Stack : CStacks.Stack;
         Temp_Cell    : Cells.Cell; --stack member

         function Export_Name (Subprog_Sym, Export_Sym : Dictionary.Symbol;
                               Scope                   : Dictionary.Scopes) return E_Strings.T
         --# global in CommandLineData.Content;
         --#        in Dictionary.Dict;
         --#        in LexTokenManager.State;
         is
            Result : E_Strings.T;
         begin
            if Dictionary.IsFormalParameter (Subprog_Sym, Export_Sym) then
               -- No prefix needed
               Result := LexTokenManager.Lex_String_To_String (Lex_Str => Dictionary.GetSimpleName (Export_Sym));
            else -- Its global and a prefix may be needed
               Result := Get_Name (Sym   => Export_Sym,
                                   Scope => Scope);
            end if;
            return E_Strings.Lower_Case (E_Str => Result);
         end Export_Name;

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

      begin -- Print_Procedure_Declaration

         -- Use stack to reverse order of exports
         CStacks.CreateStack (Import_Stack);

         Abstraction := Dictionary.GetAbstraction (Sym, Scope);
         Exp_It      := Dictionary.FirstExport (Abstraction, Sym);
         while not Dictionary.IsNullIterator (Exp_It) loop
            Export_Sym := Dictionary.CurrentSymbol (Exp_It);
            SPARK_IO.Set_Col (File, Indent);
            SPARK_IO.Put_String (File, "function ", 0);
            Print_Symbol (File  => File,
                          Scope => Scope,
                          Sym   => Sym);
            SPARK_IO.Put_String (File, "__", 0);
            E_Strings.Put_String
              (File  => File,
               E_Str => Export_Name (Subprog_Sym => Sym,
                                     Export_Sym  => Export_Sym,
                                     Scope       => Scope));
            Imp_It := Dictionary.FirstDependency (Abstraction, Sym, Export_Sym);
            while not Dictionary.IsNullIterator (Imp_It) loop
               Cells.Create_Cell (Heap, Temp_Cell);
               Cells.Set_Symbol_Value (Heap, Temp_Cell, Dictionary.CurrentSymbol (Imp_It));
               CStacks.Push (Heap, Temp_Cell, Import_Stack);
               Imp_It := Dictionary.NextSymbol (Imp_It);
            end loop;

            --now pop them one at a time and build an argument list for function
            First_One := True;
            while not CStacks.IsEmpty (Import_Stack) loop
               Import_Sym := Cells.Get_Symbol_Value (Heap, CStacks.Top (Heap, Import_Stack));
               CStacks.Pop (Heap, Import_Stack);
               if First_One then
                  SPARK_IO.Put_String (File, "(", 0);
                  First_One := False;
               else
                  SPARK_IO.Put_String (File, ", ", 0);
               end if;
               Print_Symbol_Type (File      => File,
                                  Scope     => Scope,
                                  Sub_Type  => False,
                                  Component => False,
                                  Sym       => Import_Sym);
            end loop;
            if not First_One then
               SPARK_IO.Put_String (File, ")", 0);
            end if;
            SPARK_IO.Put_String (File, " : ", 0);
            Print_Symbol_Type (File      => File,
                               Scope     => Scope,
                               Sub_Type  => False,
                               Component => False,
                               Sym       => Export_Sym);
            SPARK_IO.Put_Line (File, ";", 0);
            Exp_It := Dictionary.NextSymbol (Exp_It);
         end loop;
      end Print_Procedure_Declaration;

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

      procedure Print_Function_Declaration
        (File  : in SPARK_IO.File_Type;
         Scope : in Dictionary.Scopes;
         Sym   : in Dictionary.Symbol)
      --# global in     CommandLineData.Content;
      --#        in     Dictionary.Dict;
      --#        in     Heap;
      --#        in     LexTokenManager.State;
      --#        in     Needed_Symbols;
      --#        in     Rule_Family_Name;
      --#        in     Rule_File;
      --#        in out Rule_Counter;
      --#        in out SPARK_IO.File_Sys;
      --#        in out Statistics.TableUsage;
      --# derives Rule_Counter,
      --#         Statistics.TableUsage from *,
      --#                                    Dictionary.Dict,
      --#                                    Heap,
      --#                                    Needed_Symbols,
      --#                                    Sym &
      --#         SPARK_IO.File_Sys     from *,
      --#                                    CommandLineData.Content,
      --#                                    Dictionary.Dict,
      --#                                    File,
      --#                                    Heap,
      --#                                    LexTokenManager.State,
      --#                                    Needed_Symbols,
      --#                                    Rule_Counter,
      --#                                    Rule_Family_Name,
      --#                                    Rule_File,
      --#                                    Scope,
      --#                                    Sym;
      is
         Argument_It : Dictionary.Iterator;
         First_One   : Boolean;
         Ada_Sym     : Dictionary.Symbol;

         procedure Print_Proof_Function_Refinement (Ada_Function : in Dictionary.Symbol)
         --# global in     CommandLineData.Content;
         --#        in     Dictionary.Dict;
         --#        in     LexTokenManager.State;
         --#        in     Rule_File;
         --#        in     Scope;
         --#        in out SPARK_IO.File_Sys;
         --#        in out Statistics.TableUsage;
         --# derives SPARK_IO.File_Sys     from *,
         --#                                    Ada_Function,
         --#                                    CommandLineData.Content,
         --#                                    Dictionary.Dict,
         --#                                    LexTokenManager.State,
         --#                                    Rule_File,
         --#                                    Scope &
         --#         Statistics.TableUsage from *,
         --#                                    Ada_Function,
         --#                                    Dictionary.Dict;
         is
            Abstract_Args : Symbol_Set.T;

            --  Sym is an abstract proof function. For each of its own
            --  variable parameter X, print the check
            --  "goal(checktype(X,<type-of-X>))".
            procedure Print_Own_Type_Checks (Sym : in Dictionary.Symbol)
            --# global in     CommandLineData.Content;
            --#        in     Dictionary.Dict;
            --#        in     LexTokenManager.State;
            --#        in     Rule_File;
            --#        in     Scope;
            --#        in out SPARK_IO.File_Sys;
            --# derives SPARK_IO.File_Sys from *,
            --#                                CommandLineData.Content,
            --#                                Dictionary.Dict,
            --#                                LexTokenManager.State,
            --#                                Rule_File,
            --#                                Scope,
            --#                                Sym;
            is
               Argument_It : Dictionary.Iterator;
               First_One   : Boolean;
               Param       : Dictionary.Symbol;
            begin
               First_One   := True;
               Argument_It := Dictionary.FirstSubprogramParameter (Sym);
               while not Dictionary.IsNullIterator (Argument_It) loop
                  Param := Dictionary.CurrentSymbol (Argument_It);
                  if Dictionary.IsOwnVariable (Param) then
                     if First_One then
                        First_One := False;
                     else
                        SPARK_IO.Put_String (Rule_File, ", ", 0);
                     end if;
                     SPARK_IO.Put_String (Rule_File, "goal(checktype(", 0);
                     Print_Symbol_Upper_Case (File  => Rule_File,
                                              Scope => Scope,
                                              Sym   => Param);
                     SPARK_IO.Put_String (Rule_File, ", ", 0);
                     Print_Symbol (File  => Rule_File,
                                   Scope => Scope,
                                   Sym   => Dictionary.GetType (Param));
                     SPARK_IO.Put_String (Rule_File, "))", 0);
                  end if;
                  Argument_It := Dictionary.NextSymbol (Argument_It);
               end loop;
            end Print_Own_Type_Checks;

            --  Print parameter Sym for a call to the abstract or refined
            --  proof function. If Sym is a constituent c1 of own
            --  variable x (for the refined call), and we are looking at
            --  the refined function, then print "fld_c1(X)". Otherwise,
            --  the parameter is just printed "X".
            procedure Print_Proof_Function_Argument (Sym         : in Dictionary.Symbol;
                                                     Abstraction : in Dictionary.Abstractions)
            --# global in     CommandLineData.Content;
            --#        in     Dictionary.Dict;
            --#        in     LexTokenManager.State;
            --#        in     Rule_File;
            --#        in     Scope;
            --#        in out Abstract_Args;
            --#        in out SPARK_IO.File_Sys;
            --#        in out Statistics.TableUsage;
            --# derives Abstract_Args,
            --#         Statistics.TableUsage from *,
            --#                                    Abstraction,
            --#                                    Abstract_Args,
            --#                                    Sym &
            --#         SPARK_IO.File_Sys     from *,
            --#                                    Abstraction,
            --#                                    Abstract_Args,
            --#                                    CommandLineData.Content,
            --#                                    Dictionary.Dict,
            --#                                    LexTokenManager.State,
            --#                                    Rule_File,
            --#                                    Scope,
            --#                                    Sym;
            is
               Do_Refinement : Boolean;
            begin
               --  This procedure is called in two contexts; first for
               --  each argument for the abstract version of a
               --  function and second for each argument of the
               --  refined version. When printing the arguments for
               --  the abstract version we:
               --     * Always print the abstract, non-refined version
               --     * Make a note of the symbol
               --  When printing the arguments for the refined version
               --  it is a bit more complicated:
               --     * Arguments that are not part of any own variable
               --       are printed as-is (i.e. WIBBLE)
               --     * Arguments that are part of an own variable
               --       are printed as-is if we have seen them
               --       before (during the abstract call) (i.e. WIBBLE)
               --     * Arguments that are part of an own variable
               --       are printed using the refined view if we have not
               --       seen them before (i.e. fld_foo(WIBBLE)).
               case Abstraction is
                  when Dictionary.IsAbstract =>
                     Do_Refinement := False;
                     Symbol_Set.Add (Abstract_Args, Sym);
                  when Dictionary.IsRefined =>
                     Do_Refinement := (Dictionary.IsConstituent (Sym) and
                                         not Symbol_Set.Contains (Abstract_Args, Sym));
               end case;

               if Do_Refinement then
                  SPARK_IO.Put_String (Rule_File, "fld_", 0);
                  Print_Symbol_No_Wrap (File  => Rule_File,
                                        Scope => Scope,
                                        Sym   => Sym);
                  SPARK_IO.Put_String (Rule_File, "(", 0);
                  Print_Symbol_Upper_Case (File  => Rule_File,
                                           Scope => Scope,
                                           Sym   => Dictionary.GetSubject (Sym));
                  SPARK_IO.Put_String (Rule_File, ")", 0);
               else
                  Print_Symbol_Upper_Case (File  => Rule_File,
                                           Scope => Scope,
                                           Sym   => Sym);
               end if;
            end Print_Proof_Function_Argument;

            --  Print a call to the abstract or refined proof function
            --  for the Ada function Sym. Parameters are all universally
            --  quantified (thus upper-case), and refined own parameters
            --  are derived from the corresponding abstract own
            --  parameters with a suitable call to a "fld_" getter
            --  function.
            procedure Print_Proof_Function_Pattern (Sym         : in Dictionary.Symbol;
                                                    Abstraction : in Dictionary.Abstractions)
            --# global in     CommandLineData.Content;
            --#        in     Dictionary.Dict;
            --#        in     LexTokenManager.State;
            --#        in     Rule_File;
            --#        in     Scope;
            --#        in out Abstract_Args;
            --#        in out SPARK_IO.File_Sys;
            --#        in out Statistics.TableUsage;
            --# derives Abstract_Args,
            --#         Statistics.TableUsage from *,
            --#                                    Abstraction,
            --#                                    Abstract_Args,
            --#                                    Dictionary.Dict,
            --#                                    Sym &
            --#         SPARK_IO.File_Sys     from *,
            --#                                    Abstraction,
            --#                                    Abstract_Args,
            --#                                    CommandLineData.Content,
            --#                                    Dictionary.Dict,
            --#                                    LexTokenManager.State,
            --#                                    Rule_File,
            --#                                    Scope,
            --#                                    Sym;
            is
               Argument_It : Dictionary.Iterator;
               First_One   : Boolean;
               Proof_Sym   : Dictionary.Symbol;
            begin
               Proof_Sym := Dictionary.GetImplicitProofFunction (Abstraction, Sym);

               Print_Symbol (File  => Rule_File,
                             Scope => Scope,
                             Sym   => Proof_Sym);

               First_One   := True;
               Argument_It := Dictionary.FirstSubprogramParameter (Proof_Sym);
               while not Dictionary.IsNullIterator (Argument_It) loop
                  if First_One then
                     SPARK_IO.Put_String (Rule_File, "(", 0);
                     First_One := False;
                  else
                     SPARK_IO.Put_String (Rule_File, ", ", 0);
                  end if;
                  Print_Proof_Function_Argument (Sym         => Dictionary.CurrentSymbol (Argument_It),
                                                 Abstraction => Abstraction);
                  Argument_It := Dictionary.NextSymbol (Argument_It);
               end loop;
               if not First_One then
                  SPARK_IO.Put_String (Rule_File, ")", 0);
               end if;
            end Print_Proof_Function_Pattern;

         begin
            Symbol_Set.Initialise (Abstract_Args);

            Print_Proof_Function_Pattern (Ada_Function, Dictionary.IsAbstract);
            SPARK_IO.Put_String (Rule_File, " may_be_replaced_by ", 0);
            --# accept F, 10, Abstract_Args, "We are not actually assigning here anymore, just reading.";
            Print_Proof_Function_Pattern (Ada_Function, Dictionary.IsRefined);
            --# end accept;

            SPARK_IO.Put_String (Rule_File, " if [", 0);
            Print_Own_Type_Checks (Dictionary.GetImplicitProofFunction (Dictionary.IsAbstract, Ada_Function));
            SPARK_IO.Put_Line (Rule_File, "].", 0);
         end Print_Proof_Function_Refinement;

      begin -- Print_Function_Declaration

         --  In the case of data refinement, if Sym is a refined proof
         --  function, and the corresponding abstract proof function
         --  is needed, then generate a rule stating that a call to
         --  the abstract proof function can be rewritten in a call to
         --  the refined proof function.
         if Dictionary.IsImplicitProofFunction (Sym) then
            Ada_Sym := Dictionary.GetAdaFunction (Sym);

            --  This is a case of data refinement

            if not Dictionary.IsNullIterator (Dictionary.FirstGlobalVariable (Dictionary.IsAbstract, Ada_Sym))

              --  Sym is a refined proof function

              and then Dictionary.GetImplicitProofFunction (Dictionary.IsRefined, Ada_Sym) = Sym

              --  The corresponding abstract proof function is needed

              and then Pile.Contains (Heap   => Heap,
                                      Symbol => Dictionary.GetImplicitProofFunction (Dictionary.IsAbstract, Ada_Sym),
                                      Node   => Needed_Symbols)
            then
               Print_Rule_Name (Rule_File);
               Print_Proof_Function_Refinement (Ada_Sym);
            end if;
         end if;

         if Dictionary.GetRegion (Scope) = Sym then
            SPARK_IO.Set_Col (File, Indent);
            SPARK_IO.Put_String (File, "var ", 0);
            Print_Symbol (File  => File,
                          Scope => Scope,
                          Sym   => Sym);
            SPARK_IO.Put_String (File, " : ", 0);
            Print_Symbol_Type (File      => File,
                               Scope     => Scope,
                               Sub_Type  => False,
                               Component => False,
                               Sym       => Sym);
            SPARK_IO.Put_Line (File, ";", 0);
         else
            SPARK_IO.Set_Col (File, Indent);
            SPARK_IO.Put_String (File, "function ", 0);
            Print_Symbol (File  => File,
                          Scope => Scope,
                          Sym   => Sym);

            First_One   := True;
            Argument_It := Dictionary.FirstSubprogramParameter (Sym);
            while not Dictionary.IsNullIterator (Argument_It) loop
               if First_One then
                  SPARK_IO.Put_String (File, "(", 0);
                  First_One := False;
               else
                  SPARK_IO.Put_String (File, ", ", 0);
               end if;
               Print_Symbol_Type
                 (File      => File,
                  Scope     => Scope,
                  Sub_Type  => False,
                  Component => False,
                  Sym       => Dictionary.CurrentSymbol (Argument_It));
               Argument_It := Dictionary.NextSymbol (Argument_It);
            end loop;

            if not First_One then
               SPARK_IO.Put_String (File, ")", 0);
            end if;
            SPARK_IO.Put_String (File, " : ", 0);
            Print_Symbol_Type (File      => File,
                               Scope     => Scope,
                               Sub_Type  => False,
                               Component => False,
                               Sym       => Sym);
            SPARK_IO.Put_Line (File, ";", 0);
         end if;
      end Print_Function_Declaration;

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

   begin --Print_Declaration
      if Dictionary.Is_Variable (Sym) then
         Print_Variable_Declaration (File  => File,
                                     Scope => Scope,
                                     Sym   => Sym);
      elsif Dictionary.Is_Constant (Sym) then
         Print_Constant_Declaration (File  => File,
                                     Scope => Scope,
                                     Sym   => Sym);
      elsif Dictionary.IsKnownDiscriminant (Sym) then
         Print_Constant_Declaration (File  => File,
                                     Scope => Scope,
                                     Sym   => Sym);
      elsif Dictionary.IsTypeMark (Sym) then
         Print_Type_Declaration (File  => File,
                                 Scope => Scope,
                                 Sym   => Sym);
      elsif Dictionary.IsProcedure (Sym) then
         Print_Procedure_Declaration (File  => File,
                                      Scope => Scope,
                                      Sym   => Sym);
      elsif Dictionary.IsFunction (Sym) then
         Print_Function_Declaration (File  => File,
                                     Scope => Scope,
                                     Sym   => Sym);
      else
         null;
      end if;
   end Print_Declaration;

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

   procedure Print_Attribute_Declarations (File  : in SPARK_IO.File_Type;
                                           Scope : in Dictionary.Scopes)
   --# global in     AttributeList;
   --#        in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     Heap;
   --#        in     LexTokenManager.State;
   --#        in     Rule_Family_Name;
   --#        in     Rule_File;
   --#        in     Type_List;
   --#        in     Write_Rules;
   --#        in out L_Heap;
   --#        in out Rule_Counter;
   --#        in out SPARK_IO.File_Sys;
   --# derives L_Heap            from *,
   --#                                AttributeList,
   --#                                Heap,
   --#                                LexTokenManager.State,
   --#                                Type_List,
   --#                                Write_Rules &
   --#         Rule_Counter      from *,
   --#                                AttributeList,
   --#                                Dictionary.Dict,
   --#                                Heap,
   --#                                LexTokenManager.State,
   --#                                Scope,
   --#                                Write_Rules &
   --#         SPARK_IO.File_Sys from *,
   --#                                AttributeList,
   --#                                CommandLineData.Content,
   --#                                Dictionary.Dict,
   --#                                File,
   --#                                Heap,
   --#                                LexTokenManager.State,
   --#                                Rule_Counter,
   --#                                Rule_Family_Name,
   --#                                Rule_File,
   --#                                Scope,
   --#                                Write_Rules;
   is

      Current_Attrib, Prev_Attrib : Cells.Cell;

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

      procedure Print_One_Attribute (Tick_Cell : in Cells.Cell;
                                     Prev_Cell : in Cells.Cell)
      --# global in     CommandLineData.Content;
      --#        in     Dictionary.Dict;
      --#        in     File;
      --#        in     Heap;
      --#        in     LexTokenManager.State;
      --#        in     Rule_Family_Name;
      --#        in     Rule_File;
      --#        in     Scope;
      --#        in     Type_List;
      --#        in     Write_Rules;
      --#        in out L_Heap;
      --#        in out Rule_Counter;
      --#        in out SPARK_IO.File_Sys;
      --# derives L_Heap            from *,
      --#                                Heap,
      --#                                LexTokenManager.State,
      --#                                Tick_Cell,
      --#                                Type_List,
      --#                                Write_Rules &
      --#         Rule_Counter      from *,
      --#                                Dictionary.Dict,
      --#                                Heap,
      --#                                LexTokenManager.State,
      --#                                Prev_Cell,
      --#                                Scope,
      --#                                Tick_Cell,
      --#                                Write_Rules &
      --#         SPARK_IO.File_Sys from *,
      --#                                CommandLineData.Content,
      --#                                Dictionary.Dict,
      --#                                File,
      --#                                Heap,
      --#                                LexTokenManager.State,
      --#                                Prev_Cell,
      --#                                Rule_Counter,
      --#                                Rule_Family_Name,
      --#                                Rule_File,
      --#                                Scope,
      --#                                Tick_Cell,
      --#                                Write_Rules;
      is

         procedure Print_Attribute_Constant
         --# global in     CommandLineData.Content;
         --#        in     Dictionary.Dict;
         --#        in     File;
         --#        in     Heap;
         --#        in     LexTokenManager.State;
         --#        in     Scope;
         --#        in     Tick_Cell;
         --#        in     Type_List;
         --#        in     Write_Rules;
         --#        in out L_Heap;
         --#        in out SPARK_IO.File_Sys;
         --# derives L_Heap            from *,
         --#                                Heap,
         --#                                LexTokenManager.State,
         --#                                Tick_Cell,
         --#                                Type_List,
         --#                                Write_Rules &
         --#         SPARK_IO.File_Sys from *,
         --#                                CommandLineData.Content,
         --#                                Dictionary.Dict,
         --#                                File,
         --#                                Heap,
         --#                                LexTokenManager.State,
         --#                                Scope,
         --#                                Tick_Cell;
         is
            Lex_Str             : LexTokenManager.Lex_String;
            Prefix_Cell         : Cells.Cell;
            Has_Base            : Boolean;
            Already_Present, Ok : Boolean;

            procedure Print_Attribute_Type
              (File   : in SPARK_IO.File_Type;
               Scope  : in Dictionary.Scopes;
               Sym    : in Dictionary.Symbol;
               Attrib : in LexTokenManager.Lex_String)
            --# global in     CommandLineData.Content;
            --#        in     Dictionary.Dict;
            --#        in     LexTokenManager.State;
            --#        in out SPARK_IO.File_Sys;
            --# derives SPARK_IO.File_Sys from *,
            --#                                Attrib,
            --#                                CommandLineData.Content,
            --#                                Dictionary.Dict,
            --#                                File,
            --#                                LexTokenManager.State,
            --#                                Scope,
            --#                                Sym;
            is
               The_Type : Dictionary.Symbol;
            begin
               if Dictionary.IsTypeMark (Sym) then
                  The_Type := Sym;
               else
                  The_Type := Dictionary.GetType (Sym);
               end if;

               if Dictionary.IsArrayAttribute (Attrib, The_Type) then
                  Print_Symbol_Type
                    (File      => File,
                     Scope     => Scope,
                     Sub_Type  => False,
                     Component => False,
                     Sym       => Dictionary.GetArrayAttributeType (Attrib, The_Type, 1));
                  --note assumption of first index here pending expression evaluation
               else
                  Print_Symbol_Type
                    (File      => File,
                     Scope     => Scope,
                     Sub_Type  => False,
                     Component => False,
                     Sym       => Dictionary.GetScalarAttributeType (Attrib, The_Type));
               end if;
            end Print_Attribute_Type;

         begin -- Print_Attribute_Constant
            Has_Base    := False;
            Prefix_Cell := Cells.Get_A_Ptr (Heap, Tick_Cell);
            if Cells.Get_Kind (Heap, Prefix_Cell) = Cell_Storage.Op then
               Has_Base    := True;
               Prefix_Cell := Cells.Get_A_Ptr (Heap, Prefix_Cell);
            end if;

            SPARK_IO.Set_Col (File, Indent);
            SPARK_IO.Put_String (File, "const ", 0);

            -- Make copy of symbol in list of type for later rule generation
            if Write_Rules then
               --# accept Flow, 10, Ok, "Expected ineffective assignment to Ok" &
               --#        Flow, 10, Already_Present, "Expected ineffective assignment to Already_Present";

               --The Heap contains the full details of each referenced entity
               --(integer, myvariable, etc.), including information that
               --allows working out if the entity involves a base part
               --(__base) or the form of any any tick part (__first, __last,
               --etc.). With this fine grain information, FDL is generated
               --only for the specific entities that are referenced.
               --However, below, only the referenced entity name is recorded
               --and passed to rule generation (by referencing the cell
               --entity name in a list). With only this larger grain information,
               --every rule is generated for an entity (all base forms and
               --tick forms). Care needs to be taken to ensure that FDL is
               --generated for each entity that will be referenced in the
               --generated rules.
               Lists.Add_Symbol
                 (Heap            => L_Heap,
                  The_List        => Type_List,
                  Symbol          => Cells.Get_Symbol_Value (Heap, Prefix_Cell),
                  Already_Present => Already_Present,
                  Ok              => Ok);
               --# end accept;
            end if;

            Print_Symbol (File  => File,
                          Scope => Scope,
                          Sym   => Cells.Get_Symbol_Value (Heap, Prefix_Cell));
            if Has_Base then
               SPARK_IO.Put_String (File, "__base", 0);
            end if;
            SPARK_IO.Put_String (File, "__", 0);
            Lex_Str := Cells.Get_Lex_Str (Heap, Cells.Get_B_Ptr (Heap, Tick_Cell));
            E_Strings.Put_String
              (File  => File,
               E_Str => E_Strings.Lower_Case (E_Str => LexTokenManager.Lex_String_To_String (Lex_Str => Lex_Str)));
            SPARK_IO.Put_String (File, " : ", 0);
            Print_Attribute_Type
              (File   => File,
               Scope  => Scope,
               Sym    => Cells.Get_Symbol_Value (Heap, Prefix_Cell),
               Attrib => Lex_Str);
            SPARK_IO.Put_Line (File, " = pending; ", 0);
            --# accept Flow, 33, Ok, "Expected Ok to be neither referenced nor exported" &
            --#        Flow, 33, Already_Present, "Expected Already_Present to be neither referenced nor exported";
         end Print_Attribute_Constant;

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

         procedure Print_Attribute_Function
         --# global in     CommandLineData.Content;
         --#        in     Dictionary.Dict;
         --#        in     File;
         --#        in     Heap;
         --#        in     LexTokenManager.State;
         --#        in     Prev_Cell;
         --#        in     Rule_Family_Name;
         --#        in     Rule_File;
         --#        in     Scope;
         --#        in     Tick_Cell;
         --#        in     Write_Rules;
         --#        in out Rule_Counter;
         --#        in out SPARK_IO.File_Sys;
         --# derives Rule_Counter      from *,
         --#                                Dictionary.Dict,
         --#                                Heap,
         --#                                LexTokenManager.State,
         --#                                Prev_Cell,
         --#                                Scope,
         --#                                Tick_Cell,
         --#                                Write_Rules &
         --#         SPARK_IO.File_Sys from *,
         --#                                CommandLineData.Content,
         --#                                Dictionary.Dict,
         --#                                File,
         --#                                Heap,
         --#                                LexTokenManager.State,
         --#                                Prev_Cell,
         --#                                Rule_Counter,
         --#                                Rule_Family_Name,
         --#                                Rule_File,
         --#                                Scope,
         --#                                Tick_Cell,
         --#                                Write_Rules;
         is
            type Bounds is (Lower_Bound, Upper_Bound);

            Lex_Str                                            : LexTokenManager.Lex_String;
            Ex_Str                                             : E_Strings.T;
            Selector                                           : E_Strings.T;
            Brackets                                           : E_Strings.T;
            Component_Type, Index_Type, Rec_Variable, Type_Sym : Dictionary.Symbol;

            procedure Format_Record_Selector
              (Field_Name : in     Dictionary.Symbol;
               Selector   :    out E_Strings.T;
               Brackets   :    out E_Strings.T;
               Variable   :    out Dictionary.Symbol)
            -- Analyse the fieldname, creating a field selector to access it,
            -- and a balancing set of close brackets
            -- also pick out the variable name
            -- This is also safe to call when the variable is not a record
            --# global in Dictionary.Dict;
            --#        in LexTokenManager.State;
            --# derives Brackets,
            --#         Variable from Dictionary.Dict,
            --#                       Field_Name &
            --#         Selector from Dictionary.Dict,
            --#                       Field_Name,
            --#                       LexTokenManager.State;
            is
               Field : Dictionary.Symbol;                -- the current field
               Sel   : E_Strings.T;   -- the field selector
               Brk   : E_Strings.T;   -- the close bracket list
            begin
               Field := Field_Name;
               Sel   := E_Strings.Empty_String;
               Brk   := E_Strings.Empty_String;
               loop
                  -- exit when we've reached the variable name
                  exit when not Dictionary.IsSubcomponent (Field);
                  -- add the field selector to the end - note this serendipitously
                  -- generates the nested selectors in the corrrect order
                  E_Strings.Append_String (E_Str => Sel,
                                           Str   => "fld_");
                  E_Strings.Append_Examiner_String
                    (E_Str1 => Sel,
                     E_Str2 => E_Strings.Lower_Case
                       (E_Str => LexTokenManager.Lex_String_To_String (Lex_Str => Dictionary.GetSimpleName (Field))));
                  -- add a closing bracket, to match
                  E_Strings.Append_String (E_Str => Sel,
                                           Str   => "(");
                  E_Strings.Append_String (E_Str => Brk,
                                           Str   => ")");
                  -- get the enclosing field/variable
                  Field := Dictionary.GetEnclosingObject (Field);
               end loop;
               Selector := Sel;
               Brackets := Brk;
               Variable := Field;
            end Format_Record_Selector;

            procedure Print_Function_Header
            -- print the common function declaration header
            --# global in     CommandLineData.Content;
            --#        in     Dictionary.Dict;
            --#        in     Ex_Str;
            --#        in     File;
            --#        in     Heap;
            --#        in     LexTokenManager.State;
            --#        in     Scope;
            --#        in     Tick_Cell;
            --#        in out SPARK_IO.File_Sys;
            --# derives SPARK_IO.File_Sys from *,
            --#                                CommandLineData.Content,
            --#                                Dictionary.Dict,
            --#                                Ex_Str,
            --#                                File,
            --#                                Heap,
            --#                                LexTokenManager.State,
            --#                                Scope,
            --#                                Tick_Cell;
            is
            begin
               SPARK_IO.Set_Col (File, Indent);
               SPARK_IO.Put_String (File, "function ", 0);
               Print_Symbol
                 (File  => File,
                  Scope => Scope,
                  Sym   => Cells.Get_Symbol_Value (Heap, Cells.Get_A_Ptr (Heap, Tick_Cell)));
               SPARK_IO.Put_String (File, "__", 0);
               E_Strings.Put_String (File  => File,
                                     E_Str => E_Strings.Lower_Case (E_Str => Ex_Str));
            end Print_Function_Header;

            -- When Bound = Upper_Bound ->
            --    <Free_Var> <= <Type_Sym>__last.
            -- When Bound = Lower_Bound ->
            --    <Free_Var> >= <Type_Sym>__first.
            procedure Print_A_Bound_Constraint
              (Rule_File : in SPARK_IO.File_Type;
               Free_Var  : in String;
               Type_Sym  : in Dictionary.Symbol;
               Scope     : in Dictionary.Scopes;
               Bound     : in Bounds)
            --# global in     CommandLineData.Content;
            --#        in     Dictionary.Dict;
            --#        in     LexTokenManager.State;
            --#        in out SPARK_IO.File_Sys;
            --# derives SPARK_IO.File_Sys from *,
            --#                                Bound,
            --#                                CommandLineData.Content,
            --#                                Dictionary.Dict,
            --#                                Free_Var,
            --#                                LexTokenManager.State,
            --#                                Rule_File,
            --#                                Scope,
            --#                                Type_Sym;
            is
            begin
               if Bound = Lower_Bound then
                  SPARK_IO.Put_String (File => Rule_File,
                                       Item => Free_Var,
                                       Stop => 0);
                  SPARK_IO.Put_String (File => Rule_File,
                                       Item => " >= ",
                                       Stop => 0);
               else
                  SPARK_IO.Put_String (File => Rule_File,
                                       Item => Free_Var,
                                       Stop => 0);
                  SPARK_IO.Put_String (File => Rule_File,
                                       Item => " <= ",
                                       Stop => 0);
               end if;

               Print_Symbol (File  => Rule_File,
                             Scope => Scope,
                             Sym   => Type_Sym);

               if Bound = Lower_Bound then
                  SPARK_IO.Put_String (File => Rule_File,
                                       Item => "__first",
                                       Stop => 0);
               else
                  SPARK_IO.Put_String (File => Rule_File,
                                       Item => "__last",
                                       Stop => 0);
               end if;
            end Print_A_Bound_Constraint;

            -- Generically of the form dependent on Attribute, Bound and Complete:
            -- <Free_Var> <= <Type_Sym>__last may_be_deduced_from
            --   [ <Attr_Type>__<Attribute> ] .
            procedure Print_A_Bound_Rule
              (Rule_File : in SPARK_IO.File_Type;
               Free_Var  : in String;
               Type_Sym  : in Dictionary.Symbol;
               Scope     : in Dictionary.Scopes;
               Bound     : in Bounds;
               Attribute : in String;
               Attr_Type : in Dictionary.Symbol;
               Complete  : in Boolean)
            --# global in     CommandLineData.Content;
            --#        in     Dictionary.Dict;
            --#        in     LexTokenManager.State;
            --#        in out SPARK_IO.File_Sys;
            --# derives SPARK_IO.File_Sys from *,
            --#                                Attribute,
            --#                                Attr_Type,
            --#                                Bound,
            --#                                CommandLineData.Content,
            --#                                Complete,
            --#                                Dictionary.Dict,
            --#                                Free_Var,
            --#                                LexTokenManager.State,
            --#                                Rule_File,
            --#                                Scope,
            --#                                Type_Sym;
            is
            begin
               Print_A_Bound_Constraint
                 (Rule_File => Rule_File,
                  Free_Var  => Free_Var,
                  Type_Sym  => Type_Sym,
                  Scope     => Scope,
                  Bound     => Bound);
               SPARK_IO.Put_String (File => Rule_File,
                                    Item => " may_be_deduced",
                                    Stop => 0);

               if Attribute'Length > 0 then
                  SPARK_IO.Put_Line (File => Rule_File,
                                     Item => "_from",
                                     Stop => 0);
                  SPARK_IO.Put_String (File => Rule_File,
                                       Item => "     [ ",
                                       Stop => 0);
                  Print_Symbol (File  => Rule_File,
                                Scope => Scope,
                                Sym   => Attr_Type);
                  SPARK_IO.Put_String (File => Rule_File,
                                       Item => "__",
                                       Stop => 0);
                  SPARK_IO.Put_String (File => Rule_File,
                                       Item => Attribute,
                                       Stop => 0);
                  -- Complete determines whether to close off the predicate
                  -- or allow it to be extended.
                  if Complete then
                     SPARK_IO.Put_Line (File => Rule_File,
                                        Item => " ].",
                                        Stop => 0);
                  end if;
               else
                  SPARK_IO.Put_Line (File => Rule_File,
                                     Item => ".",
                                     Stop => 0);
               end if;
            end Print_A_Bound_Rule;

            -- Used to print side conditions to constrain that an index is in range.
            -- <Free_Var> <= <Type_Sym>__last,
            -- <Free_Var> >= <Type_Sym>__first
            procedure Print_An_Index_Constraint
              (Rule_File : in SPARK_IO.File_Type;
               Free_Var  : in String;
               Type_Sym  : in Dictionary.Symbol;
               Scope     : in Dictionary.Scopes;
               Complete  : in Boolean)
            --# global in     CommandLineData.Content;
            --#        in     Dictionary.Dict;
            --#        in     LexTokenManager.State;
            --#        in out SPARK_IO.File_Sys;
            --# derives SPARK_IO.File_Sys from *,
            --#                                CommandLineData.Content,
            --#                                Complete,
            --#                                Dictionary.Dict,
            --#                                Free_Var,
            --#                                LexTokenManager.State,
            --#                                Rule_File,
            --#                                Scope,
            --#                                Type_Sym;
            is
            begin
               SPARK_IO.Put_String (File => Rule_File,
                                    Item => "       ",
                                    Stop => 0);
               Print_A_Bound_Constraint
                 (Rule_File => Rule_File,
                  Free_Var  => Free_Var,
                  Type_Sym  => Type_Sym,
                  Scope     => Scope,
                  Bound     => Upper_Bound);
               SPARK_IO.Put_Line (File => Rule_File,
                                  Item => ",",
                                  Stop => 0);
               SPARK_IO.Put_String (File => Rule_File,
                                    Item => "       ",
                                    Stop => 0);
               Print_A_Bound_Constraint
                 (Rule_File => Rule_File,
                  Free_Var  => Free_Var,
                  Type_Sym  => Type_Sym,
                  Scope     => Scope,
                  Bound     => Lower_Bound);
               if Complete then
                  SPARK_IO.Put_Line (File => Rule_File,
                                     Item => " ].",
                                     Stop => 0);
               end if;
            end Print_An_Index_Constraint;

            -- Prints a rule of the form, dependent on Bound,
            -- (Bound = Upper_Bound) in example:
            --  element(A, [I]) <= <Component_Type>__last
            --   may_be_deduced_from [ <Array_Type>__always_valid(A),
            --                         I <= <Index_Type>__last,
            --                         I >= <Index_Type>__first ].
            procedure Print_A_Scalar_Array_Element_Rule
              (Rule_File      : in SPARK_IO.File_Type;
               Component_Type : in Dictionary.Symbol;
               Index_Type     : in Dictionary.Symbol;
               Array_Type     : in Dictionary.Symbol;
               Scope          : in Dictionary.Scopes;
               Bound          : in Bounds)
            --# global in     CommandLineData.Content;
            --#        in     Dictionary.Dict;
            --#        in     LexTokenManager.State;
            --#        in out SPARK_IO.File_Sys;
            --# derives SPARK_IO.File_Sys from *,
            --#                                Array_Type,
            --#                                Bound,
            --#                                CommandLineData.Content,
            --#                                Component_Type,
            --#                                Dictionary.Dict,
            --#                                Index_Type,
            --#                                LexTokenManager.State,
            --#                                Rule_File,
            --#                                Scope;
            is
            begin
               Print_A_Bound_Rule
                 (Rule_File => Rule_File,
                  Free_Var  => "element(A, [I])",
                  Type_Sym  => Component_Type,
                  Scope     => Scope,
                  Bound     => Bound,
                  Attribute => "always_valid(A)",
                  Attr_Type => Array_Type,
                  Complete  => False);
               if not Dictionary.TypeIsBoolean (Index_Type) then
                  -- Extend the bound rule with index constraints.
                  SPARK_IO.Put_Line (File => Rule_File,
                                     Item => ",",
                                     Stop => 0);
                  Print_An_Index_Constraint
                    (Rule_File => Rule_File,
                     Free_Var  => "I",
                     Type_Sym  => Index_Type,
                     Scope     => Scope,
                     Complete  => False);
               end if;
               -- Complete the rule.
               SPARK_IO.Put_Line (File => Rule_File,
                                  Item => " ].",
                                  Stop => 0);
            end Print_A_Scalar_Array_Element_Rule;

            -- Prints a rule of the form, dependent on Bound,
            -- (Bound = Upper_Bound) in example:
            -- fld_<Field_Name>(R) <= <Field_Type>__last
            --   [ may_be_deduced_from <Record_Type>__always_valid(R) ].
            procedure Print_A_Scalar_Record_Component_Rule
              (Rule_File       : in SPARK_IO.File_Type;
               Constrained_Var : in String;
               Applied_Var     : in String;
               Record_Type     : in Dictionary.Symbol;
               Field_Name      : in Dictionary.Symbol;
               Field_Type      : in Dictionary.Symbol;
               Scope           : in Dictionary.Scopes;
               Bound           : in Bounds;
               Complete        : in Boolean)
            --# global in     CommandLineData.Content;
            --#        in     Dictionary.Dict;
            --#        in     LexTokenManager.State;
            --#        in out SPARK_IO.File_Sys;
            --# derives SPARK_IO.File_Sys from *,
            --#                                Applied_Var,
            --#                                Bound,
            --#                                CommandLineData.Content,
            --#                                Complete,
            --#                                Constrained_Var,
            --#                                Dictionary.Dict,
            --#                                Field_Name,
            --#                                Field_Type,
            --#                                LexTokenManager.State,
            --#                                Record_Type,
            --#                                Rule_File,
            --#                                Scope;
            is
            begin
               SPARK_IO.Put_String (File => Rule_File,
                                    Item => "fld_",
                                    Stop => 0);
               Print_Symbol (File  => Rule_File,
                             Scope => Scope,
                             Sym   => Field_Name);
               Print_A_Bound_Rule
                 (Rule_File => Rule_File,
                  Free_Var  => Constrained_Var,
                  Type_Sym  => Field_Type,
                  Scope     => Scope,
                  Bound     => Bound,
                  Attribute => Applied_Var,
                  Attr_Type => Record_Type,
                  Complete  => Complete);
            end Print_A_Scalar_Record_Component_Rule;

            -- Prints a rule of the form, dependent on Bound,
            -- (Bound = Upper_Bound) in example:
            -- element(fld_<Field_Name>(R), [I]) <= <Field_Type>__last
            --   may_be_deduced_from
            --   [ <Record_Type>__always_valid(R),
            --     I <= <Index_Type>__last,
            --     I >= <Index_Type>__first ].
            procedure Print_An_Array_Record_Component_Rule
              (Rule_File       : in SPARK_IO.File_Type;
               Constrained_Var : in String;
               Applied_Var     : in String;
               Record_Type     : in Dictionary.Symbol;
               Field_Name      : in Dictionary.Symbol;
               Array_Comp_Type : in Dictionary.Symbol;
               Index_Type      : in Dictionary.Symbol;
               Scope           : in Dictionary.Scopes;
               Bound           : in Bounds;
               Complete        : in Boolean)
            --# global in     CommandLineData.Content;
            --#        in     Dictionary.Dict;
            --#        in     LexTokenManager.State;
            --#        in out SPARK_IO.File_Sys;
            --# derives SPARK_IO.File_Sys from *,
            --#                                Applied_Var,
            --#                                Array_Comp_Type,
            --#                                Bound,
            --#                                CommandLineData.Content,
            --#                                Complete,
            --#                                Constrained_Var,
            --#                                Dictionary.Dict,
            --#                                Field_Name,
            --#                                Index_Type,
            --#                                LexTokenManager.State,
            --#                                Record_Type,
            --#                                Rule_File,
            --#                                Scope;
            is
            begin
               SPARK_IO.Put_String (File => Rule_File,
                                    Item => "element(fld_",
                                    Stop => 0);
               Print_Symbol (File  => Rule_File,
                             Scope => Scope,
                             Sym   => Field_Name);
               Print_A_Bound_Rule
                 (Rule_File => Rule_File,
                  Free_Var  => Constrained_Var,
                  Type_Sym  => Array_Comp_Type,
                  Scope     => Scope,
                  Bound     => Bound,
                  Attribute => Applied_Var,
                  Attr_Type => Record_Type,
                  Complete  => False);

               if not Dictionary.TypeIsBoolean (Index_Type) then
                  -- Extend the bound rule with index constraints.
                  SPARK_IO.Put_Line (File => Rule_File,
                                     Item => ",",
                                     Stop => 0);
                  Print_An_Index_Constraint
                    (Rule_File => Rule_File,
                     Free_Var  => "I",
                     Type_Sym  => Index_Type,
                     Scope     => Scope,
                     Complete  => False);
               end if;
               if Complete then
                  SPARK_IO.Put_Line (File => Rule_File,
                                     Item => " ].",
                                     Stop => 0);
               end if;
            end Print_An_Array_Record_Component_Rule;

            -- Prints the rules related to all components of a record
            -- using the procedures Print_A_Scalar_Record_Component_Rule and
            -- Print_An_Array_Record_Component_Rule as appropriate.
            procedure Print_Record_Rules
              (Rule_File   : in SPARK_IO.File_Type;
               Record_Type : in Dictionary.Symbol;
               Scope       : in Dictionary.Scopes)
            --# global in     CommandLineData.Content;
            --#        in     Dictionary.Dict;
            --#        in     LexTokenManager.State;
            --#        in     Rule_Family_Name;
            --#        in out Rule_Counter;
            --#        in out SPARK_IO.File_Sys;
            --# derives Rule_Counter      from *,
            --#                                Dictionary.Dict,
            --#                                Record_Type,
            --#                                Scope &
            --#         SPARK_IO.File_Sys from *,
            --#                                CommandLineData.Content,
            --#                                Dictionary.Dict,
            --#                                LexTokenManager.State,
            --#                                Record_Type,
            --#                                Rule_Counter,
            --#                                Rule_Family_Name,
            --#                                Rule_File,
            --#                                Scope;
            is
               Iterator                                                : Dictionary.Iterator;
               Array_Comp_Type, Curr_Symbol, Index_Type, Rec_Comp_Type : Dictionary.Symbol;
            begin
               Iterator := Dictionary.FirstRecordComponent (Record_Type);
               while not Dictionary.IsNullIterator (Iterator) loop
                  Curr_Symbol   := Dictionary.CurrentSymbol (Iterator);
                  Rec_Comp_Type := Dictionary.GetType (Curr_Symbol);
                  if not Dictionary.Is_Null_Symbol (Rec_Comp_Type) then
                     if Dictionary.IsScalarTypeMark (Rec_Comp_Type, Scope) then
                        Print_Rule_Name (Rule_File => Rule_File);
                        Print_A_Scalar_Record_Component_Rule
                          (Rule_File       => Rule_File,
                           Constrained_Var => "(R)",
                           Applied_Var     => "always_valid(R)",
                           Record_Type     => Record_Type,
                           Field_Name      => Curr_Symbol,
                           Field_Type      => Rec_Comp_Type,
                           Scope           => Scope,
                           Bound           => Upper_Bound,
                           Complete        => True);
                        Print_Rule_Name (Rule_File => Rule_File);
                        Print_A_Scalar_Record_Component_Rule
                          (Rule_File       => Rule_File,
                           Constrained_Var => "(R)",
                           Applied_Var     => "always_valid(R)",
                           Record_Type     => Record_Type,
                           Field_Name      => Curr_Symbol,
                           Field_Type      => Rec_Comp_Type,
                           Scope           => Scope,
                           Bound           => Lower_Bound,
                           Complete        => True);
                     elsif Dictionary.IsArrayTypeMark (Rec_Comp_Type, Scope) then
                        -- Semantic checks ensure that it is an array of scalars
                        -- It is an array type mark so get the component type
                        -- and index type.
                        Array_Comp_Type := Dictionary.GetArrayComponent (Rec_Comp_Type);
                        Index_Type      := Dictionary.GetArrayIndex (Rec_Comp_Type, 1);

                        -- We assume that the array is one-dimensional
                        -- and the index type is discrete:
                        -- these constraints are enforced by static semantic checks.

                        -- Check if the components of the array are scalar and
                        -- non Boolean.
                        if Dictionary.IsScalarTypeMark (Array_Comp_Type, Scope) and
                          not Dictionary.TypeIsBoolean (Array_Comp_Type) then
                           Print_Rule_Name (Rule_File => Rule_File);
                           Print_An_Array_Record_Component_Rule
                             (Rule_File       => Rule_File,
                              Constrained_Var => "(R), [I])",
                              Applied_Var     => "always_valid(R)",
                              Record_Type     => Record_Type,
                              Field_Name      => Curr_Symbol,
                              Array_Comp_Type => Array_Comp_Type,
                              Index_Type      => Index_Type,
                              Scope           => Scope,
                              Bound           => Upper_Bound,
                              Complete        => True);
                           Print_Rule_Name (Rule_File => Rule_File);
                           Print_An_Array_Record_Component_Rule
                             (Rule_File       => Rule_File,
                              Constrained_Var => "(R), [I])",
                              Applied_Var     => "always_valid(R)",
                              Record_Type     => Record_Type,
                              Field_Name      => Curr_Symbol,
                              Array_Comp_Type => Array_Comp_Type,
                              Index_Type      => Index_Type,
                              Scope           => Scope,
                              Bound           => Lower_Bound,
                              Complete        => True);
                        end if;
                     end if;
                  end if;
                  Iterator := Dictionary.NextSymbol (Iterator);
               end loop;
            end Print_Record_Rules;

            -- Prints the rules related to all components of a record
            -- which is an element of an array, A,
            -- using the procedures Print_A_Scalar_Record_Component_Rule and
            -- Print_An_Array_Record_Component_Rule as appropriate in conjunction
            -- with Print_An_Index_Constraint to cover the index of A.
            procedure Print_Array_Of_Record_Rules
              (Rule_File   : in SPARK_IO.File_Type;
               Array_Type  : in Dictionary.Symbol;
               Outer_Index : in Dictionary.Symbol;
               Record_Type : in Dictionary.Symbol;
               Scope       : in Dictionary.Scopes)
            --# global in     CommandLineData.Content;
            --#        in     Dictionary.Dict;
            --#        in     LexTokenManager.State;
            --#        in     Rule_Family_Name;
            --#        in out Rule_Counter;
            --#        in out SPARK_IO.File_Sys;
            --# derives Rule_Counter      from *,
            --#                                Dictionary.Dict,
            --#                                Record_Type,
            --#                                Scope &
            --#         SPARK_IO.File_Sys from *,
            --#                                Array_Type,
            --#                                CommandLineData.Content,
            --#                                Dictionary.Dict,
            --#                                LexTokenManager.State,
            --#                                Outer_Index,
            --#                                Record_Type,
            --#                                Rule_Counter,
            --#                                Rule_Family_Name,
            --#                                Rule_File,
            --#                                Scope;
            is
               Iterator                                                : Dictionary.Iterator;
               Array_Comp_Type, Curr_Symbol, Index_Type, Rec_Comp_Type : Dictionary.Symbol;
            begin
               Iterator := Dictionary.FirstRecordComponent (Record_Type);
               while not Dictionary.IsNullIterator (Iterator) loop
                  Curr_Symbol   := Dictionary.CurrentSymbol (Iterator);
                  Rec_Comp_Type := Dictionary.GetType (Curr_Symbol);
                  if not Dictionary.Is_Null_Symbol (Rec_Comp_Type) then
                     if Dictionary.IsScalarTypeMark (Rec_Comp_Type, Scope) then
                        Print_Rule_Name (Rule_File => Rule_File);
                        Print_A_Scalar_Record_Component_Rule
                          (Rule_File       => Rule_File,
                           Constrained_Var => "(element(A, [I]))",
                           Applied_Var     => "always_valid(A)",
                           Record_Type     => Array_Type,
                           Field_Name      => Curr_Symbol,
                           Field_Type      => Rec_Comp_Type,
                           Scope           => Scope,
                           Bound           => Upper_Bound,
                           Complete        => False);
                        SPARK_IO.Put_Line (File => Rule_File,
                                           Item => ",",
                                           Stop => 0);
                        Print_An_Index_Constraint
                          (Rule_File => Rule_File,
                           Free_Var  => "I",
                           Type_Sym  => Outer_Index,
                           Scope     => Scope,
                           Complete  => True);
                        Print_Rule_Name (Rule_File => Rule_File);
                        Print_A_Scalar_Record_Component_Rule
                          (Rule_File       => Rule_File,
                           Constrained_Var => "(element(A, [I]))",
                           Applied_Var     => "always_valid(A)",
                           Record_Type     => Array_Type,
                           Field_Name      => Curr_Symbol,
                           Field_Type      => Rec_Comp_Type,
                           Scope           => Scope,
                           Bound           => Lower_Bound,
                           Complete        => False);
                        SPARK_IO.Put_Line (File => Rule_File,
                                           Item => ",",
                                           Stop => 0);
                        Print_An_Index_Constraint
                          (Rule_File => Rule_File,
                           Free_Var  => "I",
                           Type_Sym  => Outer_Index,
                           Scope     => Scope,
                           Complete  => True);
                     elsif Dictionary.IsArrayTypeMark (Rec_Comp_Type, Scope) then
                        -- Semantic checks ensure that it is an array of scalars
                        -- It is an array type mark so get the component type
                        -- and index type.
                        Array_Comp_Type := Dictionary.GetArrayComponent (Rec_Comp_Type);
                        Index_Type      := Dictionary.GetArrayIndex (Rec_Comp_Type, 1);

                        -- We assume that the array is one-dimensional
                        -- and the index type is discrete:
                        -- these constraints are enforced by static semantic checks.

                        -- Check if the components of the array are scalar and
                        -- non Boolean.
                        if Dictionary.IsScalarTypeMark (Array_Comp_Type, Scope) and
                          not Dictionary.TypeIsBoolean (Array_Comp_Type) then
                           Print_Rule_Name (Rule_File => Rule_File);
                           Print_An_Array_Record_Component_Rule
                             (Rule_File       => Rule_File,
                              Constrained_Var => "(element(A, [I])), [J])",
                              Applied_Var     => "always_valid(A)",
                              Record_Type     => Array_Type,
                              Field_Name      => Curr_Symbol,
                              Array_Comp_Type => Array_Comp_Type,
                              Index_Type      => Index_Type,
                              Scope           => Scope,
                              Bound           => Upper_Bound,
                              Complete        => False);
                           SPARK_IO.Put_Line (File => Rule_File,
                                              Item => ",",
                                              Stop => 0);
                           Print_An_Index_Constraint
                             (Rule_File => Rule_File,
                              Free_Var  => "J",
                              Type_Sym  => Outer_Index,
                              Scope     => Scope,
                              Complete  => True);
                           Print_Rule_Name (Rule_File => Rule_File);
                           Print_An_Array_Record_Component_Rule
                             (Rule_File       => Rule_File,
                              Constrained_Var => "(element(A, [I])), [J])",
                              Applied_Var     => "always_valid(A)",
                              Record_Type     => Array_Type,
                              Field_Name      => Curr_Symbol,
                              Array_Comp_Type => Array_Comp_Type,
                              Index_Type      => Index_Type,
                              Scope           => Scope,
                              Bound           => Lower_Bound,
                              Complete        => False);
                           SPARK_IO.Put_Line (File => Rule_File,
                                              Item => ",",
                                              Stop => 0);
                           Print_An_Index_Constraint
                             (Rule_File => Rule_File,
                              Free_Var  => "J",
                              Type_Sym  => Outer_Index,
                              Scope     => Scope,
                              Complete  => True);
                        end if;
                     end if;
                  end if;
                  Iterator := Dictionary.NextSymbol (Iterator);
               end loop;
            end Print_Array_Of_Record_Rules;

         begin -- Print_Attribute_Function

            -- Function attributes will have had 'BASE eliminated in model build
            Lex_Str := Cells.Get_Lex_Str (Heap, Cells.Get_B_Ptr (Heap, Tick_Cell));
            Ex_Str  := LexTokenManager.Lex_String_To_String (Lex_Str => Lex_Str);

            -- Support for 'Valid in SPARK95
            if LexTokenManager.Lex_String_Case_Insensitive_Compare (Lex_Str1 => Lex_Str,
                                                                    Lex_Str2 => LexTokenManager.Valid_Token) =
              LexTokenManager.Str_Eq then
               Print_Function_Header;
               Type_Sym := Cells.Get_Symbol_Value (Heap, Cells.Get_A_Ptr (Heap, Tick_Cell));
               SPARK_IO.Put_Char (File, '(');
               Print_Symbol_Type (File      => File,
                                  Scope     => Scope,
                                  Sub_Type  => False,
                                  Component => False,
                                  Sym       => Type_Sym);
               SPARK_IO.Put_String (File, ") : boolean;", 0);

               -- and associated rules
               if Write_Rules then
                  -- first rule
                  Print_Rule_Name (Rule_File => Rule_File);
                  Print_A_Bound_Rule
                    (Rule_File => Rule_File,
                     Free_Var  => "X",
                     Type_Sym  => Type_Sym,
                     Scope     => Scope,
                     Bound     => Upper_Bound,
                     Attribute => "valid(X)",
                     Attr_Type => Type_Sym,
                     Complete  => True);
                  -- second rule
                  Print_Rule_Name (Rule_File => Rule_File);
                  Print_A_Bound_Rule
                    (Rule_File => Rule_File,
                     Free_Var  => "X",
                     Type_Sym  => Type_Sym,
                     Scope     => Scope,
                     Bound     => Lower_Bound,
                     Attribute => "valid(X)",
                     Attr_Type => Type_Sym,
                     Complete  => True);
               end if;

               -- Support for 'Always_Valid
            elsif LexTokenManager.Lex_String_Case_Insensitive_Compare
              (Lex_Str1 => Lex_Str,
               Lex_Str2 => LexTokenManager.Always_Valid_Token) =
              LexTokenManager.Str_Eq then
               Type_Sym := Cells.Get_Symbol_Value (Heap, Cells.Get_A_Ptr (Heap, Tick_Cell));

               -- Only output the declarations and generic rules if this is the
               -- first occurance of 'Always_Valid for this type
               -- The simplification rule is always output, since it contains
               -- the variable name, and possibly the field selectors
               if Cells.Is_Null_Cell (Prev_Cell)
                 or else LexTokenManager.Lex_String_Case_Insensitive_Compare
                 (Lex_Str1 => Cells.Get_Lex_Str (Heap, Cells.Get_B_Ptr (Heap, Prev_Cell)),
                  Lex_Str2 => LexTokenManager.Always_Valid_Token) /=
                 LexTokenManager.Str_Eq
                 or else Cells.Get_Symbol_Value (Heap, Cells.Get_A_Ptr (Heap, Tick_Cell)) /=
                 Cells.Get_Symbol_Value (Heap, Cells.Get_A_Ptr (Heap, Prev_Cell)) then
                  Print_Function_Header;
                  SPARK_IO.Put_Char (File, '(');
                  Print_Symbol_Type (File      => File,
                                     Scope     => Scope,
                                     Sub_Type  => False,
                                     Component => False,
                                     Sym       => Type_Sym);
                  SPARK_IO.Put_String (File, ") : boolean;", 0);
                  -- and the associated rules that must only be output once per type
                  if Write_Rules then
                     if Dictionary.IsScalarTypeMark (Type_Sym, Scope) then
                        -- first rule: X <= type__last may_be_deduced_from [ type__always_valid(X) ].
                        Print_Rule_Name (Rule_File => Rule_File);
                        Print_A_Bound_Rule
                          (Rule_File => Rule_File,
                           Free_Var  => "X",
                           Type_Sym  => Type_Sym,
                           Scope     => Scope,
                           Bound     => Upper_Bound,
                           Attribute => "always_valid(X)",
                           Attr_Type => Type_Sym,
                           Complete  => True);
                        -- second rule: X >= type__first may_be_deduced_from [ type__always_valid(X) ].
                        Print_Rule_Name (Rule_File => Rule_File);
                        Print_A_Bound_Rule
                          (Rule_File => Rule_File,
                           Free_Var  => "X",
                           Type_Sym  => Type_Sym,
                           Scope     => Scope,
                           Bound     => Lower_Bound,
                           Attribute => "always_valid(X)",
                           Attr_Type => Type_Sym,
                           Complete  => True);
                     elsif
                       -- If an array is always valid then all of its components
                       -- are always valid:

                       -- First check if the symbol is an array type mark of which
                       -- the complete type declaration is visible.
                       not Dictionary.Is_Null_Symbol (Type_Sym)
                       and then (not Dictionary.IsPrivateType (Type_Sym, Scope))
                       and then Dictionary.IsArrayTypeMark (Type_Sym, Scope) then
                        -- It is an array type mark so get the component type
                        -- and index type.
                        Component_Type := Dictionary.GetArrayComponent (Type_Sym);
                        Index_Type     := Dictionary.GetArrayIndex (Type_Sym, 1);

                        -- We assume that the array is one-dimensional
                        -- and the index type is discrete:
                        -- these constraints are enforced by static semantic checks.

                        -- Check if the components of the array are scalar
                        if Dictionary.IsScalarTypeMark (Component_Type, Scope) and
                          not Dictionary.TypeIsBoolean (Component_Type) then
                           -- The components of the array are scalar
                           -- Generate deduduction rules that all scalar,
                           -- non-Boolean components are in type, eg,
                           -- element(A, [I]) >= safe_value_type__first
                           --    may_be_deduced_from
                           -- [array_type__always_valid(A),
                           --  I >= array_range__first, I <= array_range__last] .
                           -- and
                           -- element(A, [I]) <= safe_value_type__last
                           --    may_be_deduced_from
                           -- [array_type__always_valid(A),
                           -- I >= array_range__first, I <= array_range__last] .
                           Print_Rule_Name (Rule_File => Rule_File);
                           Print_A_Scalar_Array_Element_Rule
                             (Rule_File      => Rule_File,
                              Component_Type => Component_Type,
                              Index_Type     => Index_Type,
                              Array_Type     => Type_Sym,
                              Scope          => Scope,
                              Bound          => Upper_Bound);
                           Print_Rule_Name (Rule_File => Rule_File);
                           Print_A_Scalar_Array_Element_Rule
                             (Rule_File      => Rule_File,
                              Component_Type => Component_Type,
                              Index_Type     => Index_Type,
                              Array_Type     => Type_Sym,
                              Scope          => Scope,
                              Bound          => Lower_Bound);
                        elsif Dictionary.IsRecordTypeMark (Component_Type, Scope) then
                           Print_Array_Of_Record_Rules
                             (Rule_File   => Rule_File,
                              Array_Type  => Type_Sym,
                              Outer_Index => Index_Type,
                              Record_Type => Component_Type,
                              Scope       => Scope);
                        end if;
                     elsif
                       -- If a record is always valid then all of its components
                       -- are always valid:

                       -- First check if the symbol is a record type mark of which
                       -- the complete type declaration is visible.
                       not Dictionary.Is_Null_Symbol (Type_Sym)
                       and then (not Dictionary.IsPrivateType (Type_Sym, Scope))
                       and then Dictionary.IsRecordTypeMark (Type_Sym, Scope) then
                        Print_Record_Rules (Rule_File   => Rule_File,
                                            Record_Type => Type_Sym,
                                            Scope       => Scope);
                     end if;
                  end if;
               end if;
               if Write_Rules then
                  -- third rule: type__always_valid(variable__tail(X))
                  --                       may_be_deduced_from type__always_valid(X).
                  Format_Record_Selector
                    (Field_Name => Cells.Get_Assoc_Var (Heap, Cells.Get_A_Ptr (Heap, Tick_Cell)),
                     Selector   => Selector,
                     Brackets   => Brackets,
                     Variable   => Rec_Variable);

                  --                  Debug.PrintMsg ("Format_Record_Selector: ", False);
                  --                  E_Strings.PutString (SPARK_IO.Standard_Output, Selector);
                  --                  Debug.PrintMsg ("", True);
                  --                  Debug.PrintSym ("Format_Record_Selector Sym: ", Rec_Variable);

                  Print_Rule_Name (Rule_File => Rule_File);
                  Print_Symbol
                    (File  => Rule_File,
                     Scope => Scope,
                     Sym   => Cells.Get_Symbol_Value (Heap, Cells.Get_A_Ptr (Heap, Tick_Cell)));
                  SPARK_IO.Put_String (Rule_File, "__always_valid(", 0);
                  E_Strings.Put_String (File  => Rule_File,
                                        E_Str => Selector);
                  Print_Symbol (File  => Rule_File,
                                Scope => Scope,
                                Sym   => Rec_Variable);

                  SPARK_IO.Put_String (Rule_File, "__tail(X))", 0);

                  E_Strings.Put_String (File  => Rule_File,
                                        E_Str => Brackets);
                  SPARK_IO.New_Line (Rule_File, 1);
                  SPARK_IO.Put_String (Rule_File, "     may_be_deduced_from [", 0);
                  Print_Symbol
                    (File  => Rule_File,
                     Scope => Scope,
                     Sym   => Cells.Get_Symbol_Value (Heap, Cells.Get_A_Ptr (Heap, Tick_Cell)));
                  SPARK_IO.Put_String (Rule_File, "__always_valid(", 0);
                  E_Strings.Put_String (File  => Rule_File,
                                        E_Str => Selector);
                  SPARK_IO.Put_String (Rule_File, "X)", 0);

                  E_Strings.Put_String (File  => Rule_File,
                                        E_Str => Brackets);
                  SPARK_IO.Put_Line (Rule_File, "].", 0);
               end if;

            elsif LexTokenManager.Lex_String_Case_Insensitive_Compare (Lex_Str1 => Lex_Str,
                                                                       Lex_Str2 => LexTokenManager.Min_Token) =
              LexTokenManager.Str_Eq
              or else LexTokenManager.Lex_String_Case_Insensitive_Compare
              (Lex_Str1 => Lex_Str,
               Lex_Str2 => LexTokenManager.Max_Token) =
              LexTokenManager.Str_Eq then
               Print_Function_Header;
               SPARK_IO.Put_Char (File, '(');
               Print_Symbol_Type
                 (File      => File,
                  Scope     => Scope,
                  Sub_Type  => False,
                  Component => False,
                  Sym       => Cells.Get_Symbol_Value (Heap, Cells.Get_A_Ptr (Heap, Tick_Cell)));
               SPARK_IO.Put_String (File, ", ", 0);
               Print_Symbol_Type
                 (File      => File,
                  Scope     => Scope,
                  Sub_Type  => False,
                  Component => False,
                  Sym       => Cells.Get_Symbol_Value (Heap, Cells.Get_A_Ptr (Heap, Tick_Cell)));
               SPARK_IO.Put_String (File, ") : ", 0);
               Print_Symbol_Type
                 (File      => File,
                  Scope     => Scope,
                  Sub_Type  => False,
                  Component => False,
                  Sym       => Cells.Get_Symbol_Value (Heap, Cells.Get_A_Ptr (Heap, Tick_Cell)));
               SPARK_IO.Put_String (File, ";", 0);

               -- Now produce rules for Min and Max.
               -- The Ada LRM states that S'Max denotes a function with the following specification:
               --    function S'Max(Left, Right : S'Base)
               --       return S'Base;
               -- (and similarly for S'Min).
               if Write_Rules then
                  -- first case
                  Print_Rule_Name (Rule_File => Rule_File);
                  Print_Symbol
                    (File  => Rule_File,
                     Scope => Scope,
                     Sym   => Cells.Get_Symbol_Value (Heap, Cells.Get_A_Ptr (Heap, Tick_Cell)));
                  SPARK_IO.Put_String (Rule_File, "__", 0);
                  Lex_Str := Cells.Get_Lex_Str (Heap, Cells.Get_B_Ptr (Heap, Tick_Cell));
                  E_Strings.Put_String
                    (File  => Rule_File,
                     E_Str => E_Strings.Lower_Case (E_Str => LexTokenManager.Lex_String_To_String (Lex_Str => Lex_Str)));
                  SPARK_IO.Put_String (Rule_File, "(X, Y) may_be_replaced_by ", 0);
                  if LexTokenManager.Lex_String_Case_Insensitive_Compare
                    (Lex_Str1 => Lex_Str,
                     Lex_Str2 => LexTokenManager.Max_Token) =
                    LexTokenManager.Str_Eq then
                     SPARK_IO.Put_Char (Rule_File, 'X');
                  else
                     SPARK_IO.Put_Char (Rule_File, 'Y');
                  end if;
                  SPARK_IO.Put_Line (Rule_File, " if [X >= Y].", 0);
                  -- second case
                  Print_Rule_Name (Rule_File => Rule_File);
                  Print_Symbol
                    (File  => Rule_File,
                     Scope => Scope,
                     Sym   => Cells.Get_Symbol_Value (Heap, Cells.Get_A_Ptr (Heap, Tick_Cell)));
                  SPARK_IO.Put_String (Rule_File, "__", 0);
                  Lex_Str := Cells.Get_Lex_Str (Heap, Cells.Get_B_Ptr (Heap, Tick_Cell));
                  E_Strings.Put_String
                    (File  => Rule_File,
                     E_Str => E_Strings.Lower_Case (E_Str => LexTokenManager.Lex_String_To_String (Lex_Str => Lex_Str)));
                  SPARK_IO.Put_String (Rule_File, "(X, Y) may_be_replaced_by ", 0);
                  if LexTokenManager.Lex_String_Case_Insensitive_Compare
                    (Lex_Str1 => Lex_Str,
                     Lex_Str2 => LexTokenManager.Max_Token) =
                    LexTokenManager.Str_Eq then
                     SPARK_IO.Put_Char (Rule_File, 'Y');
                  else
                     SPARK_IO.Put_Char (Rule_File, 'X');
                  end if;
                  SPARK_IO.Put_Line (Rule_File, " if [Y >= X].", 0);
                  -- type range of output
                  -- lower bound
                  Print_Rule_Name (Rule_File => Rule_File);
                  Print_Symbol
                    (File  => Rule_File,
                     Scope => Scope,
                     Sym   => Cells.Get_Symbol_Value (Heap, Cells.Get_A_Ptr (Heap, Tick_Cell)));
                  SPARK_IO.Put_String (Rule_File, "__", 0);
                  Lex_Str := Cells.Get_Lex_Str (Heap, Cells.Get_B_Ptr (Heap, Tick_Cell));
                  E_Strings.Put_String
                    (File  => Rule_File,
                     E_Str => E_Strings.Lower_Case (E_Str => LexTokenManager.Lex_String_To_String (Lex_Str => Lex_Str)));
                  SPARK_IO.Put_String (Rule_File, "(X, Y) >= ", 0);
                  Print_Symbol
                    (File  => Rule_File,
                     Scope => Scope,
                     Sym   => Cells.Get_Symbol_Value (Heap, Cells.Get_A_Ptr (Heap, Tick_Cell)));
                  SPARK_IO.Put_Line (Rule_File, "__base__first may_be_deduced.", 0);
                  -- upper bound
                  Print_Rule_Name (Rule_File => Rule_File);
                  Print_Symbol
                    (File  => Rule_File,
                     Scope => Scope,
                     Sym   => Cells.Get_Symbol_Value (Heap, Cells.Get_A_Ptr (Heap, Tick_Cell)));
                  SPARK_IO.Put_String (Rule_File, "__", 0);
                  Lex_Str := Cells.Get_Lex_Str (Heap, Cells.Get_B_Ptr (Heap, Tick_Cell));
                  E_Strings.Put_String
                    (File  => Rule_File,
                     E_Str => E_Strings.Lower_Case (E_Str => LexTokenManager.Lex_String_To_String (Lex_Str => Lex_Str)));
                  SPARK_IO.Put_String (Rule_File, "(X, Y) <= ", 0);
                  Print_Symbol
                    (File  => Rule_File,
                     Scope => Scope,
                     Sym   => Cells.Get_Symbol_Value (Heap, Cells.Get_A_Ptr (Heap, Tick_Cell)));
                  SPARK_IO.Put_Line (Rule_File, "__base__last may_be_deduced.", 0);
               end if; -- Min and Max rules

               -- side effect modelling attributes for stream reads
            elsif LexTokenManager.Lex_String_Case_Insensitive_Compare
              (Lex_Str1 => Lex_Str,
               Lex_Str2 => LexTokenManager.Tail_Token) =
              LexTokenManager.Str_Eq then
               Print_Function_Header;
               SPARK_IO.Put_Char (File, '(');
               Print_Symbol_Type
                 (File      => File,
                  Scope     => Scope,
                  Sub_Type  => False,
                  Component => False,
                  Sym       => Cells.Get_Symbol_Value (Heap, Cells.Get_A_Ptr (Heap, Tick_Cell)));
               SPARK_IO.Put_String (File, ") : ", 0);
               Print_Symbol_Type
                 (File      => File,
                  Scope     => Scope,
                  Sub_Type  => False,
                  Component => False,
                  Sym       => Cells.Get_Symbol_Value (Heap, Cells.Get_A_Ptr (Heap, Tick_Cell)));
               SPARK_IO.Put_String (File, ";", 0);

               -- side effect modelling attributes for streams writes
            elsif LexTokenManager.Lex_String_Case_Insensitive_Compare
              (Lex_Str1 => Lex_Str,
               Lex_Str2 => LexTokenManager.Append_Token) =
              LexTokenManager.Str_Eq then
               Print_Function_Header;
               SPARK_IO.Put_Char (File, '(');
               Print_Symbol_Type
                 (File      => File,
                  Scope     => Scope,
                  Sub_Type  => False,
                  Component => False,
                  Sym       => Cells.Get_Symbol_Value (Heap, Cells.Get_A_Ptr (Heap, Tick_Cell)));
               SPARK_IO.Put_String (File, ", ", 0);
               Print_Symbol_Type
                 (File      => File,
                  Scope     => Scope,
                  Sub_Type  => False,
                  Component => False,
                  Sym       => Cells.Get_Symbol_Value (Heap, Cells.Get_A_Ptr (Heap, Tick_Cell)));
               SPARK_IO.Put_String (File, ") : ", 0);
               Print_Symbol_Type
                 (File      => File,
                  Scope     => Scope,
                  Sub_Type  => False,
                  Component => False,
                  Sym       => Cells.Get_Symbol_Value (Heap, Cells.Get_A_Ptr (Heap, Tick_Cell)));
               SPARK_IO.Put_String (File, ";", 0);

            elsif LexTokenManager.Lex_String_Case_Insensitive_Compare (Lex_Str1 => Lex_Str,
                                                                       Lex_Str2 => LexTokenManager.Pos_Token) =
              LexTokenManager.Str_Eq then
               Print_Function_Header;

               SPARK_IO.Put_Char (File, '(');
               Print_Symbol
                 (File  => File,
                  Scope => Scope,
                  Sym   => Cells.Get_Symbol_Value (Heap, Cells.Get_A_Ptr (Heap, Tick_Cell)));
               SPARK_IO.Put_String (File, ") : integer;", 0);
               if Write_Rules then
                  if Dictionary.TypeIsInteger (Cells.Get_Symbol_Value (Heap, Cells.Get_A_Ptr (Heap, Tick_Cell)))
                    or else Dictionary.TypeIsModular (Cells.Get_Symbol_Value (Heap, Cells.Get_A_Ptr (Heap, Tick_Cell))) then
                     Print_Rule_Name (Rule_File => Rule_File);
                     Print_Symbol
                       (File  => Rule_File,
                        Scope => Scope,
                        Sym   => Cells.Get_Symbol_Value (Heap, Cells.Get_A_Ptr (Heap, Tick_Cell)));
                     SPARK_IO.Put_Line (Rule_File, "__pos(X) may_be_replaced_by X .", 0);
                  end if;
               end if;
            elsif LexTokenManager.Lex_String_Case_Insensitive_Compare
              (Lex_Str1 => Lex_Str,
               Lex_Str2 => LexTokenManager.Ceiling_Token) =
              LexTokenManager.Str_Eq
              or else LexTokenManager.Lex_String_Case_Insensitive_Compare
              (Lex_Str1 => Lex_Str,
               Lex_Str2 => LexTokenManager.Floor_Token) =
              LexTokenManager.Str_Eq then
               Print_Function_Header;
               SPARK_IO.Put_String (File, "(real) : real;", 0);
            else -- Must be 'Val
               Print_Function_Header;
               SPARK_IO.Put_String (File, "(integer) : ", 0);
               Print_Symbol
                 (File  => File,
                  Scope => Scope,
                  Sym   => Cells.Get_Symbol_Value (Heap, Cells.Get_A_Ptr (Heap, Tick_Cell)));
               SPARK_IO.Put_Char (File, ';');
               if Write_Rules then
                  if Dictionary.TypeIsInteger (Cells.Get_Symbol_Value (Heap, Cells.Get_A_Ptr (Heap, Tick_Cell)))
                    or else Dictionary.TypeIsModular (Cells.Get_Symbol_Value (Heap, Cells.Get_A_Ptr (Heap, Tick_Cell))) then
                     Print_Rule_Name (Rule_File => Rule_File);
                     Print_Symbol
                       (File  => Rule_File,
                        Scope => Scope,
                        Sym   => Cells.Get_Symbol_Value (Heap, Cells.Get_A_Ptr (Heap, Tick_Cell)));
                     SPARK_IO.Put_Line (Rule_File, "__val(X) may_be_replaced_by X .", 0);
                  end if;
               end if;
            end if;
         end Print_Attribute_Function;

      begin -- Print_One_Attribute
         if Cells.Get_Kind (Heap, Cells.Get_B_Ptr (Heap, Tick_Cell)) = Cell_Storage.Attrib_Value then
            Print_Attribute_Constant;
         else
            Print_Attribute_Function;
         end if;
      end Print_One_Attribute;

   begin -- Print_Attribute_Declarations
      Current_Attrib := AttributeList;
      Prev_Attrib    := Cells.Null_Cell;
      while not Cells.Is_Null_Cell (Cells.Get_A_Ptr (Heap, Current_Attrib)) loop
         Current_Attrib := Cells.Get_A_Ptr (Heap, Current_Attrib);
         Print_One_Attribute
           (Tick_Cell => Cells.Get_C_Ptr (Heap, Current_Attrib),
            Prev_Cell => Cells.Get_C_Ptr (Heap, Prev_Attrib));
         Prev_Attrib := Current_Attrib;
      end loop;
   end Print_Attribute_Declarations;

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

   procedure Print_Bitwise_Op_Declarations
     (File, Rule_File : in SPARK_IO.File_Type;
      Write_Rules     : in Boolean;
      Scope           : in Dictionary.Scopes)
   --# global in     BitwiseOpList;
   --#        in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     Heap;
   --#        in     LexTokenManager.State;
   --#        in     Rule_Family_Name;
   --#        in out Rule_Counter;
   --#        in out SPARK_IO.File_Sys;
   --# derives Rule_Counter      from *,
   --#                                BitwiseOpList,
   --#                                Dictionary.Dict,
   --#                                Heap,
   --#                                Write_Rules &
   --#         SPARK_IO.File_Sys from *,
   --#                                BitwiseOpList,
   --#                                CommandLineData.Content,
   --#                                Dictionary.Dict,
   --#                                File,
   --#                                Heap,
   --#                                LexTokenManager.State,
   --#                                Rule_Counter,
   --#                                Rule_Family_Name,
   --#                                Rule_File,
   --#                                Scope,
   --#                                Write_Rules;
   is

      Current_Op : Cells.Cell;

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

      procedure Print_One_Bitwise_Op (Op_Cell : in Cells.Cell)
      --# global in     CommandLineData.Content;
      --#        in     Dictionary.Dict;
      --#        in     File;
      --#        in     Heap;
      --#        in     LexTokenManager.State;
      --#        in     Rule_Family_Name;
      --#        in     Rule_File;
      --#        in     Scope;
      --#        in     Write_Rules;
      --#        in out Rule_Counter;
      --#        in out SPARK_IO.File_Sys;
      --# derives Rule_Counter      from *,
      --#                                Dictionary.Dict,
      --#                                Heap,
      --#                                Op_Cell,
      --#                                Write_Rules &
      --#         SPARK_IO.File_Sys from *,
      --#                                CommandLineData.Content,
      --#                                Dictionary.Dict,
      --#                                File,
      --#                                Heap,
      --#                                LexTokenManager.State,
      --#                                Op_Cell,
      --#                                Rule_Counter,
      --#                                Rule_Family_Name,
      --#                                Rule_File,
      --#                                Scope,
      --#                                Write_Rules;
      is
         IndexSym              : Dictionary.Symbol;
         IndexFirst, IndexLast : LexTokenManager.Lex_String;

         -- procedure to print the common part of rules such as "thetype__and(X,Y)"
         procedure Print_Bitwise_Op_Function (Type_Sym : in Dictionary.Symbol;
                                              Operator : in SP_Symbols.SP_Symbol)
         --# global in     CommandLineData.Content;
         --#        in     Dictionary.Dict;
         --#        in     LexTokenManager.State;
         --#        in     Rule_File;
         --#        in     Scope;
         --#        in out SPARK_IO.File_Sys;
         --# derives SPARK_IO.File_Sys from *,
         --#                                CommandLineData.Content,
         --#                                Dictionary.Dict,
         --#                                LexTokenManager.State,
         --#                                Operator,
         --#                                Rule_File,
         --#                                Scope,
         --#                                Type_Sym;
         is
         begin
            Print_Symbol (File  => Rule_File,
                          Scope => Scope,
                          Sym   => Type_Sym);
            SPARK_IO.Put_String (Rule_File, "__", 0);
            case Operator is
               when SP_Symbols.RWand =>
                  SPARK_IO.Put_String (Rule_File, "and(", 0);
               when SP_Symbols.RWor =>
                  SPARK_IO.Put_String (Rule_File, "or(", 0);
               when SP_Symbols.RWxor =>
                  SPARK_IO.Put_String (Rule_File, "xor(", 0);
               when SP_Symbols.RWnot =>
                  SPARK_IO.Put_String (Rule_File, "not(", 0);
               when others =>
                  SPARK_IO.Put_String (Rule_File, "undef_op_value(", 0);
            end case;
            SPARK_IO.Put_String (Rule_File, "X", 0);
            if Operator /= SP_Symbols.RWnot then
               SPARK_IO.Put_String (Rule_File, ", Y", 0);
            end if;
            SPARK_IO.Put_String (Rule_File, ") ", 0);
         end Print_Bitwise_Op_Function;

      begin -- Print_One_Bitwise_Op
         if Dictionary.TypeIsArray (Cells.Get_Symbol_Value (Heap, Op_Cell)) then
            SPARK_IO.Set_Col (File, Indent);
            SPARK_IO.Put_String (File, "function ", 0);
            Print_Symbol (File  => File,
                          Scope => Scope,
                          Sym   => Cells.Get_Symbol_Value (Heap, Op_Cell));
            SPARK_IO.Put_String (File, "__", 0);
            case Cells.Get_Op_Symbol (Heap, Op_Cell) is
               when SP_Symbols.RWand =>
                  SPARK_IO.Put_String (File, "and(", 0);
               when SP_Symbols.RWor =>
                  SPARK_IO.Put_String (File, "or(", 0);
               when SP_Symbols.RWxor =>
                  SPARK_IO.Put_String (File, "xor(", 0);
               when SP_Symbols.RWnot =>
                  SPARK_IO.Put_String (File, "not(", 0);
               when others =>
                  SPARK_IO.Put_String (File, "undef_op_value(", 0);
            end case;
            --# assert True;
            Print_Symbol (File  => File,
                          Scope => Scope,
                          Sym   => Cells.Get_Symbol_Value (Heap, Op_Cell));
            if Cells.Get_Op_Symbol (Heap, Op_Cell) /= SP_Symbols.RWnot then
               SPARK_IO.Put_String (File, ", ", 0);
               Print_Symbol (File  => File,
                             Scope => Scope,
                             Sym   => Cells.Get_Symbol_Value (Heap, Op_Cell));
            end if;
            SPARK_IO.Put_String (File, ") :  ", 0);
            Print_Symbol (File  => File,
                          Scope => Scope,
                          Sym   => Cells.Get_Symbol_Value (Heap, Op_Cell));
            SPARK_IO.Put_Char (File, ';');
         end if;

         --# assert True;
         -- Now do rules for it
         if Write_Rules then
            -- we want rules for array bitwise ops
            if Dictionary.TypeIsArray (Cells.Get_Symbol_Value (Heap, Op_Cell)) then
               -- do array bitwise ops
               IndexSym   := Dictionary.GetArrayIndex (Cells.Get_Symbol_Value (Heap, Op_Cell), 1);
               IndexFirst := Dictionary.GetScalarAttributeValue (False, LexTokenManager.First_Token, IndexSym);
               IndexLast  := Dictionary.GetScalarAttributeValue (False, LexTokenManager.Last_Token, IndexSym);

               Print_Rule_Name (Rule_File => Rule_File);
               SPARK_IO.Put_String (Rule_File, "element(", 0);
               Print_Bitwise_Op_Function
                 (Type_Sym => Cells.Get_Symbol_Value (Heap, Op_Cell),
                  Operator => Cells.Get_Op_Symbol (Heap, Op_Cell));
               SPARK_IO.Put_Line (Rule_File, ", [I]) may_be_replaced_by ", 0);
               --# assert True;
               if Cells.Get_Op_Symbol (Heap, Op_Cell) = SP_Symbols.RWnot then
                  SPARK_IO.Put_String (Rule_File, "     not element(X, [I]) ", 0);
               elsif Cells.Get_Op_Symbol (Heap, Op_Cell) = SP_Symbols.RWxor then
                  SPARK_IO.Put_String
                    (Rule_File,
                     "     (element(X, [I]) or element(Y, [I])) and (not (element(X, [I]) and element(Y, [I])))",
                     0);
               else -- And or Or binary op directly reproducible in fdl
                  SPARK_IO.Put_String (Rule_File, "     element(X, [I]) ", 0);
                  case Cells.Get_Op_Symbol (Heap, Op_Cell) is
                     when SP_Symbols.RWand =>
                        SPARK_IO.Put_String (Rule_File, "and ", 0);
                     when SP_Symbols.RWor =>
                        SPARK_IO.Put_String (Rule_File, "or ", 0);
                     when others =>
                        SPARK_IO.Put_String (Rule_File, "undef_op_value ", 0);
                  end case;
                  SPARK_IO.Put_String (Rule_File, "element(Y, [I]) ", 0);
               end if;
               SPARK_IO.New_Line (Rule_File, 1);
               SPARK_IO.Put_String (Rule_File, "     if [", 0);
               E_Strings.Put_String
                 (File  => Rule_File,
                  E_Str => Get_Value (Store_Val => IndexFirst,
                                      Type_Mark => IndexSym,
                                      Scope     => Scope));
               SPARK_IO.Put_String (Rule_File, " <= I, I <= ", 0);
               E_Strings.Put_String
                 (File  => Rule_File,
                  E_Str => Get_Value (Store_Val => IndexLast,
                                      Type_Mark => IndexSym,
                                      Scope     => Scope));
               SPARK_IO.Put_String (Rule_File, "]", 0);
               End_A_Rule (Rule_File => Rule_File);

            end if;
         end if;
      end Print_One_Bitwise_Op;

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

   begin --Print_Bitwise_Op_Declarations
      Current_Op := BitwiseOpList;
      while not Cells.Is_Null_Cell (Cells.Get_A_Ptr (Heap, Current_Op)) loop
         Current_Op := Cells.Get_A_Ptr (Heap, Current_Op);
         Print_One_Bitwise_Op (Op_Cell => Cells.Get_C_Ptr (Heap, Current_Op));
      end loop;
   end Print_Bitwise_Op_Declarations;

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

   procedure Print_Export_Variable_Declarations (File  : in SPARK_IO.File_Type;
                                                 Scope : in Dictionary.Scopes)
   --# global in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     Heap;
   --#        in     LexTokenManager.State;
   --#        in     ProcedureExportList;
   --#        in out SPARK_IO.File_Sys;
   --# derives SPARK_IO.File_Sys from *,
   --#                                CommandLineData.Content,
   --#                                Dictionary.Dict,
   --#                                File,
   --#                                Heap,
   --#                                LexTokenManager.State,
   --#                                ProcedureExportList,
   --#                                Scope;
   is
      List_Element : Cells.Cell;
   begin
      List_Element := Cells.Get_A_Ptr (Heap, ProcedureExportList);
      while not Cells.Is_Null_Cell (List_Element) loop

         SPARK_IO.Set_Col (File, Indent);
         SPARK_IO.Put_String (File, "var ", 0);
         Print_Symbol (File  => File,
                       Scope => Scope,
                       Sym   => Cells.Get_Symbol_Value (Heap, List_Element));
         SPARK_IO.Put_String (File, "__", 0);
         E_Strings.Put_String
           (File  => File,
            E_Str => LexTokenManager.Lex_String_To_String (Lex_Str => Cells.Get_Lex_Str (Heap, List_Element)));
         SPARK_IO.Put_String (File, " : ", 0);
         Print_Symbol_Type
           (File      => File,
            Scope     => Scope,
            Sub_Type  => False,
            Component => False,
            Sym       => Cells.Get_Symbol_Value (Heap, List_Element));
         SPARK_IO.Put_Line (File, ";", 0);

         List_Element := Cells.Get_A_Ptr (Heap, List_Element);
      end loop;
   end Print_Export_Variable_Declarations;

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

   procedure PrintReturnSymbol (File  : in SPARK_IO.File_Type;
                                Scope : in Dictionary.Scopes)
   --# global in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     Heap;
   --#        in     LexTokenManager.State;
   --#        in     ReturnSymbol;
   --#        in out SPARK_IO.File_Sys;
   --# derives SPARK_IO.File_Sys from *,
   --#                                CommandLineData.Content,
   --#                                Dictionary.Dict,
   --#                                File,
   --#                                Heap,
   --#                                LexTokenManager.State,
   --#                                ReturnSymbol,
   --#                                Scope;
   is
   begin
      if ReturnSymbol /= Cells.Null_Cell then
         SPARK_IO.Set_Col (File, Indent);
         SPARK_IO.Put_String (File, "var return : ", 0);
         Print_Symbol_Type
           (File      => File,
            Scope     => Scope,
            Sub_Type  => False,
            Component => False,
            Sym       => Cells.Get_Symbol_Value (Heap, ReturnSymbol));
         SPARK_IO.Put_Line (File, ";", 0);
      end if;
   end PrintReturnSymbol;

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

   -- print pending constants for Min_Int and Max_Int but only if they appear in VC
   procedure PrintRootIntegerDeclaration (File : in SPARK_IO.File_Type)
   --# global in     RootIntegerUsed;
   --#        in out SPARK_IO.File_Sys;
   --# derives SPARK_IO.File_Sys from *,
   --#                                File,
   --#                                RootIntegerUsed;
   is
   begin
      if RootIntegerUsed then
         SPARK_IO.Set_Col (File, Indent);
         SPARK_IO.Put_Line (File, "const system__min_int : integer = pending;", 0);
         SPARK_IO.Set_Col (File, Indent);
         SPARK_IO.Put_Line (File, "const system__max_int : integer = pending;", 0);
      end if;
   end PrintRootIntegerDeclaration;

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

   -- print replacement rules for Min_Int/Max_Int if they have been used
   procedure PrintRootIntegerRules (Rule_File   : in SPARK_IO.File_Type;
                                    Write_Rules : in Boolean)
   --# global in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     LexTokenManager.State;
   --#        in     RootIntegerUsed;
   --#        in     Rule_Family_Name;
   --#        in out Rule_Counter;
   --#        in out SPARK_IO.File_Sys;
   --# derives Rule_Counter      from *,
   --#                                CommandLineData.Content,
   --#                                Dictionary.Dict,
   --#                                LexTokenManager.State,
   --#                                RootIntegerUsed,
   --#                                Write_Rules &
   --#         SPARK_IO.File_Sys from *,
   --#                                CommandLineData.Content,
   --#                                Dictionary.Dict,
   --#                                LexTokenManager.State,
   --#                                RootIntegerUsed,
   --#                                Rule_Counter,
   --#                                Rule_Family_Name,
   --#                                Rule_File,
   --#                                Write_Rules;
   is
      SystemSym, MinMaxSym : Dictionary.Symbol;

      procedure PrintRule (Sym      : in Dictionary.Symbol;
                           MinOrMax : in String)
      --# global in     Dictionary.Dict;
      --#        in     LexTokenManager.State;
      --#        in     Rule_Family_Name;
      --#        in     Rule_File;
      --#        in out Rule_Counter;
      --#        in out SPARK_IO.File_Sys;
      --# derives Rule_Counter      from *,
      --#                                Dictionary.Dict,
      --#                                LexTokenManager.State,
      --#                                Sym &
      --#         SPARK_IO.File_Sys from *,
      --#                                Dictionary.Dict,
      --#                                LexTokenManager.State,
      --#                                MinOrMax,
      --#                                Rule_Counter,
      --#                                Rule_Family_Name,
      --#                                Rule_File,
      --#                                Sym;
      is
         Store_Val : LexTokenManager.Lex_String;
      begin
         if not Dictionary.Is_Null_Symbol (Sym) then
            Store_Val := Dictionary.Get_Value (The_Constant => Sym);
            if LexTokenManager.Lex_String_Case_Insensitive_Compare
              (Lex_Str1 => Store_Val,
               Lex_Str2 => LexTokenManager.Null_String) /=
              LexTokenManager.Str_Eq then
               Print_Rule_Name (Rule_File => Rule_File);
               SPARK_IO.Put_String (Rule_File, "system__", 0);
               SPARK_IO.Put_String (Rule_File, MinOrMax, 0);
               SPARK_IO.Put_String (Rule_File, "_int may_be_replaced_by ", 0);
               E_Strings.Put_String (File  => Rule_File,
                                     E_Str => Maths.ValueToString (Maths.ValueRep (Store_Val)));
               End_A_Rule (Rule_File => Rule_File);
            end if;
         end if;
      end PrintRule;

   begin -- PrintRootIntegerRules
      if RootIntegerUsed and Write_Rules then
         -- get symbol for Min_Int
         SystemSym :=
           Dictionary.LookupItem
           (Name              => LexTokenManager.System_Token,
            Scope             => Dictionary.GlobalScope,
            Context           => Dictionary.ProgramContext,
            Full_Package_Name => False);
         if not Dictionary.Is_Null_Symbol (SystemSym) then
            -- Package System has been defined in a config file
            -- or a shadow specification, so look for Min_Int in it
            MinMaxSym :=
              Dictionary.LookupItem
              (Name              => LexTokenManager.Min_Int_Token,
               Scope             => Dictionary.Set_Visibility (The_Visibility => Dictionary.Visible,
                                                               The_Unit       => SystemSym),
               Context           => Dictionary.ProgramContext,
               Full_Package_Name => False);
            PrintRule (MinMaxSym, "min");
            -- and then for Max_Int
            MinMaxSym :=
              Dictionary.LookupItem
              (Name              => LexTokenManager.Max_Int_Token,
               Scope             => Dictionary.Set_Visibility (The_Visibility => Dictionary.Visible,
                                                               The_Unit       => SystemSym),
               Context           => Dictionary.ProgramContext,
               Full_Package_Name => False);
            PrintRule (MinMaxSym, "max");
         end if;
      end if;
   end PrintRootIntegerRules;

   procedure PrintConstantsInDeclarationOrder
   --# global in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     End_Position;
   --#        in     LexTokenManager.State;
   --#        in     Needed_Symbols;
   --#        in     Rule_Family_Name;
   --#        in     Rule_File;
   --#        in     Scope;
   --#        in     Write_Rules;
   --#        in out ErrorHandler.Error_Context;
   --#        in out Heap;
   --#        in out Rule_Counter;
   --#        in out SPARK_IO.File_Sys;
   --#        in out Statistics.TableUsage;
   --# derives ErrorHandler.Error_Context,
   --#         SPARK_IO.File_Sys          from CommandLineData.Content,
   --#                                         Dictionary.Dict,
   --#                                         End_Position,
   --#                                         ErrorHandler.Error_Context,
   --#                                         Heap,
   --#                                         LexTokenManager.State,
   --#                                         Needed_Symbols,
   --#                                         Rule_Counter,
   --#                                         Rule_Family_Name,
   --#                                         Rule_File,
   --#                                         Scope,
   --#                                         SPARK_IO.File_Sys,
   --#                                         Write_Rules &
   --#         Heap,
   --#         Statistics.TableUsage      from *,
   --#                                         Dictionary.Dict,
   --#                                         Heap,
   --#                                         Needed_Symbols,
   --#                                         Write_Rules &
   --#         Rule_Counter               from *,
   --#                                         CommandLineData.Content,
   --#                                         Dictionary.Dict,
   --#                                         Heap,
   --#                                         LexTokenManager.State,
   --#                                         Needed_Symbols,
   --#                                         Scope,
   --#                                         Write_Rules;
   is
      LSym           : Dictionary.Symbol;
      L_Declare_List : Cells.Cell;
   begin
      L_Declare_List := Needed_Symbols;
      loop
         exit when Pile.IsNull (L_Declare_List);
         LSym := Pile.NodeSymbol (Heap, L_Declare_List);
         if Dictionary.Is_Constant (LSym) or else Dictionary.IsKnownDiscriminant (LSym) then

            PrintConstantRules (Write_Rules, LSym, Rule_File, Scope, End_Position);

            if not Cells.Is_Null_Cell (Pile.DAG (Heap, L_Declare_List)) then
               PrintConstantReplacementRule (Write_Rules, LSym, Pile.DAG (Heap, L_Declare_List), Rule_File, Scope);
            end if;

         end if;
         L_Declare_List := Pile.Sibling (Heap, L_Declare_List);
      end loop;
   end PrintConstantsInDeclarationOrder;

   -- Same as above, but prints rules in reverse-declaration order.
   -- Contract is _identical_ to above.  Implementation is recursive,
   -- though, so hidden from SPARK!  This implementation is provided,
   -- but unused at present.
   procedure PrintConstantsInReverseOrder
   --# global in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     End_Position;
   --#        in     LexTokenManager.State;
   --#        in     Needed_Symbols;
   --#        in     Rule_Family_Name;
   --#        in     Rule_File;
   --#        in     Scope;
   --#        in     Write_Rules;
   --#        in out ErrorHandler.Error_Context;
   --#        in out Heap;
   --#        in out Rule_Counter;
   --#        in out SPARK_IO.File_Sys;
   --#        in out Statistics.TableUsage;
   --# derives ErrorHandler.Error_Context,
   --#         SPARK_IO.File_Sys          from CommandLineData.Content,
   --#                                         Dictionary.Dict,
   --#                                         End_Position,
   --#                                         ErrorHandler.Error_Context,
   --#                                         Heap,
   --#                                         LexTokenManager.State,
   --#                                         Needed_Symbols,
   --#                                         Rule_Counter,
   --#                                         Rule_Family_Name,
   --#                                         Rule_File,
   --#                                         Scope,
   --#                                         SPARK_IO.File_Sys,
   --#                                         Write_Rules &
   --#         Heap,
   --#         Statistics.TableUsage      from *,
   --#                                         Dictionary.Dict,
   --#                                         Heap,
   --#                                         Needed_Symbols,
   --#                                         Write_Rules &
   --#         Rule_Counter               from *,
   --#                                         CommandLineData.Content,
   --#                                         Dictionary.Dict,
   --#                                         Heap,
   --#                                         LexTokenManager.State,
   --#                                         Needed_Symbols,
   --#                                         Scope,
   --#                                         Write_Rules;
   is
      --# hide PrintConstantsInReverseOrder;

      -- Prints List C in reverse order - recursive algorithm,
      -- so hidden from SPARK.
      procedure PrintConstantsList (C : in Cells.Cell) is
         LSym : Dictionary.Symbol;
      begin
         if Pile.IsNull (C) then
            null;
         else
            PrintConstantsList (Pile.Sibling (Heap, C));

            LSym := Pile.NodeSymbol (Heap, C);
            if Dictionary.Is_Constant (LSym) or else Dictionary.IsKnownDiscriminant (LSym) then

               PrintConstantRules (Write_Rules, LSym, Rule_File, Scope, End_Position);

               if not Cells.Is_Null_Cell (Pile.DAG (Heap, C)) then
                  PrintConstantReplacementRule (Write_Rules, LSym, Pile.DAG (Heap, C), Rule_File, Scope);
               end if;
            end if;
         end if;
      end PrintConstantsList;

   begin
      PrintConstantsList (Needed_Symbols);
   end PrintConstantsInReverseOrder;
   pragma Unreferenced (PrintConstantsInReverseOrder);

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

   procedure RankDeclarations (Max_Rank : out Cells.Cell_Rank)
   --# global in     Dictionary.Dict;
   --#        in     Needed_Symbols;
   --#        in     Scope;
   --#        in out Heap;
   --# derives Heap,
   --#         Max_Rank from Dictionary.Dict,
   --#                       Heap,
   --#                       Needed_Symbols,
   --#                       Scope;
   is
      AllDeclarationsRanked : Boolean;
      Overall_Max_Rank      : Cells.Cell_Rank;

      -----------------------------------------------------------------------------
      -- RankDeclarationList
      --
      -- Ranks as many cells in the Pile rooted at Needed_Symbols as it can.
      -- The Pile is not guaranteed to be in strict declaration-before-use order,
      -- so the rank of some cells may depend on the ranks of other Cells which
      -- are currently unranked.  In this case, the offending Cell is left
      -- with UnknownRank and AllDeclarationsRanked returns as False,
      -- to be completed by a susequent iteration of RankDeclarations.
      -- When all Cells are ranked successfully, AlLDeclarationsRanked returns
      -- as True, and MaxOverallRank is set to the highest rank used in the Pile.
      -----------------------------------------------------------------------------
      procedure RankDeclarationList
      --# global in     Dictionary.Dict;
      --#        in     Needed_Symbols;
      --#        in     Scope;
      --#        in out Heap;
      --#        in out Overall_Max_Rank;
      --#           out AllDeclarationsRanked;
      --# derives AllDeclarationsRanked,
      --#         Heap                  from Dictionary.Dict,
      --#                                    Heap,
      --#                                    Needed_Symbols,
      --#                                    Scope &
      --#         Overall_Max_Rank      from *,
      --#                                    Dictionary.Dict,
      --#                                    Heap,
      --#                                    Needed_Symbols,
      --#                                    Scope;
      is
         Declare_List : Cells.Cell;

         --------------------------------------------------------------------------
         -- RankDeclaration
         --
         -- Tries to set the rank of a single type.  Basically, scalar types have
         -- rank 1, array types have rank 1 more than the rank of their component
         -- type, and records have rank 1 more than the maximum rank of all their
         -- fields' types.  AllDeclarationsRanked and MaxOverallRank are set
         -- as described above.
         --------------------------------------------------------------------------
         procedure RankDeclaration
         --# global in     Declare_List;
         --#        in     Dictionary.Dict;
         --#        in     Needed_Symbols;
         --#        in     Scope;
         --#        in out AllDeclarationsRanked;
         --#        in out Heap;
         --#        in out Overall_Max_Rank;
         --# derives AllDeclarationsRanked,
         --#         Heap,
         --#         Overall_Max_Rank      from *,
         --#                                    Declare_List,
         --#                                    Dictionary.Dict,
         --#                                    Heap,
         --#                                    Needed_Symbols,
         --#                                    Scope;
         is
            Sym             : Dictionary.Symbol;
            Own_Var_Sym     : Dictionary.Symbol;
            NewRank         : Cells.Cell_Rank;
            MaxFieldRank    : Cells.Cell_Rank;
            RecordIt        : Dictionary.Iterator;
            Component_It    : Dictionary.Iterator;
            AllFieldsRanked : Boolean;

            -- Increment rank X, but saturate at CellRank'Last
            function IncRank (X : in Cells.Cell_Rank) return Cells.Cell_Rank is
               R : Cells.Cell_Rank;
            begin
               if X < Cells.Cell_Rank'Last then
                  R := X + 1;
               else
                  R := Cells.Cell_Rank'Last;
               end if;
               return R;
            end IncRank;

            -- Searches the entire Pile roorted at Needed_Symbols and returns
            -- the Rank of the Cell containing the given Sym.  If no match is
            -- found, then UnknownRank is returned.
            function FindRankOf (Sym : in Dictionary.Symbol) return Cells.Cell_Rank
            --# global in Dictionary.Dict;
            --#        in Heap;
            --#        in Needed_Symbols;
            is
               CurrentCell : Cells.Cell;
               Result      : Cells.Cell_Rank;
            begin
               if Dictionary.IsPredefinedBooleanType (Sym) or else Dictionary.IsUnknownTypeMark (Sym) then
                  -- Special cases - Boolean is not entered in the Pile, so we
                  -- won't find it there.  It's scalar, so has rank 1.
                  -- Secondly, Unknown type can appear in the Pile following
                  -- a semantic error in a type declararation, so we need
                  -- to return something or we will fail to terminate.
                  Result := 1;
               elsif Dictionary.TypeIsScalar (Sym) then
                  -- All scalar types have rank 1, so don't bother to
                  -- search for them...
                  Result := 1;
               elsif Dictionary.IsProtectedType (Sym) then
                  -- Protected types always appear as "pending" in FDL,
                  -- so we give them rank 1
                  Result := 1;
               else
                  CurrentCell := Needed_Symbols;
                  Result      := Cells.Unknown_Rank;
                  loop
                     exit when Pile.IsNull (CurrentCell);
                     if Dictionary.IsTypeMark (Pile.NodeSymbol (Heap, CurrentCell))
                       and then Dictionary.Types_Are_Equal
                       (Left_Symbol        => Sym,
                        Right_Symbol       => Pile.NodeSymbol (Heap, CurrentCell),
                        Full_Range_Subtype => False) then
                        Result := Cells.Get_Rank (Heap, CurrentCell);
                        exit;
                     end if;
                     CurrentCell := Pile.Sibling (Heap, CurrentCell);
                  end loop;
               end if;

               return Result;
            end FindRankOf;

         begin
            if Cells.Get_Rank (Heap, Declare_List) = Cells.Unknown_Rank then
               Sym := Pile.NodeSymbol (Heap, Declare_List);
               if Dictionary.IsType (Sym) or Dictionary.IsSubtype (Sym) then

                  Debug_Rank_Sym (Msg => "Trying to rank Symbol ",
                                  Sym => Sym);

                  if Dictionary.IsPrivateType (Sym, Scope) then
                     -- All scalar types and abstract proof types have rank 1, since they
                     -- don't depend on any other type.  If a type is a private extension
                     -- of a tagged type, then its rank is one more than the rank of its
                     -- "inherit" field.
                     if Dictionary.TypeIsExtendedTagged (Sym) then
                        Sym := Dictionary.GetRootOfExtendedType (Sym);
                        Debug_Rank_Sym (Msg => "Is extended tagged with root type ",
                                        Sym => Sym);

                        NewRank := FindRankOf (Sym);

                        if NewRank = Cells.Unknown_Rank then
                           Debug_Rank_Int (Msg => "Extended tagged record, but parent has unknown rank",
                                           N   => Integer (NewRank));
                           AllDeclarationsRanked := False;
                        else
                           NewRank := IncRank (NewRank);

                           Debug_Rank_Int (Msg => "Extended tagged record, so setting rank to",
                                           N   => Integer (NewRank));
                           Cells.Set_Rank (Heap, Declare_List, NewRank);
                           if NewRank > Overall_Max_Rank then
                              Overall_Max_Rank := NewRank;
                           end if;
                        end if;
                     else
                        Debug_Rank_Int (Msg => "Private here, so setting rank to",
                                        N   => 1);
                        Cells.Set_Rank (Heap, Declare_List, 1);
                     end if;

                  elsif Dictionary.TypeIsIncompleteHere (Sym, Scope) then

                     -- Not complete, so appears as "pending" in FDL,
                     -- so we give them rank 1
                     Debug_Rank_Int (Msg => "Incomplete type, so setting rank to",
                                     N   => 1);
                     Cells.Set_Rank (Heap, Declare_List, 1);

                  elsif Dictionary.TypeIsScalar (Sym) then
                     -- All scalar types and abstract proof types have rank 1, since they
                     -- don't depend on any other type.
                     Debug_Rank_Int (Msg => "Scalar, so setting rank to",
                                     N   => 1);
                     Cells.Set_Rank (Heap, Declare_List, 1);

                  elsif Dictionary.IsProtectedType (Sym) then
                     -- Protected types always appear as "pending" in FDL,
                     -- so we give them rank 1
                     Debug_Rank_Int (Msg => "Protected, so setting rank to",
                                     N   => 1);
                     Cells.Set_Rank (Heap, Declare_List, 1);

                  elsif Dictionary.TypeIsAbstractProof (Sym) then
                     -- Abstract proof types are either "pending" or a record type
                     -- depending on the Scope.  Pending types don't depend on anything,
                     -- and so have rank 1.
                     Own_Var_Sym := Find_Own_Var_Matching_This_Type (Sym   => Sym,
                                                                     Scope => Scope);
                     if IsLocalOwnVariableWithRefinement (Own_Var_Sym, Scope) then
                        Component_It    := Dictionary.FirstConstituent (Own_Var_Sym);
                        MaxFieldRank    := 1;
                        AllFieldsRanked := True;
                        loop
                           exit when Dictionary.IsNullIterator (Component_It);
                           Sym     := Dictionary.GetRootType (Dictionary.GetType (Dictionary.CurrentSymbol (Component_It)));
                           NewRank := FindRankOf (Sym);

                           if NewRank = Cells.Unknown_Rank then
                              AllDeclarationsRanked := False;
                              AllFieldsRanked       := False;
                              exit;
                           end if;

                           if NewRank > MaxFieldRank then
                              MaxFieldRank := NewRank;
                           end if;

                           Component_It := Dictionary.NextSymbol (Component_It);
                        end loop;

                        if AllFieldsRanked then
                           NewRank := IncRank (MaxFieldRank);

                           Debug_Rank_Int (Msg => "Refinement record, so setting rank to",
                                           N   => Integer (NewRank));
                           Cells.Set_Rank (Heap, Declare_List, NewRank);
                           if NewRank > Overall_Max_Rank then
                              Overall_Max_Rank := NewRank;
                           end if;
                        end if;

                     else
                        Debug_Rank_Int (Msg => "Pending abstract proof, so setting rank to",
                                        N   => 1);
                        Cells.Set_Rank (Heap, Declare_List, 1);
                     end if;

                  elsif Dictionary.TypeIsRecord (Sym) then
                     -- The rank of record type is one more than the
                     -- maximum rank of all its field types.
                     MaxFieldRank    := 1;
                     AllFieldsRanked := True;
                     RecordIt        := Dictionary.FirstRecordComponent (Sym);
                     loop
                        exit when Dictionary.IsNullIterator (RecordIt);
                        Sym     := Dictionary.GetRootType (Dictionary.GetType (Dictionary.CurrentSymbol (RecordIt)));
                        NewRank := FindRankOf (Sym);

                        if NewRank = Cells.Unknown_Rank then
                           AllDeclarationsRanked := False;
                           AllFieldsRanked       := False;
                           exit;
                        end if;

                        if NewRank > MaxFieldRank then
                           MaxFieldRank := NewRank;
                        end if;

                        RecordIt := Dictionary.NextSymbol (RecordIt);
                     end loop;

                     if AllFieldsRanked then
                        NewRank := IncRank (MaxFieldRank);

                        Debug_Rank_Int (Msg => "Record, so setting rank to",
                                        N   => Integer (NewRank));
                        Cells.Set_Rank (Heap, Declare_List, NewRank);
                        if NewRank > Overall_Max_Rank then
                           Overall_Max_Rank := NewRank;
                        end if;
                     end if;

                  elsif Dictionary.TypeIsArray (Sym) then
                     -- Array index types are always discrete, so will always
                     -- have rank 1.  The rank of an array type is therefore one
                     -- more than the rank of its component type.
                     NewRank := FindRankOf (Dictionary.GetRootType (Dictionary.GetArrayComponent (Sym)));

                     if NewRank = Cells.Unknown_Rank then
                        AllDeclarationsRanked := False;
                     else
                        NewRank := IncRank (NewRank);
                        Debug_Rank_Int (Msg => "Array, so setting rank to",
                                        N   => Integer (NewRank));
                        Cells.Set_Rank (Heap, Declare_List, NewRank);
                        if NewRank > Overall_Max_Rank then
                           Overall_Max_Rank := NewRank;
                        end if;

                     end if;

                  else
                     SystemErrors.Fatal_Error (Sys_Err => SystemErrors.Assertion_Failure,
                                               Msg     => "RankDeclaration - unknown type");
                  end if;
               end if;
            end if;
         end RankDeclaration;

      begin
         AllDeclarationsRanked := True;
         Declare_List          := Needed_Symbols;
         loop
            exit when Pile.IsNull (Declare_List);
            RankDeclaration;
            Declare_List := Pile.Sibling (Heap, Declare_List);
         end loop;
      end RankDeclarationList;

   begin -- RankDeclarations
      Overall_Max_Rank := 1;
      loop
         RankDeclarationList;
         exit when AllDeclarationsRanked;
      end loop;
      Max_Rank := Overall_Max_Rank;
   end RankDeclarations;

   procedure Print_Type_Declarations (Up_To_Rank : in Cells.Cell_Rank)
   --# global in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     File;
   --#        in     LexTokenManager.State;
   --#        in     Needed_Symbols;
   --#        in     Rule_Family_Name;
   --#        in     Rule_File;
   --#        in     Scope;
   --#        in     Type_List;
   --#        in out Heap;
   --#        in out L_Heap;
   --#        in out Rule_Counter;
   --#        in out SPARK_IO.File_Sys;
   --#        in out Statistics.TableUsage;
   --# derives Heap,
   --#         Rule_Counter,
   --#         Statistics.TableUsage from *,
   --#                                    Dictionary.Dict,
   --#                                    Heap,
   --#                                    Needed_Symbols,
   --#                                    Scope,
   --#                                    Up_To_Rank &
   --#         L_Heap                from *,
   --#                                    Dictionary.Dict,
   --#                                    Heap,
   --#                                    LexTokenManager.State,
   --#                                    Needed_Symbols,
   --#                                    Scope,
   --#                                    Type_List,
   --#                                    Up_To_Rank &
   --#         SPARK_IO.File_Sys     from *,
   --#                                    CommandLineData.Content,
   --#                                    Dictionary.Dict,
   --#                                    File,
   --#                                    Heap,
   --#                                    LexTokenManager.State,
   --#                                    Needed_Symbols,
   --#                                    Rule_Counter,
   --#                                    Rule_Family_Name,
   --#                                    Rule_File,
   --#                                    Scope,
   --#                                    Up_To_Rank;
   is
      Declare_List    : Cells.Cell;
      Sym             : Dictionary.Symbol;
      Already_Present : Boolean;
      OK              : Boolean;
   begin
      for CurrentRank in Cells.Cell_Rank range 1 .. Up_To_Rank loop
         Debug_Rank_Int (Msg => "Printing type declarations at rank",
                         N   => Integer (CurrentRank));
         Declare_List := Needed_Symbols;
         loop
            exit when Pile.IsNull (Declare_List);
            Sym := Pile.NodeSymbol (Heap, Declare_List);

            if Dictionary.IsType (Sym) or Dictionary.IsSubtype (Sym) then
               if Cells.Get_Rank (Heap, Declare_List) = CurrentRank then
                  Debug_Rank_Sym (Msg => " Printing type declaration for ",
                                  Sym => Sym);
                  Print_Declaration (File, Scope, Sym);

                  -- If Sym denotes a full view of a record type or a private view of
                  -- an extended tagged record, then add it to Type_List so
                  -- we later have the option of generating proof rules for that type.
                  if Dictionary.TypeIsRecord (Sym) then
                     if ((Dictionary.TypeIsExtendedTagged (Sym) or not Dictionary.IsPrivateType (Sym, Scope))) and
                       not Dictionary.TypeIsOwnAbstractHere (Sym, Scope) then
                        --# accept Flow, 10, OK, "Expected ineffective assignment to Ok" &
                        --#        Flow, 10, Already_Present, "Expected ineffective assignment to Already_Present";
                        Lists.Add_Symbol
                          (Heap            => L_Heap,
                           The_List        => Type_List,
                           Symbol          => Sym,
                           Already_Present => Already_Present,
                           Ok              => OK);
                        --# end accept;
                     end if;
                  end if;

               end if;
            end if;
            Declare_List := Pile.Sibling (Heap, Declare_List);
         end loop;

      end loop;
      --# accept Flow, 33, OK, "Expected ineffective assignment to Ok" &
      --#        Flow, 33, Already_Present, "Expected ineffective assignment to Already_Present";
   end Print_Type_Declarations;

begin -- PrintDeclarations;
   Lists.Init (L_Heap);

   Print_Declaration_Head (File  => File,
                           Scope => Scope);

   SPARK_IO.Put_Line (File, "  function round__(real) : integer;", 0);

   PrintRuleHeader (Write_Rules, Rule_File);
   PrintStandardRules (Write_Rules, Rule_File);

   RankDeclarations (Max_Rank);
   Print_Type_Declarations (Up_To_Rank => Max_Rank);

   -- Print constants and discriminants declarations
   Declare_List := Needed_Symbols;
   loop
      exit when Pile.IsNull (Declare_List);
      Sym := Pile.NodeSymbol (Heap, Declare_List);
      if Dictionary.Is_Constant (Sym) or else Dictionary.IsKnownDiscriminant (Sym) then
         Print_Declaration (File, Scope, Sym);
      end if;
      Declare_List := Pile.Sibling (Heap, Declare_List);
   end loop;

   -- Print rules for constants
   PrintConstantsInDeclarationOrder;

   -- It may be better to print constant replacement rules in reverse
   -- declaration order, so that composites that refer to scalars come
   -- out first, and this get replaced in that order by the Simplifier.
   -- Further study needed, though, in co-operation with further work
   -- on the Simplifier.
   -- PrintConstantsInReverseOrder;

   PrintRootIntegerDeclaration (File);
   PrintRootIntegerRules (Rule_File, Write_Rules);
   Print_Attribute_Declarations (File  => File,
                                 Scope => Scope);
   Print_Bitwise_Op_Declarations (File        => File,
                                  Rule_File   => Rule_File,
                                  Write_Rules => Write_Rules,
                                  Scope       => Scope);
   --# accept Flow, 10, L_Heap, "Expected ineffective assignment to L_Heap" &
   --#        Flow, 10, Type_List, "Expected ineffective assignment to Type_List";
   PrintTypeRules (Write_Rules, Rule_File);
   --# end accept;

   Declare_List := Needed_Symbols;
   loop
      exit when Pile.IsNull (Declare_List);
      Sym := Pile.NodeSymbol (Heap, Declare_List);
      if Dictionary.Is_Variable (Sym) then
         Print_Declaration (File, Scope, Sym);
      end if;
      Declare_List := Pile.Sibling (Heap, Declare_List);
   end loop;

   -- Print declaration of return variable here, after other vars and
   -- before the function declarations
   PrintReturnSymbol (File, Scope);

   Declare_List := Needed_Symbols;
   loop
      exit when Pile.IsNull (Declare_List);
      Sym := Pile.NodeSymbol (Heap, Declare_List);
      if Dictionary.Is_Subprogram (Sym) then
         Print_Declaration (File, Scope, Sym);
      end if;
      Declare_List := Pile.Sibling (Heap, Declare_List);
   end loop;

   Print_Export_Variable_Declarations (File  => File,
                                       Scope => Scope);

   PrintDeclarationTail (File);
end PrintDeclarations;
