prolog read from file throws error on special characters - prolog

I am working in Prolog, and am trying to read in from a file. The first line is a password. With the password, I want to be able to use special characters.
Here is the read file code:
readfile(Filename):-
open(Filename, read, Str),
read(Str, Thepassword),
read(Str, Thefirewall),
close(Str),
nb_setval(password, Thepassword),
nb_setval(firewall, Thefirewall).
This works fine until I change the password from brittany to britta!y, then I get ERROR: computer1.txt:1: Syntax error: Operator expected.
Anyone know what I should do?

read/2 reads Prolog terms. What you probably want is to read the whole line regardless it is in Prolog syntax or not.
In SWI Prolog you can use the predicate read_line_to_codes/2 instead. (See the SWI manual entry). You must include the library with use_module(library(readutil)) first.
SICStus has a similar predicate called read_line/1/2.
If you need an atom instead of a list of codes, you can convert it with atom_codes/2.

Related

How to check that a string contains only certain characters in Prolog?

I want to write a predicate containsOnly(X,Y), which returns true, if string X contains only characters from string Y.
I wrote it this way:
containsOnly([],_).
containsOnly([H|T],AcceptableCharacters) :-
member(H, AcceptableCharacters),
containsOnly(T,AcceptableCharacters).
But the queries below return false. How can I modify the predicate in order for them to return true?
containsOnly('A', 'ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜabcdefghijklmnopqrstuvwxyzäöüАБВГДЕЁЖЗИКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдеёжзиклмнопрстуфхцчшщъыьэюя-').
containsOnly('a', 'ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜabcdefghijklmnopqrstuvwxyzäöüАБВГДЕЁЖЗИКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдеёжзиклмнопрстуфхцчшщъыьэюя-').
working with atoms, as in your question, an ISO compliant solution:
containsOnly(X,Y) :- forall(sub_atom(X,_,1,_,C), sub_atom(Y,_,1,_,C)).
while SWI-Prolog ver. >= 7 seems to accept it for 'strings' also.
Your problem is the datatype. You use atoms, but you treat them as char/code lists. You can try use double quotes " instead of single quotes ' and see if this helps.
With SWI-Prolog 7 or later, it won't help. You would have to use backticks instead of double quotes.
You really should figure out the documentation and the datatypes though.
This is a list of codes in SWI-Prolog 7:
`абвгд`
And 0'x is Prolog notation for character codes:
?- X = 0'г.
X = 1075.
?- X = `абв`.
X = [1072, 1073, 1074].
Another thing: if you are using SWI-Prolog, you should use memberchk/2 instead of member/2 in this particular case. If this is an efficiency bottleneck, however, you might also consider using the method described at the very bottom of this page. (This whole section of the manual is very important if you are going to be dealing with text in your SWI-Prolog program.)

ANSI escape characters in gprolog

Trying to print bold and underlined text in prolog but can't write them
write('\033[1mbold\033[0m')
Makes this (expected) error:
syntax error: \ expected in \constant\ sequence
What's the correct way to do it with gprolog ? Maybe with format ?
write('\33\[1mbold\33\[0m').
That is, octal escape sequences (and hexadecimal which start with \x) need to be closed with a \ too. En revanche, a leading zero is not required, but possible. This is in no way specific to GNU, in fact, probably all systems close to ISO Prolog have it.

Prolog reassigning operators

I'm new to prolog and I'm trying to reassign operators in prolog by changing their precedence. I'm running into 4 errors for the following:
:-op(1000,yf,+). %unary plus%
:-op(1000,yf,-). %unary minus%
:-op(750,yfx,"%"). %modulo%
The first two give me a similar error that goes like this:
warning: directive failed (op(1000,xf,+)) with exception (error(permission_error(create,operator,+),op/3))
I also get an error with the modulo one (a different error), but I suspect it's because I'm not supposed to enclose % in quotes (but how am I supposed to differentiate it from a comment marker?).
I've redefined a bunch of other operators (such as the addition operator :-op(500,yfx,+).) and they give me no problems. Only the 3 listed above give me errors.
Can anyone shed some light on this?
Thanks!
GNU Prolog documentation states that
An atom can have multiple operator definitions (e.g. prefix and infix like +) however an atom cannot have both an infix and a postfix operator definitions.
from here the errors on first two declaration. Then you should change the specifier to fy.
The modulo operator will need single quotes around.
You are attempting to define + as a postfix operator. However, + is also defined as an infix operator and the standard does not permit to define an operator both as postfix and infix. If you really want to do this you have to first undefine the infix operator using priority 0.
However, I can only recommend that you do not change standard operators like + or -. It's like you would change the operator precedence in C, C++, C#, Java, Perl, PHP, Javascript and the like: It would make your life as a programmer very, very miserable.
I cannot recommend to use % as operator in Prolog: % starts a comment. If you want to use it as an operator, you would have to write '%' quoted all the time. Prolog has already mod and rem defined as operators. Isn't that enough?
You are probably using GNU Prolog which is quite ISO conforming. Other Prologs permit you to define infix and postfix at the same time. See #237. But those other Prologs do a lot of things differently.
As a general remark: As a beginner, better stay away from changing the operator table. You really need to get used to the standard operators first. And with more experience you will most probably prefer to only add new operators with similar precedence than existing ones.
iso-prolog: ISO/IEC 13211-1:1995 6.3.4.3 Operators, last paragraph:
There shall not be an infix and a postfix operator with thesame name.

Using phrase_from_file to read a file's lines

I've been trying to parse a file containing lines of integers using phrase_from_file with the grammar rules
line --> I,line,{integer(I)}.
line --> ['\n'].
thusly: phrase_from_file(line,'input.txt').
It fails, and I got lost very quickly trying to trace it.
I've even tried to print I, but it doesn't even get there.
EDIT::
As none of the solutions below really fit my needs (using read/1 assumes you're reading terms, and sometimes writing that DCG might just take too long), I cannibalized this code I googled, the main changes being the addition of:
read_rest(-1,[]):-!.
read_word(C,[],C) :- ( C=32 ;
C=(-1)
) , !.
If you are using phrase_from_file/2 there is a very simple way to test your programs prior to reading actual files. Simply call the very same non-terminal with phrase/2. Thus, a goal
phrase(line,"1\n2").
is the same as calling
phrase_from_file(line,fichier)
when fichier is a file containing above 3 characters. So you can test and experiment in a very compact manner with phrase/2.
There are further issues #Jan Burse already mentioned. SWI reads in character codes. So you have to write
newline --> "\n".
for a newline. And then you still have to parse integers yourself. But all that is tested much easier with phrase/2. The nice thing is that you can then switch to reading files without changing the actual DCG code.
I guess there is a conceptional problem here. Although I don't know the details of phrase_from_file/2, i.e. which Prolog system you are using, I nevertheless assume that it will produce character codes. So for an integer 123 in the file you will get the character codes 0'1, 0'2 and 0'3. This is probably not what you want.
If you would like to process the characters, you would need to use a non-terminal instead of a bare bone variable I, to fetch them. And instead of the integer test, you would need a character test, and you can do the test earlier:
line --> [I], {0'0=<I, I=<0'9}, line.
Best Regards
P.S.: Instead of going the DCG way, you could also use term read operations. See also:
read numbers from file in prolog and sorting

how to display blackshashes in SWI-Prolog

I am trying to display a network share path in my Prolog output code.
The path is like :
\\fileserver\path\to\file.txt (ex1)
or
\\\\fileserver\\path\\to\\file.txt (ex2)
but If I try displaying it using format :
pri(Z):-
format('Printing Zx : \"~w\"',[Z]).
the slashes get truncated to
\fileserverpathtofile.txt (ex1)
Obviously some times, the path may contain \\\\ in which case the display is correct.
How to make it print proper path?
Any help please.
Thanks.
In the Prolog atoms backslash is a meta-character, i.e. if you want your atom to contain a backslash character then you need to escape it using the backslash character. E.g. in order to represent the Windows path \\fileserver\path\to\file.txt as a Prolog atom you need to write
Path = '\\\\fileserver\\path\\to\\file.txt'.
In principle there are two ways of printing stuff out, one for the humans (pretty-printing), using write
?- Path = '\\\\fileserver\\path\\to\\file.txt', write(Path).
\\fileserver\path\to\file.txt
and one for the machines (serializing), using write_canonical
?- Path = '\\\\fileserver\\path\\to\\file.txt', write_canonical(Path).
'\\\\fileserver\\path\\to\\file.txt'
write_canonical makes sure that Prolog can read the output back into the same exact atom.
Your problem seems to be that you do not correctly represent the path in Prolog. If the path comes from an external source, you first need to escape it (add a backslash in front of every backslash) before you can store it as a Prolog atom.

Resources