Using phrase_from_file to read a file's lines
Asked Answered
S

2

5

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)
                     ) , !.
Somme answered 26/7, 2011 at 9:6 Comment(2)
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) ) , !. `Somme
You are mixing characters and codes. Either stick to characters with set_prolog_flag(double_quotes, chars) or stick to codes (less recommended)Pungent
G
4

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

Guile answered 26/7, 2011 at 10:8 Comment(2)
I'm using SWI-prolog (tagged it as such). I thought I was reading terms rather than just character codes, you're right. The reason I've went the DCG way is because I didn't want to parse individual terms, but it seems to be simpler - all in all - than the DCG.Somme
I'm no expert (using this question to learn, in fact!). I did find adding a newline clause above got the DCG to read multiple lines. {0'0=<I, I=<0'9}, '\n', line, where ' are backticks.Zahn
P
5

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.

Pungent answered 26/7, 2011 at 12:11 Comment(1)
I figured out I can use phrase/2, but I was further confounded thinking I was reading terms rather than character codes. The reference manual can be a bit cryptic sometimes. Thanks!Somme
G
4

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

Guile answered 26/7, 2011 at 10:8 Comment(2)
I'm using SWI-prolog (tagged it as such). I thought I was reading terms rather than just character codes, you're right. The reason I've went the DCG way is because I didn't want to parse individual terms, but it seems to be simpler - all in all - than the DCG.Somme
I'm no expert (using this question to learn, in fact!). I did find adding a newline clause above got the DCG to read multiple lines. {0'0=<I, I=<0'9}, '\n', line, where ' are backticks.Zahn

© 2022 - 2024 — McMap. All rights reserved.