-2

How to incorporate proof aspects into the specification so that every function and procedure has a Post aspect and, if required, a Pre aspect that outlines the proper behaviour of the code below:

package Stack with SPARK_Mode is
pragma Elaborate_Body;

   Stack_Size : constant := 100;
   type Pointer_Range is range 0 .. Stack_Size;
   subtype Index_Range is Pointer_Range range 1 .. Stack_Size;
   type Vector is array(Index_Range) of Integer;

   S: Vector;
   Pointer: Pointer_Range;

   function isEmpty return Boolean;
   procedure Push(X : in Integer)
     with
       Global => (In_out => (S, Pointer)),
       Depends => (S => (S, Pointer, X),
                   Pointer => Pointer);

   procedure Pop(X : out Integer)
     with
       Global => (input => S, in_out => Pointer),
       Depends => (Pointer => Pointer,
                   X => (S, Pointer));

end Stack;
Simon Wright
  • 25,108
  • 2
  • 35
  • 62

2 Answers2

2

Following is a possible set of post conditions and pre conditions for your example. The actual set must depend upon actual requirements for your stack behavior. This example is simply a typical set of conditions for the stack.

package Stack with SPARK_MODE is
   pragma Elaborate_Body;
   
   Stack_Size : constant := 100;
   type Pointer_Range is range 0 .. Stack_Size;
   subtype Index_Range is Pointer_Range range 1..Stack_Size;
   type Vector is array (Index_Range) of Integer;
   
   S : Vector;
   Pointer : Pointer_Range := 0;
   
   function isEmpty return Boolean with
     Post => IsEmpty'Result = (if Pointer = 0 then True else False);
   
   procedure Push(X : in Integer) with
     Global => (In_Out => (S, Pointer)),
     Depends => (S => (S, Pointer, X), Pointer => Pointer),
     Pre => Pointer < Stack_Size,
     Post => Pointer = Pointer'Old + 1 and S(Pointer) = X;
   
   procedure Pop(X : out Integer) with
     Global => (In_Out => (S, Pointer)),
     Depends => (Pointer => Pointer,
                 X => (S, Pointer),
                 S => S),
     Pre => not isEmpty,
     Post => Pointer = Pointer'Old - 1 and X = S(Pointer'Old);
   
end Stack;
Jim Rogers
  • 4,822
  • 1
  • 11
  • 24
1

In brief, you should add a Post-condition aspect to every subprogram in the package, and a Pre-condition aspect to those subprograms that need it.

Preconditions and postconditions in Ada are explained at http://www.ada-auth.org/standards/22rm/html/RM-6-1-1.html.

What is your problem, really? Is it about the syntax of the pre/post-condition aspects, or about their content and meaning? Or is it about the meaning of "proper behaviour" in the problem statement? In the last case, try to imagine what might be improper behaviour, or incorrect use, of a Push or Pop operation on a stack with a fixed maximum size.

Niklas Holsti
  • 1,907
  • 3
  • 9
  • The aspects for a subprogram are written at the end of the subprogram declaration, after a "with" keyword and before the terminating semicolon. If there are several aspects, they are separated by commas. The Push and Pop operations you show already have two aspects each: a Global aspect and a Depends aspect. You add the Pre and Post aspects to those aspect lists, prefixing each with a separating comma: procedure Push ... with Global => ..., Depends => ..., Pre => ..., Post => ...; – Niklas Holsti Dec 02 '22 at 15:00