program VerifyingSpecification; (* This is an example showing how to proceed in order to make a dynamic verification of an implementation of a specification of a data structure. In our example we shall give three components: 1) a specification of stacks, 2) a class that ensures the dynamic verification of correctness of an implementing module, 3) an implementation of stacks as a class which inherits from the previous class. *) (* Nowy problem powstaje: jak rozpl\ata'c wzajemne odwo/lania operacji wymienionych w specyfikacji? Zrobilem tak: kazda operacja posiada dwie wersje np. Push i Ppush 1sza wersja jest otoczona pre- i post- conditions 2ga wersja nie zawiera takiego sprawdzania - druga wersja jest uzywana w pre- i post-conditions i wewnatrz equal ktore odwoluje sie do top i pop Nie jestem tym zachwycony. Po co dwa razy pisac te sama procedure?? *) (* --------------- specification of STACKS ---------------------------- sorts Elem, Stack, Boolean; predicates empty: Stack {SYMBOL 174 \f "Symbol"} Boolean eq: Elem {SYMBOL 180 \f "Symbol"} Elem {SYMBOL 174 \f "Symbol"} Boolean equal: Stack {SYMBOL 180 \f "Symbol"} Stack {SYMBOL 174 \f "Symbol"} Boolean operations push: Elem {SYMBOL 180 \f "Symbol"} Stack {SYMBOL 174 \f "Symbol"} Stack pop: Stack {SYMBOL 174 \f "Symbol"} Stack top: Stack {SYMBOL 174 \f "Symbol"} Elem axioms for every e in Elem, for every s in Stack A1) not empty(push(e,s)) A2) eq(e, top(push(e,s))) A3) equal(s, pop(push(e,s))) A4) not empty(s) ==> equal(s, push(top(s), pop(s))) A5) while not empty(s) do s := pop(s) od true A6) equal(s, s') <=> begin result := true; s1 := s; s2 := s'; while not empty(s1) and not empty(s2) and result do result := eq(top(s1), top(s2)); s1 := pop(s1); s2 := pop(s2); od (result and empty(s1) and empty(s2)) end of specification STACKS *) (* -------------------------- Checking STACKS --------------------------- *) unit STACKS_CHECKING: class; unit Elem: class; end Elem; unit Stack: class; end Stack; unit check_Push: class(e: Elem, s: Stack); var res, old_s: Stack; begin (* if full(s) then raise ERR_Full fi; *) old_s := s; inner; if empty(res) then raise ERR_Axiom1 fi; if not eq(e, Ttop(res)) then raise ERR_Axiom2 fi; if not equal(old_s, Ppop(res)) then raise ERR_Axiom3 fi; end check_Push; unit virtual Push: check_Push function: Stack; end Push; unit virtual Ppop: function(s:Stack): Stack; end Ppop; unit virtual Pop: check_Pop function: Stack; end Pop; unit virtual Ttop: function(s: Stack): Elem; end Ttop; unit check_Pop: class(s: Stack); var res: Stack, aux: Elem; begin if empty(s) then raise ERR_Empty fi; inner; aux := Ttop(s); if not equal(s, Ppush(aux,res)) then raise ERR_Axiom4 fi; end check_Pop; unit virtual Ppush: function(e: Elem, s: Stack): Stack; end Ppush; unit virtual Top: check_Top function: Elem; end Top; unit check_Top: class(s: Stack); var res: Elem, aux: Stack; begin if empty(s) then raise ERR_Empty fi; inner; aux := Pop(s); if not equal(s, Ppush(res,aux)) then raise ERR_Axiom4 fi; end check_Top; unit virtual Empty: function(s: Stack): Boolean; end Empty; unit virtual Eq: function(e1, e2: Elem): Boolean; end Eq; unit check_Equal: class(s1, s2: Stack); (* what to check and how? *) end check_Equal; unit virtual Equal: function(s1, s2: Stack): Boolean; end Equal; signal ERR_Full, ERR_Empty, ERR_Axiom1, ERR_Axiom2, ERR_Axiom3, ERR_Axiom4; end STACKS_CHECKING; (* ----------------------- STACKS generic ------------------------------- *) unit STACKS_Generic: STACKS_Checking class; hidden link; unit link: class(e: Elem); var next: link; end link; unit Stackl: Stack class; var top: link end Stackl; unit virtual Push: check_Push function: Stackl; var aux: link; begin aux := new Link(e); aux.next := s qua Stackl.top; result := new Stackl; result.top := aux; res := result end Push; unit virtual Ppush: function(e: Elem, s: Stackl): Stackl; var aux: link; begin aux := new Link(e); aux.next := s.top; result := new Stackl; result.top := aux; end Ppush; unit virtual Pop: check_Pop function: Stackl; begin result := new Stackl; result.top := s qua Stackl.top.next; res := result; end Pop; unit virtual Ppop: function(s: Stackl): Stackl; begin result := new Stackl; result.top := s.top.next; end Ppop; unit virtual Top: check_Top function: Elem; begin result := s qua Stackl.top.e; res := result end Top; unit virtual Ttop: function(s: Stackl): Elem; begin result := s.top.e end Ttop; unit virtual Empty: function(s: Stackl): Boolean; begin result := s.top = none end empty; unit virtual Eq: function(e1, e2: Elem): Boolean; end Eq; unit virtual Equal: function(s1, s2: Stackl): Boolean; var s3, s4: Stack; begin result := true; s3 := s1; s4 := s2; while not empty(s3) and not empty(s4) and result do result := eq(Ttop(s3), Ttop(s4)); s3 := Ppop(s3); s4 := Ppop(s4); od; result := (result and empty(s3) and empty(s4)) end Equal; end STACKS_Generic; (* ------------------------- MAIN ---------------------------------- *) begin pref STACKS_Generic block unit mElem: Elem class(i:integer); end mElem; unit virtual Eq: function(e1,e2: mElem): Boolean; begin result := e1.i = e2.i end Eq; var e1, e2: mElem, i: integer, s1, s2: Stackl; handlers when ERR_Empty: writeln("stack is empty"); when ERR_Full: writeln("stack is full"); when ERR_Axiom1: writeln("Axiom1"); when ERR_Axiom2: writeln("Axiom2"); when ERR_Axiom3: writeln("Axiom3"); when ERR_Axiom4: writeln("Axiom4"); end handlers; begin writeln("program testing stacks and its verification environment"); s1 := new Stackl; writeln("give an integer, ZERO ends"); do readln(i); e1 := new mElem(i); s1 := push(e1, s1); if i=0 then exit fi; od; s2 := s1; do if empty(s2) then exit else e2 := top(s2); s2 := pop(s2); writeln(e2.i) fi od; end (* prefixed block *) end (* of program *)