1:- module(ic_parser,
    2	 [translate_ics/2,
    3	  translate_ics_files/2,
    4      download_ics/1,
    5	  parse_ics/2,
    6	  parse_ics_string/2,
    7	  add_var/2]).    8
    9:- use_module(library(lists),
   10	     [append/3,
   11	      member/2]).   12/*:- use_module(library(system),
   13	     [system/1]).
   14*/
   15:- use_module(parser_utils).   16:- use_module(debug).   17
   18%:- use_module(ruleml_parser).
   19
   20/*
   21translate_ics_files(FileList,OutFile):-
   22	write_debug('translate_ics_files: init...'),
   23	write_debug('Parsing ICS: init...'),
   24	merge_files(FileList,'_temp_ics_file_.txt'),
   25	translate_ics('_temp_ics_file_.txt',OutFile),!,
   26	% This cut is important, as in order to signal translation errors, 
   27    % choice points are left open 
   28	write_debug('ICS successfully translated and written to:'),
   29	write_debug(OutFile),
   30	write_debug('Parsing ICS: end.'). 
   31*/
   32
   33download_ics(URLstring):-
   34    atom_codes(URL,URLstring),
   35    translate_ics_files([URL],'./temp.pl'),
   36    open('./temp.pl',read,Stream),
   37    call_terms(Stream),
   38    close(Stream).
   39
   40call_terms(Stream):-
   41    read(Stream,Term),
   42    (Term=end_of_file -> true
   43        ; (Term = ics(Body,Head)-> call(user:ic(Body,Head)) % invokes all atoms ic/2 in the file
   44            ; true),
   45          call_terms(Stream)
   46    ).
   47
   48translate_ics_files(FileList,OutFile):-
   49	open(OutFile,write,Stream),
   50	write(Stream,':-module(ics,[ics/2]).'),nl(Stream),nl(Stream),
   51	translate_ics_list(FileList,Stream),
   52	close(Stream).
   53
   54translate_ics_list([],_).
   55translate_ics_list([InFile|FileList],Stream):-
   56    write_debug('Parsing file '), write_debug(InFile),
   57    translate_ics_opened(InFile,Stream),!,
   58    write_debug(' --> OK'), nl,
   59    translate_ics_list(FileList,Stream).
   60
   61merge_files(FileList,OutFile):-
   62%	write('About to open outfile'),nl,
   63	open(OutFile,write,Stream),
   64%	write('outfile opened'),nl, write(FileList), nl,
   65	FileList=[H|T],write(H),nl,write(T),nl,
   66	merge_files_to_stream(FileList,Stream),
   67	close(Stream).
   68
   69merge_files_to_stream([],_):-write('empty list'),nl.
   70merge_files_to_stream([File|MoreFiles],OutStream):-	
   71	read_file_to_string(File,String),
   72	write_string_to_stream(String,OutStream),
   73	merge_files_to_stream(MoreFiles,OutStream).
   74
   75write_string_to_stream([],_).
   76write_string_to_stream([Code|MoreCodes],Stream):-
   77	put_code(Stream,Code),
   78	write_string_to_stream(MoreCodes,Stream).
   79
   80translate_ics(InFile,OutFile):-
   81	open(OutFile,write,Stream),
   82	write(Stream,':-module(ics,[ics/2]).'),nl(Stream),nl(Stream),
   83    translate_ics_opened(InFile,Stream),
   84	close(Stream).
   85
   86% Assumes the outfile is already open
   87translate_ics_opened(InFile,Stream):-
   88	% If the XML succeeds, OK, otherwise try to parse as normal
   89	ruleml_parse_file(InFile,ICSR,Error),
   90	(Error = no_ruleml
   91	   ->  parse_ics(InFile,ICS),
   92	       write_ics_to_stream(ICS,Stream)
   93	   ;   write_ics_to_stream(ICSR,Stream)
   94    ).
   95
   96parse_ics(FileName,ICList):-
   97	read_file_to_string(FileName,FileString),
   98	phrase(elementList(FileString2),FileString),
   99	drop_whites(FileString2, NoWhitesString),
  100	phrase(ic_list(ICList,1), NoWhitesString).
  101
  102parse_ics_string(S,ICList):-
  103	string_codes(S,String),
  104	phrase(elementList(FileString2),String),
  105	drop_whites(FileString2, NoWhitesString),
  106	phrase(ic_list(ICList,1), NoWhitesString).
  107
  108
  109
  110%----------------------------------------------------------
  111% ICS DCG
  112%----------------------------------------------------------
  113
  114ic_list([],_) -->
  115	[].
  116ic_list([IC|MoreICs],N) -->
  117	ic(IC),
  118	!,
  119	{N1 is N+1},
  120	ic_list(MoreICs,N1).
  121ic_list([_|_],N) -->
  122    {write('Error in IC number '), 
  123    write(N), write(' ***'), nl, fail}.
  124
  125ic(rule(((Head,_):-(Body,_)),0,P)) -->
  126        number(P),
  127	"::",
  128	body(Body),
  129	impl_symbol,!,
  130	head2(Head).
  131ic(_) -->
  132    {nl, write('*** Error in Body or could not find implication symbol: '), nl, fail}.
  133
  134body([BodyAtom|MoreAtoms]) -->
  135	abducible(BodyAtom),!,
  136	body_tail(MoreAtoms).
  137body([BodyAtom|MoreAtoms]) -->
  138	event(BodyAtom),!,
  139	body_tail(MoreAtoms).
  140body([BodyAtom|MoreAtoms]) -->
  141	body_atom(BodyAtom),!,
  142	body_tail(MoreAtoms).
  143body([true]) -->"true".
  144body(_) -->
  145    {nl, write('*** Body must begin with event or abducible.'), nl, fail}.
  146
  147body_tail([BodyAtom|MoreBodyAtoms]) -->
  148	and_symbol,
  149	body_atom(BodyAtom),
  150	!,
  151	body_tail(MoreBodyAtoms).
  152body_tail([]) -->
  153	[].
  154body_tail(_) -->
  155    comma,
  156    {nl, write('*** Error in body conjunct: comma instead of /\\ symbol?'), fail}.
  157
  158body_atom(BodyAtom) -->
  159	abducible(BodyAtom).
  160body_atom(BodyAtom) -->
  161	event(BodyAtom).
  162body_atom(BodyAtom) -->
  163	atom(BodyAtom).
  164body_atom(BodyAtom) -->
  165	relat(BodyAtom).
  166
  167relat(Relation) -->
  168	clp_relation(Relation),
  169	!.
  170relat(Relation) -->
  171	unify_relation(Relation).
  172
  173unify_relation(Relation) -->
  174	term(Term1),
  175	unify_operator(Operator),
  176	term(Term2),
  177	{Relation=..[Operator,Term1,Term2]}.
  178
  179clp_relation(Relation) -->
  180	expression(Expression1),
  181	clp_relop(Relop),
  182	expression(Expression2),
  183	{Relation=..[Relop,Expression1,Expression2]}.
  184
  185
  186
  187expression(Expression) -->
  188	operand(Operand1),
  189	clp_operator(CLPOperator),
  190	operand(Operand2),
  191	{Expression=..[CLPOperator,Operand1,Operand2]}.
  192expression(Expression) -->
  193	operand(Expression).
  194expression(Expression) -->
  195	term(Expression).
  196
  197is_constraint(C):-
  198	C=..[R|_],
  199	member(R,[=,<>,>=,>,=<,<,::]).
  200
  201clp_relop(=) -->
  202	"==",
  203	!.
  204clp_relop(<>) -->
  205	"<>",
  206	!.
  207clp_relop(>=) -->
  208	">=",
  209	!.
  210clp_relop(>) -->
  211	">",
  212	!.
  213clp_relop(=<) -->
  214	"<=",
  215	!.
  216clp_relop(<) -->
  217	"<".
  218clp_relop(::) -->
  219	"::".
  220
  221clp_operator(+) -->
  222	"+".
  223clp_operator(-) -->
  224	"-".
  225clp_operator(*) -->
  226	"*".
  227clp_operator(/) -->
  228	"/".
  229
  230
  231unify_operator(unif) -->
  232	"=".
  233unify_operator(not_unif) -->
  234	"!=".
  235
  236operand(Number) -->
  237	number(Number).
  238operand(Variable) -->
  239	variable(Variable).
  240
  241head2(Head) -->
  242    head1(Head),
  243	full_stop,!.
  244head2(_) -->
  245    {nl, write('*** Error in Head or could not find full stop: '), fail}.
  246
  247head1([])-->"false",!.
  248head1(Head)-->head(Head).
  249
  250head([Disjunct|MoreDisjuncts]) -->
  251	disjunct(Disjunct),
  252	head_tail(MoreDisjuncts).
  253
  254
  255disjunct_1(Disjunct1) -->
  256	disjunct(Disjunct),
  257	{constraints_before(Disjunct,Disjunct1)}.
  258
  259constraints_before(L1,L2):-
  260	divide_constraints_from_abducibles(L1,Constraints,Abducibles),
  261	append(Constraints,Abducibles,L2).
  262
  263divide_constraints_from_abducibles([],[],[]).
  264divide_constraints_from_abducibles([H|T],[H|T1],L2):-
  265	is_constraint(H),
  266	!,
  267	divide_constraints_from_abducibles(T,T1,L2).
  268divide_constraints_from_abducibles([H|T],L1,[H|T2]):-
  269	divide_constraints_from_abducibles(T,L1,T2).
  270
  271
  272
  273head_tail([Disjunct|MoreDisjuncts]) -->
  274	or_symbol,
  275	disjunct(Disjunct),
  276	!,
  277	head_tail(MoreDisjuncts).
  278head_tail([]) -->
  279	[].
  280
  281disjunct((-,[Conjunct|MoreConjuncts])) -->
  282	en(Conjunct),
  283	disjunct_tail(MoreConjuncts),!,
  284	closing_parenthesis.
  285
  286disjunct((+,[Conjunct|MoreConjuncts])) -->
  287	content(Conjunct),
  288	disjunct_tail(MoreConjuncts).
  289
  290
  291en(Content) -->
  292	"not",
  293	opening_parenthesis,
  294	content(Content).
  295
  296
  297/*disjunct([Conjunct|MoreConjuncts]) --> %% Added MarcoG: let's extend the syntax!!!!
  298	atom(Conjunct),
  299	{writeln_debug(''), writeln_debug('*** Warning: atom in head ***')},
  300	disjunct_tail(MoreConjuncts).
  301disjunct([Conjunct|MoreConjuncts]) --> %% Added MarcoG: let's extend the syntax!!!!
  302	event(Conjunct),
  303	{writeln_debug(''), writeln_debug('*** Warning: H in head ***'), nl},
  304	disjunct_tail(MoreConjuncts).
  305disjunct([Conjunct|MoreConjuncts]) --> %% Added MarcoG: let's extend the syntax!!!!
  306	relat(Conjunct),
  307	disjunct_tail(MoreConjuncts).
  308*/
  309disjunct_tail([Conjunct|MoreConjuncts]) -->
  310	and_symbol,
  311	head_conjunct(Conjunct),
  312	!,
  313	disjunct_tail(MoreConjuncts).
  314disjunct_tail([]) -->
  315	[].
  316disjunct_tail(_) -->
  317    comma,
  318    {nl, write('*** Error in conjunct: comma instead of /\\ symbol?'), fail}.
  319
  320head_conjunct(Conjunct) -->
  321	abducible(Conjunct).
  322head_conjunct(Conjunct) -->
  323	atom(Conjunct).
  324head_conjunct(Conjunct) -->
  325	relat(Conjunct).
  326
  327atom(Atom) -->
  328	funct(Functor),
  329	opening_parenthesis,
  330	!,
  331	term_list(Arguments),
  332	closing_parenthesis,
  333	{Atom=..[Functor|Arguments]}.
  334
  335
  336
  337abducible(Abducible) -->
  338	abducible_functor(Functor),
  339	opening_parenthesis,
  340	content(Content),
  341	closing_parenthesis,
  342	{Abducible=..[Functor,Content]}.
  343
  344event(Event) -->
  345	event_functor(hap),
  346	opening_parenthesis,
  347	content(Content),
  348	comma,
  349	time(Time),
  350	closing_parenthesis,
  351	{Event=..[hap,Content,Time]}.
  352
  353event((\+ Event)) -->
  354	event_functor(noth),
  355	opening_parenthesis,
  356	content(Content),
  357	comma,
  358	time(Time),
  359	closing_parenthesis,
  360	{Event=..[hap,Content,Time]}.
  361
  362
  363abducible_functor(e) -->
  364	"E".
  365abducible_functor(en) -->
  366	"EN".
  367abducible_functor(note) -->
  368	"!E".
  369abducible_functor(noten) -->
  370	"!EN".
  371abducible_functor(abd) -->
  372	"ABD".
  373		  
  374event_functor(hap) -->
  375	"hap".
  376event_functor(noth) -->
  377	"!hap".
  378
  379
  380content(Content) -->
  381	term(Content).
  382
  383
  384
  385
  386
  387			 
  388
  389	
  390
  391
  392
  393
  394or_symbol -->
  395	"\\/".
  396and_symbol -->
  397	"/\\".	
  398
  399impl_symbol -->
  400	"--->".
  401
  402
  403
  404
  405
  406
  407write_ics_to_file(FileName,ICList):-
  408	open(FileName,write,Stream),
  409	write_ics_to_stream(ICList,Stream),
  410	close(Stream).
  411
  412write_ics_to_stream([],_).
  413write_ics_to_stream([IC|MoreICs],Stream):-
  414	write_ic_to_stream(IC,Stream),
  415	write_ics_to_stream(MoreICs,Stream).
  416
  417write_ic_to_stream(ic(Body,Head),Stream):-
  418	write(Stream,'ics('),
  419	write(Stream,Body),write(Stream,','),
  420	nl(Stream),
  421	spaces(Stream),
  422	write(Stream,'['),
  423	write_head_to_stream(Head,Stream),
  424	write(Stream,']).'),
  425	nl(Stream),
  426	nl(Stream).
  427
  428write_head_to_stream([Disjunct],Stream):-
  429	write(Stream,Disjunct).
  430write_head_to_stream([Disjunct1,Disjunct2|MoreDisjuncts],Stream):-
  431	write(Stream,Disjunct1),
  432	write(Stream,','),
  433	nl(Stream),
  434	spaces(Stream),
  435	write_head_to_stream([Disjunct2|MoreDisjuncts],Stream).
  436	
  437		     
  438spaces(Stream):-
  439	write(Stream,'        ').
  440
  441
  442	
  443
  444add_var([],[]).
  445
  446add_var([rule(C,S,P)|T],[rule(CV,S,P)|TV]):-
  447  add_var_ic(C,CV),
  448  add_var(T,TV).
  449
  450add_var_ic(((H,HL):-(B,BL)),((HV,HL):-(BV,BL))):-
  451  collect_vars([H,B],[],VA),
  452  length(VA,N),
  453  length(V,N),
  454  replace_vars([H,B],[HV,BV],VA,V).
  455
  456replace_vars([],[],_VA,_V).
  457  
  458replace_vars([A|T],[Var|T1],VA,V):-
  459  atomic(A),
  460  nth1(N, VA, A),!,
  461  nth1(N,V,Var),
  462  replace_vars(T,T1,VA,V).
  463
  464replace_vars([A|T],[A|T1],VA,V):-
  465  (atomic(A);var(A)),!,
  466  replace_vars(T,T1,VA,V).
  467
  468replace_vars([A|T],[AV|T1],VA,V):-
  469  A=..[F|Args],
  470  replace_vars(Args,ArgsV,VA,V),
  471  AV=..[F|ArgsV],
  472  replace_vars(T,T1,VA,V).
  473
  474
  475
  476collect_vars([],V,V).
  477  
  478collect_vars([A|T],VIn,VOut):-
  479  atomic(A),
  480  \+number(A),
  481  A\=[],
  482  atom_codes(A,AC),
  483  is_var(AC),!,
  484  (member(A,VIn)->
  485    V1=VIn
  486  ;
  487    V1=[A|VIn]
  488  ),
  489  collect_vars(T,V1,VOut).
  490
  491collect_vars([A|T],VIn,VOut):-
  492  (atomic(A);var(A);number(A)),!,
  493  collect_vars(T,VIn,VOut).
  494
  495collect_vars([A|T],VIn,VOut):-
  496  A=..[_F|Args],
  497  collect_vars(Args,VIn,V1),
  498  collect_vars(T,V1,VOut).
  499
  500is_var([H|_T]):-
  501  (H>=65,
  502  H=<90);
  503  H=95