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


/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*
 %                                                                           %
 %      ACKNOWLEDGEMENT                                                      %
 %      ===============                                                      %
 %      This module of the checker was originally developed by Fiona         %
 %      Maclennan (Department of Electronics, University of Southampton,     %
 %      May 1984) as part of a third year project.                           %
 %                                                                           %
 *%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/


/*****************************************************************************
 * MODIFICATION HISTORY                                                      *
 * ====================                                                      *
 *                                                                           *
 * Date      CFR  Brief description of change                                *
 * --------  ---  ----------------------------------------                   *
 * 13/05/93  011  Failure to trap invalid responses in "replace"             *
 * 14/05/93  015  Allow replaying of command scripts                         *
 * 24/05/93  019  "replace all" on selected hypotheses/conclusions           *
 * 02/06/93  023  Allow wild-card patterns with replace-all                  *
 * 04/06/93  027  Substitution avoiding bound variables                      *
 * 13/08/93  041  Allow single hyps/concs in "replace ... & ..."             *
 * 17/08/93  047  Limit rule matches to 20 then ask if continue              *
 * 19/05/05 1511  Port to SICSTUS - remove singleton variables               *
 * 01/06/05 1511  Port to SICSTUS - replace non-FDL 'not' with \+            *
 * 02/06/05 1511  Replace assert with assertz                                *
 * 06/06/05 1511  Port to SICSTUS - replace non-stand fast_setof/3           *
 * 07/06/05 1511  Port to SICSTUS - print/1 replaces write/1 for variables   *
 * 08/06/05 1511  Port to SICSTUS - replace setof/3 with findall/3           *
 * 10/06/05 1511  Strengthen file_exists check to and_is_readable before see *
 * 13/07/05 1511  Move handling of quantifiers outside loop                  *
 * 05/08/05 1511  Introduction of prompt_user                                *
 *****************************************************************************/

/******** REPLACE: top-level checker command ********/
replace :-
        command_arg(expression, all),
        !,
        replace_all.
replace :-                                                      /* CFR019 */
        command_arg(expression, ARG),                           /* CFR019 */
        nonvar(ARG),                                            /* CFR019 */
        (                                                       /* CFR019 */
           ARG = (_X & _Y)                                      /* CFR019 */
        ;                                                       /* CFR019 */
           ARG = (_HC # N - M),                                 /* CFR019 */
           integer(N),                                          /* CFR019 */
           integer(M),                                          /* CFR019 */
           N < M                                                /* CFR019 */
        ),                                                      /* CFR019 */
        !,                                                      /* CFR019 */
        retractall(hyp_to_replace(_)),                          /* CFR019 */
        retractall(conc_to_replace(_)),                         /* CFR019 */
        process_replace_arg_expression(ARG),                    /* CFR019 */
        !,                                                      /* CFR019 */
        replace_all.                                            /* CFR019 */
replace :-
        (
           command_arg(expression, HC#N)
        ;
           prompt_user('REPLACE -- Which hypothesis/conclusion?', 'Type h#N or c#N as appropriate ... '),
           rread(F),
           F=HC#N
        ),
        !,
        replace(HC,N).

replace(_,_) :-
   retract(on_filename(FNAME)), file_exists_and_is_readable(FNAME),
   see(FNAME), seen, fail.

replace(HORC,N) :-
   see_correct_input_stream,                                    /* CFR015 */
   (
      HORC=h,
      HC=hyp,
      NHC=newhyp
   ;
      HORC=c,
      HC=conc,
      NHC=newconc
   ),
   retractall(trying_a_replace_all),
   retractall(replace_all_expr_type(_)),
   retractall(logfact(command, _)),
   asserta(logfact(command, replace(HORC#N))),
   retractall(rep_working_on(_,_,_)),
   asserta(rep_working_on(NHC,HC,N)),
   X=..[HC,N,E],
   retractall(con(_)),
   call(X),
   assertz(con(E)),
   !,
   check,
   retract(con(C)),
   (
      C=E,
      !,
      fail
   ;
      C\=E,
      retract(X),
      Z=..[HC,N,C],
      assertz(Z)
   ), !.


replace_all :-
   retract(on_filename(FNAME)), file_exists_and_is_readable(FNAME),
   see(FNAME), seen, fail.
replace_all :-
   see_correct_input_stream,                                    /* CFR015 */
   assertz(trying_a_replace_all),
   retractall(replace_all_expr_type(_)),
   retractall(logfact(command, _)),
   asserta(logfact(command, replace(all))),
   retractall(rep_working_on(_,_,_)),
   retractall(con(_)),
   retractall(pattern(_)),                                      /* CFR023 */
   command_arg(old, OLD),
   (                                                            /* CFR023 */
      novars(OLD),                                              /* CFR023 */
      OLD_EXP = OLD                                             /* CFR023 */
   ;                                                            /* CFR023 */
      var(OLD),                                                 /* CFR023 */
      write('Total wildcard not allowed: aborted.'),            /* CFR023 */
      nl,                                                       /* CFR023 */
      retractall(trying_a_replace_all),                         /* CFR023 */
      !,                                                        /* CFR023 */
      fail                                                      /* CFR023 */
   ;                                                            /* CFR023 */
      assertz(pattern(OLD)),                                    /* CFR023 */
      clear_facts,                                              /* CFR023 */
      get_all_subexpressions_in_vc(Tsubs),                      /* CFR023 */
      (                                                         /* CFR023 */
         Tsubs = [],                                            /* CFR023 */
         write('No matching subexpressions found: aborted.'),   /* CFR023 */
         nl,                                                    /* CFR023 */
         retractall(trying_a_replace_all),                      /* CFR023 */
         !,                                                     /* CFR023 */
         fail                                                   /* CFR023 */
      ;                                                         /* CFR023 */
         assertz(tidied_subs(Tsubs)),                           /* CFR023 */
         (                                                      /* CFR023 */
            Tsubs = [_OneElement],                              /* CFR023 */
            N = 1                                               /* CFR023 */
         ;                                                      /* CFR023 */
            print_subs([], Tsubs),                              /* CFR023 */
            determine_sub(N)                                    /* CFR023 */
         ),                                                     /* CFR023 */
         !,                                                     /* CFR023 */
         (                                                      /* CFR023 */
            N = none,                                           /* CFR023 */
            !,                                                  /* CFR023 */
            fail                                                /* CFR023 */
         ;                                                      /* CFR023 */
            gets(Tsubs, N, [OLD_EXP,_])                         /* CFR023 */
         )                                                      /* CFR023 */
      )                                                         /* CFR023 */
   ),                                                           /* CFR023 */
   checktype(OLD_EXP, TYPE),                                    /* CFR023 */
   assertz(replace_all_expr_type(TYPE)),
   !,
   assertz(con(OLD_EXP)),                                       /* CFR023 */
   retractall(command_arg(old, _)),                             /* CFR023 */
   asserta(command_arg(old, OLD_EXP)),                          /* CFR023 */
   !,
   check,
   retract(con(NEW)),
   (
      NEW=OLD_EXP,                                              /* CFR023 */
      !,
      fail
   ;
      NEW\=OLD_EXP,                                             /* CFR023 */
      !,
      do_replace_all(OLD_EXP, NEW)                              /* CFR023 */
   ),
   retractall(trying_a_replace_all),
   !.


/****************************************************************************/
/**************  RULES FOR THE REPLACEMENT OF SUBEXPRESSIONS  ***************/
/****************************************************************************/

rule(Name,X=>Y) :-
   X=..[OP|Args],
   make_up(X1,OP,Args),
   retractall(type_classification(_,_)),
   retractall(type_classification_done),
   save_type_classification_list(Args),
   asserta(type_classification_done),
   !,
   use_rulefile(X1,FNAME),
   get_term(FNAME,T),
   (
      T = (Name: (X1 may_be_replaced_by Y if Justifications))
   ;
      T = (Name: (X1 may_be_replaced_by Y)),
      Justifications = []
   ;
      (
         T = (Name: (A & B are_interchangeable if Justifications))
      ;
         T = (Name: (A & B are_interchangeable)),
         Justifications = []
      ),
      (
         X1=A,
         Y=B
      ;
         X1=B,
         Y=A
      )
   ),
   is_chosen_rulename(Name),
   \+ banned_rule(FNAME,Name),
   ok_type_classification(X,FNAME,Name),
   X1=..[OP|Args1],
   add_conds(Args=Args1,Justifications,J),
   fulfil(J,J1),
   (
      abandon_search,                                           /* CFR047 */
      !,                                                        /* CFR047 */
      fail                                                      /* CFR047 */
   ;                                                            /* CFR047 */
      true                                                      /* CFR047 */
   ),                                                           /* CFR047 */
   (\+ satisfies(Name,Y)),
   display_rep_rule(Name,X,Y,J1),
   J1=[],
   on_filename(File),
   assertz(logged_rule_match(Y,[File,Name],Justifications)).


display_rep_rule(R,X,Y,J) :-
   (
      display_subgoals_max(N)
   ;
      N = 99
   ),
   length(J, LEN),
   LEN =< N,
   (
      display_var_free_only(off)
   ;
      var_free(J)
   ),
   nl,
   print(R),
   write(' allows '),
   print(X),
   write(' to be replaced by '),
   print(Y),
   (
     (J=[],
      write(' directly'))
   ;
     (write(' provided '),
      write_justs(J))
   ),
   increment_search_count,                                      /* CFR047 */
   nl, !.
display_rep_rule(_,_,_,_) :- !.


/****************************************************************************/
/**************************  FRAMEWORK OF PROGRAM  **************************/
/****************************************************************************/
/* The following clauses comprise the framework of the program.The struct-  */
/* ure of each constituent clause can be found later in the listing         */
/****************************************************************************/

/* CHECK -- clear up then reduce expression.                                */
check:-
   nl,
   write('OLD EXPRESSION: '),
   con(E),
   print(E),
   nl,
   reduce.


/* REDUCE -- get the pattern, carry out the reduction/replacement, and
             carry on until the user wishes to give up.                     */
reduce:-
   repeat,
   specify_patt,
   reduction_procedure,
   retractall(totally_specified_replace),
   retractall(command_arg(rulename, _)),
   retractall(could_not_infer(_)),
   /* until */ reduce_again,
   !.


/* SPECIFY_PATT -- read in the pattern to be sought in the expression       */
specify_patt:-
        retractall(pattern(_)),
        (
           command_arg(old, OLD)
        ;
           prompt_user('Pattern? '),
           rread(P),
           parse_expression(P, OLD)
        ),
        assertz(pattern(OLD)), !.


/* REDUCTION_PROCEDURE -- clear up, carry out the five stages of the
                          reduction procedure, then tidy up again.          */
reduction_procedure:-
   clear_facts,
   assertz(status(go)),
   assertz(stage_num(1)),
   handle_quantifiers_in_con,                                   /* CFR027 */
   repeat,
      retract(stage_num(N)),
      stage(N),
   /* until */ (
                  N=5,                                          /* CFR027 */
                  unhandle_quantifiers_in_con                   /* CFR027 */
               ;
                 (status(stop),
                  unhandle_quantifiers_in_con,                  /* CFR027 */
                  con(E),
                  nochange(E))
               ),
   clear_facts, !.


/* CLEAR_FACTS -- clears up all temporary clauses asserted by program       */
clear_facts:-
   retractall(status(_)),
   retractall(stage_num(_)),
   retractall(tidied_subs(_)),
   retractall(required_sub(_)),
   retractall(occstoreplace(_)),
   retractall(numsubs(_)),
   retractall(newsub(_)),
   retractall(sub(_)),
   retractall(pos_newsub(_)),
   retractall(satisfies(_,_)),
   retractall(all_done(_)),
   retractall(logged_rule_match(_,_,_)),
   retractall(posslog(_,_)), !.


/* STAGE(1) -- We form the list of all subexpressions of con(E) which
               match the specified pattern.  This list is then tidied up to
               give a list in which multiple occurrences of a specific
               match are represented as a doubleton list [SUB,N], where
               SUB is the matching subexpression and N is the number of
               occurrences of the match in con(E).  This list is then
               presented to the user and if there are no matching sub-
               expressions, the status is changed to `stop'; otherwise, the
               list is asserted into the database and execution proceeds to
               stage two.                                                   */
stage(1):-
   con(E),
   find_subs(E,Subs),
   tidy_replist(Subs,Tsubs),
   print_subs(E,Tsubs),
   (
     (Tsubs=[],
      retract(status(_S)),
      assertz(status(stop)))
   ;
     (assertz(tidied_subs(Tsubs)),
      assertz(stage_num(2)))
   ), !.


/* STAGE(2) -- ask the user which subexpression is to be replaced (or, if
               there is only one subexpression, ask whether or not it is to
               be replaced).  If the user does not wish to replace any such
               subexpression, change the status to `stop', otherwise move
               on to stage three.                                           */
stage(2):-
   determine_sub(N),
   (
     (N=none,
      retract(status(_S)),
      assertz(status(stop)))
   ;
     (assertz(required_sub(N)),
      assertz(stage_num(3)))
   ), !.


/* STAGE(3) -- find out which occurrences, if any, of the matching
               subexpression are to be replaced.  If no occurrences of the
               subexpression are to be replaced, change the status to
               `stop', otherwise save the occurrence numbers to be replaced
               and move on to stage four.                                   */
stage(3):-
   retract(tidied_subs(Tsubs)),
   retract(required_sub(N)),
   gets(Tsubs,N,Term),
   ascertain(Term,Sub),
   (
     (occstoreplace([]),
      retract(status(_S)),
      assertz(status(stop)))
   ;
     (assertz(sub(Sub)),
      assertz(stage_num(4)))
   ), !.


/* STAGE(4) -- ask the user to specify the new subexpression by which the
               old match(es) is/are to be replaced.  If the answer is
               `none', the status is changed to `stop', otherwise we move
               on to stage five.                                            */
stage(4):-
   sub(Sub),
   determine_newsub(Sub),
   (
     (newsub(none),
      retract(status(_S)),
      assertz(status(stop)))
   ;
      assertz(stage_num(5))
   ), !.


/* STAGE(5) -- replace the required occurrence(s) of the matching subexp-
               ression by the replacement expression and display the new
               expression on the screen.  The user is asked if the
               replacement is acceptable.                                   */
stage(5):-
   con(E),
   retract(sub(Sub)),
   replace(E,Pos_newE,Sub),
   print_new_E(Pos_newE),
   ask_if_ok(Pos_newE,E),
   !.


/* REDUCE_AGAIN -- when the replace_more flag is set, ask the user if
                   reduction of the expression is to be
                   continued, and insists on a yes/no answer.               */
reduce_again:-
   trying_a_replace_all,
   !.
reduce_again:-
   replace_more(off).
reduce_again:-
   replace_more(on),
   read_answer('Replace more',A),
   !,
   A=no.

/****************************************************************************/
/*****************************  COMMON CLAUSES  *****************************/
/****************************************************************************/
/* The following clauses are common to other clauses in the program ie each */
/* of the following is called by more than one other clause                 */
/****************************************************************************/

/* PARSE(EXPRN,OPERATOR,COMPONENTS) -- split up expressions in right order  */
parse(X,_,Y):- var(X), var(Y), !, abort.
parse(X,_,[]):- atomic(X), !.
parse(E,'.',E):- E=..['.'|_L], !.
parse(E,F,L):- E=..[F|L], !.


/* TYPE_PATT(Pattern) -- show the user a pattern, first replacing Prolog
                         variables by capital letters, for presentability.  */
type_patt(E):- inst(E,65,_N), print(E), !.

/* INST(Exp,Oldnum,Newnum) -- instantiate Prolog variables to capital
                              letters of the alphabet, from `A' upwards     */
inst(E,N,N):- atomic(E), !.

inst(E,N,N1):-
   var(E),
   name(E,[N]),
   N1 is N+1, !.

inst(E,N,N1):-
   parse(E,_F,L),
   inst_list(L,N,N1), !.


/* INST_LIST(List,Oldnum,NewNum) -- instantiate an expression by
                                    instantiating its subexpressions.       */
inst_list([],N,N):- !.

inst_list([H|T],N,N1):-
   atomic(H),
   inst_list(T,N,N1), !.

inst_list([H|T],N,N1):-
   var(H),
   name(H,[N]),
   N0 is N+1,
   inst_list(T,N0,N1), !.

inst_list([H|T],N,N1):-
   inst(H,N,N0),
   inst_list(T,N0,N1), !.


/* READ_TERM(Term,MaxN,Numvalatoms) -- read in terms until a valid one is
                                       encountered, i.e. a number less than
                                       the maximum, or an atom such as
                                       `all' or `none'.                     */
read_term(Prompt,T,MaxN,Numvalatoms):-
   repeat,
      prompt_user(Prompt),
      rread(T),
   /* until */ check(T,MaxN,Numvalatoms), !.


/* CHECK(Term,MaxN,Numvalatoms) -- write an error message if the term is
                                   not valid.                               */
check(T,MaxN,Numvalatoms):-
   (
      invalidatom(T,Numvalatoms)
   ;
      invalidnum(T,MaxN)
   ;
      var(T)
   ),
   !,
   write('Invalid term.  Try again'),
   nl,
   fail.
check(T, _MaxN, _Numvalatoms) :-                                        /* CFR011 */
        \+ atom(T),                                             /* CFR011 */
        \+ integer(T),                                          /* CFR011 */
        !,                                                      /* CFR011 */
        write('Invalid term.  Try again'),                      /* CFR011 */
        nl,                                                     /* CFR011 */
        fail.                                                   /* CFR011 */
check(_T,_MaxN,_):- !.


/* INVALIDATOM(Term,Num) -- allow `none' if one atom is allowed (Num=1), and
                            `all' or `none' if two are allowed (Num=2).     */
invalidatom(T,1):- atom(T), T\=none, !.                         /* CFR011 */
invalidatom(T,2):- atom(T), T\=none, T\=all, !.                 /* CFR011 */


/* INVALIDNUM(Term,Max) -- allow Term if it is at most Max and at least 0.  */
invalidnum(T,MaxN):- integer(T), (T>MaxN ; T=<0), !.            /* CFR011 */


/* GETS(List,N,Term) -- set Term to the Nth. element of list List.          */
gets([Term|_T],1,Term):- !.

gets([_H|T],N,Term):-
   N1 is N-1,
   gets(T,N1,Term), !.


/* NOCHANGE(Exprn) -- displays message if no change is made to the main
                      expression.                                           */
nochange(_E) :- trying_a_replace_all, !.
nochange(E):-
   write('EXPRESSION REMAINS: '),
   print(E),
   nl, !.


/****************************************************************************/
/****************************  FIND_SUBS CLAUSE  ****************************/
/****************************************************************************/
/*       The following clauses all constitute the 'find_subs' clause        */
/****************************************************************************/

/* FIND_SUBS(Exp,List) -- find matching subexpressions and put them in List */
find_subs(E,Subs):-
   parse(E,_,L),
   obtain(L,Ss),
   determine(Subs,E,Ss), !.


/* OBTAIN(Exp_list,Sub_list) -- get all the matching subexpressions from
                                the list of subexpressions Exp_list and put
                                them in Sub_list.                           */
obtain([],[]):- !.

obtain([H|T],Ss):-
   obtain(T,St),
   find_subs(H,Sh),
   append(Sh,St,Ss), !.


/* DETERMINE(Sub_list,Exprn,New_list) -- updates the list of subexpressions
                                         according to whether or not Exprn
                                         matches the pattern.               */
determine([P|S],P,S):- pattern(P), !.
determine(Subs,_E,Subs):- !.


/****************************************************************************/
/******************************  TIDY CLAUSE  *******************************/
/****************************************************************************/
/*          The following clauses all constitute the 'tidy' clause          */
/****************************************************************************/

/* TIDY_REPLIST(Oldlist,Newlist) -- clear up multiple occurrences of the same
                                    subexpression in the list of matching
                                    subexpressions, replacing them by
                                    doubleton lists.                        */
tidy_replist([],[]):- !.

tidy_replist([H|T],[[H,N]|Ts]):-
   find_del(H,T,T1,N),
   tidy_replist(T1,Ts), !.


/* FIND_DEL(Exp,Oldlist,Newlist,N) -- delete N-1 occurrences of expression
                                      Exp from Oldlist to give Newlist.     */
find_del(_H,[],[],1):- !.

find_del(H,[H|T],T1,N):-
   find_del(H,T,T1,N1),
   N is N1+1, !.

find_del(H,[A|T],[A|T1],N):-
   find_del(H,T,T1,N), !.


/****************************************************************************/
/***************************  PRINT_SUBS CLAUSE  ****************************/
/****************************************************************************/
/*       The following clauses all constitute the 'print_subs' clause       */
/****************************************************************************/

/* PRINT_SUBS(Exp,Sublist) -- display the subexpressions on the screen.     */
print_subs(_Exp,[]):-
   write('There are NO subexpressions of the form '),
   pattern(Pattern),
   type_patt(Pattern),
   retractall(command_arg(_,_)),
   nl,
   nl, !.

print_subs(_Exp,[Term]):-
   (
      Term=[Sub,_N]
   ;
      Term=Sub
   ),
   assertz(numsubs(1)),
   write('Subexpression is '),
   print(Sub),
   nl, !.

print_subs(_Exp,Tsubs):-
   write('Possible subexpressions:-'),
   nl,
   !,
   list_subs(Tsubs,1), !.


/* LIST_SUBS(Sublist,Num) -- display subexpressions on screen, numbering
                             them with the counter Num.                     */
list_subs([],N):-
   Numsubs is N-1,
   assertz(numsubs(Numsubs)), !.

list_subs([H|Rsubs],N):-
   tab(5),
   print(N),
   write('.  '),
   type_sub(H),
   M is N+1,
   list_subs(Rsubs,M), !.


/* TYPE_SUB(Subexpr) -- type Subexpr (either [S,N] or S) out on the screen. */
type_sub([Sub,_N]):- print(Sub), nl, !.
type_sub(Sub):- print(Sub), nl, !.


/****************************************************************************/
/**************************  DETERMINE_SUB CLAUSE  **************************/
/****************************************************************************/

/* DETERMINE_SUB(Term) -- find out which subexpression is to be altered.    */
determine_sub(T):-
        numsubs(1),
        (
           retract(command_arg(old, _)),
           (
              command_arg(new, _),
              command_arg(rule, exists),
              asserta(totally_specified_replace)
           ;
              true
           ),
           T=1
        ;
           read_answer('Change this subexpression',Answer),
           !,
           (
             (Answer=yes, T=1)
           ;
             (Answer=no, T=none)
           )
        ),  !.

determine_sub(T):-
   retractall(command_arg(old, _)),
   retract(numsubs(Nsubs)),
   read_term('Change which subexpression (number/none)? ',T,Nsubs,1), !.


/****************************************************************************/
/****************************  ASCERTAIN CLAUSE  ****************************/
/****************************************************************************/
/*       The following two clauses constitute the 'ascertain' clause        */
/****************************************************************************/

/* ASCERTAIN(Term,Sub) -- find out which occurrence of the particular
                          subexpression chosen is to be replaced.           */
ascertain(Term,Sub):-
   Term=[Sub,1],
   assertz(occstoreplace([1])), !.

ascertain(Term,Sub):-
   Term=[Sub,Num],
   specify(N,Sub,Num),
   occs_list(L,N,Num),
   assertz(occstoreplace(L)), !.


/* SPECIFY(OccN,Sub,NumofOccs) -- get the occurrence number, OccN, of Sub
                                  to be replaced.  OccN must be between 1
                                  and NumofOccs inclusive.                  */
specify(N,_Sub,Num):-
   read_term('Change which occurrence (number/none/all)? ',N,Num,2), !.


/* OCCS_LIST(OccsList,Occ,NumofOccs) -- set OccsList to [] if Occ=`none',
                                        to [N] if Occ=N, or to the list of
                                        integers 1..NumofOccs if Occ=`all'. */
occs_list([],none,_):- !.
occs_list(L,all,Num):- make_occs_list(1,L,Num), !.
occs_list([N],N,_):- !.


/* MAKE_OCCS_LIST(A,List,B) -- Make List into the list of integers A..B.    */
make_occs_list(N,[],Num):- N is Num+1, !.

make_occs_list(N,[N|T],Num):-
   N1 is N+1,
   make_occs_list(N1,T,Num), !.


/****************************************************************************/
/************************  DETERMINE_NEWSUB CLAUSE  *************************/
/****************************************************************************/
/*    The following clauses all constitute the 'determine_newsub' clause    */
/****************************************************************************/

/* DETERMINE_NEWSUB(Sub) -- get the new subexpression pattern by which the
                            old match is to be replaced and the rule which
                            justifies this.  Finally, determine a unique
                            value for Sub, referring to the user if this
                            proves to be necessary.                         */
determine_newsub(Sub):-
        (
           retract(command_arg(new, Nsub))
        ;
           prompt_user('Type new subexpression pattern: '),
           rread(NS),
           parse_expression(NS, Nsub)
        ),
        assertz(pos_newsub(Nsub)),
        !,
        (
           retract(command_arg(rule, exists)),
           !
        ;
           repeat,
              retractall(command_arg(rulename,_)),
              prompt_user('By which rule? '),
              rread(Rname),
              parse_rulename(Rname)
        ),
        !,
        try_rule(Sub=>Nsub,N1),
        solution(Sub,Nsub,N1), !.


/* TRY_RULE(Sub=>Nsub,N1) -- find rules which may be applied to replace Sub
                             by Nsub and return N1, the number of different
                             such rule-applications                         */
try_rule(Sub=>Nsub,N1):-
   pos_newsub(Nsub),
   retractall(num_matches(_)),
   asserta(num_matches(0)),
   retractall(abandon_search),                                  /* CFR047 */
   retractall(search_count(_)),                                 /* CFR047 */
   search_rules(_Rulename,Sub=>Nsub),
   num_matches(N1), !.


/* SEARCH_RULES(NAME,SUB=>NSUB) -- linear search of rulebase                */
search_rules(Rulename,Sub=>Nsub) :-
   rule(Rulename,Sub=>Nsub),
   assertz(satisfies(Rulename,Nsub)),
   update_match_count,
   fail.
search_rules(_,_).


/* UPDATE_MATCH_COUNT -- increment number of matches found                  */
update_match_count :-
   retract(num_matches(N)),
   M is N+1,
   asserta(num_matches(M)),
   !.


/* SOLUTION(Sub,Nsub,Num) -- display the solution(s) (Num in number)
                             on the screen for inspection/choice            */
solution(_Sub,_Nsub,0):-
   !,
   write('There is no such rule which allows this replacement'),
   nl,
   assertz(newsub(none)), !.

solution(Sub,_Nsub,_N):-
        make_list(0,Numsubs,Nsublist),
        (
           Numsubs=1,
           (
              totally_specified_replace
           ;
              write('The only possible replacement for '),
              print(Sub),
              write(' is:')
           )
        ;
           Numsubs>1,
           write('Possible replacements for '),
           print(Sub),
           write(' are:')
        ),
        nl,
        display_list(Numsubs,Nsublist), !.


/* MAKE_LIST(N,N1,Nsublist) -- create Nsublist, a list of sublists, each
                               sublist of the form [Nsub|R], where Nsub is
                               a possible new subexpression and R is a list
                               of rulenames which can generate this new
                               subexpression from the old subexpression.    */
make_list(N,N1,Nsublist):-
   retract(satisfies(Rname,Nsub)),
   rulelist(R,Nsub),
   append([Nsub,Rname],R,L),
   N0 is N+1,
   make_list(N0,N1,T),
   Nsublist=[L|T], !.

make_list(N,N,[]):- !.


/* RULELIST(Rulelist,Nsub) -- generate a list of rules which generate Nsub
                              as the new subexpression.                     */
rulelist([Rname|Tr],Nsub):-
   retract(satisfies(Rname,Nsub)),
   rulelist(Tr,Nsub),
   !.

rulelist([],_):- !.


/* DISPLAY_LIST(N,Nsublist) -- display the possible replacement subexp-
                               ressions together with the rules which
                               justifies each and, if necessary, ask which
                               replacement to use.                          */
display_list(1,[[Nsub|[Rname|R]]]):-
        (
           totally_specified_replace,
           A=yes
        ;
           tab(5),
           print(Nsub),
           nl,
           tab(11),
           write('according to rule '),
           print(Rname),
           nl,
           list_rules(R),
           read_answer('Proceed',A)
        ),
        !,
        find_if_ok(A,Nsub,[Rname|R]), !.

display_list(N,Nsublist):-
   print_Nsubs(1,Nsublist),
   read_term('Select (number/none): ',T,N,1),
   find_newsub(T,Nsublist,Newsub),
   assertz(newsub(Newsub)), !.


/* PRINT_NSUBS(N,Nsublist) -- display the possible replacements.            */
print_Nsubs(_,[]):- !.

print_Nsubs(N,[[Nsub|[Rname|R]]|T]):-
   tab(5),
   print(N),
   write('.  '),
   print(Nsub),
   nl,
   tab(11),
   write('according to rule '),
   print(Rname),
   nl,
   list_rules(R),
   N1 is N+1,
   print_Nsubs(N1,T), !.


/* LIST_RULES(Rulelist) -- list the rulenames on the screen.                */
list_rules([]):- !.

list_rules([H|T]):-
   tab(11),
   write('and rule '),
   print(H),
   nl,
   list_rules(T), !.


/* FIND_IF_OK(Yesno,Nsub,Rules) -- update the action history by asserting
                                   the new subexpression and Rule(s) used
                                   into the database.                       */
find_if_ok(yes,Nsub,[Rule|R]):-
   sub(Sub),
   assertz(newsub(Nsub)),
   assertz(rule_applied([Rule|R])),
   retract(logged_rule_match(Nsub,[File,Rule],Goals)),
   retractall(logged_rule_match(_,_,_)),
   asserta(posslog(rulematch, ([File,Rule]: (Sub may_be_replaced_by Nsub if Goals)))),
   !.

find_if_ok(no,_,_):- assertz(newsub(none)), !.


/* FIND_NEWSUB(Occ,Nsublist,Nsub) -- find the Occ'th element of Nsublist
                                     and set Nsub to this, unless Occ is
                                     `none', in which case Nsub is `none'.  */
find_newsub(none,_Nsublist,none):- !.

find_newsub(N,Nsublist,Newsub):-
   sub(Sub),
   gets(Nsublist,N,[Newsub|[Rule|R]]),
   assertz(rule_applied([Rule|R])),
   retract(logged_rule_match(Newsub,[File,Rule],Goals)),
   retractall(logged_rule_match(_,_,_)),
   asserta(posslog(rulematch, ([File,Rule]:(Sub may_be_replaced_by Newsub if Goals)))),
   !.


/****************************************************************************/
/*****************************  REPLACE CLAUSE  *****************************/
/****************************************************************************/
/*        The following clauses all constitute the 'replace' clause         */
/****************************************************************************/

/* REPLACE(Exp,NewE,Sub) -- replace all required occurrences of Sub within
                            expression Exp to get NewE.                     */
replace(E,NewE,Sub):-
   assertz(all_done(no)),
   change(E,NewE,Sub,1,_N), !.


/* CHANGE(Exp,NewE,Sub,N0,N1) -- change Exp to NewE by changing Sub if it
                                 is one of the occurrences to be replaced
                                 according to the occstoreplace list.  N0
                                 and N1 are counters.                       */
change(E,Newsub,E,N,N):-
   occstoreplace([N]),
   !,
   retract(all_done(no)),
   assertz(all_done(yes)),
   retract(newsub(Newsub)), !.

change(E,Newsub,E,N,N1):-
   occstoreplace([N|T]),
   !,
   retract(occstoreplace([N|T])),
   assertz(occstoreplace(T)),
   newsub(Newsub),
   N1 is N+1, !.

change(E,E,E,N,N1):- N1 is N+1, !.

change(E,E,_Sub,N,N):- atomic(E), !.

change(E,NewE,Sub,N,N1):-
   parse(E,F,L),
   changelist(L,NewL,Sub,N,N1),
   parse(NewE,F,NewL), !.


/* CHANGELIST(OldL,NewL,Sub,N0,N1) -- change OldL to NewL by changing Sub
                                      to the new subexpression where
                                      necessary in OldL.                    */
changelist([],[],_,N,N):- !.

changelist([H|T],NewL,Sub,N,N1):-
   change(H,NewH,Sub,N,N0),
   (
     (all_done(yes),
      NewL=[NewH|T])
   ;
     (changelist(T,T1,Sub,N0,N1),
      NewL=[NewH|T1])
   ), !.


/****************************************************************************/
/***************************  PRINT_NEW_E CLAUSE  ***************************/
/****************************************************************************/

/* PRINT_NEW_E(NewE) -- displays new expression on the screen.              */
print_new_E(NewE):-
   write('NEW EXPRESSION: '),
   print(NewE),
   nl, !.


/****************************************************************************/
/****************************  ASK_IF_OK CLAUSE  ****************************/
/****************************************************************************/
/*       The following two clauses constitute the 'ask_if_ok' clause        */
/****************************************************************************/

/* ASK_IF_OK(Pos_newE,E) -- ask if the new expression is acceptable and,
                            according to the reply, update the expression
                            in the database accordingly.                    */
ask_if_ok(Pos_newE,E):-
   read_answer('Is this OK',Answer),
   !,
   is_it_ok(Answer,Pos_newE,E), !.


/* IS_IT_OK(Yesno,NewE,OldE) -- update the expression in the database.      */
is_it_ok(no,_,E):- nochange(E), !.

is_it_ok(yes,NewE,_):-
   (
      typechecking(on),
      (
         trying_a_replace_all,
         replace_all_expr_type(TYPE),
         checktype(NewE, TYPE)
      ;
         \+ trying_a_replace_all,
         checktype(NewE, boolean)
      ;
         write('!!! ERROR: New expression does not typecheck properly.'),
         nl,
         fail
      )
   ;
      typechecking(off)
   ),
   retract(con(_E)),
   assertz(con(NewE)),
   unhandle_quantifiers_in_con,                                 /* CFR027 */
   retract(posslog(X, Y)),
   assertz(logfact(X, Y)),
   (
      trying_a_replace_all
   ;
      rep_working_on(NHC, HC, N),
      con(UnhandledNewE),                                       /* CFR027 */
      Z=..[HC, N, UnhandledNewE],                               /* CFR027 */
      assertz(logfact(NHC, Z))
   ), !.
is_it_ok(_,_,_) :- !.


/* process_replace_arg_expression - store which hyps and conc to change */
process_replace_arg_expression(ARG) :-                          /* CFR019 */
        var(ARG),
        !,
        write('!!! Error in argument syntax: illegal Prolog variable found.'),
        nl,
        fail.
process_replace_arg_expression(X & Y) :-
        process_replace_arg_expression(X),
        !,
        process_replace_arg_expression(Y).
process_replace_arg_expression(h # N - N) :-
        assertz(hyp_to_replace(N)),
        !.
process_replace_arg_expression(c # N - N) :-
        assertz(conc_to_replace(N)),
        !.
process_replace_arg_expression(h # N - M) :-
        integer(N),
        integer(M),
        N < M,
        assertz(hyp_to_replace(N)),
        N1 is N + 1,
        !,
        process_replace_arg_expression(h # N1 - M),
        !.
process_replace_arg_expression(c # N - M) :-
        integer(N),
        integer(M),
        N < M,
        assertz(conc_to_replace(N)),
        N1 is N + 1,
        !,
        process_replace_arg_expression(c # N1 - M),
        !.
process_replace_arg_expression(h # N) :-                        /* CFR041 */
        integer(N),                                             /* CFR041 */
        assertz(hyp_to_replace(N)),                             /* CFR041 */
        !.                                                      /* CFR041 */
process_replace_arg_expression(c # N) :-                        /* CFR041 */
        integer(N),                                             /* CFR041 */
        assertz(conc_to_replace(N)),                            /* CFR041 */
        !.                                                      /* CFR041 */


/* get_all_subexpressions_in_vc(Tsubs) - from all current hyps & concs */
get_all_subexpressions_in_vc(Tsubs) :-                          /* CFR023 */
        (
           findall(Subs1, (hyp(N, H), find_subs(H, Subs1)), A),
           A \== [],
           sort(A, SubsList1)
        ;
           SubsList1 = []
        ),
        !,
        (
           findall(Subs2, (conc(N, C), find_subs(C, Subs2)), B),
           B \== [],
           sort(B, SubsList2)
        ;
           SubsList2 = []
        ),
        !,
        append(SubsList2, SubsList1, SubsList),
        !,
        general_list_append(SubsList, RawSubs),
        !,
        tidy_replist(RawSubs, Tsubs),
        !.


/* general_list_append(ListOfLists, SingleList) - append list of lists */
general_list_append([List], List) :- !.                         /* CFR023 */
general_list_append([Head|Tail], List) :-
        general_list_append(Tail, TailList),
        !,
        append(Head, TailList, List),
        !.
general_list_append([], []) :- !.


/* handle_quantifiers_in_con - rename to prevent illegal replacement */
handle_quantifiers_in_con :-                                    /* CFR027 */
        con(X),                                                 /* CFR027 */
        handle_quantifiers_in(X, Y),                            /* CFR027 */
        !,                                                      /* CFR027 */
        (                                                       /* CFR027 */
           X = Y                                                /* CFR027 */
        ;                                                       /* CFR027 */
           retract(con(X)),                                     /* CFR027 */
           assertz(con(Y))                                      /* CFR027 */
        ),                                                      /* CFR027 */
        !.                                                      /* CFR027 */


/* unhandle_quantifiers_in_con - rename quantifiers back to original names */
unhandle_quantifiers_in_con :-                                  /* CFR027 */
        \+ qbindingname(_, _),                                  /* CFR027 */
        !.                                                      /* CFR027 */
unhandle_quantifiers_in_con :-                                  /* CFR027 */
        con(X),                                                 /* CFR027 */
        unhandle_quantifiers_in(X, Y),                          /* CFR027 */
        !,                                                      /* CFR027 */
        (                                                       /* CFR027 */
           X = Y                                                /* CFR027 */
        ;                                                       /* CFR027 */
           retract(con(X)),                                     /* CFR027 */
           assertz(con(Y))                                      /* CFR027 */
        ),                                                      /* CFR027 */
        !.                                                      /* CFR027 */


/* handle_quantifiers_in(X,Y) - rename bound variables to prevent capture */
handle_quantifiers_in(X, Y) :-                                  /* CFR027 */
        retractall(qbindingname(_, _)),                         /* CFR027 */
        !,                                                      /* CFR027 */
        do_handle_quantifiers_in(X, Y, 1, _),                   /* CFR027 */
        !.                                                      /* CFR027 */


/* do_handle_quantifiers_in(X, Y, N, N') - handle, counting from N upwards */
do_handle_quantifiers_in(for_all(X:T, P), for_all(DollarX:T, Q), N, M) :-
        atom(X),                                                /* CFR027 */
        name(N, NL),                                            /* CFR027 */
        name(DollarX, [36|NL]),         /* chr(36) = '$' */     /* CFR027 */
        !,                                                      /* CFR027 */
        assertz(qbindingname(X, DollarX)),                      /* CFR027 */
        safe_subst_vbl(X, DollarX, P, PP),                      /* CFR027 */
        !,                                                      /* CFR027 */
        Nplus1 is N + 1,                                        /* CFR027 */
        do_handle_quantifiers_in(PP, Q, Nplus1, M),             /* CFR027 */
        !.                                                      /* CFR027 */
do_handle_quantifiers_in(for_some(X:T, P), for_some(DollarX:T, Q), N, M) :-
        atom(X),                                                /* CFR027 */
        name(N, NL),                                            /* CFR027 */
        name(DollarX, [36|NL]),         /* chr(36) = '$' */     /* CFR027 */
        !,                                                      /* CFR027 */
        assertz(qbindingname(X, DollarX)),                      /* CFR027 */
        safe_subst_vbl(X, DollarX, P, PP),                      /* CFR027 */
        !,                                                      /* CFR027 */
        Nplus1 is N + 1,                                        /* CFR027 */
        do_handle_quantifiers_in(PP, Q, Nplus1, M),             /* CFR027 */
        !.                                                      /* CFR027 */
do_handle_quantifiers_in(X, X, N, N) :-                         /* CFR027 */
        atomic(X),                                              /* CFR027 */
        !.                                                      /* CFR027 */
do_handle_quantifiers_in([H|T], RESULT, N, M) :-                /* CFR027 */
        do_handle_quantifiers_in_list([H|T], RESULT, N, M),     /* CFR027 */
        !.                                                      /* CFR027 */
do_handle_quantifiers_in(OLD, NEW, N, M) :-                     /* CFR027 */
        \+ atomic(OLD),                                 /* CFR027 */
        nonvar(OLD),                                            /* CFR027 */
        OLD =.. [F|OldArgs],                                    /* CFR027 */
        do_handle_quantifiers_in_list(OldArgs, NewArgs, N, M),  /* CFR027 */
        !,                                                      /* CFR027 */
        NEW =.. [F|NewArgs].                                    /* CFR027 */


do_handle_quantifiers_in_list([H|T], [NewH|NewT], N, M) :-      /* CFR027 */
        do_handle_quantifiers_in(H, NewH, N, K),                /* CFR027 */
        !,                                                      /* CFR027 */
        do_handle_quantifiers_in_list(T, NewT, K, M).           /* CFR027 */
do_handle_quantifiers_in_list([], [], N, N) :- !.               /* CFR027 */


/* SAFE_SUBST_VBL(V,X,OLD,NEW) - substitute all V in OLD by X to get NEW */
safe_subst_vbl(V,X,V,X) :- !.                                   /* CFR027 */
safe_subst_vbl(_V,_X,Y,Y) :-                                    /* CFR027 */
    atomic(Y),                                                  /* CFR027 */
    !.                                                          /* CFR027 */
safe_subst_vbl(V,_X,for_all(V:T,P),for_all(V:T,P)) :- !.                /* CFR027 */
safe_subst_vbl(V,_X,for_some(V:T,P),for_some(V:T,P)) :- !.      /* CFR027 */
safe_subst_vbl(V,X,F,F1) :-                                     /* CFR027 */
    F=..[OP|Args],                                              /* CFR027 */
    safe_subst_vbl_list(V,X,Args,Args1),                        /* CFR027 */
    F1=..[OP|Args1],                                            /* CFR027 */
    !.                                                          /* CFR027 */


/* SAFE_SUBST_VBL_LIST(V,X,OL,NL) - substitute all V in OL by X to get NL */
safe_subst_vbl_list(V,X,[A],[A1]) :-                            /* CFR027 */
        safe_subst_vbl(V,X,A,A1),                               /* CFR027 */
        !.                                                      /* CFR027 */
safe_subst_vbl_list(V,X,[A|Args],[A1|Args1]) :-                 /* CFR027 */
    safe_subst_vbl(V,X,A,A1),                                   /* CFR027 */
    !,                                                          /* CFR027 */
    safe_subst_vbl_list(V,X,Args,Args1),                        /* CFR027 */
    !.                                                          /* CFR027 */


/* unhandle_quantifiers_in(X,Y) - replace $Var's by original atoms */
unhandle_quantifiers_in(X, X) :-                                /* CFR027 */
        \+ qbindingname(_, _),                                  /* CFR027 */
        !.                                                      /* CFR027 */
unhandle_quantifiers_in(X, Y) :-                                /* CFR027 */
        fetch_vars_in(X, VL),                                   /* CFR027 */
        adjust_qbindingnames(VL),                               /* CFR027 */
        !,                                                      /* CFR027 */
        do_unhandle_quantifiers_in(X, Y),                       /* CFR027 */
        !.                                                      /* CFR027 */


/* do_unhandle_quantifiers_in(X,Y) - use updated qbindingname to revert */
do_unhandle_quantifiers_in(DollarX, X) :-                       /* CFR027 */
        atom(DollarX),                                          /* CFR027 */
        qbindingname(X, DollarX),                               /* CFR027 */
        !.                                                      /* CFR027 */
do_unhandle_quantifiers_in(X, X) :-                             /* CFR027 */
        atomic(X),                                              /* CFR027 */
        !.                                                      /* CFR027 */
do_unhandle_quantifiers_in(OLD, NEW) :-                         /* CFR027 */
        \+ atomic(OLD),                                 /* CFR027 */
        nonvar(OLD),                                            /* CFR027 */
        OLD =.. [F|OldArgs],                                    /* CFR027 */
        do_unhandle_quantifiers_in_list(OldArgs, NewArgs),      /* CFR027 */
        !,                                                      /* CFR027 */
        NEW =.. [F|NewArgs].                                    /* CFR027 */


/* do_unhandle_quantifiers_in_list(X,Y) - do for each element of list */
do_unhandle_quantifiers_in_list([H|T], [NewH|NewT]) :-          /* CFR027 */
        do_unhandle_quantifiers_in(H, NewH),                    /* CFR027 */
        !,                                                      /* CFR027 */
        do_unhandle_quantifiers_in_list(T, NewT).               /* CFR027 */
do_unhandle_quantifiers_in_list([], []) :- !.                   /* CFR027 */


/* fetch_vars_in(EXPR, LIST_OF_VARS) - return list of identifiers in EXP */
fetch_vars_in(X, L) :-                                          /* CFR027 */
        do_fetch_vars_in(X, T),                                 /* CFR027 */
        !,                                                      /* CFR027 */
        sort(T, L).                                             /* CFR027 */


/* do_fetch_vars_in(EXPR, LIST_OF_VARS) - list with duplicates etc. */
do_fetch_vars_in(X, [X]) :-                                     /* CFR027 */
        atom(X),                                                /* CFR027 */
        !.                                                      /* CFR027 */
do_fetch_vars_in(X, []) :-                                      /* CFR027 */
        atomic(X),                                              /* CFR027 */
        !.                                                      /* CFR027 */
do_fetch_vars_in(X, L) :-                                       /* CFR027 */
        nonvar(X),                                              /* CFR027 */
        X =.. [_|Xs],                                           /* CFR027 */
        !,                                                      /* CFR027 */
        do_fetch_vars_in_list(Xs, L),                           /* CFR027 */
        !.                                                      /* CFR027 */


/* do_fetch_vars_in_list(EXP_LIST, LIST_OF_VARS) - return list of identifiers */
do_fetch_vars_in_list([H|T], L) :-                              /* CFR027 */
        do_fetch_vars_in(H, Hs),                                /* CFR027 */
        !,                                                      /* CFR027 */
        do_fetch_vars_in_list(T, Ts),                           /* CFR027 */
        append(Hs, Ts, L),                                      /* CFR027 */
        !.                                                      /* CFR027 */
do_fetch_vars_in_list([], []) :- !.                             /* CFR027 */


/* adjust_qbindingnames(VL) - rename any which appear in list VL */
adjust_qbindingnames([H|T]) :-                                  /* CFR027 */
        \+ qbindingname(H, _),                                  /* CFR027 */
        !,                                                      /* CFR027 */
        adjust_qbindingnames(T).                                /* CFR027 */
adjust_qbindingnames([H|T]) :-                                  /* CFR027 */
        rename_qbinding_name(H),                                /* CFR027 */
        !,                                                      /* CFR027 */
        adjust_qbindingnames(T).                                /* CFR027 */
adjust_qbindingnames([]) :- !.                                  /* CFR027 */


/* rename_qbinding_name(ATOM) - generate a "fresh" atom based on old */
rename_qbinding_name(X) :-                                      /* CFR027 */
        generate_new_qbinding_name(X, NEWX),                    /* CFR027 */
        retract(qbindingname(X, N)),                            /* CFR027 */
        assertz(qbindingname(NEWX, N)),                         /* CFR027 */
        fail.                                                   /* CFR027 */
rename_qbinding_name(_) :- !.                                   /* CFR027 */


/* generate_new_qbinding_name(OLD, NEW) - try sticking a number on the end */
generate_new_qbinding_name(OLD, NEW) :-                         /* CFR027 */
        name(OLD, LIST),                                        /* CFR027 */
        do_generate_new_qbinding_name(LIST, 0, NEW),            /* CFR027 */
        !.                                                      /* CFR027 */


/* do_generate_new_qbinding_name(LIST, NUM, NEW_ATOM) - generate it */
do_generate_new_qbinding_name(LIST, NUM, NEW_ATOM) :-           /* CFR027 */
        name(NUM, NUMLIST),                                     /* CFR027 */
        append(LIST, NUMLIST, NEW_LIST),                        /* CFR027 */
        name(CANDIDATE_ATOM, NEW_LIST),                         /* CFR027 */
        !,                                                      /* CFR027 */
        (                                                       /* CFR027 */
           used_ident(CANDIDATE_ATOM, _),                       /* CFR027 */
           NEW_NUM is NUM + 1,                                  /* CFR027 */
           !,                                                   /* CFR027 */
           do_generate_new_qbinding_name(LIST,NEW_NUM,NEW_ATOM) /* CFR027 */
        ;                                                       /* CFR027 */
           NEW_ATOM = CANDIDATE_ATOM                            /* CFR027 */
        ),                                                      /* CFR027 */
        !.                                                      /* CFR027 */
%###############################################################################
%END-OF-FILE
