% |
% This module defines the commands that compile and upload |
% transaction programs, "comp_trans", and database programs, |
% "comp_db", into the transaction base and database respectively. |
% |
:- import ins/1, asrt/1, db/1 from updates.
:- import wff/2 from parser.
:- import append/3 from basics.
% The "updatable" operator can only be used in database programs |
% to declare the predicates representing tables that allow updates. |
% |
:- op(500, fx, [updatable]).
% A transaction program is stored in a file with the name of the |
% form "name.ctr". The "comp_trans" command takes the "name" as |
% argument, reads and parses the transaction program line by line |
% creating the output as "name.ctr.o"; the rules written in the output |
% file are then loaded into the transaction base. |
% |
comp_trans(File) :-
in_filename(File,File1),
see(File1),
out_filename(File1,FileOut),
unix('rm -f FileOut 2>/dev/null', R1),
tell(FileOut),
repeat_read_and_compile(File1,FileOut),
seen, told.
insert_file(FileOut).
% The input file is read and processed recursively until |
% the end of file is reached. |
% |
repeat_read_and_compile(FileIn,FileOut) :-
read(Term),
(
(Term == end_of_file) ->
true
;
read_and_write_rule(Term,FileIn,FileOut),
repeat_read_and_compile(FileIn,FileOut)
).
% To translate a rule from the transaction program, the head |
% of the rule becomes trans(head) and the remainder of the rule |
% does not change. |
% |
% For each rule, a new rule is created with the form head :- fail, |
% to let Prolog know that the corresponding predicate is defined. |
% The translated rule and the new rule associated to it are written |
% in the output file. |
% |
read_and_write_rule(':-'(Lhs,Rhs),_,_) :-
write('trans('),
write(Lhs),
write(')'),
write(' :- '),
wff(Rhs, PRhs),
write(PRhs),
write('.'), nl,
write(Lhs),
write(' :- fail.'), nl.
% If the transaction is an atom then it is just copied to |
% the output file. |
% |
read_and_write_rule(Term,_,_) :-
not(Term = ':-'(_,_)),
write(Term),
write('.'), nl.
% A database program is stored in a file with the name of the |
% form "name.db". The "name" has to be the same with the |
% corresponding transaction program "name". |
% |
% The "comp_db" command takes the "name" as argument, reads |
% and parses the database program line by line creating the output |
% as "name.db.o"; the rules written in the output file are then |
% inserted into the database. |
% |
comp_db(File) :-
db_filename(File,File2),
see(File2),
read(Term),
tmp_filename(File,File3),
unix('rm -f File3 2>/dev/null', R1),
tell(File3),
write_a_line(Term,File2,File3),
seen,
told,
see(File3),
read(T),
load_a_line(T,File3),
seen.
% Any "updatable" declaration of a predicate "p" is translated |
% to "p(X) = db(p(X))" and written into the output file. |
% |
write_a_line(updatable(Name/Num),File2,File3) :-
db_mod(Name,Num,Arg),
write(Arg), nl,
db_ins(Name,Num,Argi),
write(Argi), nl,
read(Next), !,
write_a_line(Next,File2,File3).
% The database rules are just copied to the output file. |
% |
write_a_line((Lhs :- Rhs),File2,File3) :-
write(Lhs),
write(' :- '),
write(Rhs),
write('.'), nl,
read(Next), !,
write_a_line(Next,File2,File3).
% If the input line contains an atom, then it is copied to the |
% output file and inserted into the database. |
% |
write_a_line(Term,File2,File3) :-
not(Term = updatable(_)),
write_and_assert(Term,File2,File3).
write_and_assert(Term,File2,File3) :-
(Term == end_of_file), !, true
;
write(Term),
write('.'), nl,
read(Next), !,
write_a_line(Next,File2,File3).
% For each "updatable" predicate "p", a tuple with the form |
% "modif(p)" is inserted into the database. |
% |
oad_a_line(modif(P),File3) :-
asrt(P),
read(Next), !,
load_a_line(Next,File3).
% The rules are inserted into the database
%
load_a_line((Lhs :- Rhs),File3) :-
assert((Lhs :- Rhs)),
read(Next), !,
load_a_line(Next,File3).
% The database tuples are inserted into the database using |
% "strong inserts". This type of inserts is implemented in the |
% "updates" module and ensures that the database is not corrupted |
% during backtracking. |
% |
load_a_line(Term,File3) :-
not(Term = modif(_)),
read_and_assert(Term,File3).
read_and_assert(Term,File3) :-
(Term == end_of_file), !, true
;
ins(Term),
read(Next), !,
load_a_line(Next,File3).
% For an updatable predicate, p, the clause "p(X) = db(p(X))" |
% is built. |
% |
db_ins(Name,Num,Argj) :- name(Name,Namel),
db_name(Namel,Name1),
db_arg(Name1,Num,Argj).
db_name(Namel,Name1) :- append(Namel,"(",Name1).
db_arg(Name1,0,Argj) :- append(Name1,")",Arg1),
append(Arg1," :- db(",Arg2),
append(Arg2,Arg1,Arg3),
append(Arg3,").",Argl),
name(Argj,Argl).
db_arg(Name1,Num,Argj) :- name(Num,L),
append("X",L,Argi),
append(Name1,Argi,Tmp1),
Num1 is Num - 1,
(Num1 = 0,
db_arg(Tmp1,Num1,Argj)
;
append(Tmp1,",",Tmp2),
db_arg(Tmp2,Num1,Argj)).
% For each updatable predicate, p, the tuple "modif(p(X))" |
% is created for insertion into the database. |
% |
db_mod(Name,Num,Arg) :- name(Name,Namel),
db_name1(Namel,Name1),
db_arg1(Name1,Num,Arg).
db_name1(Namel,Name1) :- append("modif(",Namel,Namel1),
append(Namel1,"(",Name1).
db_arg1(Name1,0,Arg) :- append(Name1,")).",Arg1),
name(Arg,Arg1).
db_arg1(Name1,Num,Arg) :- name(Num,L),
append("X",L,Argi),
append(Name1,Argi,Tmp1),
Num1 is Num - 1,
(Num1 = 0,
db_arg1(Tmp1,Num1,Arg)
;
append(Tmp1,",",Tmp2),
db_arg1(Tmp2,Num1,Arg)).
% The transaction and database program file names are |
% created based on the arguments entered in "comp_trans" and |
% "comp_db" commands. These names are required to read and |
% write the files. |
% |
in_filename(FileIn,FileOut) :-
name(FileIn,NameIn),
append(NameIn,".ctr",NameOut),
name(FileOut,NameOut).
out_filename(FileIn,FileOut) :-
name(FileIn,NameIn),
append(NameIn,".o",NameOut),
name(FileOut,NameOut).
db_filename(FileIn,FileOut) :-
name(FileIn,NameIn),
append(NameIn,".db",NameOut),
name(FileOut,NameOut).
tmp_filename(FileIn,FileOut) :-
name(FileIn,NameIn),
append(NameIn,".db.o",NameOut),
name(FileOut,NameOut).
% The translated transaction program is inserted into the |
% transaction base line by line. |
insert_file(FileName) :-
seeing(X),
see(FileName),
read_and_add_line,
see(X).
read_and_add_line :-
read(Line),
(
(Line == end_of_file)
-> true
;
assert(Line),
read_and_add_line ).