:- module(pio, [ phrase_from_file/2, % :Grammarbody, +File phrase_of_from_file/3 % :Grammarbody, :Reader(Stream, Xs0,Xs), +File ], [hidden(true)]). /** Pure, phrase based, Prolog I/O This library provides side effect free I/O. Files can be processed in a pure side effect free manner with DCGs. Many Prolog predicates only read data from a file, those programs can be made side effect free. Recommended settings: :- set_prolog_flag(double_quotes, chars). @author Ulrich Neumerkel */ %% phrase_from_file(NT__0, +File) is nondet. % % == % ... --> [] | [_], ... . % ?- phrase_from_file((..., "searchstring", ...), myfile). :- meta_predicate phrase_from_file(2, +), phrase_of_from_file(2, 3, +). :- meta_predicate reader_to_lazy_list(3,+,?), reader_step(3,+,+,?). :- meta_predicate setup_call_cleanup(0, 0, 0). % N215 compatibility setup_call_cleanup( Setup_0, Call_0, Cleanup_0) :- once(Setup_0), call_cleanup(Call_0, once(Cleanup_0)). :- use_module(library(types),[must_be/4]). phrase_from_file(NT__0, File) :- current_prolog_flag(double_quotes, Value), ( Value == chars -> R_3 = get_pending_chars % recommended ; Value == codes -> R_3 = get_pending_codes % suboptimal ; must_be(Value, oneof([chars,codes]), phrase_from_file(NT__0, File), 0) ), phrase_of_from_file(NT__0, R_3, File). phrase_of_from_file(NT__0, R_3, File) :- setup_call_cleanup( open(File, read, Stream, [reposition(true)]), ( reader_to_lazy_list(R_3, Stream, Xs), phrase(NT__0, Xs) ), close(Stream) ). reader_to_lazy_list(R_3, Stream, Xs) :- stream_property(Stream, position(Pos)), freeze(Xs, reader_step(R_3, Stream, Pos, Xs)). reader_step(R_3, Stream, Pos, Xs0) :- set_stream_position(Stream, Pos), ( at_end_of_stream(Stream) -> Xs0 = [] ; % phrase(call(call(R_3,Stream)), Xs0,Xs), % conforming call call(R_3, Stream, Xs0,Xs), % effective call reader_to_lazy_list(R_3, Stream, Xs) ). :- if(( predicate_property(prolog:get_pending_chars(_,_,_),built_in), predicate_property(prolog:get_pending_codes(_,_,_),built_in) )). get_pending_chars(Stream, Chs0,Chs) :- prolog:get_pending_chars(Stream, Chs0,Chs). get_pending_codes(Stream, Cos0,Cos) :- prolog:get_pending_codes(Stream, Cos0,Cos). :- else. get_pending_chars(Stream, Chs0,Chs) :- n_get_chars(4096, Stream, Chs, Chs0,Chs). get_pending_codes(Stream, Cos0,Cos) :- n_get_codes(4096, Stream, Cos, Cos0,Cos). % n_get_chars/5 and n_get_codes/5 should be provided as built-ins with % a blocking semantics similar to SWI's read_pending_input/3 % EOF means: If EOF == [], then EOF has definitely been reached, otherwise % it is unknown and the argument remains uninstantiated. n_get_chars(N0, Stream, EOF, Chs0,Chs) :- N0 > 0, N1 is N0-1, get_char(Stream, Ch), ( Ch == end_of_file -> Chs0 = Chs, EOF = [] ; Chs0 = [Ch|Chs1], n_get_chars(N1, Stream, EOF, Chs1,Chs) ). n_get_chars(0, _, _, Chs,Chs). n_get_codes(N0, Stream, EOF, Cos0,Cos) :- N0 > 0, N1 is N0-1, get_code(Stream, Co), ( Co == -1 -> Cos0 = Cos ; Cos0 = [Co|Cos1], n_get_codes(N1, Stream, EOF, Cos1,Cos) ). n_get_codes(0, _, _, Cos,Cos). :- endif.