[comp.lang.prolog] end_of_file treatment in prolog

bimandre@kulcs.uucp (Andre Marien) (03/22/88)

article <783@cresswell.quintus.UUCP> Richard A. O'Keefe


> It is interesting that Marien and Demoen fell into exactly this trap.

Sorry for being inaccurate: we should have taken the trouble of explaining what
BIMprolog's predicate eof/0 does and it is different from what Richard's
at_eof/0 does:
eof/0 succeeds only after a read/1 or get0/1 has failed because end of
file was encountered
so, let me change buggy_read into:

        non_buggy_read(Term) :- bim_read(Term), ! .
        non_buggy_read(end_of_file) :- eof .

actually, eof/0 is written using a predicate in_status/1 which unifies
its argument with an integer indicating the 'status' of the input stream

> end-failure approach, despite having asked Bart Demoen at the Prolog
> Benchmarking Workshop for enlightenment on this point.  Again, this

Perhaps you asked Andre' Marien, but not Bart Demoen: he was not at the Prolog
Benchmarking Workshop

Now about the transformation of

        s1: a -> s2.
        s1: b -> s1.
        s1: $  -> accept.

to a prolog procedure;

1. the textbook uses an explicit end of file marker, so it is clear that the
   behavior of Cprolog's get0/1 suites better in this transformation;
   still, I would rather represent a state by a predicate with arity 0 and let
   it get its character itself:
   
        s1 :- get0(X) ,
        	(X = a , s2 ;
        	 X = b , s1 ;
        	 X = -1 , true
        	) .

      this of course with get0/1 behaving like in Cprolog

2. Now, do it with BIMprolog's get0/1, I will call it BIMget0 so that you will
   always know which behavior to expect

   s1 :- BIMget0(X) , (X = a , s2 ;
        	       X = b , s1
        	      ) .
   s1 :- eof .
   
   this doesn't look very nice, but
   
	a. I would expect that in a parser, in most states eof indicates an
	   error, so that error recovery must be done, which is very easy
	   (in prolog) by backtracking to the appropriate level (state) in the
	   parser; so in most states, there would be no clause like s1 :- eof.
	   then, on eof, s1 fails as it does on input characters different
	   from a or b

	   see Pascal : an endpoint is the endmarker, and occurrence of eof
	                    during tokenizing means an error
	   see Prolog : every clause must have an endpoint; eof could only
	                    occur after a clause

	b. prolog (at least BIMprolog) is used for other things than writing
	   tokenizers - actually, tokenizers should not be written at all: they
	   should be generated - and in an administrative application written in
	   prolog, using BIMread or BIMget, the programmer can feel at ease:
	   after a successful BIMread or BIMget, he has got data; it is in a
	   way impossible for him to forget testing for eof, because otherwise
	   the execution of the program would never have gone so far

3. A more general approach can be used, using a state transition table.
   The previous program can be derived from this by partial evaluation.
   In the triangle puzzle problem discussion, R.O'K argued that this
   approach is more general.

	step_state(accept) :- ! .
	step_state(From) :- BIMget0(X), !,
			From : X => New,
			step_state(New) .
	step_state(From) :- BIMeof,
			From : '$' => New,
			step_state(New) .

	s1: a => s2.
	s1: b => s1.
	s1: '$' => accept.

	If eof is to be treated as an error, remove the last clause of
	step_state/1.
	Eof is handled in one place, in Cprolog one should add :

		transit(si,-1,error) .

	for all states, or write :

		state(From) :-	get0(X), noteof(X), !,
				transit(From,X,New),
				state(New) .

		noteof(-1) :- !, fail .
		noteof(_) .
 
To sum up: there is an appropriate level of testing for eof: BIMread and BIMget
(and BSIread and BSIget for that matter, to answer one of Richard's questions
and worries) allow you to do this testing of eof at these levels only, while
read and get0 of Cprolog force you to test it after every input operation


Andre' Marien
B.I.M.
bimandre@kulcs

Bart Demoen
K.U.Leuven
bimbart@kulcs