5
votes

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)
                     ) , !.
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) ) , !. `moshewe
You are mixing characters and codes. Either stick to characters with set_prolog_flag(double_quotes, chars) or stick to codes (less recommended)false

2 Answers

5
votes

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.

4
votes

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