-------------------------------------------------------------------------------
-- (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 SystemErrors;
with ErrorHandler;
separate (Declarations.OutputDeclarations.PrintDeclarations)
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)
is

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

   procedure PrintScalarConstantRules (Rule_File : in SPARK_IO.File_Type;
                                       Sym       : in Dictionary.Symbol)
   --# global in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     LexTokenManager.State;
   --#        in     Rule_Family_Name;
   --#        in     Scope;
   --#        in out Rule_Counter;
   --#        in out SPARK_IO.File_Sys;
   --# derives Rule_Counter      from *,
   --#                                Dictionary.Dict,
   --#                                LexTokenManager.State,
   --#                                Sym &
   --#         SPARK_IO.File_Sys from *,
   --#                                CommandLineData.Content,
   --#                                Dictionary.Dict,
   --#                                LexTokenManager.State,
   --#                                Rule_Counter,
   --#                                Rule_Family_Name,
   --#                                Rule_File,
   --#                                Scope,
   --#                                Sym;
   is
      StoreVal : LexTokenManager.Lex_String;
      T        : Dictionary.Symbol;
   begin
      StoreVal := Dictionary.Get_Value (The_Constant => Sym);
      if LexTokenManager.Lex_String_Case_Insensitive_Compare (Lex_Str1 => StoreVal,
                                                              Lex_Str2 => LexTokenManager.Null_String) /=
        LexTokenManager.Str_Eq then
         -- Sym has a literal value, so print a replacement rule.
         Print_Rule_Name (Rule_File => Rule_File);
         Print_Symbol (File  => Rule_File,
                       Scope => Scope,
                       Sym   => Sym);
         Print_Replacement_Rule
           (Rule_File => Rule_File,
            Store_Val => StoreVal,
            Type_Mark => Dictionary.GetType (Sym),
            Scope     => Scope);
      else
         -- Sym doesn't have a literal value - could be a deferred
         -- constant with a hidden completion, or a known discriminant.
         --
         -- In the former case, the VCG will produce hypotheses giving the
         -- subtype membership of the constant, so no action here.
         --
         -- In the case of a known discriminant, we genrate a subtype membership
         -- rule, unless its type is Boolean.
         if Dictionary.IsKnownDiscriminant (Sym) then
            T := Dictionary.GetType (Sym);
            if not Dictionary.TypeIsBoolean (T) then
               Print_Rule_Name (Rule_File => Rule_File);
               Print_Symbol (File  => Rule_File,
                             Scope => Scope,
                             Sym   => Sym);
               SPARK_IO.Put_String (Rule_File, " >= ", 0);
               Print_Symbol (File  => Rule_File,
                             Scope => Scope,
                             Sym   => T);
               SPARK_IO.Put_Line (Rule_File, "__first may_be_deduced.", 0);

               Print_Rule_Name (Rule_File => Rule_File);
               Print_Symbol (File  => Rule_File,
                             Scope => Scope,
                             Sym   => Sym);
               SPARK_IO.Put_String (Rule_File, " <= ", 0);
               Print_Symbol (File  => Rule_File,
                             Scope => Scope,
                             Sym   => T);
               SPARK_IO.Put_Line (Rule_File, "__last may_be_deduced.", 0);
            end if;
         end if;
      end if;
   end PrintScalarConstantRules;

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

   procedure PrintStructuredConstantRules
     (Rule_File   : in SPARK_IO.File_Type;
      Sym         : in Dictionary.Symbol;
      EndPosition : in LexTokenManager.Token_Position)
   --# global in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     LexTokenManager.State;
   --#        in     Rule_Family_Name;
   --#        in     Scope;
   --#        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,
   --#                                         EndPosition,
   --#                                         ErrorHandler.Error_Context,
   --#                                         LexTokenManager.State,
   --#                                         Rule_Counter,
   --#                                         Rule_Family_Name,
   --#                                         Rule_File,
   --#                                         Scope,
   --#                                         SPARK_IO.File_Sys,
   --#                                         Sym &
   --#         Rule_Counter               from *,
   --#                                         CommandLineData.Content,
   --#                                         Dictionary.Dict,
   --#                                         LexTokenManager.State,
   --#                                         Scope,
   --#                                         Sym;
   is

      Node          : Dictionary.Symbol;
      Name          : E_Strings.T;
      Constraints   : E_Strings.T;
      Constraint_OK : Boolean;

      ErrorsFound : Boolean;

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

      --# inherit SPARK_IO,
      --#         SystemErrors;
      package Index
      --# own State : Letter;
      --# initializes State;
      is

         subtype IndexNameRange is Positive range 1 .. 1;
         subtype IndexNameType is String (IndexNameRange);

         subtype Letter is Character range 'A' .. 'Z';

         State : Letter;

         function Value return IndexNameType;
         --# global in State;
         procedure Next;
         --# global in out State;
         --# derives State from *;

         procedure Reset (Valu : in Letter);
         --# global out State;
         --# derives State from Valu;

      end Index;

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

      --# inherit Dictionary,
      --#         E_Strings,
      --#         Index,
      --#         SPARK_IO,
      --#         SystemErrors;
      package Stack
      --# own State : StackType;
      --# initializes State;
      is

         procedure Push
           (Iterator      : in Dictionary.Iterator;
            Name          : in E_Strings.T;
            Constraints   : in E_Strings.T;
            Constraint_OK : in Boolean;
            CurrentIndex  : in Index.Letter);
         --# global in out State;
         --# derives State from *,
         --#                    Constraints,
         --#                    Constraint_OK,
         --#                    CurrentIndex,
         --#                    Iterator,
         --#                    Name;

         procedure Pop
           (Iterator      : out Dictionary.Iterator;
            Name          : out E_Strings.T;
            Constraints   : out E_Strings.T;
            Constraint_OK : out Boolean;
            CurrentIndex  : out Index.Letter);
         --# global in out State;
         --# derives Constraints,
         --#         Constraint_OK,
         --#         CurrentIndex,
         --#         Iterator,
         --#         Name,
         --#         State         from State;

         function IsEmpty return Boolean;
         --# global in State;
      end Stack;

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

      package body Index is

         function Value return IndexNameType is
         begin
            return IndexNameType'(1 => State);
         end Value;

         procedure Next is
         begin
            if State = Letter'Last then
               SystemErrors.Fatal_Error (Sys_Err => SystemErrors.Too_Many_Nested_Arrays,
                                         Msg     => "in PrintConstantRules");
            end if;
            State := Letter'Succ (State);
         end Next;

         procedure Reset (Valu : in Letter) is
         begin
            State := Valu;
         end Reset;

      begin
         State := 'I';
      end Index;

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

      package body Stack is

         type StackPointer is range 0 .. 50;
         --# assert StackPointer'Base is Short_Short_Integer; -- for GNAT

         subtype StackIndex is StackPointer range 1 .. StackPointer'Last;
         type StackElement is record
            Iterator      : Dictionary.Iterator;
            Name          : E_Strings.T;
            Constraints   : E_Strings.T;
            Constraint_OK : Boolean;
            CurrentIndex  : Index.Letter;
         end record;
         type StackContents is array (StackIndex) of StackElement;
         type StackType is record
            Ptr      : StackPointer;
            Contents : StackContents;
         end record;

         State : StackType;

         procedure Push
           (Iterator      : in Dictionary.Iterator;
            Name          : in E_Strings.T;
            Constraints   : in E_Strings.T;
            Constraint_OK : in Boolean;
            CurrentIndex  : in Index.Letter)
         is
         begin
            if State.Ptr = StackPointer'Last then
               SystemErrors.Fatal_Error (Sys_Err => SystemErrors.Too_Many_Nested_Records,
                                         Msg     => "in PrintConstantRules");
            end if;
            State.Ptr                                := State.Ptr + 1;
            State.Contents (State.Ptr).Iterator      := Iterator;
            State.Contents (State.Ptr).Name          := Name;
            State.Contents (State.Ptr).Constraints   := Constraints;
            State.Contents (State.Ptr).Constraint_OK := Constraint_OK;
            State.Contents (State.Ptr).CurrentIndex  := CurrentIndex;
         end Push;

         procedure Pop
           (Iterator      : out Dictionary.Iterator;
            Name          : out E_Strings.T;
            Constraints   : out E_Strings.T;
            Constraint_OK : out Boolean;
            CurrentIndex  : out Index.Letter)
         is
         begin
            Iterator      := State.Contents (State.Ptr).Iterator;
            Name          := State.Contents (State.Ptr).Name;
            Constraints   := State.Contents (State.Ptr).Constraints;
            Constraint_OK := State.Contents (State.Ptr).Constraint_OK;
            CurrentIndex  := State.Contents (State.Ptr).CurrentIndex;
            State.Ptr     := State.Ptr - 1;
         end Pop;

         function IsEmpty return Boolean is
         begin
            return State.Ptr = 0;
         end IsEmpty;

      begin
         State.Ptr := 0;
         --# accept Flow, 32, State.Contents, "Init is partial but effective." &
         --#        Flow, 31, State.Contents, "Init is partial but effective." &
         --#        Flow, 602, State, State.Contents, "Init is partial but effective.";
      end Stack;

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

      procedure PushState
        (Iterator      : in Dictionary.Iterator;
         Name          : in E_Strings.T;
         Constraints   : in E_Strings.T;
         Constraint_OK : in Boolean)
      --# global in     Dictionary.Dict;
      --#        in     Index.State;
      --#        in out Stack.State;
      --# derives Stack.State from *,
      --#                          Constraints,
      --#                          Constraint_OK,
      --#                          Dictionary.Dict,
      --#                          Index.State,
      --#                          Iterator,
      --#                          Name;
      is
         Next : Dictionary.Iterator;
      begin
         Next := Dictionary.NextSymbol (Iterator);
         if not Dictionary.IsNullIterator (Next) then
            Stack.Push (Next, Name, Constraints, Constraint_OK, Index.State);
         end if;
      end PushState;

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

      procedure Walk_Record
        (Sym           :    out Dictionary.Symbol;
         Components    : in     Dictionary.Iterator;
         Name          : in out E_Strings.T;
         Constraints   : in     E_Strings.T;
         Constraint_OK : in     Boolean)
      --# global in     Dictionary.Dict;
      --#        in     Index.State;
      --#        in     LexTokenManager.State;
      --#        in out Stack.State;
      --# derives Name        from *,
      --#                          Components,
      --#                          Dictionary.Dict,
      --#                          LexTokenManager.State &
      --#         Stack.State from *,
      --#                          Components,
      --#                          Constraints,
      --#                          Constraint_OK,
      --#                          Dictionary.Dict,
      --#                          Index.State,
      --#                          Name &
      --#         Sym         from Components,
      --#                          Dictionary.Dict;
      is
         Component   : Dictionary.Symbol;
         Record_Name : E_Strings.T;
      begin
         Component := Dictionary.CurrentSymbol (Components);
         PushState (Components, Name, Constraints, Constraint_OK);

         Record_Name := Name;
         Name        := E_Strings.Copy_String (Str => "fld_");
         E_Strings.Append_Examiner_String
           (E_Str1 => Name,
            E_Str2 => E_Strings.Lower_Case
              (E_Str => LexTokenManager.Lex_String_To_String (Lex_Str => Dictionary.GetSimpleName (Component))));
         E_Strings.Append_String (E_Str => Name,
                                  Str   => "(");
         E_Strings.Append_Examiner_String (E_Str1 => Name,
                                           E_Str2 => Record_Name);
         E_Strings.Append_String (E_Str => Name,
                                  Str   => ")");

         Sym := Dictionary.GetType (Component);

      end Walk_Record;

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

      procedure TreeWalk
        (Sym           : in out Dictionary.Symbol;
         Name          : in out E_Strings.T;
         Constraints   : in out E_Strings.T;
         Constraint_OK : in out Boolean)
      --# global in     CommandLineData.Content;
      --#        in     Dictionary.Dict;
      --#        in     LexTokenManager.State;
      --#        in     Scope;
      --#        in out Index.State;
      --#        in out Stack.State;
      --# derives Constraints   from *,
      --#                            CommandLineData.Content,
      --#                            Dictionary.Dict,
      --#                            Index.State,
      --#                            LexTokenManager.State,
      --#                            Scope,
      --#                            Sym &
      --#         Constraint_OK,
      --#         Index.State,
      --#         Sym           from *,
      --#                            Dictionary.Dict,
      --#                            Scope,
      --#                            Sym &
      --#         Name          from *,
      --#                            Dictionary.Dict,
      --#                            Index.State,
      --#                            LexTokenManager.State,
      --#                            Scope,
      --#                            Sym &
      --#         Stack.State   from *,
      --#                            CommandLineData.Content,
      --#                            Constraints,
      --#                            Constraint_OK,
      --#                            Dictionary.Dict,
      --#                            Index.State,
      --#                            LexTokenManager.State,
      --#                            Name,
      --#                            Scope,
      --#                            Sym;
      is

         procedure WalkArray
           (Sym           : in out Dictionary.Symbol;
            Name          : in out E_Strings.T;
            Constraints   : in out E_Strings.T;
            Constraint_OK : in out Boolean)
         --# global in     CommandLineData.Content;
         --#        in     Dictionary.Dict;
         --#        in     LexTokenManager.State;
         --#        in     Scope;
         --#        in out Index.State;
         --# derives Constraints   from *,
         --#                            CommandLineData.Content,
         --#                            Dictionary.Dict,
         --#                            Index.State,
         --#                            LexTokenManager.State,
         --#                            Scope,
         --#                            Sym &
         --#         Constraint_OK,
         --#         Index.State,
         --#         Sym           from *,
         --#                            Dictionary.Dict,
         --#                            Sym &
         --#         Name          from *,
         --#                            Dictionary.Dict,
         --#                            Index.State,
         --#                            Sym;
         is

            ArrayName : E_Strings.T;
            Indices   : Dictionary.Iterator;

            procedure AppendIndexConstraints (Indices     : in     Dictionary.Iterator;
                                              Constraints : in out E_Strings.T)
            --# global in     CommandLineData.Content;
            --#        in     Dictionary.Dict;
            --#        in     Index.State;
            --#        in     LexTokenManager.State;
            --#        in     Scope;
            --#        in out Constraint_OK;
            --# derives Constraints   from *,
            --#                            CommandLineData.Content,
            --#                            Dictionary.Dict,
            --#                            Index.State,
            --#                            Indices,
            --#                            LexTokenManager.State,
            --#                            Scope &
            --#         Constraint_OK from *,
            --#                            Dictionary.Dict,
            --#                            Indices;
            is

               IndexType  : Dictionary.Symbol;
               Constraint : E_Strings.T;
               FirstValue : LexTokenManager.Lex_String;
               LastValue  : LexTokenManager.Lex_String;

               procedure NewConstraint (Constraint  : in     E_Strings.T;
                                        Constraints : in out E_Strings.T)
               --# derives Constraints from *,
               --#                          Constraint;
               is
               begin
                  if not E_Strings.Is_Empty (E_Str => Constraints) then
                     E_Strings.Append_String (E_Str => Constraints,
                                              Str   => ", ");
                  end if;
                  E_Strings.Append_Examiner_String (E_Str1 => Constraints,
                                                    E_Str2 => Constraint);
               end NewConstraint;

            begin

               IndexType := Dictionary.CurrentSymbol (Indices);

               if not Dictionary.IsUnknownTypeMark (IndexType) then
                  -- Guard to prevent constraint being generated for boolean index
                  if not Dictionary.TypeIsBoolean (IndexType) then
                     FirstValue := Dictionary.GetScalarAttributeValue (False, LexTokenManager.First_Token, IndexType);
                     Constraint := Get_Value (Store_Val => FirstValue,
                                              Type_Mark => IndexType,
                                              Scope     => Scope);
                     E_Strings.Append_String (E_Str => Constraint,
                                              Str   => " <= ");
                     E_Strings.Append_String (E_Str => Constraint,
                                              Str   => Index.Value);
                     NewConstraint (Constraint, Constraints);

                     Constraint := E_Strings.Copy_String (Str => Index.Value);
                     E_Strings.Append_String (E_Str => Constraint,
                                              Str   => " <= ");
                     LastValue := Dictionary.GetScalarAttributeValue (False, LexTokenManager.Last_Token, IndexType);
                     E_Strings.Append_Examiner_String
                       (E_Str1 => Constraint,
                        E_Str2 => Get_Value (Store_Val => LastValue,
                                             Type_Mark => IndexType,
                                             Scope     => Scope));
                     NewConstraint (Constraint, Constraints);
                  end if;
               else
                  Constraint_OK := False;
               end if;
            end AppendIndexConstraints;

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

         begin

            ArrayName := Name;
            Name      := E_Strings.Copy_String (Str => "element(");
            E_Strings.Append_Examiner_String (E_Str1 => Name,
                                              E_Str2 => ArrayName);
            E_Strings.Append_String (E_Str => Name,
                                     Str   => ", [");
            E_Strings.Append_String (E_Str => Name,
                                     Str   => Index.Value);
            Indices := Dictionary.FirstArrayIndex (Sym);

            AppendIndexConstraints (Indices, Constraints);
            Index.Next;

            loop
               Indices := Dictionary.NextSymbol (Indices);
               exit when Dictionary.IsNullIterator (Indices);
               E_Strings.Append_String (E_Str => Name,
                                        Str   => ", ");
               E_Strings.Append_String (E_Str => Name,
                                        Str   => Index.Value);
               AppendIndexConstraints (Indices, Constraints);
               Index.Next;
            end loop;

            E_Strings.Append_String (E_Str => Name,
                                     Str   => "])");
            Sym := Dictionary.GetArrayComponent (Sym);

         end WalkArray;

      begin
         loop
            exit when Dictionary.IsUnknownTypeMark (Sym);
            exit when Dictionary.TypeIsScalar (Sym);
            exit when Dictionary.IsPrivateType (Sym, Scope);
            exit when Dictionary.TypeIsGeneric (Sym); -- no rules for generic types

            exit when Dictionary.TypeIsRecord (Sym)
              and then -- no rules for null records
              not Dictionary.RecordHasSomeFields (Sym);

            if Dictionary.TypeIsArray (Sym) then
               WalkArray (Sym, Name, Constraints, Constraint_OK);
            elsif Dictionary.TypeIsRecord (Sym) then
               -- Sym might denote a record subtype here, so...
               Sym := Dictionary.GetRootType (Sym);
               Walk_Record
                 (Sym           => Sym,
                  Components    => Dictionary.FirstRecordComponent (Sym),
                  Name          => Name,
                  Constraints   => Constraints,
                  Constraint_OK => Constraint_OK);
            else
               -- Should never be reached.  We have covered scalar, private, generic,
               -- unknown, array and record above
               -- and task and protected types can't appear in expressions.
               SystemErrors.Fatal_Error
                 (Sys_Err => SystemErrors.Other_Internal_Error,
                  Msg     => "Unexpected type symbol in PrintConstantRules.TreeWalk");
            end if;
         end loop;
      end TreeWalk;

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

      procedure PrintTypeBounds
        (Rule_File   : in SPARK_IO.File_Type;
         Sym         : in Dictionary.Symbol;
         Name        : in E_Strings.T;
         Constraints : in E_Strings.T)
      --# global in     CommandLineData.Content;
      --#        in     Dictionary.Dict;
      --#        in     LexTokenManager.State;
      --#        in     Rule_Family_Name;
      --#        in     Scope;
      --#        in out Rule_Counter;
      --#        in out SPARK_IO.File_Sys;
      --# derives Rule_Counter      from *,
      --#                                Dictionary.Dict,
      --#                                Sym &
      --#         SPARK_IO.File_Sys from *,
      --#                                CommandLineData.Content,
      --#                                Constraints,
      --#                                Dictionary.Dict,
      --#                                LexTokenManager.State,
      --#                                Name,
      --#                                Rule_Counter,
      --#                                Rule_Family_Name,
      --#                                Rule_File,
      --#                                Scope,
      --#                                Sym;
      is

         procedure PrintLowerBound
           (Rule_File   : in SPARK_IO.File_Type;
            Sym         : in Dictionary.Symbol;
            Name        : in E_Strings.T;
            Constraints : in E_Strings.T)
         --# global in     CommandLineData.Content;
         --#        in     Dictionary.Dict;
         --#        in     LexTokenManager.State;
         --#        in     Rule_Family_Name;
         --#        in     Scope;
         --#        in out Rule_Counter;
         --#        in out SPARK_IO.File_Sys;
         --# derives Rule_Counter      from * &
         --#         SPARK_IO.File_Sys from *,
         --#                                CommandLineData.Content,
         --#                                Constraints,
         --#                                Dictionary.Dict,
         --#                                LexTokenManager.State,
         --#                                Name,
         --#                                Rule_Counter,
         --#                                Rule_Family_Name,
         --#                                Rule_File,
         --#                                Scope,
         --#                                Sym;
         is
         begin
            Print_Rule_Name (Rule_File => Rule_File);
            Print_Symbol (File  => Rule_File,
                          Scope => Scope,
                          Sym   => Sym);
            SPARK_IO.Put_String (Rule_File, "__first <= ", 0);
            E_Strings.Put_String (File  => Rule_File,
                                  E_Str => Name);
            SPARK_IO.Put_String (Rule_File, " may_be_deduced", 0);
            if not E_Strings.Is_Empty (E_Str => Constraints) then
               SPARK_IO.Put_String (Rule_File, "_from [", 0);
               E_Strings.Put_String (File  => Rule_File,
                                     E_Str => Constraints);
               SPARK_IO.Put_String (Rule_File, "]", 0);
            end if;
            End_A_Rule (Rule_File => Rule_File);
         end PrintLowerBound;

         procedure PrintUpperBound
           (Rule_File   : in SPARK_IO.File_Type;
            Sym         : in Dictionary.Symbol;
            Name        : in E_Strings.T;
            Constraints : in E_Strings.T)
         --# global in     CommandLineData.Content;
         --#        in     Dictionary.Dict;
         --#        in     LexTokenManager.State;
         --#        in     Rule_Family_Name;
         --#        in     Scope;
         --#        in out Rule_Counter;
         --#        in out SPARK_IO.File_Sys;
         --# derives Rule_Counter      from * &
         --#         SPARK_IO.File_Sys from *,
         --#                                CommandLineData.Content,
         --#                                Constraints,
         --#                                Dictionary.Dict,
         --#                                LexTokenManager.State,
         --#                                Name,
         --#                                Rule_Counter,
         --#                                Rule_Family_Name,
         --#                                Rule_File,
         --#                                Scope,
         --#                                Sym;
         is
         begin
            Print_Rule_Name (Rule_File => Rule_File);
            E_Strings.Put_String (File  => Rule_File,
                                  E_Str => Name);
            SPARK_IO.Put_String (Rule_File, " <= ", 0);
            Print_Symbol (File  => Rule_File,
                          Scope => Scope,
                          Sym   => Sym);
            SPARK_IO.Put_String (Rule_File, "__last may_be_deduced", 0);
            if not E_Strings.Is_Empty (E_Str => Constraints) then
               SPARK_IO.Put_String (Rule_File, "_from [", 0);
               E_Strings.Put_String (File  => Rule_File,
                                     E_Str => Constraints);
               SPARK_IO.Put_String (Rule_File, "]", 0);
            end if;
            End_A_Rule (Rule_File => Rule_File);
         end PrintUpperBound;

      begin
         -- Boolean types are scalar, but do not have "<=" or ">=" operators
         -- in FDL, so there's no range constraint for them.
         if not Dictionary.TypeIsBoolean (Sym) then
            PrintLowerBound (Rule_File, Sym, Name, Constraints);
            PrintUpperBound (Rule_File, Sym, Name, Constraints);
         end if;
      end PrintTypeBounds;

      procedure Backtrack
        (Sym           : out Dictionary.Symbol;
         Name          : out E_Strings.T;
         Constraints   : out E_Strings.T;
         Constraint_OK : out Boolean)
      --# global in     Dictionary.Dict;
      --#        in     LexTokenManager.State;
      --#        in out Stack.State;
      --#           out Index.State;
      --# derives Constraints,
      --#         Constraint_OK,
      --#         Index.State   from Stack.State &
      --#         Name          from Dictionary.Dict,
      --#                            LexTokenManager.State,
      --#                            Stack.State &
      --#         Stack.State,
      --#         Sym           from Dictionary.Dict,
      --#                            Stack.State;
      is
         CurrentIndex      : Index.Letter;
         TheSym            : Dictionary.Symbol;
         Components        : Dictionary.Iterator;
         TheName           : E_Strings.T;
         TheConstraints    : E_Strings.T;
         The_Constraint_OK : Boolean;
      begin
         Stack.Pop (Components, TheName, TheConstraints, The_Constraint_OK, CurrentIndex);
         Index.Reset (CurrentIndex);
         Walk_Record
           (Sym           => TheSym,
            Components    => Components,
            Name          => TheName,
            Constraints   => TheConstraints,
            Constraint_OK => The_Constraint_OK);
         Sym           := TheSym;
         Name          := TheName;
         Constraints   := TheConstraints;
         Constraint_OK := The_Constraint_OK;
      end Backtrack;

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

   begin
      Node := Dictionary.GetType (Sym);
      Name := Get_Name (Sym   => Sym,
                        Scope => Scope);

      Constraint_OK := True;
      Constraints   := E_Strings.Empty_String;

      ErrorsFound := False;
      -- Note: This accept annotation should be inside the loop around the TreeWalk call
      -- but currently this is rejected by the parser. See SEPR 2067
      --# accept Flow, 10, Index.State, "Expected ineffective assignment to Index.State";
      loop
         -- Expect ineffective assignment to Index.State, as this
         -- state is discarded when we leave PrintConstantRules
         TreeWalk (Node, Name, Constraints, Constraint_OK); -- 782 - Expect 1 ineffective assignment
         if not Dictionary.TypeIsPrivate (TheType => Node) then -- no bounds available for private types
            if not Dictionary.IsUnknownTypeMark (Node) then -- nor unknown types
               if Constraint_OK then
                  PrintTypeBounds (Rule_File, Node, Name, Constraints);
               else
                  ErrorsFound := True;
               end if;
            else
               ErrorsFound := True;
            end if;
         end if;
         exit when Stack.IsEmpty;
         Backtrack (Node, Name, Constraints, Constraint_OK);
      end loop;
      --# end accept;
      if ErrorsFound then
         ErrorHandler.Semantic_Warning_Sym
           (Err_Num  => 314,
            Position => EndPosition,
            Sym      => Sym,
            Scope    => Dictionary.GetScope (Sym));
      end if;
   end PrintStructuredConstantRules;

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

begin
   if Write_Rules then
      if not Dictionary.IsPrivateType (Dictionary.GetType (Sym), Scope) then
         if Dictionary.TypeIsScalar (Dictionary.GetType (Sym)) then
            PrintScalarConstantRules (Rule_File, Sym);
         else
            PrintStructuredConstantRules (Rule_File, Sym, End_Position);
         end if;
      end if;
   end if;
end PrintConstantRules;
