-------------------------------------------------------------------------------
-- (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.
--
--=============================================================================

separate (Sem.Walk_Expression_P)
procedure Wf_Attribute_Designator
  (Node     : in     STree.SyntaxNode;
   Scope    : in     Dictionary.Scopes;
   E_Stack  : in out Exp_Stack.Exp_Stack_Type;
   The_Heap : in out Heap.HeapRecord;
   Ref_Var  : in     SeqAlgebra.Seq)
is
   Ident_Node, Arg_Exp_Node, Second_Arg_Exp_Node             : STree.SyntaxNode;
   Ident_Node_Pos, Arg_Exp_Node_Pos, Second_Arg_Exp_Node_Pos : LexTokenManager.Token_Position;
   Type_So_Far, Argument_Expression                          : Sem.Exp_Record;
   Second_Argument_Expression                                : Sem.Exp_Record;
   Argument_Found, Second_Argument_Found                     : Boolean := False;
   Ident_Str                                                 : LexTokenManager.Lex_String;
   Val, Unused_Val, RHS_Val                                  : Maths.Value;
   Base_Found                                                : Boolean;
   Ok_So_Far                                                 : Boolean;
   Prefix_Kind                                               : Dictionary.PrefixSort;
   Prefix_Type                                               : Dictionary.Symbol;
   VCG_Type                                                  : Dictionary.Symbol;

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

   procedure Get_Prefix
     (Ident_Node_Pos : in     LexTokenManager.Token_Position;
      Node_Pos       : in     LexTokenManager.Token_Position;
      Scope          : in     Dictionary.Scopes;
      Base_Found     : in     Boolean;
      Prefix         :    out Sem.Exp_Record;
      Kind           :    out Dictionary.PrefixSort;
      E_Stack        : in out Exp_Stack.Exp_Stack_Type)
   --# global in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     LexTokenManager.State;
   --#        in out ErrorHandler.Error_Context;
   --#        in out SPARK_IO.File_Sys;
   --# derives ErrorHandler.Error_Context,
   --#         SPARK_IO.File_Sys          from Base_Found,
   --#                                         CommandLineData.Content,
   --#                                         Dictionary.Dict,
   --#                                         ErrorHandler.Error_Context,
   --#                                         E_Stack,
   --#                                         Ident_Node_Pos,
   --#                                         LexTokenManager.State,
   --#                                         Node_Pos,
   --#                                         SPARK_IO.File_Sys &
   --#         E_Stack                    from * &
   --#         Kind                       from Base_Found,
   --#                                         Dictionary.Dict,
   --#                                         E_Stack &
   --#         Prefix                     from Base_Found,
   --#                                         CommandLineData.Content,
   --#                                         Dictionary.Dict,
   --#                                         E_Stack,
   --#                                         Scope;
   --# post Dictionary.Is_Null_Symbol (Prefix.Type_Symbol) or Dictionary.IsTypeMark (Prefix.Type_Symbol, Dictionary.Dict);
   is
      Result : Sem.Exp_Record;
   begin
      Kind := Dictionary.AType;
      Exp_Stack.Pop (Item  => Result,
                     Stack => E_Stack); -- this is type of prefix expression
      if Result.Sort = Sem.Is_Unknown then
         Result := Sem.Unknown_Type_Record;
      elsif Result.Sort = Sem.Is_Type_Mark then
         Result.Is_Static   := Dictionary.IsStatic (Result.Type_Symbol, Scope);
         Result.Is_Constant := True;
         Result.Is_ARange   := False;
         if Base_Found then
            if CommandLineData.Content.Language_Profile /= CommandLineData.SPARK83
              and then not Dictionary.TypeIsScalar (Result.Type_Symbol) then
               Result := Sem.Unknown_Type_Record;
               ErrorHandler.Semantic_Error
                 (Err_Num   => 96,
                  Reference => ErrorHandler.No_Reference,
                  Position  => Node_Pos,
                  Id_Str    => LexTokenManager.Base_Token);
            end if;
            Kind := Dictionary.ABaseType;
         end if;
      elsif Dictionary.IsObject (Result.Other_Symbol) or else Dictionary.IsSubcomponent (Result.Other_Symbol) then
         if Dictionary.IsUniversalIntegerType (Result.Type_Symbol)
           or else Dictionary.IsUniversalRealType (Result.Type_Symbol) then
            -- its a named number and not a proper object
            Result := Sem.Unknown_Type_Record;
            ErrorHandler.Semantic_Error
              (Err_Num   => 31,
               Reference => ErrorHandler.No_Reference,
               Position  => Ident_Node_Pos,
               Id_Str    => LexTokenManager.Null_String);
         else
            Result.Is_Static             := Dictionary.IsStatic (Result.Type_Symbol, Scope);
            Result.Is_Constant           := Dictionary.Is_Constant (Result.Type_Symbol);
            Result.Is_ARange             := False;
            Result.Variable_Symbol       := Dictionary.NullSymbol;
            Result.Is_AVariable          := False;
            Result.Is_An_Entire_Variable := False;
            Kind                         := Dictionary.AnObject;
         end if;
      elsif Result = Sem.Unknown_Type_Record then
         null;
      else
         Result := Sem.Unknown_Type_Record;
         ErrorHandler.Semantic_Error
           (Err_Num   => 31,
            Reference => ErrorHandler.No_Reference,
            Position  => Ident_Node_Pos,
            Id_Str    => LexTokenManager.Null_String);
      end if;
      Prefix := Result;
   end Get_Prefix;

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

   function Proof_Attribute_Is_Visible
     (Ident_Str   : LexTokenManager.Lex_String;
      Prefix_Kind : Dictionary.PrefixSort;
      Prefix_Sym  : Dictionary.Symbol)
     return        Boolean
   --# global in Dictionary.Dict;
   --#        in LexTokenManager.State;
   is
   begin
      return Prefix_Kind = Dictionary.AnObject
        and then ((LexTokenManager.Lex_String_Case_Insensitive_Compare
                     (Lex_Str1 => Ident_Str,
                      Lex_Str2 => LexTokenManager.Tail_Token) =
                     LexTokenManager.Str_Eq
                     and then Dictionary.GetOwnVariableOrConstituentMode (Prefix_Sym) = Dictionary.InMode)
                  or else (LexTokenManager.Lex_String_Case_Insensitive_Compare
                             (Lex_Str1 => Ident_Str,
                              Lex_Str2 => LexTokenManager.Append_Token) =
                             LexTokenManager.Str_Eq
                             and then Dictionary.GetOwnVariableOrConstituentMode (Prefix_Sym) = Dictionary.OutMode));
   end Proof_Attribute_Is_Visible;

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

   function Always_Takes_One_Argument (Str : LexTokenManager.Lex_String) return Boolean
   --# global in LexTokenManager.State;
   is
   begin
      return LexTokenManager.Lex_String_Case_Insensitive_Compare (Lex_Str1 => Str,
                                                                  Lex_Str2 => LexTokenManager.Pos_Token) =
        LexTokenManager.Str_Eq
        or else LexTokenManager.Lex_String_Case_Insensitive_Compare (Lex_Str1 => Str,
                                                                     Lex_Str2 => LexTokenManager.Pred_Token) =
        LexTokenManager.Str_Eq
        or else LexTokenManager.Lex_String_Case_Insensitive_Compare (Lex_Str1 => Str,
                                                                     Lex_Str2 => LexTokenManager.Succ_Token) =
        LexTokenManager.Str_Eq
        or else LexTokenManager.Lex_String_Case_Insensitive_Compare (Lex_Str1 => Str,
                                                                     Lex_Str2 => LexTokenManager.Val_Token) =
        LexTokenManager.Str_Eq
        or else LexTokenManager.Lex_String_Case_Insensitive_Compare (Lex_Str1 => Str,
                                                                     Lex_Str2 => LexTokenManager.Floor_Token) =
        LexTokenManager.Str_Eq
        or else LexTokenManager.Lex_String_Case_Insensitive_Compare
        (Lex_Str1 => Str,
         Lex_Str2 => LexTokenManager.Ceiling_Token) =
        LexTokenManager.Str_Eq
        or else LexTokenManager.Lex_String_Case_Insensitive_Compare (Lex_Str1 => Str,
                                                                     Lex_Str2 => LexTokenManager.Tail_Token) =
        LexTokenManager.Str_Eq
        or else LexTokenManager.Lex_String_Case_Insensitive_Compare (Lex_Str1 => Str,
                                                                     Lex_Str2 => LexTokenManager.Mod_Token) =
        LexTokenManager.Str_Eq;
   end Always_Takes_One_Argument;

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

   function Always_Takes_Two_Arguments (Str : LexTokenManager.Lex_String) return Boolean
   --# global in LexTokenManager.State;
   is
   begin
      return LexTokenManager.Lex_String_Case_Insensitive_Compare (Lex_Str1 => Str,
                                                                  Lex_Str2 => LexTokenManager.Min_Token) =
        LexTokenManager.Str_Eq
        or else LexTokenManager.Lex_String_Case_Insensitive_Compare (Lex_Str1 => Str,
                                                                     Lex_Str2 => LexTokenManager.Max_Token) =
        LexTokenManager.Str_Eq
        or else LexTokenManager.Lex_String_Case_Insensitive_Compare
        (Lex_Str1 => Str,
         Lex_Str2 => LexTokenManager.Append_Token) =
        LexTokenManager.Str_Eq;
   end Always_Takes_Two_Arguments;

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

   function Argument_Type_Correct
     (Str                   : LexTokenManager.Lex_String;
      Prefix_Type, Arg_Type : Dictionary.Symbol;
      Scope                 : Dictionary.Scopes)
     return                  Boolean
   --# global in Dictionary.Dict;
   --#        in LexTokenManager.State;
   is
      Result : Boolean;
   begin
      if LexTokenManager.Lex_String_Case_Insensitive_Compare (Lex_Str1 => Str,
                                                              Lex_Str2 => LexTokenManager.Val_Token) =
        LexTokenManager.Str_Eq
        or else LexTokenManager.Lex_String_Case_Insensitive_Compare (Lex_Str1 => Str,
                                                                     Lex_Str2 => LexTokenManager.Mod_Token) =
        LexTokenManager.Str_Eq then
         Result := Dictionary.IsIntegerTypeMark (Arg_Type, Scope)
           or else Dictionary.IsModularTypeMark (Arg_Type, Scope)
           or else Dictionary.IsUnknownTypeMark (Arg_Type);
      else
         Result := Dictionary.CompatibleTypes (Scope, Prefix_Type, Arg_Type);
      end if;
      return Result;
   end Argument_Type_Correct;

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

   function Check_Static
     (Ident_Str           : LexTokenManager.Lex_String;
      Prefix_Type         : Dictionary.Symbol;
      Type_So_Far         : Sem.Exp_Record;
      Argument_Expression : Sem.Exp_Record;
      Argument_Found      : Boolean;
      Scope               : Dictionary.Scopes)
     return                Boolean
   --# global in CommandLineData.Content;
   --#        in Dictionary.Dict;
   --#        in LexTokenManager.State;
   is
      Result : Boolean;

      function Is_Static_Array_Attribute
        (Ident_Str   : LexTokenManager.Lex_String;
         Prefix_Type : Dictionary.Symbol;
         Scope       : Dictionary.Scopes)
        return        Boolean
      --# global in CommandLineData.Content;
      --#        in Dictionary.Dict;
      --#        in LexTokenManager.State;
      is
      begin
         return CommandLineData.Content.Language_Profile /= CommandLineData.SPARK83
           and then (LexTokenManager.Lex_String_Case_Insensitive_Compare
                       (Lex_Str1 => Ident_Str,
                        Lex_Str2 => LexTokenManager.First_Token) =
                       LexTokenManager.Str_Eq
                       or else LexTokenManager.Lex_String_Case_Insensitive_Compare
                       (Lex_Str1 => Ident_Str,
                        Lex_Str2 => LexTokenManager.Last_Token) =
                       LexTokenManager.Str_Eq
                       or else LexTokenManager.Lex_String_Case_Insensitive_Compare
                       (Lex_Str1 => Ident_Str,
                        Lex_Str2 => LexTokenManager.Length_Token) =
                       LexTokenManager.Str_Eq)
           and then Dictionary.Is_Constrained_Array_Type_Mark (Prefix_Type, Scope);
      end Is_Static_Array_Attribute;

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

      function Attribute_Considered_Static
        (Str         : LexTokenManager.Lex_String;
         Scope       : Dictionary.Scopes;
         Type_So_Far : Sem.Exp_Record)
        return        Boolean
      --# global in Dictionary.Dict;
      --#        in LexTokenManager.State;
      is
         Result : Boolean;
      begin
         if LexTokenManager.Lex_String_Case_Insensitive_Compare (Lex_Str1 => Str,
                                                                 Lex_Str2 => LexTokenManager.Aft_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare (Lex_Str1 => Str,
                                                                        Lex_Str2 => LexTokenManager.Base_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare (Lex_Str1 => Str,
                                                                        Lex_Str2 => LexTokenManager.Delta_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare (Lex_Str1 => Str,
                                                                        Lex_Str2 => LexTokenManager.Digits_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare (Lex_Str1 => Str,
                                                                        Lex_Str2 => LexTokenManager.Emax_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Str,
            Lex_Str2 => LexTokenManager.Epsilon_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare (Lex_Str1 => Str,
                                                                        Lex_Str2 => LexTokenManager.First_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare (Lex_Str1 => Str,
                                                                        Lex_Str2 => LexTokenManager.Fore_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare (Lex_Str1 => Str,
                                                                        Lex_Str2 => LexTokenManager.Large_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare (Lex_Str1 => Str,
                                                                        Lex_Str2 => LexTokenManager.Last_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Str,
            Lex_Str2 => LexTokenManager.Machine_Emax_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Str,
            Lex_Str2 => LexTokenManager.Machine_Emin_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Str,
            Lex_Str2 => LexTokenManager.Machine_Mantissa_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Str,
            Lex_Str2 => LexTokenManager.Machine_Overflows_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Str,
            Lex_Str2 => LexTokenManager.Machine_Radix_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Str,
            Lex_Str2 => LexTokenManager.Machine_Rounds_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Str,
            Lex_Str2 => LexTokenManager.Mantissa_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare (Lex_Str1 => Str,
                                                                        Lex_Str2 => LexTokenManager.Pred_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare (Lex_Str1 => Str,
                                                                        Lex_Str2 => LexTokenManager.Pos_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Str,
            Lex_Str2 => LexTokenManager.Safe_Emax_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Str,
            Lex_Str2 => LexTokenManager.Safe_Large_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Str,
            Lex_Str2 => LexTokenManager.Safe_Small_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare (Lex_Str1 => Str,
                                                                        Lex_Str2 => LexTokenManager.Small_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare (Lex_Str1 => Str,
                                                                        Lex_Str2 => LexTokenManager.Succ_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare (Lex_Str1 => Str,
                                                                        Lex_Str2 => LexTokenManager.Val_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Str,
            Lex_Str2 => LexTokenManager.Component_Size_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare (Lex_Str1 => Str,
                                                                        Lex_Str2 => LexTokenManager.Denorm_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Str,
            Lex_Str2 => LexTokenManager.Model_Emin_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Str,
            Lex_Str2 => LexTokenManager.Model_Epsilon_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Str,
            Lex_Str2 => LexTokenManager.Model_Mantissa_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Str,
            Lex_Str2 => LexTokenManager.Model_Small_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Str,
            Lex_Str2 => LexTokenManager.Safe_First_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Str,
            Lex_Str2 => LexTokenManager.Safe_Last_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Str,
            Lex_Str2 => LexTokenManager.Signed_Zeros_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare (Lex_Str1 => Str,
                                                                        Lex_Str2 => LexTokenManager.Min_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare (Lex_Str1 => Str,
                                                                        Lex_Str2 => LexTokenManager.Max_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Str,
            Lex_Str2 => LexTokenManager.Modulus_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare (Lex_Str1 => Str,
                                                                        Lex_Str2 => LexTokenManager.Floor_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Str,
            Lex_Str2 => LexTokenManager.Ceiling_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare (Lex_Str1 => Str,
                                                                        Lex_Str2 => LexTokenManager.Mod_Token) =
           LexTokenManager.Str_Eq then
            Result := True;
         elsif LexTokenManager.Lex_String_Case_Insensitive_Compare (Lex_Str1 => Str,
                                                                    Lex_Str2 => LexTokenManager.Size_Token) =
           LexTokenManager.Str_Eq then
            -- 'Size is static only for a prefix that denotes a static
            -- scalar subtype
            Result := Dictionary.IsScalarType (Type_So_Far.Type_Symbol, Scope);
         else
            Result := False;
         end if;
         return Result;
      end Attribute_Considered_Static;

   begin -- Check_Static
      Result :=
        (Type_So_Far.Is_Static
           and then Attribute_Considered_Static (Str         => Ident_Str,
                                                 Scope       => Scope,
                                                 Type_So_Far => Type_So_Far))
        or else Is_Static_Array_Attribute (Ident_Str   => Ident_Str,
                                           Prefix_Type => Prefix_Type,
                                           Scope       => Scope);
      if Result and then Argument_Found then
         Result := Argument_Expression.Is_Static;
      end if;
      return Result;
   end Check_Static;

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

   function Check_Constant
     (Ident_Str           : LexTokenManager.Lex_String;
      Type_So_Far         : Sem.Exp_Record;
      Argument_Expression : Sem.Exp_Record;
      Argument_Found      : Boolean;
      Scope               : Dictionary.Scopes)
     return                Boolean
   --# global in Dictionary.Dict;
   --#        in LexTokenManager.State;
   is
      Result : Boolean;
   begin
      Result := Type_So_Far.Is_Constant or else Dictionary.Is_Constrained_Array_Type_Mark (Type_So_Far.Type_Symbol, Scope);
      if Result then
         if LexTokenManager.Lex_String_Case_Insensitive_Compare (Lex_Str1 => Ident_Str,
                                                                 Lex_Str2 => LexTokenManager.Base_Token) =
           LexTokenManager.Str_Eq then
            Result := not Dictionary.IsUnconstrainedArrayType (Dictionary.GetRootType (Type_So_Far.Type_Symbol));
         elsif LexTokenManager.Lex_String_Case_Insensitive_Compare (Lex_Str1 => Ident_Str,
                                                                    Lex_Str2 => LexTokenManager.Size_Token) =
           LexTokenManager.Str_Eq then
            -- S'Size is only considered to be constant/static for
            -- scalar types
            Result := Dictionary.IsScalarType (Type_So_Far.Type_Symbol, Scope);
         end if;
      end if;
      if Result and then Argument_Found then
         Result := Argument_Expression.Is_Constant;
      end if;
      return Result;
   end Check_Constant;

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

   function Check_Range (Ident_Str : LexTokenManager.Lex_String) return Boolean
   --# global in LexTokenManager.State;
   is
   begin
      return LexTokenManager.Lex_String_Case_Insensitive_Compare (Lex_Str1 => Ident_Str,
                                                                  Lex_Str2 => LexTokenManager.Range_Token) =
        LexTokenManager.Str_Eq;
   end Check_Range;

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

   procedure Basic_Checks
     (Node                    : in     STree.SyntaxNode;
      Ident_Node_Pos          : in     LexTokenManager.Token_Position;
      Ident_Str               : in     LexTokenManager.Lex_String;
      Arg_Exp_Node_Pos        : in     LexTokenManager.Token_Position;
      Second_Arg_Exp_Node_Pos : in     LexTokenManager.Token_Position;
      Argument_Found          : in     Boolean;
      Second_Argument_Found   : in     Boolean;
      Type_So_Far             : in out Sem.Exp_Record;
      Ok                      :    out Boolean)
   --# global in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     LexTokenManager.State;
   --#        in     STree.Table;
   --#        in out ErrorHandler.Error_Context;
   --#        in out SPARK_IO.File_Sys;
   --# derives ErrorHandler.Error_Context,
   --#         SPARK_IO.File_Sys          from Argument_Found,
   --#                                         Arg_Exp_Node_Pos,
   --#                                         CommandLineData.Content,
   --#                                         Dictionary.Dict,
   --#                                         ErrorHandler.Error_Context,
   --#                                         Ident_Node_Pos,
   --#                                         Ident_Str,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         Second_Argument_Found,
   --#                                         Second_Arg_Exp_Node_Pos,
   --#                                         SPARK_IO.File_Sys,
   --#                                         STree.Table,
   --#                                         Type_So_Far &
   --#         Ok                         from Argument_Found,
   --#                                         CommandLineData.Content,
   --#                                         Ident_Str,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         Second_Argument_Found,
   --#                                         STree.Table,
   --#                                         Type_So_Far &
   --#         Type_So_Far                from *,
   --#                                         Argument_Found,
   --#                                         CommandLineData.Content,
   --#                                         Dictionary.Dict,
   --#                                         Ident_Str,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         Second_Argument_Found,
   --#                                         STree.Table;
   --# pre STree.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.attribute_designator or
   --#   STree.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.annotation_attribute_designator;
   is

      -- this function should gradually wither away as attributes are implemented
      function Not_Yet_Implemented (Str : LexTokenManager.Lex_String) return Boolean
      --# global in LexTokenManager.State;
      is
      begin
         return LexTokenManager.Lex_String_Case_Insensitive_Compare (Lex_Str1 => Str,
                                                                     Lex_Str2 => LexTokenManager.Adjacent_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Str,
            Lex_Str2 => LexTokenManager.Compose_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Str,
            Lex_Str2 => LexTokenManager.Copy_Sign_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Str,
            Lex_Str2 => LexTokenManager.Leading_Part_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Str,
            Lex_Str2 => LexTokenManager.Remainder_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Str,
            Lex_Str2 => LexTokenManager.Scaling_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Str,
            Lex_Str2 => LexTokenManager.Exponent_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Str,
            Lex_Str2 => LexTokenManager.Fraction_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Str,
            Lex_Str2 => LexTokenManager.Machine_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Str,
            Lex_Str2 => LexTokenManager.Model_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Str,
            Lex_Str2 => LexTokenManager.Rounding_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Str,
            Lex_Str2 => LexTokenManager.Truncation_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Str,
            Lex_Str2 => LexTokenManager.Machine_Rounding_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Str,
            Lex_Str2 => LexTokenManager.Unbiased_Rounding_Token) =
           LexTokenManager.Str_Eq;
      end Not_Yet_Implemented;

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

      -- identifies special attributes that are part of the pre/post annotation
      -- language only
      function Is_Proof_Attribute (Str : LexTokenManager.Lex_String) return Boolean
      --# global in LexTokenManager.State;
      is
      begin
         return LexTokenManager.Lex_String_Case_Insensitive_Compare (Lex_Str1 => Str,
                                                                     Lex_Str2 => LexTokenManager.Tail_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Str,
            Lex_Str2 => LexTokenManager.Append_Token) =
           LexTokenManager.Str_Eq;
      end Is_Proof_Attribute;

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

      function Never_Takes_Arguments (Str : LexTokenManager.Lex_String) return Boolean
      --# global in LexTokenManager.State;
      is
      begin
         return not (LexTokenManager.Lex_String_Case_Insensitive_Compare
                       (Lex_Str1 => Str,
                        Lex_Str2 => LexTokenManager.First_Token) =
                       LexTokenManager.Str_Eq
                       or else LexTokenManager.Lex_String_Case_Insensitive_Compare
                       (Lex_Str1 => Str,
                        Lex_Str2 => LexTokenManager.Last_Token) =
                       LexTokenManager.Str_Eq
                       or else LexTokenManager.Lex_String_Case_Insensitive_Compare
                       (Lex_Str1 => Str,
                        Lex_Str2 => LexTokenManager.Length_Token) =
                       LexTokenManager.Str_Eq
                       or else LexTokenManager.Lex_String_Case_Insensitive_Compare
                       (Lex_Str1 => Str,
                        Lex_Str2 => LexTokenManager.Pos_Token) =
                       LexTokenManager.Str_Eq
                       or else LexTokenManager.Lex_String_Case_Insensitive_Compare
                       (Lex_Str1 => Str,
                        Lex_Str2 => LexTokenManager.Pred_Token) =
                       LexTokenManager.Str_Eq
                       or else LexTokenManager.Lex_String_Case_Insensitive_Compare
                       (Lex_Str1 => Str,
                        Lex_Str2 => LexTokenManager.Range_Token) =
                       LexTokenManager.Str_Eq
                       or else LexTokenManager.Lex_String_Case_Insensitive_Compare
                       (Lex_Str1 => Str,
                        Lex_Str2 => LexTokenManager.Succ_Token) =
                       LexTokenManager.Str_Eq
                       or else LexTokenManager.Lex_String_Case_Insensitive_Compare
                       (Lex_Str1 => Str,
                        Lex_Str2 => LexTokenManager.Val_Token) =
                       LexTokenManager.Str_Eq
                       or else LexTokenManager.Lex_String_Case_Insensitive_Compare
                       (Lex_Str1 => Str,
                        Lex_Str2 => LexTokenManager.Min_Token) =
                       LexTokenManager.Str_Eq
                       or else LexTokenManager.Lex_String_Case_Insensitive_Compare
                       (Lex_Str1 => Str,
                        Lex_Str2 => LexTokenManager.Max_Token) =
                       LexTokenManager.Str_Eq
                       or else LexTokenManager.Lex_String_Case_Insensitive_Compare
                       (Lex_Str1 => Str,
                        Lex_Str2 => LexTokenManager.Tail_Token) =
                       LexTokenManager.Str_Eq
                       or else LexTokenManager.Lex_String_Case_Insensitive_Compare
                       (Lex_Str1 => Str,
                        Lex_Str2 => LexTokenManager.Ceiling_Token) =
                       LexTokenManager.Str_Eq
                       or else LexTokenManager.Lex_String_Case_Insensitive_Compare
                       (Lex_Str1 => Str,
                        Lex_Str2 => LexTokenManager.Floor_Token) =
                       LexTokenManager.Str_Eq
                       or else LexTokenManager.Lex_String_Case_Insensitive_Compare
                       (Lex_Str1 => Str,
                        Lex_Str2 => LexTokenManager.Append_Token) =
                       LexTokenManager.Str_Eq
                       or else LexTokenManager.Lex_String_Case_Insensitive_Compare
                       (Lex_Str1 => Str,
                        Lex_Str2 => LexTokenManager.Mod_Token) =
                       LexTokenManager.Str_Eq);
      end Never_Takes_Arguments;

      -- Returns True iff Node appears in an expression tree below
      -- the left or right hand side of an "&" operator.  "&" is
      -- a binary_adding_operator so appears as part of a simple_expression
      -- or an annotation_simple_expression.
      function Attribute_Is_Below_Catenation_Operator (Node : STree.SyntaxNode) return Boolean
      --# global in STree.Table;
      --# pre STree.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.attribute_designator or
      --#   STree.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.annotation_attribute_designator;
      is
         Result       : Boolean;
         Current_Node : STree.SyntaxNode;
      begin
         -- Depends on the structure of "simple_expression" and
         -- "annotation_simple_expression" in SPARK.LLA

         Current_Node := Node;
         -- Find parent [annotation_]primary or [annotation_]arange
         while STree.Syntax_Node_Type (Node => Current_Node) /= SP_Symbols.annotation_primary
           and then STree.Syntax_Node_Type (Node => Current_Node) /= SP_Symbols.primary
           and then STree.Syntax_Node_Type (Node => Current_Node) /= SP_Symbols.annotation_arange
           and then STree.Syntax_Node_Type (Node => Current_Node) /= SP_Symbols.arange loop
            Current_Node := STree.Parent_Node (Current_Node => Current_Node);
         end loop;
         -- ASSUME Current_Node = annotation_primary OR primary OR annotation_arange OR arange
         if STree.Syntax_Node_Type (Node => Current_Node) = SP_Symbols.annotation_arange
           or else STree.Syntax_Node_Type (Node => Current_Node) = SP_Symbols.arange then
            -- ASSUME Current_Node = annotation_arange OR arange
            Result := False;
         elsif STree.Syntax_Node_Type (Node => Current_Node) = SP_Symbols.annotation_primary
           or else STree.Syntax_Node_Type (Node => Current_Node) = SP_Symbols.primary then
            -- ASSUME Current_Node = annotation_primary OR primary
            -- Find parent [annotation_]simple_expression[_opt]
            while STree.Syntax_Node_Type (Node => Current_Node) /= SP_Symbols.simple_expression
              and then STree.Syntax_Node_Type (Node => Current_Node) /= SP_Symbols.annotation_simple_expression
              and then STree.Syntax_Node_Type (Node => Current_Node) /= SP_Symbols.simple_expression_opt
              and then STree.Syntax_Node_Type (Node => Current_Node) /= SP_Symbols.annotation_simple_expression_opt loop
               Current_Node := STree.Parent_Node (Current_Node => Current_Node);
            end loop;
            -- ASSUME Current_Node = simple_expression     OR annotation_simple_expression OR
            --                       simple_expression_opt OR annotation_simple_expression_opt
            if STree.Syntax_Node_Type (Node => Current_Node) = SP_Symbols.simple_expression_opt
              or else STree.Syntax_Node_Type (Node => Current_Node) = SP_Symbols.annotation_simple_expression_opt then
               -- ASSUME Current_Node = simple_expression_opt OR annotation_simple_expression_opt
               Current_Node := STree.Parent_Node (Current_Node => Current_Node);
               -- ASSUME Current_Node = simple_expression OR annotation_simple_expression
               SystemErrors.RT_Assert
                 (C       => STree.Syntax_Node_Type (Node => Current_Node) = SP_Symbols.simple_expression
                    or else STree.Syntax_Node_Type (Node => Current_Node) = SP_Symbols.annotation_simple_expression,
                  Sys_Err => SystemErrors.Invalid_Syntax_Tree,
                  Msg     => "Expect Current_Node = simple_expression OR annotation_simple_expression " &
                    "in Attribute_Is_Below_Catenation_Operator");
               Current_Node := STree.Next_Sibling (Current_Node => Current_Node);
               -- ASSUME Current_Node =            simple_expression OR            range_constraint OR inside  OR
               --                       annotation_simple_expression OR annotation_range_constraint OR outside OR
               --                       relational_operator OR binary_adding_operator OR arange OR NULL

               -- From SPARK.LLA:
               --
               -- simple_expression :
               --     simple_expression binary_adding_operator term
               --   | simple_expression_opt ;
               -- (and similarly for annotation_simple_expression)
               -- So...we might be looking at an attribute which is on the Left or
               -- the Right hand side of the binary_adding_operator.

               -- If we're on the Left side, then the simple_expression found
               -- might have a binary_adding_operator as its sibling, so
               if Current_Node = STree.NullNode
                 or else STree.Syntax_Node_Type (Node => Current_Node) = SP_Symbols.simple_expression
                 or else STree.Syntax_Node_Type (Node => Current_Node) = SP_Symbols.annotation_simple_expression
                 or else STree.Syntax_Node_Type (Node => Current_Node) = SP_Symbols.range_constraint
                 or else STree.Syntax_Node_Type (Node => Current_Node) = SP_Symbols.annotation_range_constraint
                 or else STree.Syntax_Node_Type (Node => Current_Node) = SP_Symbols.inside
                 or else STree.Syntax_Node_Type (Node => Current_Node) = SP_Symbols.outside
                 or else STree.Syntax_Node_Type (Node => Current_Node) = SP_Symbols.relational_operator
                 or else STree.Syntax_Node_Type (Node => Current_Node) = SP_Symbols.arange then
                  -- ASSUME Current_Node =            simple_expression OR            range_constraint OR inside  OR
                  --                       annotation_simple_expression OR annotation_range_constraint OR outside OR
                  --                       relational_operator OR arange OR NULL
                  Current_Node := STree.NullNode;
               elsif STree.Syntax_Node_Type (Node => Current_Node) /= SP_Symbols.binary_adding_operator then
                  Current_Node := STree.NullNode;
                  SystemErrors.Fatal_Error
                    (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
                     Msg     => "Expect Current_Node = relational_operator OR binary_adding_operator OR arange OR " &
                       "           simple_expression OR            range_constraint OR inside  OR " &
                       "annotation_simple_expression OR annotation_range_constraint OR outside OR " &
                       "NULL in Attribute_Is_Below_Catenation_Operator");
               end if;
            elsif STree.Syntax_Node_Type (Node => Current_Node) = SP_Symbols.simple_expression
              or else STree.Syntax_Node_Type (Node => Current_Node) = SP_Symbols.annotation_simple_expression then
               -- ASSUME Current_Node = simple_expression OR annotation_simple_expression

               -- If the attribute was on the Right of the "&", then we'll have stepped
               -- over the "term" and arrived at the simple_expression _above_ the operator
               -- node, so
               Current_Node := STree.Child_Node (Current_Node => Current_Node);
               -- ASSUME Current_Node = annotation_simple_expression OR simple_expression
               SystemErrors.RT_Assert
                 (C       => STree.Syntax_Node_Type (Node => Current_Node) = SP_Symbols.simple_expression
                    or else STree.Syntax_Node_Type (Node => Current_Node) = SP_Symbols.annotation_simple_expression,
                  Sys_Err => SystemErrors.Invalid_Syntax_Tree,
                  Msg     => "Expect Current_Node = simple_expression OR annotation_simple_expression " &
                    "in Attribute_Is_Below_Catenation_Operator");
               Current_Node := STree.Next_Sibling (Current_Node => Current_Node);
               -- ASSUME Current_Node = binary_adding_operator
               SystemErrors.RT_Assert
                 (C       => STree.Syntax_Node_Type (Node => Current_Node) = SP_Symbols.binary_adding_operator,
                  Sys_Err => SystemErrors.Invalid_Syntax_Tree,
                  Msg     => "Expect Current_Node = binary_adding_operator in Attribute_Is_Below_Catenation_Operator");
            else
               Current_Node := STree.NullNode;
               SystemErrors.Fatal_Error
                 (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
                  Msg     => "Expect Current_Node = simple_expression OR annotation_simple_expression OR " &
                    "simple_expression_opt OR annotation_simple_expression_opt " &
                    "in Attribute_Is_Below_Catenation_Operator");
            end if;
            -- ASSUME Current_Node = binary_adding_operator OR NULL
            if Current_Node = STree.NullNode then
               Result := False;
            elsif STree.Syntax_Node_Type (Node => Current_Node) = SP_Symbols.binary_adding_operator then
               -- ASSUME Current_Node = binary_adding_operator
               Current_Node := STree.Child_Node (Current_Node => Current_Node);
               -- ASSUME Current_Node = plus OR minus OR ampersand
               SystemErrors.RT_Assert
                 (C       => STree.Syntax_Node_Type (Node => Current_Node) = SP_Symbols.plus
                    or else STree.Syntax_Node_Type (Node => Current_Node) = SP_Symbols.minus
                    or else STree.Syntax_Node_Type (Node => Current_Node) = SP_Symbols.ampersand,
                  Sys_Err => SystemErrors.Invalid_Syntax_Tree,
                  Msg     => "Expect Current_Node = plus OR minus OR ampersand in Attribute_Is_Below_Catenation_Operator");
               Result := STree.Syntax_Node_Type (Node => Current_Node) = SP_Symbols.ampersand;
            else
               Result := False;
               SystemErrors.Fatal_Error
                 (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
                  Msg     => "Expect Current_Node = binary_adding_operator OR NULL in Attribute_Is_Below_Catenation_Operator");
            end if;
         else
            Result := False;
            SystemErrors.Fatal_Error
              (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
               Msg     => "Expect Current_Node = annotation_primary OR primary OR annotation_arange OR arange " &
                 "in Attribute_Is_Below_Catenation_Operator");
         end if;
         return Result;
      end Attribute_Is_Below_Catenation_Operator;

   begin -- Basic_Checks
      Ok := False;
      if not LexTokenManager.Is_Attribute_Token (Tok      => Ident_Str,
                                                 Language => CommandLineData.Content.Language_Profile) then
         Type_So_Far := Sem.Unknown_Type_Record;
         ErrorHandler.Semantic_Error
           (Err_Num   => 54,
            Reference => ErrorHandler.No_Reference,
            Position  => Ident_Node_Pos,
            Id_Str    => Ident_Str);

      elsif Not_Yet_Implemented (Str => Ident_Str) then
         Type_So_Far := Sem.Unknown_Type_Record;
         ErrorHandler.Semantic_Error
           (Err_Num   => 30,
            Reference => ErrorHandler.No_Reference,
            Position  => Ident_Node_Pos,
            Id_Str    => Ident_Str);

      elsif Is_Proof_Attribute (Str => Ident_Str)
        and then STree.Syntax_Node_Type (Node => Node) = SP_Symbols.attribute_designator then
         Type_So_Far := Sem.Unknown_Type_Record;
         ErrorHandler.Semantic_Error
           (Err_Num   => 54,
            Reference => ErrorHandler.No_Reference,
            Position  => Ident_Node_Pos,
            Id_Str    => Ident_Str);

      elsif Argument_Found and then Never_Takes_Arguments (Str => Ident_Str) then
         Type_So_Far := Sem.Unknown_Type_Record;
         ErrorHandler.Semantic_Error
           (Err_Num   => 55,
            Reference => ErrorHandler.No_Reference,
            Position  => Arg_Exp_Node_Pos,
            Id_Str    => Ident_Str);

      elsif not Argument_Found
        and then (Always_Takes_One_Argument (Str => Ident_Str) or else (Always_Takes_Two_Arguments (Str => Ident_Str))) then
         Type_So_Far := Sem.Unknown_Type_Record;
         ErrorHandler.Semantic_Error
           (Err_Num   => 56,
            Reference => ErrorHandler.No_Reference,
            Position  => Ident_Node_Pos,
            Id_Str    => LexTokenManager.Null_String);

      elsif not Second_Argument_Found and then (Always_Takes_Two_Arguments (Str => Ident_Str)) then
         Type_So_Far := Sem.Unknown_Type_Record;
         ErrorHandler.Semantic_Error
           (Err_Num   => 56,
            Reference => ErrorHandler.No_Reference,
            Position  => Arg_Exp_Node_Pos,
            Id_Str    => LexTokenManager.Null_String);

      elsif Second_Argument_Found and then Always_Takes_One_Argument (Str => Ident_Str) then
         Type_So_Far := Sem.Unknown_Type_Record;
         ErrorHandler.Semantic_Error
           (Err_Num   => 49,
            Reference => ErrorHandler.No_Reference,
            Position  => Second_Arg_Exp_Node_Pos,
            Id_Str    => Ident_Str);

         -- check that prefix of Pred, Succ, Pos, Val is typemark
      elsif Always_Takes_One_Argument (Str => Ident_Str)
        and then not Is_Proof_Attribute (Str => Ident_Str)
        and then -- don't want 'Tail to trip this test
        Type_So_Far.Sort = Sem.Is_Object then
         ErrorHandler.Semantic_Error
           (Err_Num   => 63,
            Reference => ErrorHandler.No_Reference,
            Position  => STree.Node_Position (Node => STree.Parent_Node (Current_Node => Node)),
            Id_Str    => Dictionary.GetSimpleName (Type_So_Far.Other_Symbol));
         Type_So_Far := Sem.Unknown_Type_Record;

      elsif Attribute_Is_Below_Catenation_Operator (Node => Node) then

         -- FDL has no "&" operator, so the VCG has to be able to
         -- statically evaluate all "&" operators (for Strings and Characters).
         -- Therefore, for simplicity, the SPARK LRM (4.5.3) forbids attributes
         -- below an "&" operator.  Chacacter'Val ( ... ) is particularly
         -- troublesome, since this would require the VCG to be able to
         -- statically evaluate some arbitrary integer-valued expression.
         Type_So_Far := Sem.Unknown_Type_Record;

         -- Assume Character type result to avoid additional type-checking errors
         Type_So_Far.Type_Symbol := Dictionary.GetPredefinedCharacterType;

         ErrorHandler.Semantic_Error
           (Err_Num   => 424,
            Reference => ErrorHandler.No_Reference,
            Position  => Ident_Node_Pos,
            Id_Str    => Ident_Str);
      else
         Ok := True;
      end if;
   end Basic_Checks;

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

   procedure Base_Checks
     (Node           : in     STree.SyntaxNode;
      Ident_Node_Pos : in     LexTokenManager.Token_Position;
      Ident_Str      : in     LexTokenManager.Lex_String;
      Type_So_Far    : in out Sem.Exp_Record;
      Continue       :    out Boolean)
   --# global in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     LexTokenManager.State;
   --#        in     STree.Table;
   --#        in out ErrorHandler.Error_Context;
   --#        in out SPARK_IO.File_Sys;
   --# derives Continue                   from Ident_Str,
   --#                                         LexTokenManager.State &
   --#         ErrorHandler.Error_Context,
   --#         SPARK_IO.File_Sys          from CommandLineData.Content,
   --#                                         Dictionary.Dict,
   --#                                         ErrorHandler.Error_Context,
   --#                                         Ident_Node_Pos,
   --#                                         Ident_Str,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         SPARK_IO.File_Sys,
   --#                                         STree.Table,
   --#                                         Type_So_Far &
   --#         Type_So_Far                from *,
   --#                                         Dictionary.Dict,
   --#                                         Ident_Str,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         STree.Table;
   --# pre STree.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.attribute_designator or
   --#   STree.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.annotation_attribute_designator;
   is
      The_Parent_Node, The_Child_Node : STree.SyntaxNode;
   begin
      if LexTokenManager.Lex_String_Case_Insensitive_Compare (Lex_Str1 => Ident_Str,
                                                              Lex_Str2 => LexTokenManager.Base_Token) =
        LexTokenManager.Str_Eq then
         Continue        := False; -- whatever happens we don't want to do any more checks
         The_Parent_Node := STree.Parent_Node (Current_Node => Node);
         -- ASSUME The_Parent_Node = attribute            OR attribute_designator OR
         --                          annotation_attribute OR annotation_attribute_designator
         SystemErrors.RT_Assert
           (C       => STree.Syntax_Node_Type (Node => The_Parent_Node) = SP_Symbols.attribute
              or else STree.Syntax_Node_Type (Node => The_Parent_Node) = SP_Symbols.attribute_designator
              or else STree.Syntax_Node_Type (Node => The_Parent_Node) = SP_Symbols.annotation_attribute
              or else STree.Syntax_Node_Type (Node => The_Parent_Node) = SP_Symbols.annotation_attribute_designator,
            Sys_Err => SystemErrors.Invalid_Syntax_Tree,
            Msg     => "Expect The_Parent_Node = attribute OR attribute_designator OR " &
              "annotation_attribute OR annotation_attribute_designator in Base_Checks");
         The_Child_Node := STree.Child_Node (Current_Node => Node);
         -- ASSUME The_Child_Node = attribute_designator OR annotation_attribute_designator OR attribute_ident
         SystemErrors.RT_Assert
           (C       => STree.Syntax_Node_Type (Node => The_Child_Node) = SP_Symbols.attribute_designator
              or else STree.Syntax_Node_Type (Node => The_Child_Node) = SP_Symbols.annotation_attribute_designator
              or else STree.Syntax_Node_Type (Node => The_Child_Node) = SP_Symbols.attribute_ident,
            Sys_Err => SystemErrors.Invalid_Syntax_Tree,
            Msg     => "Expect The_Child_Node = attribute_designator OR annotation_attribute_designator OR " &
              "attribute_ident in Base_Checks");
         if STree.Syntax_Node_Type (Node => The_Parent_Node) = SP_Symbols.attribute
           or else STree.Syntax_Node_Type (Node => The_Parent_Node) = SP_Symbols.annotation_attribute
           or else STree.Syntax_Node_Type (Node => The_Child_Node) = SP_Symbols.attribute_designator
           or else STree.Syntax_Node_Type (Node => The_Child_Node) = SP_Symbols.annotation_attribute_designator then
            Type_So_Far := Sem.Unknown_Type_Record;
            if STree.Syntax_Node_Type (Node => Node) = SP_Symbols.annotation_attribute_designator then
               ErrorHandler.Semantic_Error
                 (Err_Num   => 97,
                  Reference => 2,
                  Position  => STree.Node_Position (Node => Node),
                  Id_Str    => LexTokenManager.Null_String);
            else
               ErrorHandler.Semantic_Error
                 (Err_Num   => 97,
                  Reference => 1,
                  Position  => STree.Node_Position (Node => Node),
                  Id_Str    => LexTokenManager.Null_String);
            end if;
         elsif Type_So_Far.Sort /= Sem.Is_Type_Mark then
            Type_So_Far := Sem.Unknown_Type_Record;
            ErrorHandler.Semantic_Error
              (Err_Num   => 96,
               Reference => ErrorHandler.No_Reference,
               Position  => Ident_Node_Pos,
               Id_Str    => Ident_Str);
         end if;
      else
         Continue := True;
      end if;
   end Base_Checks;

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

   procedure Process_Array_Attribute
     (Ident_Str           : in     LexTokenManager.Lex_String;
      Prefix_Type         : in     Dictionary.Symbol;
      Arg_Exp_Node_Pos    : in     LexTokenManager.Token_Position;
      Argument_Expression : in     Sem.Exp_Record;
      Argument_Found      : in     Boolean;
      Scope               : in     Dictionary.Scopes;
      Type_So_Far         : in out Sem.Exp_Record;
      Ok_So_Far           : in out Boolean;
      VCG_Type            : in out Dictionary.Symbol)
   --# global in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     LexTokenManager.State;
   --#        in out ErrorHandler.Error_Context;
   --#        in out SPARK_IO.File_Sys;
   --# derives ErrorHandler.Error_Context,
   --#         SPARK_IO.File_Sys          from Argument_Expression,
   --#                                         Argument_Found,
   --#                                         Arg_Exp_Node_Pos,
   --#                                         CommandLineData.Content,
   --#                                         Dictionary.Dict,
   --#                                         ErrorHandler.Error_Context,
   --#                                         LexTokenManager.State,
   --#                                         Scope,
   --#                                         SPARK_IO.File_Sys,
   --#                                         Type_So_Far &
   --#         Ok_So_Far                  from *,
   --#                                         Argument_Expression,
   --#                                         Argument_Found,
   --#                                         CommandLineData.Content,
   --#                                         Dictionary.Dict,
   --#                                         Type_So_Far &
   --#         Type_So_Far                from *,
   --#                                         Argument_Expression,
   --#                                         Argument_Found,
   --#                                         CommandLineData.Content,
   --#                                         Dictionary.Dict,
   --#                                         Ident_Str,
   --#                                         LexTokenManager.State,
   --#                                         Prefix_Type,
   --#                                         Scope &
   --#         VCG_Type                   from *,
   --#                                         Argument_Expression,
   --#                                         Argument_Found,
   --#                                         CommandLineData.Content,
   --#                                         Dictionary.Dict,
   --#                                         Ident_Str,
   --#                                         LexTokenManager.State,
   --#                                         Scope,
   --#                                         Type_So_Far;
   --#
   --# pre Dictionary.Is_Null_Symbol (VCG_Type) or Dictionary.IsTypeMark (VCG_Type, Dictionary.Dict);
   --# post Dictionary.Is_Null_Symbol (VCG_Type) or
   --#   Dictionary.IsTypeMark (VCG_Type, Dictionary.Dict) or
   --#   Dictionary.IsParameterConstraint (VCG_Type, Dictionary.Dict);
   is
      Index_Number : Positive;
      Continue     : Boolean;

      procedure Process_Argument
        (Ident_Str           : in     LexTokenManager.Lex_String;
         Arg_Exp_Node_Pos    : in     LexTokenManager.Token_Position;
         Argument_Expression : in     Sem.Exp_Record;
         Scope               : in     Dictionary.Scopes;
         Index_Number        : in out Positive;
         Type_So_Far         : in out Sem.Exp_Record;
         Ok_So_Far           : in out Boolean;
         Ok                  :    out Boolean)
      -- 430 annotation completed
      --# global in     CommandLineData.Content;
      --#        in     Dictionary.Dict;
      --#        in     LexTokenManager.State;
      --#        in out ErrorHandler.Error_Context;
      --#        in out SPARK_IO.File_Sys;
      --# derives ErrorHandler.Error_Context,
      --#         SPARK_IO.File_Sys          from Argument_Expression,
      --#                                         Arg_Exp_Node_Pos,
      --#                                         CommandLineData.Content,
      --#                                         Dictionary.Dict,
      --#                                         ErrorHandler.Error_Context,
      --#                                         LexTokenManager.State,
      --#                                         Scope,
      --#                                         SPARK_IO.File_Sys,
      --#                                         Type_So_Far &
      --#         Index_Number,
      --#         Ok_So_Far                  from *,
      --#                                         Argument_Expression,
      --#                                         CommandLineData.Content,
      --#                                         Dictionary.Dict,
      --#                                         Type_So_Far &
      --#         Ok                         from Argument_Expression,
      --#                                         CommandLineData.Content,
      --#                                         Dictionary.Dict,
      --#                                         Type_So_Far &
      --#         Type_So_Far                from *,
      --#                                         Argument_Expression,
      --#                                         CommandLineData.Content,
      --#                                         Dictionary.Dict,
      --#                                         Ident_Str,
      --#                                         LexTokenManager.State;
      is
         Err                : Maths.ErrorCode;
         Local_Index_Number : Integer;

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

         procedure Set_Illegal_Result
           (Ident_Str   : in     LexTokenManager.Lex_String;
            Type_So_Far :    out Sem.Exp_Record;
            Ok_So_Far   :    out Boolean)
         --# global in Dictionary.Dict;
         --#        in LexTokenManager.State;
         --# derives Ok_So_Far   from  &
         --#         Type_So_Far from Dictionary.Dict,
         --#                          Ident_Str,
         --#                          LexTokenManager.State;
         is
         begin
            Ok_So_Far             := False;
            Type_So_Far           := Sem.Unknown_Type_Record;
            Type_So_Far.Is_ARange := Check_Range (Ident_Str => Ident_Str);
         end Set_Illegal_Result;

      begin -- Process_Argument
         Ok := False;
         -- Ada83 LRM says arg N must be Universal Integer.
         -- Ada95 LRM says arg N must be Universal Integer or any integer
         --   (signed or modular) type.
         if not (Dictionary.IsUniversalIntegerType (Argument_Expression.Type_Symbol)
                   or else Dictionary.IsUnknownTypeMark (Argument_Expression.Type_Symbol)
                   or else ((Dictionary.TypeIsInteger (Argument_Expression.Type_Symbol)
                               or else Dictionary.TypeIsModular (Argument_Expression.Type_Symbol))
                            and then CommandLineData.Content.Language_Profile /= CommandLineData.SPARK83)) then
            Set_Illegal_Result (Ident_Str   => Ident_Str,
                                Type_So_Far => Type_So_Far,
                                Ok_So_Far   => Ok_So_Far);
            ErrorHandler.Semantic_Error
              (Err_Num   => 38,
               Reference => ErrorHandler.No_Reference,
               Position  => Arg_Exp_Node_Pos,
               Id_Str    => LexTokenManager.Null_String);
         elsif not Argument_Expression.Is_Static then
            Set_Illegal_Result (Ident_Str   => Ident_Str,
                                Type_So_Far => Type_So_Far,
                                Ok_So_Far   => Ok_So_Far);
            ErrorHandler.Semantic_Error
              (Err_Num   => 36,
               Reference => 1,
               Position  => Arg_Exp_Node_Pos,
               Id_Str    => LexTokenManager.Null_String);
         else -- we have a static expression of the correct type
            Maths.ValueToInteger (Argument_Expression.Value,
                                  -- to get
                                  Local_Index_Number, Err);
            if Err = Maths.NoError then
               if Local_Index_Number > 0
                 and then Local_Index_Number <= Dictionary.GetNumberOfDimensions (Type_So_Far.Type_Symbol) then
                  Index_Number := Local_Index_Number;
                  Ok           := True;
               else -- number out of range
                  ErrorHandler.Semantic_Error_Sym
                    (Err_Num   => 403,
                     Reference => ErrorHandler.No_Reference,
                     Position  => Arg_Exp_Node_Pos,
                     Sym       => Type_So_Far.Type_Symbol,
                     Scope     => Scope);
                  Set_Illegal_Result (Ident_Str   => Ident_Str,
                                      Type_So_Far => Type_So_Far,
                                      Ok_So_Far   => Ok_So_Far);
               end if;
            else -- maths conversion error
               Set_Illegal_Result (Ident_Str   => Ident_Str,
                                   Type_So_Far => Type_So_Far,
                                   Ok_So_Far   => Ok_So_Far);
            end if;
         end if;
      end Process_Argument;

   begin -- Process_Array_Attribute
      Continue     := True;
      Index_Number := 1; -- default value if no argument found
      if Argument_Found then
         Process_Argument
           (Ident_Str           => Ident_Str,
            Arg_Exp_Node_Pos    => Arg_Exp_Node_Pos,
            Argument_Expression => Argument_Expression,
            Scope               => Scope,
            Index_Number        => Index_Number,
            Type_So_Far         => Type_So_Far,
            Ok_So_Far           => Ok_So_Far,
            Ok                  => Continue);
      end if;
      if Continue then
         -- Set suitable symbol to be planted in the syntax tree for use by VCG
         if LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Ident_Str,
            Lex_Str2 => LexTokenManager.Component_Size_Token) =
           LexTokenManager.Str_Eq then
            -- For component_size we want the type of the array for use by the VCG
            VCG_Type := Dictionary.GetRootType (Type_So_Far.Type_Symbol);
         elsif Dictionary.Is_Unconstrained_Array_Type_Mark (Type_So_Far.Type_Symbol, Scope) then
            -- For unconstrained arrays, obtain the implcitly declared constraint symbol for the array object
            VCG_Type := Dictionary.GetSubprogramParameterConstraint (Type_So_Far.Other_Symbol, Index_Number);
            if Dictionary.Is_Null_Symbol (VCG_Type) then
               VCG_Type := Dictionary.GetUnknownTypeMark;
            end if;
         else
            -- For constrained arrays then obtain appropriate index for the array type; this is what the VCG needs
            VCG_Type := Dictionary.GetArrayIndex (Type_So_Far.Type_Symbol, Index_Number);
         end if;

         Type_So_Far.Is_Static    :=
           Check_Static
           (Ident_Str           => Ident_Str,
            Prefix_Type         => Prefix_Type,
            Type_So_Far         => Type_So_Far,
            Argument_Expression => Argument_Expression,
            Argument_Found      => Argument_Found,
            Scope               => Scope);
         Type_So_Far.Is_Constant  :=
           Check_Constant
           (Ident_Str           => Ident_Str,
            Type_So_Far         => Type_So_Far,
            Argument_Expression => Argument_Expression,
            Argument_Found      => Argument_Found,
            Scope               => Scope);
         Type_So_Far.Is_ARange    := Check_Range (Ident_Str => Ident_Str);
         Type_So_Far.Type_Symbol  := Dictionary.GetArrayAttributeType (Ident_Str, Type_So_Far.Type_Symbol, Index_Number);
         Type_So_Far.Other_Symbol := Dictionary.NullSymbol;
         Type_So_Far.Sort         := Sem.Type_Result;
      end if;
   end Process_Array_Attribute;

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

   procedure Calc_Attribute
     (Node         : in     STree.SyntaxNode;
      Attrib_Name  : in     LexTokenManager.Lex_String;
      Prefix       : in     Dictionary.Symbol;
      Scope        : in     Dictionary.Scopes;
      Base_Found   : in     Boolean;
      Argument     : in out Maths.Value;
      RHS_Of_Range :    out Maths.Value)
   --# global in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     LexTokenManager.State;
   --#        in     STree.Table;
   --#        in out ErrorHandler.Error_Context;
   --#        in out SPARK_IO.File_Sys;
   --# derives Argument,
   --#         RHS_Of_Range               from Argument,
   --#                                         Attrib_Name,
   --#                                         Base_Found,
   --#                                         Dictionary.Dict,
   --#                                         LexTokenManager.State,
   --#                                         Prefix,
   --#                                         Scope &
   --#         ErrorHandler.Error_Context,
   --#         SPARK_IO.File_Sys          from Argument,
   --#                                         Attrib_Name,
   --#                                         Base_Found,
   --#                                         CommandLineData.Content,
   --#                                         Dictionary.Dict,
   --#                                         ErrorHandler.Error_Context,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         Prefix,
   --#                                         Scope,
   --#                                         SPARK_IO.File_Sys,
   --#                                         STree.Table;
   --# pre STree.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.attribute_designator or
   --#   STree.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.annotation_attribute_designator;
      is separate;

begin -- Wf_Attribute_Designator
   Argument_Expression        := Sem.Null_Exp_Record;
   Second_Argument_Expression := Sem.Null_Exp_Record;
   Base_Found                 := False;
   Ident_Node                 := STree.Child_Node (Current_Node => Node);
   -- ASSUME Ident_Node = attribute_designator OR annotation_attribute_designator OR attribute_ident
   if STree.Syntax_Node_Type (Node => Ident_Node) = SP_Symbols.attribute_designator
     or else STree.Syntax_Node_Type (Node => Ident_Node) = SP_Symbols.annotation_attribute_designator then
      -- ASSUME Ident_Node = attribute_designator OR annotation_attribute_designator
      Ident_Node := STree.Next_Sibling (Current_Node => Ident_Node);
      Base_Found := True;
   elsif STree.Syntax_Node_Type (Node => Ident_Node) /= SP_Symbols.attribute_ident then
      SystemErrors.Fatal_Error
        (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
         Msg     => "Expect Ident_Node = attribute_designator OR annotation_attribute_designator OR " &
           "attribute_ident in Wf_Attribute_Designator");
   end if;
   -- ASSUME Ident_Node = attribute_ident
   SystemErrors.RT_Assert
     (C       => STree.Syntax_Node_Type (Node => Ident_Node) = SP_Symbols.attribute_ident,
      Sys_Err => SystemErrors.Invalid_Syntax_Tree,
      Msg     => "Expect Ident_Node = attribute_ident in Wf_Attribute_Designator");
   Ident_Str      := STree.Node_Lex_String (Node => Ident_Node);
   Ident_Node_Pos := STree.Node_Position (Node => Ident_Node);

   Second_Arg_Exp_Node := STree.NullNode;
   Arg_Exp_Node        := STree.Child_Node (Current_Node => STree.Next_Sibling (Current_Node => Ident_Node));
   -- ASSUME Arg_Exp_Node = expression OR annotation_expression OR NULL
   if STree.Syntax_Node_Type (Node => Arg_Exp_Node) = SP_Symbols.expression
     or else STree.Syntax_Node_Type (Node => Arg_Exp_Node) = SP_Symbols.annotation_expression then
      -- ASSUME Arg_Exp_Node = expression OR annotation_expression
      Second_Arg_Exp_Node := STree.Next_Sibling (Current_Node => Arg_Exp_Node);
   elsif Arg_Exp_Node /= STree.NullNode then
      SystemErrors.Fatal_Error
        (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
         Msg     => "Expect Arg_Exp_Node = expression OR annotation_expression OR NULL in Wf_Attribute_Designator");
   end if;

   -- look for second argument
   -- ASSUME Second_Arg_Exp_Node = expression OR annotation_expression OR NULL
   if STree.Syntax_Node_Type (Node => Second_Arg_Exp_Node) = SP_Symbols.expression
     or else STree.Syntax_Node_Type (Node => Second_Arg_Exp_Node) = SP_Symbols.annotation_expression then
      -- ASSUME Second_Arg_Exp_Node = expression OR annotation_expression
      Second_Argument_Found := True;
      Exp_Stack.Pop (Item  => Second_Argument_Expression,
                     Stack => E_Stack);
   elsif Second_Arg_Exp_Node = STree.NullNode then
      -- ASSUME Second_Arg_Exp_Node = NULL
      Second_Argument_Found := False;
   else
      SystemErrors.Fatal_Error
        (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
         Msg     => "Expect Second_Arg_Exp_Node = expression OR annotation_expression OR NULL in Wf_Attribute_Designator");
   end if;
   Second_Arg_Exp_Node_Pos := STree.Node_Position (Node => Second_Arg_Exp_Node);

   -- look for first argument
   -- ASSUME Arg_Exp_Node = expression OR annotation_expression OR NULL
   if STree.Syntax_Node_Type (Node => Arg_Exp_Node) = SP_Symbols.expression
     or else STree.Syntax_Node_Type (Node => Arg_Exp_Node) = SP_Symbols.annotation_expression then
      -- ASSUME Arg_Exp_Node = expression OR annotation_expression
      Argument_Found := True;
      Exp_Stack.Pop (Item  => Argument_Expression,
                     Stack => E_Stack);
   elsif Arg_Exp_Node = STree.NullNode then
      -- ASSUME Arg_Exp_Node = NULL
      Argument_Found := False;
   end if;
   Arg_Exp_Node_Pos := STree.Node_Position (Node => Arg_Exp_Node);

   Get_Prefix
     (Ident_Node_Pos => Ident_Node_Pos,
      Node_Pos       => STree.Node_Position (Node => Node),
      Scope          => Scope,
      Base_Found     => Base_Found,
      Prefix         => Type_So_Far,
      Kind           => Prefix_Kind,
      E_Stack        => E_Stack);
   Prefix_Type := Type_So_Far.Type_Symbol;
   VCG_Type    := Prefix_Type;

   -- if clause to add prefix variable to reference list

   --# assert STree.Table = STree.Table~ and
   --#   (STree.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.attribute_designator or
   --#      STree.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.annotation_attribute_designator) and
   --#   (Dictionary.Is_Null_Symbol (VCG_Type) or Dictionary.IsTypeMark (VCG_Type, Dictionary.Dict));

   -- X'Valid _IS_ considered a read of X for flow analysis.
   if STree.Syntax_Node_Type (Node => Node) = SP_Symbols.attribute_designator
     and then Dictionary.IsVariableOrSubcomponent (Type_So_Far.Other_Symbol)
     and then (Dictionary.Is_Unconstrained_Array_Type_Mark (Type_So_Far.Type_Symbol, Scope)
                 or else LexTokenManager.Lex_String_Case_Insensitive_Compare
                 (Lex_Str1 => Ident_Str,
                  Lex_Str2 => LexTokenManager.Valid_Token) =
                 LexTokenManager.Str_Eq) then
      SeqAlgebra.AddMember (The_Heap, Ref_Var, Natural (Dictionary.SymbolRef (Type_So_Far.Other_Symbol)));
   end if;

   Basic_Checks
     (Node                    => Node,
      Ident_Node_Pos          => Ident_Node_Pos,
      Ident_Str               => Ident_Str,
      Arg_Exp_Node_Pos        => Arg_Exp_Node_Pos,
      Second_Arg_Exp_Node_Pos => Second_Arg_Exp_Node_Pos,
      Argument_Found          => Argument_Found,
      Second_Argument_Found   => Second_Argument_Found,
      Type_So_Far             => Type_So_Far,
      Ok                      => Ok_So_Far);
   if Ok_So_Far then
      Base_Checks
        (Node           => Node,
         Ident_Node_Pos => Ident_Node_Pos,
         Ident_Str      => Ident_Str,
         Type_So_Far    => Type_So_Far,
         Continue       => Ok_So_Far);
   end if;

   --# assert STree.Table = STree.Table~ and
   --#   (STree.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.attribute_designator or
   --#      STree.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.annotation_attribute_designator) and
   --#   (Dictionary.Is_Null_Symbol (VCG_Type) or Dictionary.IsTypeMark (VCG_Type, Dictionary.Dict));

   -- any attempt to use proof attributes 'Tail and 'Append in program context
   -- will have been trapped by basic checks which will have set Ok_So_Far to False.
   -- We can therefore treat type and argument checking of these proof attributes
   -- normally from here on because if they are being checked then they must be
   -- being used in a valid context

   if Ok_So_Far then
      if Dictionary.Attribute_Is_Visible_But_Obsolete (Ident_Str, Prefix_Kind, Type_So_Far.Type_Symbol, Scope) then
         ErrorHandler.Semantic_Warning (Err_Num  => 310,
                                        Position => Ident_Node_Pos,
                                        Id_Str   => Ident_Str);
      end if;

      if not (Dictionary.AttributeIsVisible (Ident_Str, Prefix_Kind, Type_So_Far.Type_Symbol, Scope)
                or else Proof_Attribute_Is_Visible
                (Ident_Str   => Ident_Str,
                 Prefix_Kind => Prefix_Kind,
                 Prefix_Sym  => Type_So_Far.Other_Symbol)) then
         Type_So_Far := Sem.Unknown_Type_Record;
         Ok_So_Far   := False;
         ErrorHandler.Semantic_Error
           (Err_Num   => 96,
            Reference => ErrorHandler.No_Reference,
            Position  => Ident_Node_Pos,
            Id_Str    => Ident_Str);
      elsif Dictionary.IsArrayAttribute (Ident_Str, Type_So_Far.Type_Symbol) then
         if Second_Argument_Found then
            -- must be error, array attributes take a maximum of one argument
            Type_So_Far := Sem.Unknown_Type_Record;
            Ok_So_Far   := False;
            ErrorHandler.Semantic_Error
              (Err_Num   => 49,
               Reference => ErrorHandler.No_Reference,
               Position  => Second_Arg_Exp_Node_Pos,
               Id_Str    => Ident_Str);
         else -- zero or one expression provided
            Process_Array_Attribute
              (Ident_Str           => Ident_Str,
               Prefix_Type         => Prefix_Type,
               Arg_Exp_Node_Pos    => Arg_Exp_Node_Pos,
               Argument_Expression => Argument_Expression,
               Argument_Found      => Argument_Found,
               Scope               => Scope,
               Type_So_Far         => Type_So_Far,
               Ok_So_Far           => Ok_So_Far,
               VCG_Type            => VCG_Type);
         end if;

      elsif LexTokenManager.Lex_String_Case_Insensitive_Compare (Lex_Str1 => Ident_Str,
                                                                 Lex_Str2 => LexTokenManager.Access_Token) =
        LexTokenManager.Str_Eq then
         -- 'Access only allowed if subject is aliased.  We could roll this into AttributeIsVisible
         -- but this would make the error unclear, so we do a special check here
         if Dictionary.VariableIsAliased (Type_So_Far.Other_Symbol) then
            -- valid application
            Type_So_Far.Is_Static       := False;
            Type_So_Far.Is_Constant     := True;
            Type_So_Far.Is_ARange       := False;
            Type_So_Far.Type_Symbol     := Dictionary.GetScalarAttributeType (Ident_Str, Type_So_Far.Type_Symbol);
            Type_So_Far.Variable_Symbol := Type_So_Far.Other_Symbol;
            Type_So_Far.Other_Symbol    := Dictionary.NullSymbol;
            Type_So_Far.Sort            := Sem.Type_Result;
            -- note we preserve OtherSymbol in VariableSymbol for use in wf_discriminant_constraint
         else
            Ok_So_Far := False;
            ErrorHandler.Semantic_Error_Sym
              (Err_Num   => 895,
               Reference => ErrorHandler.No_Reference,
               Position  => STree.Node_Position (Node => Node),
               Sym       => Type_So_Far.Other_Symbol,
               Scope     => Scope);
         end if;

      else -- an "ordinary" attribute
         if Argument_Found then
            if not (Always_Takes_One_Argument (Str => Ident_Str) or else Always_Takes_Two_Arguments (Str => Ident_Str)) then
               Type_So_Far := Sem.Unknown_Type_Record;
               Ok_So_Far   := False;
               ErrorHandler.Semantic_Error
                 (Err_Num   => 55,
                  Reference => ErrorHandler.No_Reference,
                  Position  => Arg_Exp_Node_Pos,
                  Id_Str    => Ident_Str);

            elsif Argument_Type_Correct
              (Str         => Ident_Str,
               Prefix_Type => Type_So_Far.Type_Symbol,
               Arg_Type    => Argument_Expression.Type_Symbol,
               Scope       => Scope) then
               -- first argument type is ok, is there a second
               if not Second_Argument_Found
                 or else Argument_Type_Correct
                 (Str         => Ident_Str,
                  Prefix_Type => Type_So_Far.Type_Symbol,
                  Arg_Type    => Second_Argument_Expression.Type_Symbol,
                  Scope       => Scope) then
                  -- either no second arg or it type checks ok
                  Type_So_Far.Is_Static    :=
                    Check_Static
                    (Ident_Str           => Ident_Str,
                     Prefix_Type         => Prefix_Type,
                     Type_So_Far         => Type_So_Far,
                     Argument_Expression => Argument_Expression,
                     Argument_Found      => Argument_Found,
                     Scope               => Scope);
                  Type_So_Far.Is_Constant  :=
                    Check_Constant
                    (Ident_Str           => Ident_Str,
                     Type_So_Far         => Type_So_Far,
                     Argument_Expression => Argument_Expression,
                     Argument_Found      => Argument_Found,
                     Scope               => Scope);
                  Type_So_Far.Is_ARange    := Check_Range (Ident_Str => Ident_Str);
                  Type_So_Far.Type_Symbol  := Dictionary.GetScalarAttributeType (Ident_Str, Type_So_Far.Type_Symbol);
                  Type_So_Far.Other_Symbol := Dictionary.NullSymbol;
                  Type_So_Far.Sort         := Sem.Type_Result;

               else -- second argument type wrong
                  Type_So_Far := Sem.Unknown_Type_Record;
                  Ok_So_Far   := False;
                  ErrorHandler.Semantic_Error
                    (Err_Num   => 38,
                     Reference => ErrorHandler.No_Reference,
                     Position  => Second_Arg_Exp_Node_Pos,
                     Id_Str    => LexTokenManager.Null_String);
               end if;

            else -- first argument type wrong
               Type_So_Far := Sem.Unknown_Type_Record;
               Ok_So_Far   := False;
               ErrorHandler.Semantic_Error
                 (Err_Num   => 38,
                  Reference => ErrorHandler.No_Reference,
                  Position  => Arg_Exp_Node_Pos,
                  Id_Str    => LexTokenManager.Null_String);
            end if;
         else -- no argument found so just set up result
            Type_So_Far.Is_Static    :=
              Check_Static
              (Ident_Str           => Ident_Str,
               Prefix_Type         => Prefix_Type,
               Type_So_Far         => Type_So_Far,
               Argument_Expression => Argument_Expression,
               Argument_Found      => Argument_Found,
               Scope               => Scope);
            Type_So_Far.Is_Constant  :=
              Check_Constant
              (Ident_Str           => Ident_Str,
               Type_So_Far         => Type_So_Far,
               Argument_Expression => Argument_Expression,
               Argument_Found      => Argument_Found,
               Scope               => Scope);
            Type_So_Far.Is_ARange    := Check_Range (Ident_Str => Ident_Str);
            Type_So_Far.Type_Symbol  := Dictionary.GetScalarAttributeType (Ident_Str, Type_So_Far.Type_Symbol);
            Type_So_Far.Other_Symbol := Dictionary.NullSymbol;
            Type_So_Far.Sort         := Sem.Type_Result;
         end if;
      end if;
   end if;

   --# assert STree.Table = STree.Table~ and
   --#   (STree.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.attribute_designator or
   --#      STree.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.annotation_attribute_designator) and
   --#   (Dictionary.Is_Null_Symbol (VCG_Type) or
   --#      Dictionary.IsTypeMark (VCG_Type, Dictionary.Dict) or
   --#      Dictionary.IsParameterConstraint (VCG_Type, Dictionary.Dict));
   -- if Dict has returned a null symbol for the attribute type then convert it to
   -- the unknown type symbol
   if Dictionary.Is_Null_Symbol (Type_So_Far.Type_Symbol) then
      Type_So_Far.Type_Symbol := Dictionary.GetUnknownTypeMark;
   end if;

   if Ok_So_Far then
      if Argument_Found then
         if Second_Argument_Found then
            -- we could statically evaluate Max and Min here but since use of these functions
            -- with two static arguments seems unlikely it has been left for now.  However,
            -- we must check that any static argument is in type range.
            Val := Argument_Expression.Value;
            --# accept Flow, 10, Unused_Val, "Expected ineffective assignment";
            Sem.Constraint_Check
              (Val           => Val,
               New_Val       => Unused_Val,
               Is_Annotation => STree.Syntax_Node_Type (Node => Node) = SP_Symbols.annotation_attribute_designator,
               Typ           => Dictionary.GetRootType (Prefix_Type),
               Position      => Arg_Exp_Node_Pos);
            --# end accept;
            Val := Second_Argument_Expression.Value;
            --# accept Flow, 10, Unused_Val, "Expected ineffective assignment";
            Sem.Constraint_Check
              (Val           => Val,
               New_Val       => Unused_Val,
               Is_Annotation => STree.Syntax_Node_Type (Node => Node) = SP_Symbols.annotation_attribute_designator,
               Typ           => Dictionary.GetRootType (Prefix_Type),
               Position      => Second_Arg_Exp_Node_Pos);
            --# end accept;
         else -- just one argument found
            Val := Argument_Expression.Value;
         end if;

      else -- no arguments found
         Val := Maths.NoValue;
      end if;
      -- constraint checking of arguments to attributes other than Min/Max done as part
      -- of CalcAttribute
      Calc_Attribute
        (Node         => Node,
         Attrib_Name  => Ident_Str,
         Prefix       => Prefix_Type,
         Scope        => Scope,
         Base_Found   => Base_Found,
         Argument     => Val,
         RHS_Of_Range => RHS_Val);
      Type_So_Far.Value     := Val;
      Type_So_Far.Range_RHS := RHS_Val;
   end if;

   Exp_Stack.Push (X     => Type_So_Far,
                   Stack => E_Stack);

   STree.Add_Node_Symbol (Node => Node,
                          Sym  => VCG_Type);
   --# accept Flow, 33, Unused_Val, "Expected ineffective assignment";
end Wf_Attribute_Designator;
