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

start :-
        restore_temp_del_hyps,
        repeat,
           see_correct_input_stream,                            /* CFR015 */
           nl,
           write_check_prompt,                                  /* CFR015 */
           retractall(command_arg(_,_)),
           read_user_command(COMMAND,ARGUMENTS),
           check_command_arguments(COMMAND,ARGUMENTS),
           execute_command(COMMAND),
           (                                                    /* CFR005 */
              COMMAND \= exit,                                  /* CFR005 */
              COMMAND \= forceexit,
              write_log,                                        /* CFR005 */
              maybe_do_auto_newvc                               /* CFR025 */
           ;                                                    /* CFR005 */
              COMMAND = exit                                    /* CFR005 */
           ;                                                    /* CFR005 */
              COMMAND = forceexit
           ),                                                   /* CFR005 */
        /* UNTIL */ verified_exit_command(COMMAND),             /* CFR005 */
        retract(step_number(N)),                                /* CFR005 */
        M is N+1,                                               /* CFR005 */
        asserta(step_number(M)),                                /* CFR005 */
        write_log,                                              /* CFR005 */
        set_exit_status,
        close_all_streams,
        halt.

/* Check performed in getdcldat to ensure FILE exists and is readable */
see_correct_input_stream :-                                     /* CFR015 */
        perform_script_file(FILE),                              /* CFR015 */
        see(FILE),                                              /* CFR015 */
        !.                                                      /* CFR015 */
see_correct_input_stream :-                                     /* CFR015 */
        see(user),                                              /* CFR015 */
        !.                                                      /* CFR015 */


write_check_prompt :-                                           /* CFR015 */
        seeing(user),                                           /* CFR015 */
        prompt_user('CHECK|:'),                                 /* CFR015 */
        !.                                                      /* CFR015 */
write_check_prompt :-                                           /* CFR015 */
        write('[EXECUTE]: '),                                   /* CFR015 */
        !.                                                      /* CFR015 */


maybe_do_auto_newvc :-                                          /* CFR025 */
        retract(time_for_new_vc),                               /* CFR025 */
        auto_newvc(on),                                         /* CFR025 */
        \+ vcs_to_prove([]),                                    /* CFR025 */
        nl,                                                     /* CFR025 */
        write('AUTO-NEWVC:'),                                   /* CFR025 */
        execute_command(newvc),                                 /* CFR025 */
        write_log,                                              /* CFR025 */
        !.                                                      /* CFR025 */


check_command_arguments(COMMAND,ARGUMENTS) :-
        (
           parse_command_arguments(COMMAND,ARGUMENTS),
           !
        ;
           show_permitted_arguments(COMMAND)
        ), !.


read_user_command(COMMAND,ARGUMENTS) :-
        fetch_keyword(KEYWORD,NEXTCHAR),
        (
           match_command(KEYWORD,COMMAND),
           !,
           (
              NEXTCHAR=46,
              ARGUMENTS=[]
           ;
              rread(ARGUMENTS)
           )
        ;
           warn_of_unknown_command,
           !,
           (
              NEXTCHAR=46
           ;
              eol_char(EOL),
              lskip(EOL)                                        /* CFR015 */
           ),
           !,
           fail
        ), !.

fetch_keyword(KEYWORD,NEXTCHAR) :-
        fetch_chars(KEYWORD,[],NEXTCHAR),
        !.

fetch_chars(KEYWORD,SO_FAR,NEXTCHAR) :-
        eol_char(EOL),
        lget0(CHAR),                                            /* CFR015 */
        (
           CHAR=46,
           !,
           KEYWORD=SO_FAR,
           NEXTCHAR=46,
           lskip(EOL)                                           /* CFR015 */
        ;
           (
              CHAR=9
           ;
              CHAR=EOL
           ;
              CHAR=32
           ),
           !,
           (
              SO_FAR=[],
              !,
              fetch_chars(KEYWORD,SO_FAR,NEXTCHAR)
           ;
              KEYWORD=SO_FAR,
              (
                 CHAR=EOL,
                 !,
                 NEXTCHAR=46
              ;
                 NEXTCHAR=32
              )
           )
        ;
           make_lower_case(CHAR,LOWER_CASE_CHAR),
           name(CHAR_ATOM,[LOWER_CASE_CHAR]),
           append(SO_FAR,[CHAR_ATOM],FURTHER),
           fetch_chars(KEYWORD,FURTHER,NEXTCHAR)
        ), !.



lskip(CH) :-                                                    /* CFR015 */
        repeat,                                                 /* CFR015 */
           lget0(X),                                            /* CFR015 */
        /* until */ X = CH,                                     /* CFR015 */
        !.                                                      /* CFR015 */


match_command([r,e,p|LACE],replace) :- gen_append(LACE,_,[l,a,c,e]), !.
match_command([l,i|ST],list) :- gen_append(ST,_,[s,t]), !.
match_command([s,t,a,n|DARDISE],standardise) :- gen_append(DARDISE,_,[d,a,r,d,i,s,e]), !.
match_command([d,o|NE],done) :- gen_append(NE,_,[n,e]), !.
match_command([i,n,f|ER],infer) :- gen_append(ER,_,[e,r]), !.
match_command([d,e,d|UCE],deduce) :- gen_append(UCE,_,[u,c,e]), !.
match_command([s,i|MPLIFY],simplify) :- gen_append(MPLIFY,_,[m,p,l,i,f,y]), !.
match_command([c,a,s,e],case) :- !.
match_command([s,t,a,t|US],status) :- gen_append(US,_,[u,s]), !.
match_command([f,o,r,w|ARDCHAIN],forwardchain) :- gen_append(ARDCHAIN,_,[a,r,d,c,h,a,i,n]), !.
match_command([e,x,i,t],exit) :- !.
match_command([f,o,r,c,e,e,x,i,t],forceexit) :- !.
match_command([h|ELP],'help') :- gen_append(ELP,_,[e,l,p]), !.
match_command([f,o,r,g|ET],forget) :- gen_append(ET,_,[e,t]), !.
match_command([r,e,m|EMBER],remember) :- gen_append(EMBER,_,[e,m,b,e,r]), !.
match_command([d,e,l|ETE],delete) :- gen_append(ETE,_,[e,t,e]), !.
match_command([u,n,d|ELETE],undelete) :- gen_append(ELETE,_,[e,l,e,t,e]), !.
match_command([n,e|WVC],newvc) :- gen_append(WVC,_,[w,v,c]), !.
match_command([p,r,o|VE],prove) :- gen_append(VE,_,[v,e]), !.
match_command([q,u,i,t],quit) :- !.
match_command([c,o|NSULT],consult) :- gen_append(NSULT,_,[n,s,u,l,t]), !.
match_command([u,n,w|RAP],unwrap) :- gen_append(RAP,_,[r,a,p]), !.
match_command([i,n,s|TANTIATE],instantiate) :- gen_append(TANTIATE,_,[t,a,n,t,i,a,t,e]), !.
match_command([s,e|T],set) :- gen_append(T,_,[t]), !.
match_command([s,h|OW],show) :- gen_append(OW,_,[o,w]), !.
match_command([d,e,c|LARE],declare) :- gen_append(LARE,_,[l,a,r,e]), !.
match_command([s,a|VE],save_state) :- gen_append(VE,_,[v,e]), !.
match_command([p,r,i|NTVC],printvc) :- gen_append(NTVC,_,[n,t,v,c]), !.
match_command([t|RAVERSE],traverse) :- gen_append(RAVERSE,_,[r,a,v,e,r,s,e]), !.
match_command([e,x,e|CUTE],execute) :-                          /* CFR017 */
        gen_append(CUTE, _, [c,u,t,e]), !.                      /* CFR017 */
match_command([c,a,l,l,p,r,o],callpro) :- !.


/*** PARSE_COMMAND_ARGUMENTS(CMND,ARGS) -- check & save o.k. ARGS for CMND ***/
parse_command_arguments(_,X) :-
        var(X),
        nl,
        write('!!! VAR argument not permitted: retype command.'),
        nl,
        !,
        fail.
parse_command_arguments(_,[]) :- !.
parse_command_arguments(list,HC#N) :-
        (
           HC==h
        ;
           HC==c
        ),
        !,
        integer(N),
        assertz(command_arg(list,HC#N)),
        !.
parse_command_arguments(list,HHCC-U) :-
        nonvar(HHCC),
        integer(U),
        HHCC=HC#L,
        (
           HC==h
        ;
           HC==c
        ),
        !,
        integer(L),
        L<U,
        assertz(command_arg(list,HHCC-U)),
        !.
parse_command_arguments(list,X & Y) :-
        nonvar(X),
        nonvar(Y),
        !,
        parse_command_arguments(list,X),
        parse_command_arguments(list,Y),
        !.
parse_command_arguments(list, WORD) :-                          /* CFR010 */
        atom(WORD),                                             /* CFR010 */
        name(WORD, [CHAR|CHARS]),                               /* CFR010 */
        !,                                                      /* CFR010 */
        (                                                       /* CFR010 */
           gen_append([CHAR|CHARS], _, "deleted"),              /* CFR010 */
           assertz(command_arg(list, deleted))                  /* CFR010 */
        ;                                                       /* CFR010 */
           gen_append([CHAR|CHARS], _, "forgotten"),            /* CFR010 */
           assertz(command_arg(list, forgotten))                /* CFR010 */
        ),                                                      /* CFR010 */
        !.                                                      /* CFR010 */
parse_command_arguments(simplify,HC#N) :-
        (
           HC==h
        ;
           HC==c
        ),
        !,
        integer(N),
        assertz(command_arg(simplify,HC#N)),
        !.
parse_command_arguments(simplify,HHCC-U) :-
        nonvar(HHCC),
        integer(U),
        HHCC=HC#L,
        (
           HC==h
        ;
           HC==c
        ),
        !,
        integer(L),
        L<U,
        assertz(command_arg(simplify,HHCC-U)),
        !.
parse_command_arguments(simplify,X & Y) :-
        nonvar(X),
        nonvar(Y),
        !,
        parse_command_arguments(simplify,X),
        parse_command_arguments(simplify,Y),
        !.
parse_command_arguments(deduce,EXPRN from HYPLIST) :-
        nonvar(EXPRN),
        nonvar(HYPLIST),
        !,
        parse_goal_expression(EXPRN,EXPRESSION),                /* CFR008 */
        check_hyplist(HYPLIST),
        assertz(command_arg(expression,EXPRESSION)),
        assertz(command_arg(hyplist,HYPLIST)),
        !.
parse_command_arguments(deduce,EXPRN) :-
        !,
        parse_goal_expression(EXPRN,EXPRESSION),                /* CFR008 */
        assertz(command_arg(expression,EXPRESSION)),
        !.
parse_command_arguments(infer,EXPRN_using_RULE from HYPLIST) :-
        nonvar(EXPRN_using_RULE),
        nonvar(HYPLIST),
        EXPRN_using_RULE=(EXPRN using RULE),
        !,
        parse_goal_expression(EXPRN,EXPRESSION),                /* CFR008 */
        parse_rulename(RULE),
        check_hyplist(HYPLIST),
        assertz(command_arg(expression,EXPRESSION)),
        assertz(command_arg(rule, exists)),
        assertz(command_arg(hyplist,HYPLIST)),
        !.
parse_command_arguments(infer,EXPRN from HYPLIST_using_RULE) :-
        nonvar(EXPRN),
        nonvar(HYPLIST_using_RULE),
        HYPLIST_using_RULE=(HYPLIST using RULE),
        !,
        parse_command_arguments(infer,EXPRN using RULE from HYPLIST),
        !.
parse_command_arguments(infer,EXPRN using RULE) :-
        nonvar(EXPRN),
        !,
        parse_goal_expression(EXPRN,EXPRESSION),                /* CFR008 */
        parse_rulename(RULE),
        assertz(command_arg(expression,EXPRESSION)),
        assertz(command_arg(rule, exists)),
        !.
parse_command_arguments(infer,EXPRN from HYPLIST) :-
        nonvar(EXPRN),
        nonvar(HYPLIST),
        !,
        parse_goal_expression(EXPRN,EXPRESSION),                /* CFR008 */
        check_hyplist(HYPLIST),
        assertz(command_arg(expression,EXPRESSION)),
        assertz(command_arg(hyplist,HYPLIST)),
        !.
parse_command_arguments(infer,EXPRN) :-
        !,
        parse_goal_expression(EXPRN,EXPRESSION),                /* CFR008 */
        assertz(command_arg(expression,EXPRESSION)),
        !.
parse_command_arguments(replace,HC: OLD_by_NEW_using_RULE) :-
        check_hyp_or_conc(HC),
        nonvar(OLD_by_NEW_using_RULE),
        OLD_by_NEW_using_RULE=(OLD_by_NEW using RULE),
        nonvar(OLD_by_NEW),
        OLD_by_NEW=(OLD by NEW),
        !,
        parse_rulename(RULE),
        parse_expression(OLD, OLD_EXPRN),
        parse_expression(NEW, NEW_EXPRN),
        assertz(command_arg(expression, HC)),
        assertz(command_arg(old, OLD_EXPRN)),
        assertz(command_arg(new, NEW_EXPRN)),
        assertz(command_arg(rule, exists)),
        !.
parse_command_arguments(replace,HC: OLD_by_NEW_using_RULE) :-
        nonvar(HC),
        HC = all,
        nonvar(OLD_by_NEW_using_RULE),
        OLD_by_NEW_using_RULE=(OLD_by_NEW using RULE),
        nonvar(OLD_by_NEW),
        OLD_by_NEW=(OLD by NEW),
        !,
        parse_rulename(RULE),
        parse_expression(OLD, OLD_EXPRN),
        parse_expression(NEW, NEW_EXPRN),
        assertz(command_arg(expression, all)),
        assertz(command_arg(old, OLD_EXPRN)),
        assertz(command_arg(new, NEW_EXPRN)),
        assertz(command_arg(rule, exists)),
        !.
parse_command_arguments(replace,HC: OLD_by_NEW_using_RULE) :-   /* CFR019 */
        nonvar(HC),                                             /* CFR019 */
        (                                                       /* CFR019 */
           HC = (_HC1 & _HC2)                                   /* CFR019 */
        ;                                                       /* CFR019 */
           HC = (_HCn - _M)                                     /* CFR019 */
        ),                                                      /* CFR019 */
        nonvar(OLD_by_NEW_using_RULE),                          /* CFR019 */
        OLD_by_NEW_using_RULE=(OLD_by_NEW using RULE),          /* CFR019 */
        nonvar(OLD_by_NEW),                                     /* CFR019 */
        OLD_by_NEW=(OLD by NEW),                                /* CFR019 */
        !,                                                      /* CFR019 */
        parse_rulename(RULE),                                   /* CFR019 */
        parse_expression(OLD, OLD_EXPRN),                       /* CFR019 */
        parse_expression(NEW, NEW_EXPRN),                       /* CFR019 */
        assertz(command_arg(expression, HC)),                   /* CFR019 */
        assertz(command_arg(old, OLD_EXPRN)),                   /* CFR019 */
        assertz(command_arg(new, NEW_EXPRN)),                   /* CFR019 */
        assertz(command_arg(rule, exists)),                     /* CFR019 */
        !.                                                      /* CFR019 */
parse_command_arguments(replace,HC: OLD_by_NEW) :-
        check_hyp_or_conc(HC),
        nonvar(OLD_by_NEW),
        OLD_by_NEW=(OLD by NEW),
        !,
        parse_expression(OLD,OLD_EXPRN),
        parse_expression(NEW,NEW_EXPRN),
        assertz(command_arg(expression,HC)),
        assertz(command_arg(old,OLD_EXPRN)),
        assertz(command_arg(new,NEW_EXPRN)),
        !.
parse_command_arguments(replace,HC: OLD) :-
        check_hyp_or_conc(HC),
        !,
        parse_expression(OLD,OLD_EXPRN),
        assertz(command_arg(expression,HC)),
        assertz(command_arg(old,OLD_EXPRN)),
        !.
parse_command_arguments(replace,HC) :-
        check_hyp_or_conc(HC),
        !,
        assertz(command_arg(expression,HC)),
        !.
parse_command_arguments(standardise,EXPRN) :-
        !,
        parse_expression(EXPRN,EXPRESSION),
        assertz(command_arg(expression,EXPRESSION)),
        !.
parse_command_arguments(forwardchain,HC) :-
        check_hyp_or_conc(HC),
        !,
        assertz(command_arg(expression,HC)),
        !.
parse_command_arguments(done,OTHERS & CONC) :-
        nonvar(OTHERS),
        nonvar(CONC),
        !,
        parse_command_arguments(done,OTHERS),
        parse_command_arguments(done,CONC),
        !.
parse_command_arguments(done,C#N) :-
        C==c,
        !,
        integer(N),
        assertz(command_arg(to_do,c#N)),                        /* CFR024 */
        !.
parse_command_arguments(done,CCN-M) :-
        nonvar(CCN),
        CCN=C#N,
        nonvar(C),
        C==c,
        !,
        integer(N),
        integer(M),
        M>N,
        assertz(command_arg(to_do,c#N-M)),                      /* CFR024 */
        !.
parse_command_arguments(case,N) :-
        !,
        integer(N),
        assertz(command_arg(case_number,N)),
        !.
parse_command_arguments(prove,EXPRN_by_STRAT on FORM) :-
        !,
        nonvar(EXPRN_by_STRAT),
        EXPRN_by_STRAT=(EXPRN by STRAT),
        strategy_keyword(STRAT,cases),
        parse_expression(FORM,FORMULA),
        parse_goal_expression(EXPRN,EXPRESSION),                /* CFR008 */
        assertz(command_arg(on,FORMULA)),
        assertz(command_arg(strategy,cases)),
        assertz(command_arg(expression,EXPRESSION)),
        !.
parse_command_arguments(prove,EXPRN by STRAT) :-
        !,
        strategy_keyword(STRAT,STRATEGY),
        parse_goal_expression(EXPRN,EXPRESSION),                /* CFR008 */
        assertz(command_arg(strategy,STRATEGY)),
        assertz(command_arg(expression,EXPRESSION)),
        !.
parse_command_arguments(unwrap,HC) :-
        check_hyp_or_conc(HC),
        !,
        assertz(command_arg(expression,HC)),
        !.
parse_command_arguments(instantiate,QVAR with EXPRN) :-
        atom(QVAR),
        qvar(QVAR),
        !,
        parse_expression(EXPRN,EXPRESSION),
        assertz(command_arg(value,EXPRESSION)),
        assertz(command_arg(var,QVAR)),
        !.
parse_command_arguments(instantiate,QVAR) :-
        atom(QVAR),
        qvar(QVAR),
        !,
        assertz(command_arg(var,QVAR)),
        !.
parse_command_arguments(instantiate,EXPRN) :-
        \+ qvar(EXPRN),
        !,
        parse_goal_expression(EXPRN,EXPRESSION),                /* CFR008 */
        assertz(command_arg(value,EXPRESSION)),
        !.
parse_command_arguments(newvc,N) :-
        !,
        integer(N),
        assertz(command_arg(vc_number,N)),
        !.
parse_command_arguments(consult,FILENAME) :-
        !,
        atom(FILENAME),
        assertz(command_arg(filename,FILENAME)),
        !.
parse_command_arguments(execute,FILENAME) :-                    /* CFR017 */
        !,                                                      /* CFR017 */
        atom(FILENAME),                                         /* CFR017 */
        assertz(command_arg(filename,FILENAME)),                /* CFR017 */
        !.                                                      /* CFR017 */
parse_command_arguments('help',IDENTIFIER) :-
        assertz(command_arg(subject,IDENTIFIER)),
        !.
parse_command_arguments(forget,X & Y) :-
        nonvar(X),
        nonvar(Y),
        !,
        parse_command_arguments(forget,X),
        parse_command_arguments(forget,Y),
        !.
parse_command_arguments(forget,H#N) :-
        H==h,
        !,
        integer(N),
        assertz(command_arg(hyplist,[N])),
        !.
parse_command_arguments(forget,HHN-M) :-
        nonvar(HHN),
        HHN=H#N,
        H==h,
        !,
        integer(N),
        integer(M),
        N<M,
        make_numbers_list(N,M,HYPLIST),
        assertz(command_arg(hyplist,HYPLIST)),
        !.
parse_command_arguments(forget,HYPLIST) :-
        !,
        check_hyplist(HYPLIST),
        assertz(command_arg(hyplist,HYPLIST)),
        !.
parse_command_arguments(remember,X & Y) :-
        nonvar(X),
        nonvar(Y),
        !,
        parse_command_arguments(remember,X),
        parse_command_arguments(remember,Y),
        !.
parse_command_arguments(remember,H#N) :-
        H==h,
        !,
        integer(N),
        assertz(command_arg(hyplist,[N])),
        !.
parse_command_arguments(remember,HHN-M) :-
        nonvar(HHN),
        HHN=H#N,
        H==h,
        !,
        integer(N),
        integer(M),
        N<M,
        make_numbers_list(N,M,HYPLIST),
        assertz(command_arg(hyplist,HYPLIST)),
        !.
parse_command_arguments(remember,HYPLIST) :-
        !,
        check_hyplist(HYPLIST),
        assertz(command_arg(hyplist,HYPLIST)),
        !.
parse_command_arguments(delete,X & Y) :-
        nonvar(X),
        nonvar(Y),
        !,
        parse_command_arguments(delete,X),
        parse_command_arguments(delete,Y),
        !.
parse_command_arguments(delete,H#N) :-
        H==h,
        !,
        integer(N),
        assertz(command_arg(hyplist,[N])),
        !.
parse_command_arguments(delete,HHN-M) :-
        nonvar(HHN),
        HHN=H#N,
        H==h,
        !,
        integer(N),
        integer(M),
        N<M,
        make_numbers_list(N,M,HYPLIST),
        assertz(command_arg(hyplist,HYPLIST)),
        !.
parse_command_arguments(delete,HYPLIST) :-
        !,
        check_hyplist(HYPLIST),
        assertz(command_arg(hyplist,HYPLIST)),
        !.
parse_command_arguments(undelete,X & Y) :-
        nonvar(X),
        nonvar(Y),
        !,
        parse_command_arguments(undelete,X),
        parse_command_arguments(undelete,Y),
        !.
parse_command_arguments(undelete,H#N) :-
        H==h,
        !,
        integer(N),
        assertz(command_arg(hyplist,[N])),
        !.
parse_command_arguments(undelete,HHN-M) :-
        nonvar(HHN),
        HHN=H#N,
        H==h,
        !,
        integer(N),
        integer(M),
        N<M,
        make_numbers_list(N,M,HYPLIST),
        assertz(command_arg(hyplist,HYPLIST)),
        !.
parse_command_arguments(undelete,HYPLIST) :-
        !,
        check_hyplist(HYPLIST),
        assertz(command_arg(hyplist,HYPLIST)),
        !.
parse_command_arguments(set,FLAG to VALUE) :-
        is_a_flag(FLAG, VALUETYPE),
        !,
        nonvar(VALUE),
        ok_value(VALUE, VALUETYPE),
        assertz(command_arg(flag,FLAG)),
        assertz(command_arg(value,VALUE)),
        !.
parse_command_arguments(set,FLAG) :-
        is_a_flag(FLAG, _),
        !,
        assertz(command_arg(flag,FLAG)),
        !.
parse_command_arguments(traverse,EXPRN) :-
        !,
        parse_expression(EXPRN,EXPRESSION),
        novars(EXPRESSION),
        (
           EXPRESSION = (_X # _Y)
        ;
           checktype(EXPRESSION, _)
        ),
        assertz(command_arg(expression,EXPRESSION)),
        !.
parse_command_arguments(callpro,GOAL) :-
        !,
        nonvar(GOAL),
        assertz(command_arg(goal,GOAL)),
        !.
parse_command_arguments(_X,_Y) :-
        nl,
        write('!!! Argument(s) not recognised: retype command'),
        nl,
        !,
        fail.


/*** CHECK_HYPLIST(HL) -- is HL a list of integer hypothesis numbers? ***/
check_hyplist([]) :- !.
check_hyplist([H|T]) :- integer(H), hyp(H,_), check_hyplist(T), !.


/*** CHECK_HYP_OR_CONC(X) -- is X a hypothesis or conclusion? ***/
check_hyp_or_conc(X) :-
        var(X),
        !,
        nl,
        write('!!! Warning: VAR not allowed.  Retype command.'),
        nl,
        fail.
check_hyp_or_conc(HC#N) :-
        (
           HC=h,
           FUNCTOR=hyp
        ;
           HC=c,
           FUNCTOR=conc
        ),
        integer(N),
        CALL=..[FUNCTOR,N,_],
        call(CALL),
        !.


/*** PARSE_GOAL_EXPRESSION(IN,OUT) -- convert IN to ready-to-use exp. OUT ***/
parse_goal_expression(IN, OUT) :-                               /* CFR008 */
        parse_expression(IN, OUT),                              /* CFR008 */
        !,                                                      /* CFR008 */
        OUT \= (h # _).                                         /* CFR008 */


/*** PARSE_EXPRESSION(IN,OUT) -- convert IN to ready-to-use exprn. OUT ***/
parse_expression(EXPR,EXPR) :- var(EXPR), !.
parse_expression(EXPR where X=Y,EXPR) :-
        !,
        (
           var(X),
           !,
           parse_expression(Y,Y1),
           novars(Y1),
           X=Y1
        ;
           X=h#N,
           hyp(N,X1),
           X1=Y
        ;
           X=c#N,
           conc(N,X1),
           X1=Y
        ), !.
parse_expression(EXPR where BINDINGS & X=Y,EXPR) :-
        !,
        parse_expression(EXPR where BINDINGS,EXPR),
        (
           var(X),
           !,
           parse_expression(Y,Y1),
           novars(Y1),
           X=Y1
        ;
           X=h#N,
           hyp(N,X1),
           X1=Y
        ;
           X=c#N,
           conc(N,X1),
           X1=Y
        ), !.
parse_expression(X,X) :- !.


/*** PARSE_RULENAME(RULE) -- parse RULE, allowing for family-rulenames ***/
parse_rulename(RULE) :-
        var(RULE),
        !,
        RULENAME=RULE,
        assertz(command_arg(rulename, RULENAME)),
        !.
parse_rulename(X & Y) :-
        !,
        parse_rulename(X),
        parse_rulename(Y),
        !.
parse_rulename(RULE) :-
        (
           atom(RULE),
           RULENAME=..[RULE,_],
           SAVE=(command_arg(rulename, RULENAME))
        ;
           nonvar(RULE),
           RULE=..[FAMILY,RANGE],
           atom(FAMILY),
           (
              integer(RANGE),
              RULENAME=RULE,
              SAVE=(command_arg(rulename, RULENAME))
           ;
              var(RANGE),
              SAVE=(command_arg(rulename, RULE))
           ;
              RULENAME=..[FAMILY,XXX],
              RANGE=LOW-UPP,
              (
                 integer(LOW),
                 (
                    integer(UPP),
                    LOW<UPP,
                    SAVE=((command_arg(rulename, RULENAME) :-
                                integer(XXX), LOW=<XXX, XXX=<UPP))
                 ;
                    var(UPP),
                    SAVE=((command_arg(rulename, RULENAME) :-
                                integer(XXX), LOW=<XXX))
                 )
              ;
                 var(LOW),
                 integer(UPP),
                 SAVE=((command_arg(rulename, RULENAME) :-
                          integer(XXX), XXX=<UPP))
              )
           )
        ),
        assertz(SAVE),
        !.


/*** STRATEGY_KEYWORD(X,Y) -- is X a valid strategy keyword substring? ***/
strategy_keyword(WORD,STRATEGY) :-
        name(WORD,LIST),
        length(LIST,N),
        N>=2,
        (
           STRATEGY='implication'
        ;
           STRATEGY='induction'
        ;
           STRATEGY='contradiction'
        ;
           STRATEGY='cases'
        ),
        name(STRATEGY,SL),
        gen_append(LIST,_,SL),
        !.


/*** WARN_OF_UNKNOWN_COMMAND -- what the heck's this? ***/
warn_of_unknown_command :-
        nl,
        write('!!! Command not recognised.  Please retype.'),
        nl,
        !.


/*** VERIFIED_EXIT_COMMAND(C) -- check if it's safe to exit from Checker ***/
verified_exit_command(exit) :-                                  /* CFR005 */
        vcs_to_prove([]),       /* it's safe if there are no VCs left */
        !.
verified_exit_command(exit) :-
        recent_save_command_issued,
        !.
verified_exit_command(exit) :-
        write('There are still VCs to prove and you have not "save"d recently.'),
        nl,
        read_answer('Do you still wish to exit', Answer),
        !,
        Answer=yes.
verified_exit_command(forceexit).

/* 'help' is predefined in sicstus - need to convert to 'checkerhelp' */
convertHelp(help, checkerhelp)  :- !.
convertHelp(C, C) :- !.

/***** EXECUTE_COMMAND(C) - execute & save proof log fact *****/
execute_command(C) :-
        retractall(logfact(_,_)),
        asserta(logfact(command, C)),
        tidy_up_inference_database(C),
        convertHelp(C, CC),
        call_once(CC),
        !,
        (                                                       /* CFR005 */
           trivial_command(CC)                                  /* CFR005 */
        ;                                                       /* CFR005 */
           CC = exit                                            /* CFR005 */
        ;                                                       /* CFR005 */
           CC = forceexit
        ;                                                       /* CFR005 */
           retractall(recent_save_command_issued)               /* CFR005 */
        ),                                                      /* CFR005 */
        !,                                                      /* CFR005 */
        tidy_up_logfacts,
        !.
execute_command(_C) :-
        write('FAIL'),
        nl,
        retractall(logfact(_,_)),
        !,
        fail.

%Make command calls visible to the spxref tool.
:- public replace/0.
:- public list/0.
:- public standardise/0.
:- public done/0.
:- public infer/0.
:- public deduce/0.
:- public simplify/0.
:- public case/0.
:- public status/0.
:- public forwardchain/0.
:- public exit/0.
:- public forceexit/0.
% Note that command 'help' is executed as 'checkerhelp'.
:- public checkerhelp/0.
:- public forget/0.
:- public remember/0.
:- public delete/0.
:- public undelete/0.
:- public newvc/0.
:- public prove/0.
:- public quit/0.
:- public consult/0.
:- public unwrap/0.
:- public instantiate/0.
:- public set/0.
:- public show/0.
:- public declare/0.
:- public save_state/0.
:- public printvc/0.
:- public traverse/0.
:- public execute/0.
:- public callpro/0.

call_once(C) :- call(C), !.


/***** TIDY_UP_LOGFACTS: increment step no (if necessary) & collect args ***/
tidy_up_logfacts :-
        logfact(command, C),
        trivial_command(C),
        retractall(logfact(_,_)),
        !,
        fail.
tidy_up_logfacts :-
        logfact(command, exit),
        !.
tidy_up_logfacts :-
        logfact(command, forceexit),
        !.
tidy_up_logfacts :-
        write('OK'),
        nl,
        retract(step_number(N)),
        M is N+1,
        asserta(step_number(M)),
        !.


tidy_up_inference_database(delete) :-
        retractall(could_infer(_)),
        !.
tidy_up_inference_database(undelete) :-
        retractall(could_not_infer(_)),
        !.
tidy_up_inference_database(consult) :- !.
tidy_up_inference_database(save_state) :-                       /* CFR005 */
        assertz(recent_save_command_issued),                    /* CFR005 */
        !.                                                      /* CFR005 */
tidy_up_inference_database(C) :-
        trivial_command(C),
        !.
tidy_up_inference_database(done) :- !.
tidy_up_inference_database(_C) :-
        retractall(could_not_infer(_)),
        !.


/*** SHOW_PERMITTED_ARGUMENTS(COMMAND) -- show allowed syntax ***/
show_permitted_arguments(COMMAND) :-
        nl,
        nl,
        write('General syntax of command:'),
        nl,
        gfa(COMMAND,FORM),
        print(FORM),
        nl,
        fail.
show_permitted_arguments(COMMAND) :-
        nl,
        write('Examples of valid command syntax for "'),
        print(COMMAND),
        write('" are:'),
        nl,
        nl,
        tab(5),
        print(COMMAND),
        write('.'),
        nl,
        spa(COMMAND,TEXT),
        tab(5),
        print(COMMAND),
        put_code(32),
        print(TEXT),
        write('.'),
        nl,
        fail.


spa(list,'h#5').
spa(list,'h#3-6').
spa(list,'c#2').
spa(list,'c#1-5').
spa(list,'h#1-3 & h#7 & c#2-3 & h#15-17').

/* spa(simplify,X) :- spa(list,X). -- NOT YET! */

spa(deduce,'c#1').
spa(deduce,'not x=y').
spa(deduce,'n>0 or n=0 from [2,3]').
spa(deduce,'X or not X where c#1=X from []').

spa(infer,'c#3').
spa(infer,'X+1>0 where h#2=(X>=0)').
spa(infer,'c#1 using inequals').
spa(infer,'is_even(a+b) using even(1)').
spa(infer,'RHS where c#2=(LHS -> RHS) using logic from [2,3,6]').

spa(replace,'h#6').
spa(replace,'c#4').
spa(replace,'h#2: X+Y').
spa(replace,'c#3: X+0 by Y').
spa(replace,'h#14: X+(Y+Z) by B where h#1=(A=B)').
spa(replace,'c#5: A+B by B+A using commut').
spa(replace,'all: n+0 by n using arith').

spa(standardise,'h#6').
spa(standardise,'c#1').
spa(standardise,'i-1+1').
spa(standardise,'X=Y+1 -> Y=X-1 where h#2=(X=A) & h#3=(A=Y+1)').

spa(forwardchain,'h#3').
spa(forwardchain,'c#3').

spa(done,'c#1').
spa(done,'c#1-3').
spa(done,'c#2-3 & c#8-11 & c#5').

spa(case,'2').

spa(prove,'c#1 by implication').
spa(prove,'X or Y where c#1=X & c#2=Y by contradiction').
spa(prove,'c#5 by induction').
spa(prove,'c#3 by cases').
spa(prove,'p(x+y) by cases on h#7').
spa(prove,'x*x>=0 by cases on x<0 or x=0 or x>0').

spa(unwrap,'h#5').
spa(unwrap,'c#2').

spa(instantiate,'h#8').
spa(instantiate,'c#11').
spa(instantiate,'h#1 with 2*n-1').
spa(instantiate,'c#7 with int_p_2 for int_P_1').

spa(newvc,'3').

spa(consult,'\'sort.rls\'').
spa(consult,'\'DISK$1:[-.RULES]INOUT.RLS\'').

spa(execute,'\'prove1to5.cmd\'').
spa(execute,'\'DISK$1:[-.PROOFS]REPLAY1.CMD\'').

spa('help','infer').
spa('help','instantiate').

spa(forget,'h#3').
spa(forget,'h#1-3 & h#5-6 & h#10').
spa(forget,'[1,2,3,5,6,10]').

spa(remember,'h#3').
spa(remember,'h#1-3 & h#5-6 & h#10').
spa(remember,'[1,2,3,5,6,10]').

spa(delete,'h#3').
spa(delete,'h#1-3 & h#5-6 & h#10').
spa(delete,'[1,2,3,5,6,10]').

spa(undelete,'h#3').
spa(undelete,'h#1-3 & h#5-6 & h#10').
spa(undelete,'[1,2,3,5,6,10]').

spa(set,'simplify_in_infer').
spa(set,'auto_done to on').
spa(set,'display_subgoals_max to 2').

spa(traverse,'h#6').
spa(traverse,'c#2').
spa(traverse,'X where c#5=(X or _)').

spa(callpro,'statistics').

gfa(list,'li(st) [ HYP_OR_CONC_RANGE { & HYP_OR_CONC_RANGE } ].').
gfa(list,'').
gfa(list,'where: HYP_OR_CONC_RANGE is HC#N-M or HC#N,').
gfa(list,'       HC is "h" or "c", and N & M are integers (with N<M).').

gfa(simplify,'si(mplify) [ HYP_OR_CONC_RANGE { & HYP_OR_CONC_RANGE } ].').
gfa(simplify,'').
gfa(simplify,'where: HYP_OR_CONC_RANGE is HC#N-M or HC#N,').
gfa(simplify,'       HC is "h" or "c", and N & M are integers (with N<M).').

gfa(deduce,'ded(uce) [ EXPRESSION [ from HYPLIST ] ].').
gfa(deduce,'').
gfa(deduce,'where: EXPRESSION is a valid checker expression and').
gfa(deduce,'       HYPLIST is a list of integers (hypothesis numbers).').

gfa(infer,'inf(er) [ EXPRESSION [ using RULE [ from HYPLIST ] ] ].').
gfa(infer,'').
gfa(infer,'where: EXPRESSION is a valid checker expression,').
gfa(infer,'       RULE is a rulename (or family, or Prolog variable) and').
gfa(infer,'       HYPLIST is a list of integers (hypothesis numbers).').

gfa(replace,'re(place) [ HYP_OR_CONC [ : OLD [ by NEW [ using RULE ] ] ] ].').
gfa(replace,'').
gfa(replace,'where: HYP_OR_CONC is a hypothesis or conclusion (i.e. h#N or c#N),').
gfa(replace,'       OLD & NEW are valid checker expression patterns and').
gfa(replace,'       RULE is a rulename (or family, or Prolog variable).').

gfa(standardise,'stan(dardise) [ EXPRESSION ].').
gfa(standardise,'').
gfa(standardise,'where EXPRESSION is a valid checker expression.').

gfa(forwardchain,'forw(ardchain) [ HYP_OR_CONC ].').
gfa(forwardchain,'').
gfa(forwardchain,'where HYP_OR_CONC is a hypothesis or conclusion (i.e. h#N or c#N).').

gfa(done,'do(ne) [ CONC_RANGE { & CONC_RANGE } ].').
gfa(done,'').
gfa(done,'where CONC_RANGE is c#N or C#N-M, for integers M & N (with N<M).').

gfa(case,'case N.').
gfa(case,'').
gfa(case,'where N is the case number (an integer).').

gfa(prove,'pro(ve) [ EXPRESSION by STRATEGY [ on FORMULA ] ].').
gfa(prove,'').
gfa(prove,'where: EXPRESSION is a valid checker expression,').
gfa(prove,'       STRATEGY is one of "implication", "contradiction",').
gfa(prove,'       "induction" or "cases", and').
gfa(prove,'       FORMULA (which may only be used for "cases") is a disjunction').

gfa(quit,'quit.').

gfa(unwrap,'unw(rap) [ HYP_OR_CONC ].').
gfa(unwrap,'').
gfa(unwrap,'where HYP_OR_CONC is of the form h#N or c#N for some integer N.').

gfa(instantiate,'ins(tantiate) [ HYP_OR_CONC [ with EXPRESSION [ for VAR ] ] ].').
gfa(instantiate,'').
gfa(instantiate,'where: HYP_OR_CONC is of the form h#N or c#N for some integer N,').
gfa(instantiate,'       EXPRESSION is a valid checker expression and').
gfa(instantiate,'       VAR is the universal variable to be instantiated.').

gfa(newvc,'ne(wvc) [ NUMBER ].').
gfa(newvc,'').
gfa(newvc,'where NUMBER is the number of the (as yet unproven) VC to be proved.').

gfa(consult,'con(sult) [ FILENAME ].').
gfa(consult,'').
gfa(consult,'where FILENAME is a Prolog atom naming the rulefile to use.').

gfa(execute,'exe(cute) [ FILENAME ].').
gfa(execute,'').
gfa(execute,'where FILENAME is a Prolog atom naming the command script to use.').

gfa('help','h(elp) [ COMMAND ].').
gfa('help','').
gfa('help','where COMMAND is the (unabbreviated) command on which help is needed.').

gfa(forget,'forg(et) [ HYPS_OR_HYPLIST ].').
gfa(forget,'').
gfa(forget,'where HYPS_OR_HYPSLIST is either a list of integers giving the').
gfa(forget,'hypothesis numbers to be forgotten, or one or more HYPRANGEs joined').
gfa(forget,'together with "&", each HYPRANGE being either a hypothesis (h#N) or').
gfa(forget,'a range of hypotheses (h#N-M, with N<M).').

gfa(remember,'rem(ember) [ HYPS_OR_HYPLIST ].').
gfa(remember,'').
gfa(remember,'where HYPS_OR_HYPSLIST is either a list of integers giving the').
gfa(remember,'hypothesis numbers to be remembered, or one or more HYPRANGEs joined').
gfa(remember,'together with "&", each HYPRANGE being either a hypothesis (h#N) or').
gfa(remember,'a range of hypotheses (h#N-M, with N<M).').

gfa(delete,'del(ete) [ HYPS_OR_HYPLIST ].').
gfa(delete,'').
gfa(delete,'where HYPS_OR_HYPSLIST is either a list of integers giving the').
gfa(delete,'hypothesis numbers to be deleted, or one or more HYPRANGEs joined').
gfa(delete,'together with "&", each HYPRANGE being either a hypothesis (h#N) or').
gfa(delete,'a range of hypotheses (h#N-M, with N<M).').

gfa(undelete,'und(elete) [ HYPS_OR_HYPLIST ].').
gfa(undelete,'').
gfa(undelete,'where HYPS_OR_HYPSLIST is either a list of integers giving the').
gfa(undelete,'hypothesis numbers to be undeleted, or one or more HYPRANGEs joined').
gfa(undelete,'together with "&", each HYPRANGE being either a hypothesis (h#N) or').
gfa(undelete,'a range of hypotheses (h#N-M, with N<M).').

gfa(set,'se(t) [ FLAG [ to VALUE ] ].').
gfa(set,'').
gfa(set,'where FLAG is a user-modifiable flag and VALUE is the new value to').
gfa(set,'be assigned to that flag.').

gfa(show,'sh(ow).').

gfa(traverse,'t(raverse) [ EXPRESSION ].').
gfa(traverse,'').
gfa(traverse,'where EXPRESSION may be h#N for hypothesis N, c#N for conclusion N').
gfa(traverse,'or some other valid expression to be traversed.').

gfa(printvc,'pri(ntvc).').

gfa(declare,'dec(lare).').

gfa(callpro,'callpro [ PROLOG_GOAL ].').
gfa(callpro,'').
gfa(callpro,'where PROLOG_GOAL is a Prolog goal to be called.').
gfa(callpro,'FOR USE BY PROGRAM VALIDATION LIMITED ONLY!').

gfa(exit,'exit.').


execute :-                                                      /* CFR017 */
        (                                                       /* CFR017 */
           command_arg(filename, FILE)                          /* CFR017 */
        ;                                                       /* CFR017 */
           prompt_user('Filename? '),                           /* CFR017 */
           rread(FILE)                                          /* CFR017 */
        ),                                                      /* CFR017 */
        !,                                                      /* CFR017 */
        atom(FILE),                                             /* CFR017 */
        (                                                       /* CFR017 */
           file_exists(FILE)                                    /* CFR017 */
        ;                                                       /* CFR017 */
           write('File cannot be found.'),                      /* CFR017 */
           nl,                                                  /* CFR017 */
           fail                                                 /* CFR017 */
        ),                                                      /* CFR017 */
        asserta(perform_script_file(FILE)),                     /* CFR017 */
        write('<<< Commencing command script '),                /* CFR017 */
        print(FILE),                                            /* CFR017 */
        write(' >>>'),                                          /* CFR017 */
        nl,                                                     /* CFR017 */
        retractall(command_logging(_)),
        assertz(command_logging(off)),
        !.                                                      /* CFR017 */
%###############################################################################
%END-OF-FILE
