-------------------------------------------------------------------------------
-- (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)
procedure Wf_Pragma (Node  : in STree.SyntaxNode;
                     Scope : in Dictionary.Scopes) is
   Pack_Ident_Node, Pack_Spec_Node, Id_Node, Subprog_Or_Variable_Node : STree.SyntaxNode;
   Pack_Ident_Sym                                                     : Dictionary.Symbol;
   Statement_OK                                                       : Boolean;
   Error_To_Raise                                                     : Natural;

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

   procedure Wf_Elaborate_Body (Pragma_Node : in STree.SyntaxNode;
                                Pack_Sym    : in Dictionary.Symbol)
   --# global in     CommandLineData.Content;
   --#        in     LexTokenManager.State;
   --#        in out Dictionary.Dict;
   --#        in out ErrorHandler.Error_Context;
   --#        in out SPARK_IO.File_Sys;
   --#        in out STree.Table;
   --# derives Dictionary.Dict            from *,
   --#                                         Pack_Sym,
   --#                                         Pragma_Node,
   --#                                         STree.Table &
   --#         ErrorHandler.Error_Context,
   --#         SPARK_IO.File_Sys          from CommandLineData.Content,
   --#                                         Dictionary.Dict,
   --#                                         ErrorHandler.Error_Context,
   --#                                         LexTokenManager.State,
   --#                                         Pack_Sym,
   --#                                         Pragma_Node,
   --#                                         SPARK_IO.File_Sys,
   --#                                         STree.Table &
   --#         STree.Table                from *,
   --#                                         Dictionary.Dict,
   --#                                         LexTokenManager.State,
   --#                                         Pack_Sym,
   --#                                         Pragma_Node;
   --# pre Syntax_Node_Type (Pragma_Node, STree.Table) = SP_Symbols.apragma;
   --# post STree.Table = STree.Table~;
      is separate;

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

   procedure Wf_Pragma_Atomic (Pragma_Node : in STree.SyntaxNode;
                               Scope       : in Dictionary.Scopes)
   --# global in     CommandLineData.Content;
   --#        in     LexTokenManager.State;
   --#        in out Dictionary.Dict;
   --#        in out ErrorHandler.Error_Context;
   --#        in out SPARK_IO.File_Sys;
   --#        in out STree.Table;
   --# derives Dictionary.Dict,
   --#         STree.Table                from CommandLineData.Content,
   --#                                         Dictionary.Dict,
   --#                                         LexTokenManager.State,
   --#                                         Pragma_Node,
   --#                                         Scope,
   --#                                         STree.Table &
   --#         ErrorHandler.Error_Context,
   --#         SPARK_IO.File_Sys          from CommandLineData.Content,
   --#                                         Dictionary.Dict,
   --#                                         ErrorHandler.Error_Context,
   --#                                         LexTokenManager.State,
   --#                                         Pragma_Node,
   --#                                         Scope,
   --#                                         SPARK_IO.File_Sys,
   --#                                         STree.Table;
   --# pre Syntax_Node_Type (Pragma_Node, STree.Table) = SP_Symbols.apragma;
   --# post STree.Table = STree.Table~;
   is
      Arg_Ass_Node, Atomic_Arg, Parent_Apragma : STree.SyntaxNode;
      Is_Chain                                 : Boolean;
      Subject_Sym                              : Dictionary.Symbol;

      procedure Check_Arg_Count (Node       : in out STree.SyntaxNode;
                                 Atomic_Arg :    out STree.SyntaxNode)
      --# global in STree.Table;
      --# derives Atomic_Arg,
      --#         Node       from Node,
      --#                         STree.Table;
      --# pre Syntax_Node_Type (Node, STree.Table) = SP_Symbols.argument_association_rep;
      --# post (Syntax_Node_Type (Node, STree.Table) = SP_Symbols.argument_association or Node = STree.NullNode) and
      --#   (Syntax_Node_Type (Atomic_Arg, STree.Table) = SP_Symbols.identifier or
      --#      Syntax_Node_Type (Atomic_Arg, STree.Table) = SP_Symbols.ADA_expression);
      is
      begin
         while Syntax_Node_Type (Node => Node) = SP_Symbols.argument_association_rep loop
            -- ASSUME Node = argument_association_rep
            Node := Child_Node (Current_Node => Node);
         end loop;
         -- ASSUME Node = argument_association
         SystemErrors.RT_Assert
           (C       => Syntax_Node_Type (Node => Node) = SP_Symbols.argument_association,
            Sys_Err => SystemErrors.Invalid_Syntax_Tree,
            Msg     => "Expect Node = argument_association in Check_Arg_Count");

         Atomic_Arg := Child_Node (Current_Node => Node);
         -- ASSUME Atomic_Arg = identifier OR ADA_expression
         SystemErrors.RT_Assert
           (C       => Syntax_Node_Type (Node => Atomic_Arg) = SP_Symbols.identifier
              or else Syntax_Node_Type (Node => Atomic_Arg) = SP_Symbols.ADA_expression,
            Sys_Err => SystemErrors.Invalid_Syntax_Tree,
            Msg     => "Expect Atomic_Arg = identifier OR ADA_expression in Check_Arg_Count");

         Node := Next_Sibling (Current_Node => Parent_Node (Current_Node => Node));
         -- ASSUME Node = argument_association OR NULL
         SystemErrors.RT_Assert
           (C       => Node = STree.NullNode or else Syntax_Node_Type (Node => Node) = SP_Symbols.argument_association,
            Sys_Err => SystemErrors.Invalid_Syntax_Tree,
            Msg     => "Expect Node = argument_association OR NULL in Check_Arg_Count");
      end Check_Arg_Count;

      procedure Check_Is_Chain (Node     : in out STree.SyntaxNode;
                                Is_Chain :    out Boolean)
      --# global in STree.Table;
      --# derives Is_Chain,
      --#         Node     from Node,
      --#                       STree.Table;
      --# pre Syntax_Node_Type (Node, STree.Table) = SP_Symbols.ADA_expression;
      --# post Is_Chain and
      --#   (Syntax_Node_Type (Node, STree.Table) = SP_Symbols.identifier or
      --#      Syntax_Node_Type (Node, STree.Table) = SP_Symbols.character_literal or
      --#      Syntax_Node_Type (Node, STree.Table) = SP_Symbols.string_literal);
      is
         Next_Node : STree.SyntaxNode;
      begin
         -- Walk down the syntax tree; if there's ever a Next_Sibling
         -- on the way down, then this isn't a chain - so we can stop the
         -- walk. Otherwise, find the node at the end of the chain.
         loop
            Is_Chain  := Next_Sibling (Current_Node => Node) = STree.NullNode;
            Next_Node := Child_Node (Current_Node => Node);
            exit when not Is_Chain or else Next_Node = STree.NullNode;
            Node := Next_Node;
         end loop;
         -- ASSUME Node = identifier OR character_literal OR string_literal
         SystemErrors.RT_Assert
           (C       => Is_Chain
              and then (Syntax_Node_Type (Node => Node) = SP_Symbols.identifier
                          or else Syntax_Node_Type (Node => Node) = SP_Symbols.character_literal
                          or else Syntax_Node_Type (Node => Node) = SP_Symbols.string_literal),
            Sys_Err => SystemErrors.Invalid_Syntax_Tree,
            Msg     => "Expect Node = ADA_expression in Check_Is_Chain");
      end Check_Is_Chain;

      function Check_Location (Node_To_Check : STree.SyntaxNode) return Boolean
      --# global in STree.Table;
      --# pre Syntax_Node_Type (Node_To_Check, STree.Table) = SP_Symbols.compilation_unit or
      --#   Syntax_Node_Type (Node_To_Check, STree.Table) = SP_Symbols.pragma_rep or
      --#   Syntax_Node_Type (Node_To_Check, STree.Table) = SP_Symbols.initial_declarative_item_rep or
      --#   Syntax_Node_Type (Node_To_Check, STree.Table) = SP_Symbols.later_declarative_item_rep or
      --#   Syntax_Node_Type (Node_To_Check, STree.Table) = SP_Symbols.statement or
      --#   Syntax_Node_Type (Node_To_Check, STree.Table) = SP_Symbols.code_insertion or
      --#   Syntax_Node_Type (Node_To_Check, STree.Table) = SP_Symbols.visible_part_rep or
      --#   Syntax_Node_Type (Node_To_Check, STree.Table) = SP_Symbols.basic_declarative_item_rep or
      --#   Syntax_Node_Type (Node_To_Check, STree.Table) = SP_Symbols.renaming_declaration_rep or
      --#   Syntax_Node_Type (Node_To_Check, STree.Table) = SP_Symbols.task_pragma or
      --#   Syntax_Node_Type (Node_To_Check, STree.Table) = SP_Symbols.protected_operation_declaration_rep or
      --#   Syntax_Node_Type (Node_To_Check, STree.Table) = SP_Symbols.body_stub;
      is
         Node_Type : SP_Symbols.SP_Symbol;
      begin
         Node_Type := Syntax_Node_Type (Node => Node_To_Check);
         -- allows use in declarative parts of subprogram, package bodies,
         -- package visible parts and package private parts.
         return Node_Type = SP_Symbols.initial_declarative_item_rep
           or else Node_Type = SP_Symbols.basic_declarative_item_rep
           or else Node_Type = SP_Symbols.visible_part_rep;
      end Check_Location;

      -------------------------------------------------------------------------
      -- SEPR 2253 introduced the need for objects which are atomic but of a
      -- predefined type like Boolean, Character, or System.Address.
      -- RavenSPARK forbids Atomic on objects, and we can't apply pragma Atomic
      -- to these types, since they are predefined.
      -- Therefore, we allow a record type to be Atomic if it has a single
      -- field which ((is predefined and a scalar basetype) or (is System.Address))
      -------------------------------------------------------------------------
      function Is_Potentially_Atomic_Record_Type (Sym   : in Dictionary.Symbol;
                                                  Scope : in Dictionary.Scopes) return Boolean
      --# global in CommandLineData.Content;
      --#        in Dictionary.Dict;
      --#        in LexTokenManager.State;
      is
         Result         : Boolean;
         The_Component  : Dictionary.Symbol;
         The_Type       : Dictionary.Symbol;
         Package_System : Dictionary.Symbol;
         Type_Address   : Dictionary.Symbol;
      begin
         if Dictionary.IsRecordTypeMark (Sym, Scope) then
            if Dictionary.GetNumberOfComponents (Sym) = 1 and then not Dictionary.TypeIsTagged (Sym) then
               The_Component := Dictionary.GetRecordComponent (Sym, 1);
               The_Type      := Dictionary.GetType (The_Component);

               -- Acceptable if it's predefined, scalar, and not a subtype
               if Dictionary.IsPredefined (The_Type)
                 and then Dictionary.TypeIsScalar (The_Type)
                 and then not Dictionary.IsSubtype (The_Type) then
                  Result := True;
               else
                  -- Not predefined and scalar, so check for special
                  -- case of System.Address
                  Package_System :=
                    Dictionary.LookupItem
                    (Name              => LexTokenManager.System_Token,
                     Scope             => Dictionary.GlobalScope,
                     Context           => Dictionary.ProgramContext,
                     Full_Package_Name => False);
                  if not Dictionary.Is_Null_Symbol (Package_System) then
                     Type_Address :=
                       Dictionary.LookupSelectedItem
                       (Prefix   => Package_System,
                        Selector => LexTokenManager.Address_Token,
                        Scope    => Dictionary.Set_Visibility (The_Visibility => Dictionary.Visible,
                                                               The_Unit       => Package_System),
                        Context  => Dictionary.ProgramContext);
                     Result       :=
                       Dictionary.Types_Are_Equal
                       (Left_Symbol        => The_Type,
                        Right_Symbol       => Type_Address,
                        Full_Range_Subtype => False);
                  else
                     -- can't find package System, so
                     Result := False;
                  end if;
               end if;
            else
               -- Record with 0 or >= 2 fields, or a tagged record
               Result := False;
            end if;
         else
            -- Not a record type at all
            Result := False;
         end if;
         return Result;
      end Is_Potentially_Atomic_Record_Type;

   begin -- Wf_Pragma_Atomic
      Arg_Ass_Node := Next_Sibling (Current_Node => Child_Node (Current_Node => Pragma_Node));
      -- ASSUME Arg_Ass_Node = argument_association_rep OR NULL
      if Syntax_Node_Type (Node => Arg_Ass_Node) = SP_Symbols.argument_association_rep then
         -- ASSUME Arg_Ass_Node = argument_association_rep
         Check_Arg_Count (Node       => Arg_Ass_Node,
                          Atomic_Arg => Atomic_Arg);
         -- ASSUME Arg_Ass_Node = argument_association OR NULL
         if Arg_Ass_Node = STree.NullNode then
            -- ASSUME Arg_Ass_Node = NULL
            -- ASSUME Atomic_Arg = identifier OR ADA_expression
            if Syntax_Node_Type (Node => Atomic_Arg) = SP_Symbols.identifier then
               -- ASSUME Atomic_Arg = identifier
               -- The parameter to pragma Atomic must be a simple_name,
               -- not a named association.
               ErrorHandler.Semantic_Error
                 (Err_Num   => 851,
                  Reference => ErrorHandler.No_Reference,
                  Position  => Node_Position (Node => Atomic_Arg),
                  Id_Str    => LexTokenManager.Null_String);
            elsif Syntax_Node_Type (Node => Atomic_Arg) = SP_Symbols.ADA_expression then
               -- ASSUME Atomic_Arg = ADA_expression
               Check_Is_Chain (Node     => Atomic_Arg,
                               Is_Chain => Is_Chain);
               if Is_Chain and then Syntax_Node_Type (Node => Atomic_Arg) = SP_Symbols.identifier then
                  -- ASSUME Atomic_Arg = identifier
                  -- happy; found a simple_name; have the identifier
                  Subject_Sym :=
                    Dictionary.LookupItem
                    (Name              => Node_Lex_String (Node => Atomic_Arg),
                     Scope             => Scope,
                     Context           => Dictionary.ProgramContext,
                     Full_Package_Name => False);
                  if Dictionary.Is_Null_Symbol (Subject_Sym) then
                     -- the pragma refers to an identifier which isn't visible
                     -- at this point.
                     ErrorHandler.Semantic_Error
                       (Err_Num   => 1,
                        Reference => ErrorHandler.No_Reference,
                        Position  => Node_Position (Node => Atomic_Arg),
                        Id_Str    => Node_Lex_String (Node => Atomic_Arg));
                  else
                     if (Dictionary.IsTypeMark (Subject_Sym)
                           and then not Dictionary.IsSubtype (Subject_Sym)
                           and then (Dictionary.IsScalarTypeMark (Subject_Sym, Scope)
                                       or else Is_Potentially_Atomic_Record_Type (Sym   => Subject_Sym,
                                                                                  Scope => Scope))) then
                        -- OK; the pragma refers to a scalar base type or to
                        -- a record type that may be Atomic
                        Parent_Apragma := Parent_Node (Current_Node => Pragma_Node);
                        -- ASSUME Parent_Apragma = compilation_unit OR
                        --                         pragma_rep OR
                        --                         initial_declarative_item_rep OR
                        --                         later_declarative_item_rep OR
                        --                         statement OR
                        --                         code_insertion OR
                        --                         visible_part_rep OR
                        --                         basic_declarative_item_rep OR
                        --                         renaming_declaration_rep OR
                        --                         task_pragma OR
                        --                         protected_operation_declaration_rep OR
                        --                         body_stub
                        SystemErrors.RT_Assert
                          (C       => Syntax_Node_Type (Node => Parent_Apragma) = SP_Symbols.compilation_unit
                             or else Syntax_Node_Type (Node => Parent_Apragma) = SP_Symbols.pragma_rep
                             or else Syntax_Node_Type (Node => Parent_Apragma) = SP_Symbols.initial_declarative_item_rep
                             or else Syntax_Node_Type (Node => Parent_Apragma) = SP_Symbols.later_declarative_item_rep
                             or else Syntax_Node_Type (Node => Parent_Apragma) = SP_Symbols.statement
                             or else Syntax_Node_Type (Node => Parent_Apragma) = SP_Symbols.code_insertion
                             or else Syntax_Node_Type (Node => Parent_Apragma) = SP_Symbols.visible_part_rep
                             or else Syntax_Node_Type (Node => Parent_Apragma) = SP_Symbols.basic_declarative_item_rep
                             or else Syntax_Node_Type (Node => Parent_Apragma) = SP_Symbols.renaming_declaration_rep
                             or else Syntax_Node_Type (Node => Parent_Apragma) = SP_Symbols.task_pragma
                             or else Syntax_Node_Type (Node => Parent_Apragma) = SP_Symbols.protected_operation_declaration_rep
                             or else Syntax_Node_Type (Node => Parent_Apragma) = SP_Symbols.body_stub,
                           Sys_Err => SystemErrors.Invalid_Syntax_Tree,
                           Msg     => "Expect Parent_Apragma = compilation_unit OR pragma_rep OR " &
                             "initial_declarative_item_rep OR later_declarative_item_rep OR statement OR code_insertion OR " &
                             "visible_part_rep OR basic_declarative_item_rep OR renaming_declaration_rep OR task_pragma OR " &
                             "protected_operation_declaration_rep OR body_stub in Wf_Pragma_Atomic");
                        if Check_Location (Node_To_Check => Parent_Apragma)
                          and then Dictionary.GetScope (Subject_Sym) = Scope then
                           -- it's also in a legitimate part of the syntax tree,
                           -- and in the same scope as the variable or type it identifies.
                           STree.Set_Node_Lex_String (Sym  => Subject_Sym,
                                                      Node => Atomic_Arg);
                           Dictionary.SetTypeAtomic (Subject_Sym);
                        else
                           -- the pragma isn't legal here
                           ErrorHandler.Semantic_Error
                             (Err_Num   => 852,
                              Reference => ErrorHandler.No_Reference,
                              Position  => Node_Position (Node => Atomic_Arg),
                              Id_Str    => LexTokenManager.Null_String);
                        end if;
                     else
                        -- the argument to pragma Atomic must be a scalar base type,
                        -- or a record type that is potentially Atomic.
                        -- it's not here, issue an error
                        ErrorHandler.Semantic_Error
                          (Err_Num   => 853,
                           Reference => ErrorHandler.No_Reference,
                           Position  => Node_Position (Node => Atomic_Arg),
                           Id_Str    => LexTokenManager.Null_String);
                     end if;
                  end if;
               else
                  -- The parameter to pragma Atomic must be a simple_name
                  ErrorHandler.Semantic_Error
                    (Err_Num   => 851,
                     Reference => ErrorHandler.No_Reference,
                     Position  => Node_Position (Node => Atomic_Arg),
                     Id_Str    => LexTokenManager.Null_String);
               end if;
            end if;
         elsif Syntax_Node_Type (Node => Arg_Ass_Node) = SP_Symbols.argument_association then
            -- ASSUME Arg_Ass_Node = argument_association
            -- pragma atomic takes exactly one argument, more than one was found
            -- in this case, so issue an error
            ErrorHandler.Semantic_Error
              (Err_Num   => 854,
               Reference => ErrorHandler.No_Reference,
               Position  => Node_Position (Node => Arg_Ass_Node),
               Id_Str    => LexTokenManager.Null_String);
         end if;
      elsif Arg_Ass_Node = STree.NullNode then
         -- ASSUME Arg_Ass_Node = NULL
         -- no argument association was found; so no parameters were supplied.
         ErrorHandler.Semantic_Error
           (Err_Num   => 854,
            Reference => ErrorHandler.No_Reference,
            Position  => Node_Position (Node => Pragma_Node),
            Id_Str    => LexTokenManager.Null_String);
      else
         SystemErrors.Fatal_Error
           (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
            Msg     => "Expect Arg_Ass_Node = argument_association_rep OR NULL in Wf_Pragma_Atomic");
      end if;
   end Wf_Pragma_Atomic;

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

   function We_Are_Not_In_A_Protected_Type (Scope : Dictionary.Scopes) return Boolean
   --# global in Dictionary.Dict;
   is
   begin
      return not Dictionary.IsType (Dictionary.GetRegion (Scope));
   end We_Are_Not_In_A_Protected_Type;

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

   procedure Wf_Attach_Handler (Pragma_Node : in STree.SyntaxNode;
                                Scope       : in Dictionary.Scopes)
   --# global in     CommandLineData.Content;
   --#        in     LexTokenManager.State;
   --#        in out Dictionary.Dict;
   --#        in out ErrorHandler.Error_Context;
   --#        in out SPARK_IO.File_Sys;
   --#        in out STree.Table;
   --# derives Dictionary.Dict,
   --#         STree.Table                from CommandLineData.Content,
   --#                                         Dictionary.Dict,
   --#                                         LexTokenManager.State,
   --#                                         Pragma_Node,
   --#                                         Scope,
   --#                                         STree.Table &
   --#         ErrorHandler.Error_Context,
   --#         SPARK_IO.File_Sys          from CommandLineData.Content,
   --#                                         Dictionary.Dict,
   --#                                         ErrorHandler.Error_Context,
   --#                                         LexTokenManager.State,
   --#                                         Pragma_Node,
   --#                                         Scope,
   --#                                         SPARK_IO.File_Sys,
   --#                                         STree.Table;
   --# pre Syntax_Node_Type (Pragma_Node, STree.Table) = SP_Symbols.apragma;
   --# post STree.Table = STree.Table~;
      is separate;

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

   procedure Wf_Main_Program_Priority (Id_Node : in STree.SyntaxNode;
                                       Node    : in STree.SyntaxNode;
                                       Scope   : in Dictionary.Scopes)
   --# global in     CommandLineData.Content;
   --#        in out Dictionary.Dict;
   --#        in out ErrorHandler.Error_Context;
   --#        in out LexTokenManager.State;
   --#        in out SPARK_IO.File_Sys;
   --#        in out STree.Table;
   --# derives Dictionary.Dict,
   --#         LexTokenManager.State,
   --#         STree.Table                from CommandLineData.Content,
   --#                                         Dictionary.Dict,
   --#                                         Id_Node,
   --#                                         LexTokenManager.State,
   --#                                         Scope,
   --#                                         STree.Table &
   --#         ErrorHandler.Error_Context,
   --#         SPARK_IO.File_Sys          from CommandLineData.Content,
   --#                                         Dictionary.Dict,
   --#                                         ErrorHandler.Error_Context,
   --#                                         Id_Node,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         Scope,
   --#                                         SPARK_IO.File_Sys,
   --#                                         STree.Table;
   --# pre Syntax_Node_Type (Id_Node, STree.Table) = SP_Symbols.identifier and
   --#   Syntax_Node_Type (Node, STree.Table) = SP_Symbols.apragma;
   --# post STree.Table = STree.Table~;
   is
      Iterator, Err_Node : STree.SyntaxNode;
      Sym                : Dictionary.Symbol;
      Error              : Boolean;
      Priority_Val       : Maths.Value := Maths.NoValue;
      Priority_Lex       : LexTokenManager.Lex_String;
   begin
      -- Reject if pragma Priority has already been given.
      if not Dictionary.MainProgramPrioritySupplied then
         --
         -- We restrict the argument to pragma Priority to be a single ADA_primary
         -- over one of the following:
         -- (a) numeric_literal that resolves to integer_number
         --     numeric_literal
         --            |
         --     decimal_literal
         --            |
         --     integer_number
         -- (b) ADA_Name that resolves to a simple identifier in the current scope
         --     that is either a named number or a constant of type System.Priority.
         --     ADA_Name
         --        |
         --     identifier
         -- This is done by walking down the Child_Nodes of the
         -- Argument_Association_Rep until the ADA_primary is found, ensuring at
         -- each step of the way that NextDerivative is null (to ensure a single
         -- argument which has no operators), and then ensuring that the child of
         -- the ADA_primary is one of the allowed kinds of node.
         --
         Iterator := Next_Sibling (Current_Node => Id_Node);
         -- Set the error reporting node.
         -- ASSUME Iterator = argument_association_rep OR NULL
         if Iterator = STree.NullNode then
            -- ASSUME Iterator = NULL
            Err_Node := Id_Node;
         elsif Syntax_Node_Type (Node => Iterator) = SP_Symbols.argument_association_rep then
            -- ASSUME Iterator = argument_association_rep
            Err_Node := Iterator;
         else
            Err_Node := STree.NullNode;
            SystemErrors.Fatal_Error
              (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
               Msg     => "Expect Iterator = argument_association_rep OR NULL in Wf_Main_Program_Priority");
         end if;
         loop
            --# assert STree.Table = STree.Table~;
            Error := Iterator = STree.NullNode or else Next_Sibling (Current_Node => Iterator) /= STree.NullNode;
            exit when Error or else Syntax_Node_Type (Node => Iterator) = SP_Symbols.ADA_primary;
            Iterator := Child_Node (Current_Node => Iterator);
         end loop;

         if not Error then
            -- ASSUME Iterator = ADA_primary
            --# check Syntax_Node_Type (Iterator, STree.Table) = SP_Symbols.ADA_primary;
            -- Check that we have the right kind of Primary.
            Iterator := Child_Node (Current_Node => Iterator);
            -- ASSUME Iterator = numeric_literal OR ADA_association_list OR ADA_expression OR ADA_name OR NULL
            if Iterator = STree.NullNode then
               -- ASSUME Iterator = NULL
               Error := True;
            else
               -- ASSUME Iterator = numeric_literal OR ADA_association_list OR ADA_expression OR ADA_name
               case Syntax_Node_Type (Node => Iterator) is
                  when SP_Symbols.numeric_literal =>
                     -- ASSUME Iterator = numeric_literal
                     Iterator := Child_Node (Current_Node => Child_Node (Current_Node => Iterator));
                     -- ASSUME Iterator = integer_number OR real_number OR based_integer OR based_real
                     if Syntax_Node_Type (Node => Iterator) = SP_Symbols.integer_number then
                        Get_Literal_Value (Node => Iterator,
                                           Val  => Priority_Val);
                     elsif Syntax_Node_Type (Node => Iterator) = SP_Symbols.real_number
                       or else Syntax_Node_Type (Node => Iterator) = SP_Symbols.based_integer
                       or else Syntax_Node_Type (Node => Iterator) = SP_Symbols.based_real then
                        Error := True;
                     else
                        SystemErrors.Fatal_Error
                          (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
                           Msg     => "Expect Iterator = integer_number OR real_number OR based_integer OR " &
                             "based_real in Wf_Main_Program_Priority");
                     end if;
                  when SP_Symbols.ADA_name =>
                     -- ASSUME Iterator = ADA_name
                     Iterator := Child_Node (Current_Node => Iterator);
                     -- ASSUME Iterator = ADA_name OR identifier OR character_literal OR string_literal
                     if Syntax_Node_Type (Node => Iterator) = SP_Symbols.identifier then
                        -- ASSUME Iterator = identifier
                        Sym :=
                          Dictionary.LookupItem
                          (Name              => Node_Lex_String (Node => Iterator),
                           Scope             => Scope,
                           Context           => Dictionary.ProgramContext,
                           Full_Package_Name => False);
                        -- Ensure we have a local constant with a static integer value
                        if not Dictionary.Is_Null_Symbol (Sym)
                          and then Dictionary.Is_Constant (Sym)
                          and then Dictionary.IsStatic (Sym, Scope)
                          and then Dictionary.CompatibleTypes
                          (Scope,
                           Dictionary.GetType (Sym),
                           Dictionary.GetPredefinedIntegerType) then
                           STree.Set_Node_Lex_String (Sym  => Sym,
                                                      Node => Iterator);
                           Priority_Val := Maths.ValueRep (Dictionary.Get_Value (The_Constant => Sym));
                        else
                           Error := True;
                        end if;
                     elsif Syntax_Node_Type (Node => Iterator) = SP_Symbols.ADA_name
                       or else Syntax_Node_Type (Node => Iterator) = SP_Symbols.character_literal
                       or else Syntax_Node_Type (Node => Iterator) = SP_Symbols.string_literal then
                        Error := True;
                     else
                        SystemErrors.Fatal_Error
                          (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
                           Msg     => "Expect Iterator = ADA_name OR identifier OR character_literal OR " &
                             "string_literal in Wf_Main_Program_Priority");
                     end if;
                  when SP_Symbols.ADA_association_list | SP_Symbols.ADA_expression =>
                     Error := True;
                  when others =>
                     SystemErrors.Fatal_Error
                       (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
                        Msg     => "Expect Iterator = numeric_literal OR ADA_association_list OR " &
                          "ADA_expression OR ADA_name in Wf_Main_Program_Priority");
               end case;
            end if;
         end if;

         if not Error then
            -- We may be able to do a range check on Priority_Val, if package System is provided.
            -- The value must be in the range of System.Priority (see RM D.1(8)).
            Check_Priority_Range
              (Error_Sym   => Dictionary.GetMainProgram,
               Scope       => Scope,
               Pragma_Kind => Dictionary.Priority,
               Err_Pos     => Node_Position (Node => Err_Node),
               Value       => Priority_Val,
               Value_Rep   => Priority_Lex);
            -- CheckPriorityRange will report any out of range value. The returned Priority_Lex
            -- will be NullString if known to be out of range, or else the input value, so we
            -- add this result to the Dictionary.
            Dictionary.SetMainProgramPriority (Priority_Lex);
         else
            -- Invalid argument for pragma Priority. Must be integer literal or local constant
            -- whose value is static integer.
            ErrorHandler.Semantic_Error
              (Err_Num   => 911,
               Reference => ErrorHandler.No_Reference,
               Position  => Node_Position (Node => Err_Node),
               Id_Str    => LexTokenManager.Null_String);
         end if;
      else
         ErrorHandler.Semantic_Error
           (Err_Num   => 879,
            Reference => ErrorHandler.No_Reference,
            Position  => Node_Position (Node => Node),
            Id_Str    => Node_Lex_String (Node => Id_Node));
      end if;
   end Wf_Main_Program_Priority;

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

   procedure Handle_Interface_On_Subprogram
     (Subprog_Declaration_Node : in STree.SyntaxNode;
      Node                     : in STree.SyntaxNode;
      Scope                    : in Dictionary.Scopes)
   --# global in     CommandLineData.Content;
   --#        in     ContextManager.Ops.Unit_Stack;
   --#        in     LexTokenManager.State;
   --#        in out Dictionary.Dict;
   --#        in out ErrorHandler.Error_Context;
   --#        in out SPARK_IO.File_Sys;
   --#        in out STree.Table;
   --# derives Dictionary.Dict            from *,
   --#                                         CommandLineData.Content,
   --#                                         ContextManager.Ops.Unit_Stack,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         Scope,
   --#                                         STree.Table,
   --#                                         Subprog_Declaration_Node &
   --#         ErrorHandler.Error_Context from *,
   --#                                         CommandLineData.Content,
   --#                                         Dictionary.Dict,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         Scope,
   --#                                         SPARK_IO.File_Sys,
   --#                                         STree.Table,
   --#                                         Subprog_Declaration_Node &
   --#         SPARK_IO.File_Sys          from *,
   --#                                         CommandLineData.Content,
   --#                                         ContextManager.Ops.Unit_Stack,
   --#                                         Dictionary.Dict,
   --#                                         ErrorHandler.Error_Context,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         Scope,
   --#                                         STree.Table,
   --#                                         Subprog_Declaration_Node &
   --#         STree.Table                from *,
   --#                                         CommandLineData.Content,
   --#                                         Dictionary.Dict,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         Scope,
   --#                                         Subprog_Declaration_Node;
   --# pre Syntax_Node_Type (Subprog_Declaration_Node, STree.Table) = SP_Symbols.subprogram_declaration and
   --#   Syntax_Node_Type (Node, STree.Table) = SP_Symbols.apragma;
   --# post STree.Table = STree.Table~;
   is
      Name_Node       : STree.SyntaxNode;
      Subprog_Sym     : Dictionary.Symbol;
      Name            : LexTokenManager.Lex_String;
      Error_In_Pragma : Boolean;
   begin
      -- find name of subprogram starting from subprogram_declaration
      Name_Node := Child_Node (Current_Node => Subprog_Declaration_Node);
      -- ASSUME Name_Node = overriding_indicator OR procedure_specification OR function_specification OR
      --                    proof_function_declaration
      if Syntax_Node_Type (Node => Name_Node) = SP_Symbols.overriding_indicator then
         -- ASSUME Name_Node = overriding_indicator
         Name_Node := Next_Sibling (Current_Node => Name_Node);
      elsif Syntax_Node_Type (Node => Name_Node) /= SP_Symbols.procedure_specification
        and then Syntax_Node_Type (Node => Name_Node) /= SP_Symbols.function_specification
        and then Syntax_Node_Type (Node => Name_Node) /= SP_Symbols.proof_function_declaration then
         SystemErrors.Fatal_Error
           (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
            Msg     => "Expect Name_Node = overriding_indicator OR procedure_specification OR function_specification OR " &
              "proof_function_declaration in Handle_Interface_On_Subprogram");
      end if;
      -- ASSUME Name_Node = procedure_specification OR function_specification OR proof_function_declaration
      if Syntax_Node_Type (Node => Name_Node) = SP_Symbols.procedure_specification
        or else Syntax_Node_Type (Node => Name_Node) = SP_Symbols.function_specification then
         Name_Node := Child_Node (Current_Node => Child_Node (Current_Node => Name_Node));
         -- ASSUME Name_Node = identifier
         SystemErrors.RT_Assert
           (C       => Syntax_Node_Type (Node => Name_Node) = SP_Symbols.identifier,
            Sys_Err => SystemErrors.Invalid_Syntax_Tree,
            Msg     => "Expect Name_Node = identifier in Handle_Interface_On_Subprogram");
         Name        := Node_Lex_String (Node => Name_Node);
         Subprog_Sym :=
           Dictionary.LookupItem (Name              => Name,
                                  Scope             => Scope,
                                  Context           => Dictionary.ProgramContext,
                                  Full_Package_Name => False);
         Wf_External_Interface (Pragma_Node => Node,
                                Entity_Sym  => Subprog_Sym,
                                Error_Found => Error_In_Pragma);
         if not Error_In_Pragma then
            Dictionary.AddBody
              (CompilationUnit => Subprog_Sym,
               Comp_Unit       => ContextManager.Ops.Current_Unit,
               TheBody         => Dictionary.Location'(Start_Position => Node_Position (Node => Node),
                                                       End_Position   => Node_Position (Node => Node)),
               Hidden          => True); -- treat interface procs as hidden
         end if;
      elsif Syntax_Node_Type (Node => Name_Node) /= SP_Symbols.proof_function_declaration then
         SystemErrors.Fatal_Error
           (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
            Msg     => "Expect Name_Node = procedure_specification OR function_specification OR " &
              "proof_function_declaration in Handle_Interface_On_Subprogram");
      end if;
   end Handle_Interface_On_Subprogram;

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

   procedure Handle_Import_On_Variable
     (Basic_Declaration_Node : in STree.SyntaxNode;
      Id_Node                : in STree.SyntaxNode;
      Node                   : in STree.SyntaxNode;
      Scope                  : in Dictionary.Scopes)
   --# global in     CommandLineData.Content;
   --#        in     LexTokenManager.State;
   --#        in out Dictionary.Dict;
   --#        in out ErrorHandler.Error_Context;
   --#        in out SPARK_IO.File_Sys;
   --#        in out STree.Table;
   --# derives Dictionary.Dict,
   --#         STree.Table                from Basic_Declaration_Node,
   --#                                         CommandLineData.Content,
   --#                                         Dictionary.Dict,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         Scope,
   --#                                         STree.Table &
   --#         ErrorHandler.Error_Context,
   --#         SPARK_IO.File_Sys          from Basic_Declaration_Node,
   --#                                         CommandLineData.Content,
   --#                                         Dictionary.Dict,
   --#                                         ErrorHandler.Error_Context,
   --#                                         Id_Node,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         Scope,
   --#                                         SPARK_IO.File_Sys,
   --#                                         STree.Table;
   --# pre Syntax_Node_Type (Basic_Declaration_Node, STree.Table) = SP_Symbols.basic_declarative_item and
   --#   Syntax_Node_Type (Id_Node, STree.Table) = SP_Symbols.identifier and
   --#   Syntax_Node_Type (Node, STree.Table) = SP_Symbols.apragma;
   --# post STree.Table = STree.Table~;
   is
      Var_Dec_Node    : STree.SyntaxNode;
      Name_Node       : STree.SyntaxNode;
      Var_Name        : LexTokenManager.Lex_String;
      Var_Sym         : Dictionary.Symbol;
      Error_In_Pragma : Boolean;
      Error_Found     : Boolean;
   begin -- Handle_Import_On_Variable

      -- ASSUME Basic_Declaration_Node = basic_declarative_item

      -- Grammar:
      -- basic_declarative_item
      --            |
      --    basic_declaration
      --            |
      --   object_declaration
      --            |
      --   variable_declaration
      --            |
      --       identifier_list
      --            |
      --       identifier (assumes V : T, not V1, V2, V3 ; T, otherwise there are N identifier_lists)
      --
      -- Checks:
      -- 1. illegal in Ada 83
      -- 2. must be a variable declaration
      -- 3. name consistency
      -- 4. no explicit initialization allowed
      -- 5. mode, init rules and warnings

      -- Check 1
      case CommandLineData.Content.Language_Profile is
         when CommandLineData.SPARK83 =>
            -- will report unexpected pragma INTERFACE.
            ErrorHandler.Semantic_Error
              (Err_Num   => 72,
               Reference => ErrorHandler.No_Reference,
               Position  => Node_Position (Node => Node),
               Id_Str    => Node_Lex_String (Node => Id_Node));
         when CommandLineData.SPARK95_Onwards =>
            -- Check 2
            Var_Dec_Node := Child_Node (Current_Node => Basic_Declaration_Node);
            -- ASSUME Var_Dec_Node = basic_declaration OR justification_statement OR
            --                       representation_clause OR basic_proof_declaration
            if Syntax_Node_Type (Node => Var_Dec_Node) = SP_Symbols.basic_declaration then
               -- ASSUME Var_Dec_Node = basic_declaration
               Var_Dec_Node := Child_Node (Current_Node => Var_Dec_Node);
               -- ASSUME Var_Dec_Node = object_declaration OR full_type_declaration OR subtype_declaration
               if Syntax_Node_Type (Node => Var_Dec_Node) = SP_Symbols.object_declaration then
                  -- ASSUME Var_Dec_Node = object_declaration
                  Var_Dec_Node := Child_Node (Current_Node => Var_Dec_Node);
                  -- ASSUME Var_Dec_Node = constant_declaration OR variable_declaration
                  if Syntax_Node_Type (Node => Var_Dec_Node) = SP_Symbols.variable_declaration then
                     -- ASSUME Var_Dec_Node = variable_declaration
                     -- check 3
                     Name_Node := Last_Child_Of (Start_Node => Var_Dec_Node);
                     -- ASSUME Name_Node = identifier
                     SystemErrors.RT_Assert
                       (C       => Syntax_Node_Type (Node => Name_Node) = SP_Symbols.identifier,
                        Sys_Err => SystemErrors.Invalid_Syntax_Tree,
                        Msg     => "Expect Name_Node = identifier in Handle_Import_On_Variable");
                     Var_Name := Node_Lex_String (Node => Name_Node);
                     -- Potentially OK to add pragma to variable in dictionary,
                     -- for which we will need a symbol
                     Var_Sym :=
                       Dictionary.LookupItem
                       (Name              => Var_Name,
                        Scope             => Scope,
                        Context           => Dictionary.ProgramContext,
                        Full_Package_Name => False);

                     -- If the pragma Import "looks right" in that it names the
                     -- variable declared immediately above it, LookupItem still might
                     -- return NullSymbol if the variable declaration itself was illegal -
                     -- for example, in the case of a missing own annotation.  If LookupItem
                     -- does return NullSymbol, then do nothing since an error message on the
                     -- offending variable declaration will have already been issued.
                     if not Dictionary.Is_Null_Symbol (Var_Sym) then

                        -- use existing wf to check name consistency
                        Wf_External_Interface (Pragma_Node => Node,
                                               Entity_Sym  => Var_Sym,
                                               Error_Found => Error_In_Pragma);
                        if not Error_In_Pragma then

                           -- since the pragma import has just been checked to ensure it directly
                           -- follows a variable declaration, the abov elook up must always succeed
                           SystemErrors.RT_Assert
                             (C       => Dictionary.Is_Variable (Var_Sym),
                              Sys_Err => SystemErrors.Assertion_Failure,
                              Msg     => "Variable not found in Handle_Import_On_Variable");

                           -- Check 4
                           if Dictionary.VariableIsInitialized (Var_Sym) then
                              ErrorHandler.Semantic_Error
                                (Err_Num   => 120,
                                 Reference => ErrorHandler.No_Reference,
                                 Position  => Node_Position (Node => Node),
                                 Id_Str    => Var_Name);

                           else
                              -- Now we really can add the pragma to the Dictionary
                              -- Following call also marks variable as being initialized "at declaration"
                              Dictionary.AddVariablePragmaImport (Var_Sym);
                              Error_Found := False;
                              -- Check 5
                              -- First deal with own variables that have a pragma import but aren't in an
                              -- initializes clause and don't have a mode, an existing function gives the desired answer
                              if Unexpected_Initialization (Sym => Var_Sym) then
                                 Error_Found := True;
                                 ErrorHandler.Semantic_Error
                                   (Err_Num   => 333,
                                    Reference => ErrorHandler.No_Reference,
                                    Position  => Node_Position (Node => Node),
                                    Id_Str    => Var_Name);
                              end if;
                              -- Now warn in the case where we have ANY variable that lacks a "stream" mode (even if it
                              -- passes the previous test because it is an initialized own variable)
                              if Dictionary.GetOwnVariableOrConstituentMode (Var_Sym) = Dictionary.DefaultMode then
                                 Error_Found := True;
                                 ErrorHandler.Semantic_Warning
                                   (Err_Num  => 350,
                                    Position => Node_Position (Node => Node),
                                    Id_Str   => Var_Name);
                              end if;
                              if not Error_Found then
                                 STree.Set_Node_Lex_String (Sym  => Var_Sym,
                                                            Node => Name_Node);
                              end if;
                           end if;
                        end if;
                     end if;
                  elsif Syntax_Node_Type (Node => Var_Dec_Node) = SP_Symbols.constant_declaration then
                     -- ASSUME Var_Dec_Node = constant_declaration
                     ErrorHandler.Semantic_Error
                       (Err_Num   => 72,
                        Reference => ErrorHandler.No_Reference,
                        Position  => Node_Position (Node => Node),
                        Id_Str    => Node_Lex_String (Node => Id_Node));
                  else
                     SystemErrors.Fatal_Error
                       (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
                        Msg     => "Expect Var_Dec_Node = constant_declaration OR " &
                          "variable_declaration in Handle_Import_On_Variable");
                  end if;
               elsif Syntax_Node_Type (Node => Var_Dec_Node) = SP_Symbols.full_type_declaration
                 or else Syntax_Node_Type (Node => Var_Dec_Node) = SP_Symbols.subtype_declaration then
                  -- ASSUME Var_Dec_Node = full_type_declaration OR subtype_declaration
                  ErrorHandler.Semantic_Error
                    (Err_Num   => 72,
                     Reference => ErrorHandler.No_Reference,
                     Position  => Node_Position (Node => Node),
                     Id_Str    => Node_Lex_String (Node => Id_Node));
               else
                  SystemErrors.Fatal_Error
                    (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
                     Msg     => "Expect Var_Dec_Node = object_declaration OR full_type_declaration OR " &
                       "subtype_declaration in Handle_Import_On_Variable");
               end if;
            elsif Syntax_Node_Type (Node => Var_Dec_Node) = SP_Symbols.justification_statement
              or else Syntax_Node_Type (Node => Var_Dec_Node) = SP_Symbols.representation_clause
              or else Syntax_Node_Type (Node => Var_Dec_Node) = SP_Symbols.basic_proof_declaration then
               -- ASSUME Var_Dec_Node = justification_statement OR representation_clause OR basic_proof_declaration
               ErrorHandler.Semantic_Error
                 (Err_Num   => 72,
                  Reference => ErrorHandler.No_Reference,
                  Position  => Node_Position (Node => Node),
                  Id_Str    => Node_Lex_String (Node => Id_Node));
            else
               SystemErrors.Fatal_Error
                 (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
                  Msg     => "Expect Var_Dec_Node = basic_declaration OR justification_statement OR " &
                    "representation_clause OR basic_proof_declaration in Handle_Import_On_Variable");
            end if;
      end case;
   end Handle_Import_On_Variable;

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

   -------------------------------------------------
   -- This function checks the number of arguments
   -- present in a pragma statement by counting the
   -- number of argument_association_rep symbols.
   -- This is then compared against known acceptable
   -- numbers of arguments taken from the LRM.
   --
   -- Return:  True if number of arguments OK,
   --          False otherwise
   -------------------------------------------------

   procedure Check_Arg_Count (Node           : in     STree.SyntaxNode;
                              Statement_OK   :    out Boolean;
                              Error_To_Raise :    out Natural)
   --# global in CommandLineData.Content;
   --#        in LexTokenManager.State;
   --#        in STree.Table;
   --# derives Error_To_Raise,
   --#         Statement_OK   from CommandLineData.Content,
   --#                             LexTokenManager.State,
   --#                             Node,
   --#                             STree.Table;
   --# pre Syntax_Node_Type (Node, STree.Table) = SP_Symbols.apragma;
   is

      function Number_Of_Args (Pragma_Node : STree.SyntaxNode;
                               Max         : Natural) return Natural
      --# global in STree.Table;
      --# pre Syntax_Node_Type (Pragma_Node, STree.Table) = SP_Symbols.apragma;
      --# return Num_Args => (Num_Args <= Max);
      is
         Arg_Ass_Node : STree.SyntaxNode;
         Num_Args     : Natural := 0;
      begin
         Arg_Ass_Node := Child_Node (Current_Node => Pragma_Node);
         -- ASSUME Arg_Ass_Node = identifier OR assert_pragma
         if Syntax_Node_Type (Node => Arg_Ass_Node) = SP_Symbols.identifier then
            -- ASSUME Arg_Ass_Node = identifier
            Arg_Ass_Node := Next_Sibling (Current_Node => Arg_Ass_Node);
            -- ASSUME Arg_Ass_Node = argument_association_rep OR NULL
            if Syntax_Node_Type (Node => Arg_Ass_Node) = SP_Symbols.argument_association_rep then
               -- ASSUME Arg_Ass_Node = argument_association_rep
               while Syntax_Node_Type (Node => Arg_Ass_Node) = SP_Symbols.argument_association_rep and then Num_Args < Max loop
                  --# assert Syntax_Node_Type (Arg_Ass_Node, STree.Table) = SP_Symbols.argument_association_rep and
                  --#   Num_Args < Max;
                  Num_Args     := Num_Args + 1;
                  Arg_Ass_Node := Child_Node (Current_Node => Arg_Ass_Node);
                  -- ASSUME Arg_Ass_Node = argument_association_rep OR argument_association
                  SystemErrors.RT_Assert
                    (C       => Syntax_Node_Type (Node => Arg_Ass_Node) = SP_Symbols.argument_association_rep
                       or else Syntax_Node_Type (Node => Arg_Ass_Node) = SP_Symbols.argument_association,
                     Sys_Err => SystemErrors.Invalid_Syntax_Tree,
                     Msg     => "Expect Arg_Ass_Node = argument_association_rep OR argument_association in Number_Of_Args");
               end loop;
            elsif Arg_Ass_Node /= STree.NullNode then
               Num_Args := 0;
               SystemErrors.Fatal_Error
                 (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
                  Msg     => "Expect Arg_Ass_Node = argument_association_rep OR NULL in Number_Of_Args");
            end if;
         elsif Syntax_Node_Type (Node => Arg_Ass_Node) /= SP_Symbols.assert_pragma then
            Num_Args := 0;
            SystemErrors.Fatal_Error
              (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
               Msg     => "Expect Arg_Ass_Node = identifier OR assert_pragma in Number_Of_Args");
         end if;
         return Num_Args;
      end Number_Of_Args;

      procedure Check_Arg_Count_95 (Node           : in     STree.SyntaxNode;
                                    Statement_OK   :    out Boolean;
                                    Error_To_Raise :    out Natural)
      --# global in LexTokenManager.State;
      --#        in STree.Table;
      --# derives Error_To_Raise,
      --#         Statement_OK   from LexTokenManager.State,
      --#                             Node,
      --#                             STree.Table;
      --# pre Syntax_Node_Type (Node, STree.Table) = SP_Symbols.apragma;
      is
         Pragma_Type : LexTokenManager.Lex_String;
      begin
         Pragma_Type := Node_Lex_String (Node => Child_Node (Current_Node => Node));

         if LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Pragma_Type,
            Lex_Str2 => LexTokenManager.Normalize_Scalars_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Pragma_Type,
            Lex_Str2 => LexTokenManager.Page_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Pragma_Type,
            Lex_Str2 => LexTokenManager.Reviewable_Token) =
           LexTokenManager.Str_Eq then
            -- Check for 0 args
            Statement_OK   := Number_Of_Args (Pragma_Node => Node,
                                              Max         => 1) = 0;
            Error_To_Raise := 365;

         elsif LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Pragma_Type,
            Lex_Str2 => LexTokenManager.All_Calls_Remote_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Pragma_Type,
            Lex_Str2 => LexTokenManager.Discard_Names_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Pragma_Type,
            Lex_Str2 => LexTokenManager.Elaborate_Body_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Pragma_Type,
            Lex_Str2 => LexTokenManager.Interrupt_Priority_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Pragma_Type,
            Lex_Str2 => LexTokenManager.Preelaborate_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Pragma_Type,
            Lex_Str2 => LexTokenManager.Pure_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Pragma_Type,
            Lex_Str2 => LexTokenManager.Remote_Call_Interface_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Pragma_Type,
            Lex_Str2 => LexTokenManager.Remote_Types_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Pragma_Type,
            Lex_Str2 => LexTokenManager.Shared_Passive_Token) =
           LexTokenManager.Str_Eq then
            -- Check for 0/1 arg
            Statement_OK   := Number_Of_Args (Pragma_Node => Node,
                                              Max         => 1) = 0
              or else Number_Of_Args (Pragma_Node => Node,
                                      Max         => 2) = 1;
            Error_To_Raise := 360;

         elsif LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Pragma_Type,
            Lex_Str2 => LexTokenManager.Asynchronous_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Pragma_Type,
            Lex_Str2 => LexTokenManager.Atomic_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Pragma_Type,
            Lex_Str2 => LexTokenManager.Atomic_Components_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Pragma_Type,
            Lex_Str2 => LexTokenManager.Controlled_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Pragma_Type,
            Lex_Str2 => LexTokenManager.Interrupt_Handler_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Pragma_Type,
            Lex_Str2 => LexTokenManager.Linker_Options_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Pragma_Type,
            Lex_Str2 => LexTokenManager.List_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Pragma_Type,
            Lex_Str2 => LexTokenManager.Locking_Policy_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Pragma_Type,
            Lex_Str2 => LexTokenManager.Optimize_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Pragma_Type,
            Lex_Str2 => LexTokenManager.Pack_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Pragma_Type,
            Lex_Str2 => LexTokenManager.Priority_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Pragma_Type,
            Lex_Str2 => LexTokenManager.Queueing_Policy_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Pragma_Type,
            Lex_Str2 => LexTokenManager.Storage_Size_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Pragma_Type,
            Lex_Str2 => LexTokenManager.Task_Dispatching_Policy_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Pragma_Type,
            Lex_Str2 => LexTokenManager.Volatile_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Pragma_Type,
            Lex_Str2 => LexTokenManager.Volatile_Components_Token) =
           LexTokenManager.Str_Eq then
            -- Check for 1 arg
            Statement_OK   := Number_Of_Args (Pragma_Node => Node,
                                              Max         => 2) = 1;
            Error_To_Raise := 361;

         elsif LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Pragma_Type,
            Lex_Str2 => LexTokenManager.Suppress_Token) =
           LexTokenManager.Str_Eq then
            -- Check for 1/2 args
            Statement_OK   := Number_Of_Args (Pragma_Node => Node,
                                              Max         => 2) = 1
              or else Number_Of_Args (Pragma_Node => Node,
                                      Max         => 3) = 2;
            Error_To_Raise := 366;

         elsif LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Pragma_Type,
            Lex_Str2 => LexTokenManager.Elaborate_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Pragma_Type,
            Lex_Str2 => LexTokenManager.Elaborate_All_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Pragma_Type,
            Lex_Str2 => LexTokenManager.Inline_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Pragma_Type,
            Lex_Str2 => LexTokenManager.Restrictions_Token) =
           LexTokenManager.Str_Eq then
            -- Check for >=1 args
            Statement_OK   := Number_Of_Args (Pragma_Node => Node,
                                              Max         => 1) /= 0;
            Error_To_Raise := 363;

         elsif LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Pragma_Type,
            Lex_Str2 => LexTokenManager.Attach_Handler_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Pragma_Type,
            Lex_Str2 => LexTokenManager.Convention_Token) =
           LexTokenManager.Str_Eq then
            -- Check for 2 args
            Statement_OK   := Number_Of_Args (Pragma_Node => Node,
                                              Max         => 3) = 2;
            Error_To_Raise := 362;

         elsif LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Pragma_Type,
            Lex_Str2 => LexTokenManager.Export_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Pragma_Type,
            Lex_Str2 => LexTokenManager.Import_Token) =
           LexTokenManager.Str_Eq then
            -- Check for 2-4 args
            Statement_OK   := Number_Of_Args (Pragma_Node => Node,
                                              Max         => 3) >= 2
              and then Number_Of_Args (Pragma_Node => Node,
                                       Max         => 5) <= 4;
            Error_To_Raise := 364;

         elsif LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Pragma_Type,
            Lex_Str2 => LexTokenManager.Inspection_Point_Token) =
           LexTokenManager.Str_Eq then
            -- Any number of arguments
            Statement_OK   := True;
            Error_To_Raise := 0;

         else
            -- Unknown pragma! Ada 2005? Implementation defined?
            Statement_OK   := True;
            Error_To_Raise := 0;
         end if;
      end Check_Arg_Count_95;

      procedure Check_Arg_Count_83 (Node           : in     STree.SyntaxNode;
                                    Statement_OK   :    out Boolean;
                                    Error_To_Raise :    out Natural)
      --# global in LexTokenManager.State;
      --#        in STree.Table;
      --# derives Error_To_Raise,
      --#         Statement_OK   from LexTokenManager.State,
      --#                             Node,
      --#                             STree.Table;
      --# pre Syntax_Node_Type (Node, STree.Table) = SP_Symbols.apragma;
      is
         Pragma_Type : LexTokenManager.Lex_String;
      begin
         Pragma_Type := Node_Lex_String (Node => Child_Node (Current_Node => Node));

         if LexTokenManager.Lex_String_Case_Insensitive_Compare (Lex_Str1 => Pragma_Type,
                                                                 Lex_Str2 => LexTokenManager.Page_Token) =
           LexTokenManager.Str_Eq then
            -- Check for 0 args
            Statement_OK   := Number_Of_Args (Pragma_Node => Node,
                                              Max         => 1) = 0;
            Error_To_Raise := 365;

         elsif LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Pragma_Type,
            Lex_Str2 => LexTokenManager.Controlled_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Pragma_Type,
            Lex_Str2 => LexTokenManager.List_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Pragma_Type,
            Lex_Str2 => LexTokenManager.Memory_Size_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Pragma_Type,
            Lex_Str2 => LexTokenManager.Optimize_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Pragma_Type,
            Lex_Str2 => LexTokenManager.Pack_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Pragma_Type,
            Lex_Str2 => LexTokenManager.Priority_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Pragma_Type,
            Lex_Str2 => LexTokenManager.Shared_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Pragma_Type,
            Lex_Str2 => LexTokenManager.Storage_Unit_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Pragma_Type,
            Lex_Str2 => LexTokenManager.System_Name_Token) =
           LexTokenManager.Str_Eq then
            -- Check for 1 arg
            Statement_OK   := Number_Of_Args (Pragma_Node => Node,
                                              Max         => 2) = 1;
            Error_To_Raise := 361;

         elsif LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Pragma_Type,
            Lex_Str2 => LexTokenManager.Suppress_Token) =
           LexTokenManager.Str_Eq then
            -- Check for 1/2 args
            Statement_OK   := Number_Of_Args (Pragma_Node => Node,
                                              Max         => 2) = 1
              or else Number_Of_Args (Pragma_Node => Node,
                                      Max         => 3) = 2;
            Error_To_Raise := 366;

         elsif LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Pragma_Type,
            Lex_Str2 => LexTokenManager.Elaborate_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Pragma_Type,
            Lex_Str2 => LexTokenManager.Inline_Token) =
           LexTokenManager.Str_Eq then
            -- Check for >=1 args
            Statement_OK   := Number_Of_Args (Pragma_Node => Node,
                                              Max         => 1) /= 0;
            Error_To_Raise := 363;

            -- InterfaceToken requires 2 arguments, but always checked
            -- before entry to this subprogram

         else
            -- Unknown pragma! Ada 2005? Implementation defined?
            Statement_OK   := True;
            Error_To_Raise := 0;
         end if;
      end Check_Arg_Count_83;

   begin -- Check_Arg_Count
      case CommandLineData.Content.Language_Profile is
         when CommandLineData.SPARK83 =>
            Check_Arg_Count_83 (Node           => Node,
                                Statement_OK   => Statement_OK,
                                Error_To_Raise => Error_To_Raise);
         when CommandLineData.SPARK95_Onwards =>
            Check_Arg_Count_95 (Node           => Node,
                                Statement_OK   => Statement_OK,
                                Error_To_Raise => Error_To_Raise);
      end case;
   end Check_Arg_Count;

begin -- Wf_Pragma
   Id_Node := Child_Node (Current_Node => Node);
   -- ASSUME Id_Node = identifier OR assert_pragma
   if Syntax_Node_Type (Node => Id_Node) = SP_Symbols.assert_pragma then
      -- ASSUME Id_Node = assert_pragma
      ErrorHandler.A_Pragma (LexTokenManager.Assert_Token, Node_Position (Node => Node));
   elsif Syntax_Node_Type (Node => Id_Node) = SP_Symbols.identifier then
      -- ASSUME Id_Node = identifier
      if Is_External_Interface (Pragma_Node => Node) then
         if We_Are_Not_In_A_Protected_Type (Scope => Scope) then -- Import/Interface MAY be ok

            -- Look for the preceeding declaration
            Subprog_Or_Variable_Node := Parent_Node (Current_Node => Node);
            -- ASSUME Subprog_Or_Variable_Node = compilation_unit OR
            --                                   pragma_rep OR
            --                                   initial_declarative_item_rep OR
            --                                   later_declarative_item_rep OR
            --                                   statement OR
            --                                   code_insertion OR
            --                                   visible_part_rep OR
            --                                   basic_declarative_item_rep OR
            --                                   renaming_declaration_rep OR
            --                                   task_pragma OR
            --                                   protected_operation_declaration_rep OR
            --                                   body_stub
            if Syntax_Node_Type (Node => Subprog_Or_Variable_Node) = SP_Symbols.visible_part_rep
              or else Syntax_Node_Type (Node => Subprog_Or_Variable_Node) = SP_Symbols.basic_declarative_item_rep then
               -- ASSUME Subprog_Or_Variable_Node = visible_part_rep OR basic_declarative_item_rep
               Subprog_Or_Variable_Node := Child_Node (Current_Node => Subprog_Or_Variable_Node);
               -- ASSUME Subprog_Or_Variable_Node = visible_part_rep OR basic_declarative_item_rep OR NULL
               if Syntax_Node_Type (Node => Subprog_Or_Variable_Node) = SP_Symbols.visible_part_rep
                 or else Syntax_Node_Type (Node => Subprog_Or_Variable_Node) = SP_Symbols.basic_declarative_item_rep then
                  -- ASSUME Subprog_Or_Variable_Node = visible_part_rep OR basic_declarative_item_rep
                  Subprog_Or_Variable_Node := Child_Node (Current_Node => Subprog_Or_Variable_Node);
                  -- ASSUME Subprog_Or_Variable_Node = visible_part_rep OR basic_declarative_item_rep OR NULL
                  if Syntax_Node_Type (Node => Subprog_Or_Variable_Node) = SP_Symbols.visible_part_rep
                    or else Syntax_Node_Type (Node => Subprog_Or_Variable_Node) = SP_Symbols.basic_declarative_item_rep then
                     Subprog_Or_Variable_Node := Next_Sibling (Current_Node => Subprog_Or_Variable_Node);
                     -- ASSUME Subprog_Or_Variable_Node = basic_declarative_item OR
                     --                                   private_type_declaration OR
                     --                                   deferred_constant_declaration OR
                     --                                   subprogram_declaration OR
                     --                                   generic_subprogram_instantiation OR
                     --                                   apragma OR
                     --                                   renaming_declaration
                     if Syntax_Node_Type (Node => Subprog_Or_Variable_Node) = SP_Symbols.private_type_declaration
                       or else Syntax_Node_Type (Node => Subprog_Or_Variable_Node) = SP_Symbols.deferred_constant_declaration
                       or else Syntax_Node_Type (Node => Subprog_Or_Variable_Node) = SP_Symbols.generic_subprogram_instantiation
                       or else Syntax_Node_Type (Node => Subprog_Or_Variable_Node) = SP_Symbols.apragma
                       or else Syntax_Node_Type (Node => Subprog_Or_Variable_Node) = SP_Symbols.renaming_declaration then
                        -- ASSUME Subprog_Or_Variable_Node = private_type_declaration OR
                        --                                   deferred_constant_declaration OR
                        --                                   generic_subprogram_instantiation OR
                        --                                   apragma OR
                        --                                   renaming_declaration
                        Subprog_Or_Variable_Node := STree.NullNode;
                     elsif Syntax_Node_Type (Node => Subprog_Or_Variable_Node) /= SP_Symbols.basic_declarative_item
                       and then Syntax_Node_Type (Node => Subprog_Or_Variable_Node) /= SP_Symbols.subprogram_declaration then
                        SystemErrors.Fatal_Error
                          (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
                           Msg     => "Expect Subprog_Or_Variable_Node = basic_declarative_item OR " &
                             "private_type_declaration OR deferred_constant_declaration OR subprogram_declaration OR " &
                             "generic_subprogram_instantiation OR apragma OR renaming_declaration in Wf_Pragma");
                     end if;
                  elsif Subprog_Or_Variable_Node /= STree.NullNode then
                     SystemErrors.Fatal_Error
                       (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
                        Msg     => "Expect Subprog_Or_Variable_Node = visible_part_rep OR " &
                          "basic_declarative_item_rep OR NULL in Wf_Pragma");
                  end if;
               elsif Subprog_Or_Variable_Node /= STree.NullNode then
                  SystemErrors.Fatal_Error
                    (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
                     Msg     => "Expect Subprog_Or_Variable_Node = visible_part_rep OR " &
                       "basic_declarative_item_rep OR NULL in Wf_Pragma");
               end if;
            elsif Syntax_Node_Type (Node => Subprog_Or_Variable_Node) = SP_Symbols.initial_declarative_item_rep then
               -- ASSUME Subprog_Or_Variable_Node = initial_declarative_item_rep
               Subprog_Or_Variable_Node := Child_Node (Current_Node => Subprog_Or_Variable_Node);
               -- ASSUME Subprog_Or_Variable_Node = initial_declarative_item_rep OR basic_declarative_item OR
               --                                   package_declaration OR generic_package_instantiation
               if Syntax_Node_Type (Node => Subprog_Or_Variable_Node) = SP_Symbols.initial_declarative_item_rep then
                  -- ASSUME Subprog_Or_Variable_Node = initial_declarative_item_rep
                  Subprog_Or_Variable_Node := Child_Node (Current_Node => Subprog_Or_Variable_Node);
                  -- ASSUME Subprog_Or_Variable_Node = initial_declarative_item_rep OR basic_declarative_item OR
                  --                                   package_declaration OR generic_package_instantiation
                  if Syntax_Node_Type (Node => Subprog_Or_Variable_Node) = SP_Symbols.initial_declarative_item_rep then
                     -- ASSUME Subprog_Or_Variable_Node = initial_declarative_item_rep
                     Subprog_Or_Variable_Node := Next_Sibling (Current_Node => Subprog_Or_Variable_Node);
                     -- ASSUME Subprog_Or_Variable_Node = basic_declarative_item OR
                     --                                   package_declaration OR
                     --                                   renaming_declaration OR
                     --                                   use_type_clause OR
                     --                                   proof_renaming_declaration OR
                     --                                   apragma
                     if Syntax_Node_Type (Node => Subprog_Or_Variable_Node) = SP_Symbols.package_declaration
                       or else Syntax_Node_Type (Node => Subprog_Or_Variable_Node) = SP_Symbols.renaming_declaration
                       or else Syntax_Node_Type (Node => Subprog_Or_Variable_Node) = SP_Symbols.use_type_clause
                       or else Syntax_Node_Type (Node => Subprog_Or_Variable_Node) = SP_Symbols.proof_renaming_declaration
                       or else Syntax_Node_Type (Node => Subprog_Or_Variable_Node) = SP_Symbols.apragma then
                        -- ASSUME Subprog_Or_Variable_Node = package_declaration OR
                        --                                   renaming_declaration OR
                        --                                   use_type_clause OR
                        --                                   proof_renaming_declaration OR
                        --                                   apragma
                        Subprog_Or_Variable_Node := STree.NullNode;
                     elsif Syntax_Node_Type (Node => Subprog_Or_Variable_Node) /= SP_Symbols.basic_declarative_item then
                        SystemErrors.Fatal_Error
                          (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
                           Msg     => "Expect Subprog_Or_Variable_Node = basic_declarative_item OR package_declaration OR " &
                             "renaming_declaration OR use_type_clause OR proof_renaming_declaration OR apragma in Wf_Pragma");
                     end if;
                  elsif Syntax_Node_Type (Node => Subprog_Or_Variable_Node) = SP_Symbols.package_declaration
                    or else Syntax_Node_Type (Node => Subprog_Or_Variable_Node) = SP_Symbols.generic_package_instantiation then
                     -- ASSUME Subprog_Or_Variable_Node = package_declaration OR generic_package_instantiation
                     Subprog_Or_Variable_Node := STree.NullNode;
                  elsif Syntax_Node_Type (Node => Subprog_Or_Variable_Node) /= SP_Symbols.basic_declarative_item then
                     SystemErrors.Fatal_Error
                       (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
                        Msg     => "Expect Subprog_Or_Variable_Node = initial_declarative_item_rep OR " &
                          "basic_declarative_item OR package_declaration OR generic_package_instantiation in Wf_Pragma");
                  end if;
               elsif Syntax_Node_Type (Node => Subprog_Or_Variable_Node) = SP_Symbols.basic_declarative_item
                 or else Syntax_Node_Type (Node => Subprog_Or_Variable_Node) = SP_Symbols.package_declaration
                 or else Syntax_Node_Type (Node => Subprog_Or_Variable_Node) = SP_Symbols.generic_package_instantiation then
                  -- ASSUME Subprog_Or_Variable_Node = basic_declarative_item OR package_declaration OR
                  --                                   generic_package_instantiation
                  Subprog_Or_Variable_Node := STree.NullNode;
               else
                  SystemErrors.Fatal_Error
                    (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
                     Msg     => "Expect Subprog_Or_Variable_Node = initial_declarative_item_rep OR " &
                       "basic_declarative_item OR package_declaration OR generic_package_instantiation in Wf_Pragma");
               end if;
            elsif Syntax_Node_Type (Node => Subprog_Or_Variable_Node) = SP_Symbols.compilation_unit
              or else Syntax_Node_Type (Node => Subprog_Or_Variable_Node) = SP_Symbols.pragma_rep
              or else Syntax_Node_Type (Node => Subprog_Or_Variable_Node) = SP_Symbols.later_declarative_item_rep
              or else Syntax_Node_Type (Node => Subprog_Or_Variable_Node) = SP_Symbols.statement
              or else Syntax_Node_Type (Node => Subprog_Or_Variable_Node) = SP_Symbols.code_insertion
              or else Syntax_Node_Type (Node => Subprog_Or_Variable_Node) = SP_Symbols.renaming_declaration_rep
              or else Syntax_Node_Type (Node => Subprog_Or_Variable_Node) = SP_Symbols.task_pragma
              or else Syntax_Node_Type (Node => Subprog_Or_Variable_Node) = SP_Symbols.protected_operation_declaration_rep
              or else Syntax_Node_Type (Node => Subprog_Or_Variable_Node) = SP_Symbols.body_stub then
               -- ASSUME Subprog_Or_Variable_Node = compilation_unit OR
               --                                   pragma_rep OR
               --                                   later_declarative_item_rep OR
               --                                   statement OR
               --                                   code_insertion OR
               --                                   renaming_declaration_rep OR
               --                                   task_pragma OR
               --                                   protected_operation_declaration_rep OR
               --                                   body_stub
               Subprog_Or_Variable_Node := STree.NullNode;
            else
               SystemErrors.Fatal_Error
                 (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
                  Msg     => "Expect Subprog_Or_Variable_Node = compilation_unit OR pragma_rep OR " &
                    "initial_declarative_item_rep OR later_declarative_item_rep OR statement OR code_insertion OR " &
                    "visible_part_rep OR basic_declarative_item_rep OR renaming_declaration_rep OR task_pragma OR " &
                    "protected_operation_declaration_rep OR body_stub in Wf_Pragma");
            end if;
            -- ASSUME Subprog_Or_Variable_Node = subprogram_declaration OR basic_declarative_item OR NULL
            --# check Syntax_Node_Type (Subprog_Or_Variable_Node, STree.Table) = SP_Symbols.subprogram_declaration or
            --#   Syntax_Node_Type (Subprog_Or_Variable_Node, STree.Table) = SP_Symbols.basic_declarative_item or
            --#   Subprog_Or_Variable_Node = STree.NullNode;
            if Syntax_Node_Type (Node => Subprog_Or_Variable_Node) = SP_Symbols.subprogram_declaration then
               -- ASSUME Subprog_Or_Variable_Node = subprogram_declaration
               -- It's a subprogram_declaration, note that pragma Import must immediately follow
               -- the subprogram declaration so going one step up the syntax tree will find the subprogram
               -- if one is there.
               Handle_Interface_On_Subprogram (Subprog_Declaration_Node => Subprog_Or_Variable_Node,
                                               Node                     => Node,
                                               Scope                    => Scope);
            elsif Syntax_Node_Type (Node => Subprog_Or_Variable_Node) = SP_Symbols.basic_declarative_item then
               -- ASSUME Subprog_Or_Variable_Node = basic_declarative_item
               -- it might be a variable declaration
               Handle_Import_On_Variable
                 (Basic_Declaration_Node => Subprog_Or_Variable_Node,
                  Id_Node                => Id_Node,
                  Node                   => Node,
                  Scope                  => Scope);
            elsif Subprog_Or_Variable_Node = STree.NullNode then
               -- ASSUME Subprog_Or_Variable_Node = NULL
               -- none of the things where pragma import allowed has been found so it's an error
               ErrorHandler.Semantic_Error
                 (Err_Num   => 72,
                  Reference => ErrorHandler.No_Reference,
                  Position  => Node_Position (Node => Node),
                  Id_Str    => Node_Lex_String (Node => Id_Node));
            end if;
         else -- we ARE in a protected type, so pragma import is unexpected
            ErrorHandler.Semantic_Error
              (Err_Num   => 72,
               Reference => ErrorHandler.No_Reference,
               Position  => Node_Position (Node => Node),
               Id_Str    => Node_Lex_String (Node => Id_Node));
         end if; -- in protected type

         -- handle pragma elaborate_body which must be the first
         -- visible_part_rep in a package specification to be acceptable
      elsif CommandLineData.Content.Language_Profile /= CommandLineData.SPARK83
        and then LexTokenManager.Lex_String_Case_Insensitive_Compare
        (Lex_Str1 => Node_Lex_String (Node => Id_Node),
         Lex_Str2 => LexTokenManager.Elaborate_Body_Token) =
        LexTokenManager.Str_Eq then
         -- A pragma Elaborate_Body has been found and must be processed.
         -- First check it is correctly positioned
         Pack_Spec_Node := Parent_Node (Current_Node => Node);
         -- ASSUME Pack_Spec_Node = compilation_unit OR
         --                         pragma_rep OR
         --                         initial_declarative_item_rep OR
         --                         later_declarative_item_rep OR
         --                         statement OR
         --                         code_insertion OR
         --                         visible_part_rep OR
         --                         basic_declarative_item_rep OR
         --                         renaming_declaration_rep OR
         --                         task_pragma OR
         --                         protected_operation_declaration_rep OR
         --                         body_stub
         if Syntax_Node_Type (Node => Pack_Spec_Node) = SP_Symbols.visible_part_rep then
            -- ASSUME Pack_Spec_Node = visible_part_rep
            if Child_Node (Current_Node => Child_Node (Current_Node => Pack_Spec_Node)) = STree.NullNode then
               -- Potentially legal.
               -- Work up chain to package specification node
               while Syntax_Node_Type (Node => Pack_Spec_Node) /= SP_Symbols.package_specification loop
                  --# assert STree.Table = STree.Table~;
                  Pack_Spec_Node := Parent_Node (Current_Node => Pack_Spec_Node);
               end loop;
               -- ASSUME Pack_Spec_Node = package_specification
               -- find identifier of package
               Pack_Ident_Node := Child_Node (Current_Node => Child_Node (Current_Node => Pack_Spec_Node));
               while Syntax_Node_Type (Node => Pack_Ident_Node) /= SP_Symbols.identifier loop
                  --# assert STree.Table = STree.Table~;
                  Pack_Ident_Node := Next_Sibling (Current_Node => Pack_Ident_Node);
               end loop;
               -- ASSUME Pack_Ident_Node = identifier
               Pack_Ident_Sym :=
                 Dictionary.LookupItem
                 (Name              => Node_Lex_String (Node => Pack_Ident_Node),
                  Scope             => Scope,
                  Context           => Dictionary.ProgramContext,
                  Full_Package_Name => False);
               Wf_Elaborate_Body (Pragma_Node => Node,
                                  Pack_Sym    => Pack_Ident_Sym);
            else
               -- unexpected in this position
               ErrorHandler.Semantic_Error
                 (Err_Num   => 72,
                  Reference => ErrorHandler.No_Reference,
                  Position  => Node_Position (Node => Node),
                  Id_Str    => Node_Lex_String (Node => Id_Node));
            end if;
         elsif Syntax_Node_Type (Node => Pack_Spec_Node) = SP_Symbols.compilation_unit
           or else Syntax_Node_Type (Node => Pack_Spec_Node) = SP_Symbols.pragma_rep
           or else Syntax_Node_Type (Node => Pack_Spec_Node) = SP_Symbols.initial_declarative_item_rep
           or else Syntax_Node_Type (Node => Pack_Spec_Node) = SP_Symbols.later_declarative_item_rep
           or else Syntax_Node_Type (Node => Pack_Spec_Node) = SP_Symbols.statement
           or else Syntax_Node_Type (Node => Pack_Spec_Node) = SP_Symbols.code_insertion
           or else Syntax_Node_Type (Node => Pack_Spec_Node) = SP_Symbols.basic_declarative_item_rep
           or else Syntax_Node_Type (Node => Pack_Spec_Node) = SP_Symbols.renaming_declaration_rep
           or else Syntax_Node_Type (Node => Pack_Spec_Node) = SP_Symbols.task_pragma
           or else Syntax_Node_Type (Node => Pack_Spec_Node) = SP_Symbols.protected_operation_declaration_rep
           or else Syntax_Node_Type (Node => Pack_Spec_Node) = SP_Symbols.body_stub then
            -- ASSUME Pack_Spec_Node = compilation_unit OR
            --                         pragma_rep OR
            --                         initial_declarative_item_rep OR
            --                         later_declarative_item_rep OR
            --                         statement OR
            --                         code_insertion OR
            --                         basic_declarative_item_rep OR
            --                         renaming_declaration_rep OR
            --                         task_pragma OR
            --                         protected_operation_declaration_rep OR
            --                         body_stub
            -- unexpected in this position
            ErrorHandler.Semantic_Error
              (Err_Num   => 72,
               Reference => ErrorHandler.No_Reference,
               Position  => Node_Position (Node => Node),
               Id_Str    => Node_Lex_String (Node => Id_Node));
         else
            SystemErrors.Fatal_Error
              (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
               Msg     => "Expect Pack_Spec_Node = compilation_unit OR pragma_rep OR initial_declarative_item_rep OR " &
                 "later_declarative_item_rep OR statement OR code_insertion OR visible_part_rep OR " &
                 "basic_declarative_item_rep OR renaming_declaration_rep OR task_pragma OR " &
                 "protected_operation_declaration_rep OR body_stub in Wf_Pragma");
         end if;
      elsif CommandLineData.Ravenscar_Selected then
         if LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Node_Lex_String (Node => Id_Node),
            Lex_Str2 => LexTokenManager.Atomic_Token) =
           LexTokenManager.Str_Eq then
            -- special handling for Pragma Atomic (...) in Ravenscar mode
            Wf_Pragma_Atomic (Pragma_Node => Node,
                              Scope       => Scope);
         elsif LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Node_Lex_String (Node => Id_Node),
            Lex_Str2 => LexTokenManager.Priority_Token) =
           LexTokenManager.Str_Eq
           or else LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Node_Lex_String (Node => Id_Node),
            Lex_Str2 => LexTokenManager.Interrupt_Priority_Token) =
           LexTokenManager.Str_Eq then
            -- Other than pragma Priority in the declarative part of the main program,
            -- we have an out-of-place priority pragma; these are handled by
            -- wf_priority_pragma which is called from grammar-specific locations
            -- where a priority pragma is allowed.
            if Dictionary.MainProgramExists
              and then Dictionary.IsMainProgram (Dictionary.GetRegion (Scope))
              and then Syntax_Node_Type (Node => Parent_Node (Current_Node => Node)) /= SP_Symbols.statement
              and then LexTokenManager.Lex_String_Case_Insensitive_Compare
              (Lex_Str1 => Node_Lex_String (Node => Id_Node),
               Lex_Str2 => LexTokenManager.Priority_Token) =
              LexTokenManager.Str_Eq then
               Wf_Main_Program_Priority (Id_Node => Id_Node,
                                         Node    => Node,
                                         Scope   => Scope);
            else
               ErrorHandler.Semantic_Error
                 (Err_Num   => 879,
                  Reference => ErrorHandler.No_Reference,
                  Position  => Node_Position (Node => Node),
                  Id_Str    => Node_Lex_String (Node => Id_Node));
            end if;
         elsif LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Node_Lex_String (Node => Id_Node),
            Lex_Str2 => LexTokenManager.Interrupt_Handler_Token) =
           LexTokenManager.Str_Eq then
            ErrorHandler.Semantic_Error
              (Err_Num   => 883,
               Reference => ErrorHandler.No_Reference,
               Position  => Node_Position (Node => Node),
               Id_Str    => LexTokenManager.Null_String);
         elsif LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Node_Lex_String (Node => Id_Node),
            Lex_Str2 => LexTokenManager.Atomic_Components_Token) =
           LexTokenManager.Str_Eq then
            ErrorHandler.Semantic_Error
              (Err_Num   => 842,
               Reference => ErrorHandler.No_Reference,
               Position  => Node_Position (Node => Node),
               Id_Str    => LexTokenManager.Null_String);
         elsif LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Node_Lex_String (Node => Id_Node),
            Lex_Str2 => LexTokenManager.Volatile_Components_Token) =
           LexTokenManager.Str_Eq then
            ErrorHandler.Semantic_Error
              (Err_Num   => 843,
               Reference => ErrorHandler.No_Reference,
               Position  => Node_Position (Node => Node),
               Id_Str    => LexTokenManager.Null_String);
         elsif LexTokenManager.Lex_String_Case_Insensitive_Compare
           (Lex_Str1 => Node_Lex_String (Node => Id_Node),
            Lex_Str2 => LexTokenManager.Attach_Handler_Token) =
           LexTokenManager.Str_Eq then
            Wf_Attach_Handler (Pragma_Node => Node,
                               Scope       => Scope);
         else
            ErrorHandler.A_Pragma (Node_Lex_String (Node => Id_Node), Node_Position (Node => Node));
         end if;
      else -- not a "special" pragma so handle with normal warning

         --  Check the number of arguments associated with particular
         --  pragmas.
         Check_Arg_Count (Node           => Node,
                          Statement_OK   => Statement_OK,
                          Error_To_Raise => Error_To_Raise);
         if not Statement_OK then
            ErrorHandler.Semantic_Warning
              (Err_Num  => Error_To_Raise,
               Position => Node_Position (Node => Node),
               Id_Str   => LexTokenManager.Null_String);
         else
            ErrorHandler.A_Pragma (Node_Lex_String (Node => Id_Node), Node_Position (Node => Node));
         end if;
      end if;
   else
      SystemErrors.Fatal_Error
        (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
         Msg     => "Expect Id_Node = identifier OR assert_pragma in Wf_Pragma");
   end if;
end Wf_Pragma;
