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)
                     ) , !.
false
  • 10,264
  • 13
  • 101
  • 209
moshewe
  • 127
  • 1
  • 9
  • 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](http://www.csupomona.edu/~jrfisher/www/prolog_tutorial/read_linepl.txt) code I googled, the main changes being the addition of: ` read_rest(-1,[]):-!. read_word(C,[],C) :- ( C=32 ; C=(-1) ) , !. ` – moshewe Jul 27 '11 at 21:32
  • You are mixing characters and codes. Either stick to characters with `set_prolog_flag(double_quotes, chars)` or stick to codes (less recommended) – false Apr 23 '16 at 18:59

2 Answers2

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.

false
  • 10,264
  • 13
  • 101
  • 209
  • 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! – moshewe Jul 26 '11 at 20:26
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

Community
  • 1
  • 1
  • 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. – moshewe Jul 26 '11 at 20:17
  • 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= – kwutchak Apr 07 '20 at 22:51