1:-module(parser_utils,
    2	 [read_file_to_string/2,
    3	 atomic_constant_list/3,
    4	 atomic_constant/3,
    5	 elementList/3, %PAY ATTENTION: HERE THE ORIGINAL PRED IS /1, BUT SINCE IT'S DCG, IT BECOMES /3 !!!
    6	 drop_whites/2,
    7	 drop_comments/2,
    8	 opening_parenthesis/2,
    9	 term/3,
   10	 term_list/3,
   11	 comma/2,
   12	 time/3,
   13	 closing_parenthesis/2,
   14	 funct/3,
   15	 number/3,
   16	 variable/3,
   17	 full_stop/2,
   18     integer/3,
   19     signed_int/3,
   20     alphanumeric_string/3]).   21
   22
   23:-use_module(library(lists)).   24%	     [append/3,
   25%	      member/2, memberchk/2]).
   26
   27% If the path is a URL, then download the file
   28read_file_to_string(Path,String):-
   29    atom_concat('http://',_,Path),!,
   30    ensure_loaded(library(pillow)), % load the library only if needed
   31    url_info(Path,Info),
   32    fetch_url(Info,[],Response),
   33    
   34    memberchk(status(Type,Code,Message),Response),
   35    (Type = success
   36        -> memberchk(content(String),Response)
   37        ;  write(Type), write(' '), write(Code), write(': '), print_resp(Message), nl, fail
   38    ).
   39% Otherwise, if the file is local, open it
   40read_file_to_string(File,String):-
   41	open(File,read,Stream),
   42	%write('Open OK'),nl,
   43	read_stream_to_string(Stream,String),
   44	close(Stream).
   45
   46print_resp([]):-!.
   47print_resp([C|S]):- !,format('~s',[[C]]), print_resp(S).
   48
   49
   50
   51read_stream_to_string(Stream,[]):-
   52	at_end_of_stream(Stream),
   53	!.
   54read_stream_to_string(Stream,[C|T]):-
   55	get_code(Stream,C),
   56	read_stream_to_string(Stream,T).
   57
   58drop_whites([],[]).
   59drop_whites(Codes,NoWhiteCodes):-
   60	whites(Codes,MoreCodes),
   61	!,
   62	drop_whites(MoreCodes,NoWhiteCodes).
   63drop_whites([Code|MoreCodes],[Code|MoreNoWhiteCodes]):-
   64	drop_whites(MoreCodes,MoreNoWhiteCodes).
   65
   66
   67full_stop -->
   68	".".
   69comma -->
   70	",".
   71opening_parenthesis -->
   72	"(".
   73closing_parenthesis -->
   74	")".
   75
   76whites(Codes,MoreCodes):-
   77	white_codes(WhiteCodes),
   78	append(WhiteCodes,MoreCodes,Codes).
   79
   80white_codes(WhiteCodes):-
   81	white_atom(Atom),
   82	atom_codes(Atom,WhiteCodes).
   83white_codes([13]).
   84white_codes([-1]). % Sometimes in Linux the end-of-file has code -1
   85	
   86white_atom(' ').
   87white_atom('\t').
   88white_atom('\n').
   89
   90funct(Functor) -->
   91	atomic_constant(Functor),
   92	!.
   93funct(',')-->
   94	"".
   95
   96atomic_constant(Const) -->
   97	lowercase(LowerCase),
   98	alphanumeric_string_tail(Alpha),
   99	{atom_codes(Const,[LowerCase|Alpha])}.
  100atomic_constant(Const) -->
  101	"'",
  102	any_char_tail(Alpha),
  103	"'",
  104	{
  105		char_code('\'', A),
  106		append(Alpha, [A], L1),
  107		append([A], L1, L2),
  108		atom_codes(Const,L2)
  109	}.
  110	
  111any_char_tail(String) -->
  112	any_char(String),
  113	!.
  114any_char_tail([]) -->
  115	[].
  116any_char([Code|MoreCodes]) -->
  117	any_char_excluded_apice(Code),
  118	!,
  119	any_char_tail(MoreCodes).
  120
  121any_char_excluded_apice(Code) -->
  122	[Code],
  123	{
  124		char_code('\'', A),
  125		Code =\= A
  126	}.
  127
  128
  129
  130lowercase(C) -->
  131	[C],
  132	{char_code('a',A),
  133	 char_code('z',Z),
  134	 A =< C,
  135	 C =< Z}.
  136
  137uppercase(C) -->
  138	[C],
  139	{char_code('A',A),
  140	 char_code('Z',Z),
  141	 A =< C,
  142	 C =< Z}.
  143underscore(C) -->
  144	[C],
  145	{char_code('_',C)}.
  146
  147uppercase_or_underscore(C)-->
  148	uppercase(C),
  149	!.
  150uppercase_or_underscore(C)-->
  151	underscore(C).
  152
  153alphanumeric_string([Code|MoreCodes]) -->
  154	alphanumeric(Code),
  155	!,
  156	alphanumeric_string_tail(MoreCodes).
  157
  158alphanumeric_string_tail(String) -->
  159	alphanumeric_string(String),
  160	!.
  161alphanumeric_string_tail([]) -->
  162	[].
  163
  164alphanumeric(Code) -->
  165	lowercase(Code).
  166alphanumeric(Code) -->
  167	uppercase(Code).
  168alphanumeric(Code) -->
  169	digit(Code).
  170alphanumeric(Code) -->
  171	[Code],
  172	{char_code('_',Code)}.
  173
  174integer(Integer) -->
  175	digit_string(DigitString),
  176	{number_codes(Integer,DigitString)}.
  177signed_int(Integer) -->
  178    "+", integer(Integer).
  179signed_int(Integer) -->
  180    "-", integer(Neg),
  181    {Integer is 0-Neg}.
  182
  183digit_string([Digit|MoreDigits]) -->
  184	digit(Digit),
  185	!,
  186	digit_string_tail(MoreDigits).
  187
  188digit_string_tail(DigitStringTail) -->
  189	digit_string(DigitStringTail),
  190	!.
  191digit_string_tail([]) -->
  192	[].
  193
  194digit(Digit) -->
  195	[Digit],
  196	{char_code('0',Zero),
  197	 char_code('9',Nine),
  198	 Zero =< Digit,
  199	 Digit =< Nine}.
  200
  201float(Float) -->
  202	digit_string(DigitString1),
  203	".",
  204	digit_string(DigitString2),
  205	{char_code('.',FullStopCode),
  206	 append(DigitString1,[FullStopCode|DigitString2],DigitString),
  207	 number_codes(Float,DigitString)}.
  208
  209number(Number) -->
  210	float(Number),
  211	!.
  212number(Number) -->
  213	integer(Number).
  214
  215
  216term(Term) -->
  217	funct(Functor),
  218	opening_parenthesis,
  219	!,
  220	term_list(Arguments),
  221	closing_parenthesis,
  222	{Term=..[Functor|Arguments]}.
  223
  224
  225
  226term(TermList) -->
  227	"[",
  228	!,
  229	term_list(TermList),
  230	"]".
  231	
  232term(Term) -->
  233	constant(Term),
  234	!.
  235term(Term) -->
  236	variable(Term),
  237	!.
  238
  239term1(Term) -->
  240	term(Term).
  241term1(Term) -->
  242	unary_operator_term(Term).
  243term1(Term) -->
  244	binary_operator_term(Term).
  245
  246unary_operator_term(Term) -->
  247	oper(Operator),
  248	term(Term1),
  249	{concat_atoms(Operator,Term1,Term)}.
  250
  251binary_operator_term(Term) -->
  252	term(Term1),
  253	oper(Operator),
  254	term(Term2),
  255	{concat_atoms(Term1,Operator,Term3),
  256	concat_atoms(Term3,Term2,Term)}.
  257
  258term_list([Term|MoreTerms]) -->
  259	term1(Term),
  260	term_list_tail(MoreTerms).
  261term_list([]) -->
  262	[].
  263
  264term_list_tail(TermListTail) -->
  265	comma,
  266	!,
  267	term_list(TermListTail).
  268term_list_tail([]) -->
  269	[].
  270
  271atomic_constant_list([Const|MoreConsts]) -->
  272	atomic_constant(Const),
  273	!,
  274	atomic_constant_list(MoreConsts).
  275atomic_constant_list([]) -->
  276	[].
  277
  278
  279constant(Const) -->
  280	atomic_constant(Const).
  281constant(Const) -->
  282	number(Const).
  283
  284oper(Operator) -->
  285	{member(Operator,[+,-,*,/]),
  286	 atom_codes(Operator,Codes)},
  287	Codes.
  288	 
  289
  290time(Time) -->
  291	variable(Time).
  292time(Time) -->
  293	number(Time).
  294
  295
  296variable(Variable) -->
  297	uppercase_or_underscore(UpperCase),
  298	alphanumeric_string_tail(Alpha),
  299	{atom_codes(Variable,[UpperCase|Alpha])}.
  300
  301concat_atoms(A1,A2,A3) :-
  302	atomo_codes(A1,S1),
  303	atomo_codes(A2,S2),
  304	append(S1,S2,S3),
  305	atomo_codes(A3,S3).
  306
  307atomo_codes(A,S):-
  308	number(A),
  309	!,
  310	number_codes(A,S).
  311atomo_codes(A,S):-
  312	atom_codes(A,S).
  313
  314
  315
  316%----------------------------------------------------------
  317% COMMENTS DCG
  318%----------------------------------------------------------
  319drop_comments(InputList, OutputList) :-
  320	phrase(elementList(OutputList),InputList).
  321
  322
  323elementList(MoreElements) -->
  324	comment,
  325	!,
  326	elementList(MoreElements).
  327elementList([Element|MoreElements]) --> 
  328	anElement(Element),
  329	!,
  330	elementList(MoreElements).
  331elementList([]) -->
  332	[].
  333
  334anElement(Element) -->
  335	[Element].
  336
  337comment -->
  338	commentStarter_sl, !, commentContent_sl.
  339comment -->
  340	commentStarter_ml, commentContent_ml.
  341
  342
  343%%% Comments on single-line
  344
  345commentStarter_sl -->
  346	"//", !.
  347commentStarter_sl -->
  348	"%".
  349
  350commentContent_sl -->
  351	commentEnder_sl, !.
  352commentContent_sl -->
  353	[_], commentContent_sl.
  354
  355commentEnder_sl -->
  356	{atom_codes('\n', X)}, X.
  357
  358
  359%%% Comments on multi-lines...
  360
  361commentStarter_ml -->
  362	"/*".
  363
  364commentContent_ml -->
  365	commentEnder_ml, !.
  366commentContent_ml -->
  367	[_], commentContent_ml.
  368
  369commentEnder_ml -->
  370	"*/"