home *** CD-ROM | disk | FTP | other *** search
/ ftp.cs.yorku.ca 2015 / ftp.cs.yorku.ca.tar / ftp.cs.yorku.ca / pub / peter / SVT / SWI / symbex.pl < prev    next >
Text File  |  2007-03-11  |  20KB  |  628 lines

  1. % SYMBOLIC EXECUTION
  2. %   copyright Peter H. Roosen-Runge, 1991-2007
  3.  
  4. % Ver. 2.0, March 5, 1991: handles assignment statements, goals, and IFs. 
  5. %      2.3, Feb. 24, 1992:  Statements can *begin* with an assertion.
  6. %      2.3.1, March 6:  Initial values supplied automatically (again!)
  7. %      3.1 Feb. 27, 1998: uses getTheories to load simplification rules.
  8. %      3.1.2 March 20: clean expressions before converting to term.
  9. %                     allow white space between // and {
  10. %      4.0  Dec. 22, 1998: reads "contracts" and procedure calls
  11. %      4.2.4 March 8: test if assertion is impossible
  12. %      4.2.4.3 March 19: recompiled with clean.prolog v 1.4
  13. %                    allows A[E] in expressions.
  14. %                  still doesn't do parallel assignment
  15. %      4.2.4.6 April 6: print "{", "}" around a statement block
  16. %      4.2.4.8 April 9: repaired procedure post-condition processing
  17. %      4.2.4.9 April 11: simplify if and else conditions before checking
  18. %      4.2.5 March 19, 2000: added multifile and dynamic directives,
  19. %                    processes 'simplification.rules' as a theory file
  20. %                    rather than consulting it. makefun repaired to
  21. %                    allow general pre-conditions as well as identities.
  22. %      4.2.5.1 March 25: checks if simplification.rules exists before
  23. %           trying to open it.
  24.  
  25. %      4.2.6   March 29: symex repaired to handle X or Y conditions
  26. %      5.0     August 25: allow while loops with invariants
  27. %      5.0A    March 31, 2002: attempt to repair from 5.3
  28. %      5.3ASWI February 24, 2007: SWI version
  29. % =====================================================================
  30. % Reads an initial condition in the form
  31. % //{ C and x = e1  and y = e2 . . . etc. } 
  32. % or //{x = e1  and y = e2 . . . and C}
  33. % where the ei are expressions specifying the initial values of variables
  34. % in the code which follows and C is a pre-condition on the initial values.
  35. % The initial condition is followed by a sequence of assignment or 
  36. % IF-statements which are 'symbolically executed'.
  37.  
  38. % a program fragment can be preceded by one more procedure specification 
  39. % in the form
  40. %   //{ precondition }
  41. %   void IDENTIFIER(ARGS);
  42. %   //{ postcondition}
  43.  
  44. % The parameters in the pre- and post-conditions must be in upper case.
  45.  
  46.  
  47. % symbex reports the precondition which holds before THEN or ELSE branches
  48. % and notes branches which are never or always taken.
  49. % Allowable statement forms --
  50. %        V = Expression ;
  51. %        if (B) statement
  52. %        if (B) statement1 else statement2
  53. %               while(B) //{ invariant } statement            
  54. %
  55. %        { statements }
  56.  
  57. % N. B. The right-hand sides of the initial conditions *must not*
  58. % contain occurrences (as atoms) of any variables which occur on the left
  59. % of any equality. You can however use conditions such as x = x(0).
  60.  
  61. % An assertion in the form { proposition } can precede a statement
  62. % or follow the entire code fragment.
  63. % If one occurs, a test is made to see if the previous post-condition
  64. % implies this assertion and the result of the test is reported.
  65. %
  66. % symbex searches the home, working, and working directories for
  67. % arithmetic.simp, equality.simp, and logic.simp, and loads a file 
  68. % "simplification.rules" from the working directory, if there is one.
  69. % ==============================================================
  70.  
  71. % error(Message) :- nl, write('!! '), write(Message), nl, halt.
  72. % user_error_handler(_,_,_,_) :- error('Something wrong.').
  73. %:-unknown(_,fail).
  74. %:- nofileerrors.  (handled in getTheories)
  75.  
  76. :- multifile '->>'/2.  :- dynamic '->>'/2.
  77.  
  78. :- ensure_loaded([qlib(files), qlib(lineio), qlib(ctypes), qlib(occurs) ]).
  79. % qlib(charsio), qlib(lists), qlib(basics) not needed in SWI
  80.  
  81. % For consistency, operator declarations used by wang, taut, simp, symbex, and
  82. % quants.
  83.  
  84. :-op(999,xfx, '!'). % used to separate condition from current function.
  85. :-op(995,xfx, '->>').  % simplification
  86. :-op(995,xfy,'>>').    % sequent
  87. :-op(995,xfy, '::').  % separate parts of a quantified expression
  88. :-op(990, yfx, iff).  % Left-associative (yfx) for consistency with
  89.                       % commutative arithmetic operators.
  90. :-op(1199, xfx, if).  % separate condition from rule.
  91.  
  92. :-op(990,yfx,implies). % for consistency with iff
  93. :-op(980,yfx, [or, cor]).
  94. :-op(970,xfx,xor). % xor isn't associative.  force parenthesization.
  95. :-op(960,yfx,[and, cand, div, mod]).
  96. :-op(950,fy,not).
  97. :-op(700,xfx,assigned).  % used in simplification. A safe 'is' operator.
  98. :-op(700,xfy,['<=','<', '>', '>=', '<>', '==', '!=']).
  99. :-op(200,xfy,'**').
  100. :-op(200,xfy, in).  % used in quants.
  101.  
  102. % uses path in .plrc
  103. :- ensure_loaded([  % lib('input.prolog') for getText(Text)?, loads ctypes
  104.           lib(output), % indent(N), newline, writeString
  105.                   lib(equtaut), lib(simp),
  106.                   lib(clean), % to clean up C 
  107.           lib(charsio), qlib(qlists)]).
  108.  
  109. :-op(100, fx, '&').  % used in symbex for procedure args.
  110.  
  111. % C-operators for symbex and wp.
  112.  
  113. :-op(100, xf,['++', '--']).
  114. :-op(100, fx, ['++', '--']).
  115. :-op(100, xfy, ['+=', '-=', '*=', '/=']).
  116. :-op(601, xfy, ':').
  117. :-op(602, xfy, '?').
  118.  
  119. % =========================================================================
  120.  
  121. activate :- write('Version 5ASWI'), nl,
  122.     getTheories,
  123.         (exists_file('simplification.rules'),
  124.                theory('simplification.rules'); true),
  125.     readCode(C), !, program(C), 
  126.         nl, halt.
  127. %     ;
  128. %    error('Something wrong.').
  129.  
  130. % read lines of code and concatenate into Code.
  131. readCode(Code) :-
  132.         get_line(Line, Terminator),
  133.        (
  134.         is_endfile(Terminator), Code = Line
  135.         ;
  136.         readCode(More), append(Line,More, Code)
  137.        ).   
  138.  
  139. testInput2("if(b) x = y+2; if(!b) x = y + 2; x=y;").
  140. testInput3("//{ true } void swap(X, Y); //{ X = 'old Y' and Y = 'old X'}
  141. x=7; swap(&x, &y);").
  142. testInput4("//{x=a and y=0 and a > 0}
  143. while(x != 0) //{x+y=a}{ x = x-1; y = y+1;}").
  144.  
  145. program(S0) :- 
  146.     fixComment(S, S0, []),
  147.     contracts(S, S1),
  148.     precond0(P,S1,S2), 
  149.     makefun(P, C, F), !,  % C is true by default
  150.     applyFun(F, C, CC),
  151.     statement(1, CC ! F, NewF, S2, Rest), !,
  152.     statements(1, NewF, Post, Rest, LeftOver), 
  153.     unfun(Post, PostTerm),
  154.     simplify(PostTerm, SimpPost),
  155.     nl, writeCond(SimpPost),
  156.     testContra(SimpPost),
  157.     break(LeftOver, Remains),
  158.         (Remains == [] 
  159.     ;
  160.          nl, writeStrings(["// Couldn't parse: ", Remains])
  161.     ).
  162.  
  163. contracts --> break, contract, (contracts ; []) ; [].
  164.  
  165. opT([OpC | "="], OpT) :- atom_codes(OpT, [OpC]).
  166.     
  167. precond0(P) --> break, precond(P), break.
  168. precond(true) -->  "//", break, [12, 12], break, { nl, writeCond(true) }. 
  169. precond(PTerm) --> "//", break, [12], upto(P, [12]), break,
  170.         {  chars_to_term(P, PTerm)
  171. %    ,   nl, writeCond(PTerm) 
  172.         }.
  173. precond(true) --> break, { nl, writeCond(true) }.
  174.  
  175. goal(N, Cond) --> "//", break, [12], upto(Goal, [12], [12]), !, 
  176.     { 
  177.       chars_to_term(Goal, GoalTerm), unfun(Cond, CTerm),
  178.       simplify(GoalTerm, SimGoal),
  179.       indent(N), write('// assert: '), write(SimGoal),
  180.       (
  181.         simtaut(not(CTerm and SimGoal)),
  182.             indent(N), write('// -- assertion is impossible!'),
  183.         indent(N), write('// -- current state is '),
  184. %           pretty(CTerm)
  185.                write(CTerm), nl
  186.            ;  
  187.        simtaut(CTerm implies SimGoal), 
  188.         indent(N), write('// -- assertion is verified.'), nl
  189.            ;
  190.         indent(N), write('//  -- assertion may not be valid.'),
  191.         indent(N), write('//  -- could not prove '),
  192. %            pretty(CTerm implies SimGoal)
  193.                 write(CTerm implies SimGoal), nl
  194.       )
  195.      }, break.
  196.  
  197. unfun(P ! [], P).    
  198. unfun(P ! F, SPT) :- unfun1(F, Term), simplify(P and Term, SPT).
  199. unfun(Rest or P, SYX) :- unfun(P, Y), unfun(Rest, X), simplify(X or Y, SYX).
  200. unfun(_, _) :- error('Error in unfun.').
  201.  
  202. unfun1([[R, V]], R=V).
  203. unfun1([[R, V] | Rest], Term and (R=V)) :- unfun1(Rest, Term).
  204. unfun1(_, _) :- error('Error in unfun.').
  205.  
  206. /*
  207. processAssign(X=V, Args, In, Pin, Pin,  Out) :-
  208.         memberchk(&X, Args),
  209.         symex(In, X, V, Out).
  210. processAssign(Rest and (X=V), Args, In, Pin, Pin, Out) :-
  211.         memberchk(&X, Args),
  212.         symex(In, X, V, Out1),
  213.         processAssign(Rest, Args, Out1, Pin, Pin, Out).
  214. processAssign(T, _, In, Pin, Pin and T, In).
  215. */
  216.  
  217. assignDummy(X, Args, In, V, Out, InList, [DummyX | InList]) :-
  218.         memberchk(&X, Args),
  219.         name(X,XStr), name('$', [Dollar]), name(DummyX, [Dollar|XStr]),
  220.         symex(In, DummyX, V, Out).
  221.  
  222. processAssign1(X=V, Args, In, Pin, Pin,  Out, InList, OutList) :-
  223.         assignDummy(X, Args, In, V, Out, InList, OutList).
  224.  
  225. processAssign1(Rest and (X=V), Args, In, Pin, Pin, Out, InList, OutList) :-
  226.         assignDummy(X, Args, In, V, Out1, InList, NewList),
  227.         processAssign1(Rest, Args, Out1, Pin, Pin, Out, NewList, OutList).
  228.  
  229. unassignDummy(X, In, Out) :-
  230.         name('$', [Dollar]), name(X, [Dollar|XStr]), name(UnDollar, XStr),
  231.         symex(In, UnDollar, X, Out).
  232. processAssign1(T, _, In, Pin, Pin and T, In).
  233.  
  234. deleteDollar([], In, In).
  235. deleteDollar([[X, _] | Rest], In, Out) :-
  236.         name('$', [Dollar]), name(X, [Dollar|_]),
  237.         deleteDollar(Rest, In, Out).
  238. deleteDollar([[X, Y] | Rest], In, Out) :-
  239.         deleteDollar(Rest, [[X, Y] | In], Out).
  240.  
  241. processAssign2([], P ! In, P ! Cleaned) :- deleteDollar(In, [], Cleaned).
  242. processAssign2([X | List], In, Out) :-
  243.         unassignDummy(X, In, New),
  244.         processAssign2(List, New, Out).
  245.  
  246. processAssign(T, Args, In, Pin, Pout, Out) :-
  247.         processAssign1(T, Args, In, Pin, Pout, New, [], OutList),
  248.         processAssign2(OutList, New, Out).
  249.  
  250. processPostCon(Rest and T, In, Out) :-
  251.        combine(In, T, Out1),
  252.        processPostCon(Rest, Out1, Out).   
  253. processPostCon(P, In, Out) :-
  254.        combine(In, P, Out).
  255.  
  256. processPostCon(P, Args, In, Out) :-
  257.     processAssign(P, Args, In, true, Pout, Out1),
  258.     processPostCon(Pout, Out1, Out).
  259.  
  260. statements(N, Pre, Post)  --> 
  261.     statement(N, Pre, PP), 
  262.     statements(N, PP, Post).
  263. statements(_, Pre, Pre) --> [].
  264.  
  265. statement(N, Pre, Pre) --> goal(N, Pre), break.
  266. statement(N, Pre, Pre) --> 
  267.     ";", break,
  268.     {indent(N), write(';')}.
  269. statement(N, Pre, Post) --> 
  270.     matchP("{", "}", Balanced),
  271.     { 
  272.       indent(N), write('{ '),
  273.           statements(N, Pre, Post, Balanced, []),
  274.           indent(N), write(' }')
  275.     }, 
  276.     break.
  277.  
  278. statement(N, Pre, IfPost or ElsePost) -->
  279.                 ifThen(N, Pre, BTerm, IfPre), break,
  280.                 statement(N+1, IfPre, IfPost), break,
  281.                 elseClause(N, Pre, BTerm, ElsePost), break.
  282.  
  283. statement(N, Pre, Post) -->
  284.         "while", break, matchP("(", ")", B), break, !,
  285.         { indent(N), writeStrings(["while (", B, ") "]),
  286.           string_to_term(B, BTerm),
  287.           combine(Pre, BTerm, Entry) },
  288.         assertion(Inv), 
  289.        {string_to_term(Inv, InvTerm), 
  290.         unfun(Entry, EntryP),
  291.         (
  292.          simtaut(EntryP implies InvTerm)
  293.         ;
  294.          indent(N+1), 
  295.      write('Cannot prove that the invariant holds at loop entry.')
  296.         )
  297.        },
  298.     statement(N+1, Entry, Exit),
  299.        {unfun(Exit, ExitP),
  300.         (simtaut(ExitP implies InvTerm)
  301.         ;
  302.          indent(N+1),
  303.          write('Cannot prove that the invariant holds at loop exit.')
  304.         ),
  305.         combine(Pre, InvTerm and not BTerm, Post)
  306.        }.
  307.                     
  308. statement(N, Cond, NewCond) -->
  309.      "switch", break, matchP("(", ")", Var), break,
  310.     {indent(N), writeStrings(["switch (", Var, ") {"])},
  311.      matchP("{", "}", Cases), break,
  312.     { cases(N, Cond, NewCond, Var, Cases, [])}, break.
  313.  
  314. statement(N, Cond, NewCond) -->
  315.          opAssign(Ref, Val, OpAssign),
  316.         { 
  317.      opT(OpAssign, OpT),   
  318.      atom_codes(OpT, OpString),
  319.      indent(N),
  320.      writeStrings([Ref, " = ", Ref, OpString, Val, " ;"]),
  321.          chars_to_term(Ref, R), string_to_term(Val, V),
  322.          RHS =.. [OpT, R, V],  
  323.          symex(Cond, R, RHS, NewCond), !
  324.     }, 
  325.     break.
  326. statement(N, Cond, NewCond) -->
  327.         upto(Ref, "=", ";"), upto(Val, ";"),
  328.         { 
  329.      indent(N), writeStrings([Ref, " = ", Val, " ;"]),
  330.          chars_to_term(Ref, R), string_to_term(Val, V),
  331.          symex(Cond, R, V, NewCond), !
  332.     }, 
  333.     break.            
  334. statement(N, Cond, NewCond) -->
  335.     incdec(Ref, Op), break,
  336.     { 
  337.           indent(N), writeStrings([Ref, " = ", Ref, " ", [Op], " 1;"]),
  338.           chars_to_term(Ref, R), atom_chars(OpT, [Op]),
  339.       RHS =.. [OpT, R, 1],
  340.       symex(Cond, R, RHS, NewCond), !
  341.          }.
  342. statement(N, Pre, Post) -->
  343.     upto(Call,  ";", ";"), break,
  344.     { doCall(N, Pre, Call, Post), !}.
  345.  
  346.  
  347. cases(N, PreCases, PostCases, V) -->
  348.     "case ", break, upto(Case, ":", ":"), break,
  349.     {
  350.          indent(N+1), writeStrings(["case: ", Case]),
  351.          append([V," == ", Case], B),
  352.          string_to_term(B, BTerm),
  353.          combine(PreCases, BTerm, PreCase), unfun(PreCase, UPreCase),
  354.      writeCond(UPreCase)
  355.      },
  356.      caseStatements(N+1, PreCase, PostCase), break,
  357.      cases(N, PreCases, PostCases, V)
  358.        ;
  359.         "default ", break, ":", break, 
  360.     { 
  361.       indent(N+1), write('default :'),
  362.       unfun(PreCases, UPreCases),
  363.          writeCond(UPreCases) 
  364.     },
  365.     statements(N+1, PreCases, PostCases), 
  366.     ("break ", break, ";" , break ; break) % last break optional
  367.        ;
  368.        break.  % default optional.
  369.  
  370. caseStatements(N, PreCase, PostCase) -->
  371.     "break ", break, ";", break
  372.        ;
  373.         "case ", break, ":", break, caseStatements(N, PreCase, PostCase)
  374.        ;
  375.         statement(N, PreCases, PostCases),
  376.     caseStatements(N,  PreCase, PostCase)
  377.        ;
  378.         break.
  379.                                           
  380. incdec(Ref, Op) -->
  381.      {memberchk(OpC, ["++", "--"])},
  382.      upto(Ref, OpC, ";"), break, ";", break,
  383.      {OpC = [Op, Op]}.
  384.          
  385. doCall(N, Pre, Call, Post) :-
  386.      indent(N), writeStrings([Call, ";"]),
  387.      chars_to_term(Call, CallTerm),
  388.          contract(PreCon1, CallTerm, PostCon1), !,
  389.      cleanPointers(PreCon1, PreCon), cleanPointers(PostCon1, PostCon),
  390.      unfun(Pre, PreProp),
  391.      simplify(PreProp implies PreCon, SimpCon), 
  392.      ( 
  393.       tautology(SimpCon)
  394.      ; 
  395.       indent(N), write( '... cannot show '), 
  396. %      pretty(SimpCon), 
  397.           write(SimpCon),
  398.       write(' for '),
  399.       write(CallTerm), write('.')
  400.      ),
  401.       CallTerm =.. [_ | Args],
  402.       processPostCon(PostCon, Args, Pre, Post).
  403.  
  404. elseClause(N, Pre, BTerm, Post) --> 
  405.     "else", break,
  406.     { indent(N), write('else '),
  407.       combine(Pre, not BTerm, EP), unfun(EP, UEP),
  408.       simplify(UEP, SUEP), writeCond(SUEP),
  409.       checkCond(N, Pre, SUEP),
  410.       !},
  411.     statement(N+1, EP, Post).
  412. elseClause(_, Pre, BTerm, Post) --> 
  413.     { combine(Pre, not BTerm, Post), !}.
  414.  
  415. ifThen(Indent, Pre, BTerm, IfP) --> 
  416.     "if", break, matchP("(", ")", B), break,
  417.         { indent(Indent), writeStrings(["if (", B, ") "]),
  418.       string_to_term(B, BTerm),
  419.           combine(Pre, BTerm,IfP), unfun(IfP, UIfP),
  420.       simplify(UIfP, SUIfP), writeCond(SUIfP),
  421.       checkCond(Indent, Pre, SUIfP),
  422.       ! }.
  423.  
  424. opAssign(Ref, Val, OpAssign) -->
  425.     { member(OpAssign, ["+=", "*=", "/=", "&=", "-=", "|="])},
  426.         upto(Ref, OpAssign, ";"),  upto(Val, ";", ";").
  427.  
  428. checkCond(Indent, Pre, C) :- unfun(Pre, UPre), 
  429.      ( simtaut(UPre implies C) ->
  430.     indent(Indent), write('// This branch is always taken.')
  431.      ;
  432.        simtaut(UPre implies not C) ->  
  433.         indent(Indent), write('// This branch is never taken.')
  434.      ;
  435.       true
  436.      ).
  437.  
  438. pretty(P) :- pretty(P, 72).
  439.  
  440. writeCond(P) :- write('//{ '), writeC(P), write(' }').
  441. % writeC(P ! []) :- pretty(P).
  442. writeC(P ! []) :- write(P).
  443. % writeC(P ! F) :- pretty(P), write(' and '), writeF(F).
  444. writeC(P ! F) :- write(P), write(' and '), writeF(F).
  445. writeC((P ! F) or Rest) :- 
  446.     write('( '), writeC(P ! F), write(' )'), write(' or '), writeC(Rest).
  447. % writeC(P) :- pretty(P).
  448. writeC(P) :- write(P).
  449.  
  450. combine(P ! F, B, S ! F) :- 
  451.     applyFun(F, B, Result), simplify(P and Result, S).
  452. combine(Rest or (P ! F), B, RestP or S) :-
  453.     combine(P ! F, B, S),
  454.     combine(Rest, B, RestP).
  455. combine(_,_,_) :- error('!! Error in combine procedure.').
  456.  
  457.  
  458. symex(P ! F, R, V, NewCond) :-
  459.           \+ member([R, _], F),
  460.          applyInitial1(R, V, ModifiedV),
  461.          applyInitial1(R, P, ModifiedP),
  462.          applyInitial(R, F, ModifiedF),
  463.          symex0(ModifiedP ! ModifiedF, R, ModifiedV, NewCond)
  464.      ; 
  465.              symex0(P ! F, R, V, NewCond).
  466.  
  467. symex(X, R, V, N) :-
  468.         symex0(X, R, V, N)
  469.     ;
  470.         error('Bug in symex.').
  471.         
  472. symex0(P ! F, R, V, NewP ! NewF) :- symex1(P ! F, R, V, NewP ! NewF).
  473. symex0(Rest or (P ! F), R, V, Result or (NewP ! NewF)) :-
  474.         symex(P ! F, R, V, NewP ! NewF), symex(Rest, R, V, Result).
  475. symex0(Branch1 or Branch2, R, V, Result1 or Result2) :-
  476.     symex(Branch1, R, V, Result1), symex(Branch2, R, V, Result2).
  477. symex1(P ! F, R, V, NewP ! NewF) :-
  478.         applyFun(F, V, NewV),
  479.         simplify(NewV, SimV),
  480.         update(F, R, SimV, NewF),
  481.         applyFun(NewF, P, NewP).
  482.  
  483. applyInitial1(V, Expr, Result) :-
  484.         path_arg(Path, Expr, V), makeOld(V, OldV),
  485.         change_path_arg(Path, Expr, Modified, OldV),
  486.         !,
  487.         applyInitial1(V, Modified, Result).
  488. applyInitial1(_, Expr, Expr).   
  489.  
  490. makeOld(V, OldV) :-
  491.         atom_codes(V, Vstr), 
  492.        (
  493.         append("old", _, Vstr), OldV = V
  494.        ;
  495.     append("old ", Vstr, OldVstr),
  496.         atom_codes(OldV, OldVstr)
  497.        ).
  498.  
  499.  
  500. applyInitial(_, [], []).
  501. applyInitial(Initial, [[Z, Expr] | Rest], [[Z, Applied] | AppliedRest]) :-
  502.         applyInitial1(Initial, Expr, Applied),
  503.         applyInitial(Initial, Rest, AppliedRest).
  504.  
  505.  
  506. % based on Quintus Prolog Library Manual, p. 40
  507. applyFun(Function, Expr, Final) :-
  508.         path_arg(Path, Expr, Lhs), 
  509.     (
  510.      Lhs = 'OLD'(A), 
  511.      ( memberchk([A, E], Function) -> Rhs = E
  512.       ;
  513.        makeOld(A, Rhs)
  514.          )
  515.     ;
  516.      atom(Lhs), memberchk([Lhs, Rhs], Function)
  517.     ),
  518.         change_path_arg(Path, Expr, Modified, Rhs),
  519.         !,
  520.         applyFun(Function, Modified, Final).
  521. applyFun( _, Expr, Expr).
  522.  
  523. update(F, R, NewV, NewF) :-
  524.     change_path_arg(_, F, [R, _], NewF, [R, NewV])
  525.     ;
  526.     append([[R, NewV]], F, NewF).
  527.  
  528. writefun([]).
  529. writefun(F) :- write('{ '), writeF(F), write(' }').
  530. writeF([[R,V] | Rest]) :-  write(R = V), writeF1(Rest).
  531. writeF1([]).
  532. writeF1([[R, V] | Rest]) :- write(' and '), write(R = V), writeF1(Rest).
  533. /*
  534. makefun(X=Y, C, [[X,Y]]) :- 
  535.     atom(X), 
  536.     (
  537.      free_of_term(X,Y), 
  538.      (var(C) -> C = true ; true)
  539.     ; 
  540.      error('Something wrong in the initial condition.')
  541.     ).
  542. makefun(Rest and X=Y, C, [[X,Y] | RestF]) :- atom(X), makefun(Rest, C, RestF).
  543. makefun(F and C, C, FList) :- makefun(F, C, FList).
  544. makefun(C, C, []) :- var(C) -> C=true ; true.
  545. makefun(_,_,_) :- error('Something wrong in the initial condition.').
  546. */
  547. % makefun(InCon, OutCon, Flist)
  548. makefun(C, C, []) :- var(C) -> C=true.
  549. makefun(X=Y, C, [[X,Y]]) :-
  550.         atom(X),
  551.         (
  552.          free_of_term(X,Y),
  553.          (var(C) -> C = true ; true)
  554.         ).
  555.  
  556. makefun(Rest and X=Y, C, [[X,Y] | RestF]) :- atom(X), makefun(Rest, C, RestF).
  557. makefun(F and C,NewC and C, FList) :- makefun(F, NewC, FList).
  558. makefun(C, C, []).
  559. makefun(_,_,_) :- error('Something wrong in the initial condition.').    
  560.  
  561. contract -->
  562.     assertion(Pre),
  563.     proc(Call),
  564.     assertion(Post),
  565.       { nl, nl,
  566.         append(["contract(", Pre, ",",  Call, ",", Post, ")"], ContractString),
  567.     mapOld(ContractString, Contract),
  568.     chars_to_term(Contract, ContractTerm),
  569.     assertz(ContractTerm)
  570.        }.
  571.  
  572. mapOld(Old, New) :-
  573.         mapOld1(Prefix, NewSubstring, Old, Rest),
  574.         mapOld(Rest, NewRest),
  575.         append([Prefix, NewSubstring, NewRest], New).
  576. mapOld(Old, Old).
  577.  
  578.  
  579. mapOld1(Prefix, New) --> 
  580.     upto(Prefix, "'","'"),
  581.     "old ", upto(Var, "'", "'"),
  582.     {append(["'OLD'(", Var, ")"], New)}.
  583.  
  584. unmapOld(Term, New) :-
  585.     path_arg(Path, Term, 'OLD'(X)),
  586.     atom_codes(X, Name),
  587.     append("old ", Name, OldName),
  588.     atom_chars(Atom, OldName),
  589.         change_path_arg(Path, Term, Modified, Atom),
  590.         !,
  591.         unmapOld(Modified, New).   
  592. unmapOld(Term, Term).
  593.  
  594. assertion(P) --> "//", break, [12], upto(P, [12], ";"), break,
  595.     {nl, writeStrings(["//{ ", P, " }"]), !}.
  596.  
  597. proc(Call) -->
  598.     "void ", upto(Call, ";", ";"), break,
  599.     {nl, writeStrings(["void ", Call, ";"]), !}.
  600.  
  601. cleanPointers(Expr, Final) :-
  602.         path_arg(Path, Expr, &X),
  603.         change_path_arg(Path, Expr, Modified, X),
  604.         !,
  605.         cleanPointers(Modified, Final).
  606. cleanPointers(Expr, Expr).                 
  607.  
  608. testContra(Prop) :-
  609.     simtaut(not(Prop)) ->
  610.       nl, write('The final state is a contradiction.'), nl
  611.        ;
  612.         true.
  613.  
  614. simtaut(T) :- simplify(T, ST), !, tautology(ST).
  615.  
  616.  
  617.  
  618.  
  619.  
  620.  
  621.  
  622.  
  623.  
  624.  
  625.  
  626.  
  627.