Is there any way to seek through string ports? When I try to use input-port-byte-position I get this:
(call-with-input-string "asdf" (either (char/exactly #\c) (char/exactly #\s)))
*** ERROR IN #<procedure #10>, "tcv-gambit-parse.scm"@66.20 -- (Argument 1) Device INPUT PORT expected (input-port-byte-position '#<input-port #11 (string)>)
(I'm doubtful that input-port-byte-position would be what I want anyway if the string included characters that weren't encoded as single bytes, but that's a digression.)
I'm trying to write a parser combinator library, and part of that entails some rewinding of streams for ordered-choice operations (as illustrated above). A potential alternative would be to duplicate the port's contents and use a different port for each alternative, but I am not aware of any API to do this either. Any ideas on how to accomplish this objective? I need something that works for at least string ports and device ports.
My current code, for background:
(define char/exactly (lambda (c) (lambda (stream) (let ((char (read-char stream))) (cond ((eof-object? char) #f) ((not (char=? char c)) #f) (else char))))))
(define either (lambda combinators (lambda (stream) (let loop ((c combinators)) (cond ((null? c) #f) ((apply (car c) (list stream)) #t) (else (loop (cdr c))))))))
As defined here, the either function will not undo the changes done by char/exactly (in the example above), thus each choice will advance the stream by one character. We could work around it here by using peek-char rather than read-char but that wouldn't scale to when either is used on functions that read large chunks of data before failing.
Thanks for any ideas,
Afficher les réponses par date
On 11-Jun-09, at 11:11 PM, Taylor Venable wrote:
Is there any way to seek through string ports? When I try to use input-port-byte-position I get this:
(call-with-input-string "asdf" (either (char/exactly #\c) (char/ exactly #\s)))
*** ERROR IN #<procedure #10>, "tcv-gambit-parse.scm"@66.20 -- (Argument 1) Device INPUT PORT expected (input-port-byte-position '#<input-port #11 (string)>)
(I'm doubtful that input-port-byte-position would be what I want anyway if the string included characters that weren't encoded as single bytes, but that's a digression.)
String ports are implemented in such a way that the consumed part of the string is garbage collected. A repositioning operation can't be implemented without losing this important feature.
I'm trying to write a parser combinator library, and part of that entails some rewinding of streams for ordered-choice operations (as illustrated above). A potential alternative would be to duplicate the port's contents and use a different port for each alternative, but I am not aware of any API to do this either. Any ideas on how to accomplish this objective? I need something that works for at least string ports and device ports.
How about:
(define (my-open-input-string str) (cons str 0))
(define (my-read-char p) (let ((str (car p)) (pos (cdr p))) (if (< pos (string-length str))) (begin (set-cdr! p (+ pos 1)) (string-ref str pos)) '#!eof)))
(define (my-input-port-position-set! p pos) (set-cdr! p pos))
Marc
2009/6/12 Taylor Venable taylor@metasyntax.net:
I'm trying to write a parser combinator library, and part of that entails some rewinding of streams for ordered-choice operations (as illustrated above). A potential alternative would be to duplicate the port's contents and use a different port for each alternative, but I am not aware of any API to do this either. Any ideas on how to accomplish this objective?
I realize this is not what you are looking for, but when I hit this kind of problem in the lisp world, I found that life became much simpler by using a list of chars than by using string-ports (or ports of any kind for that matter). Yes it's expensive in terms of memory, but it's not that often that you need to keep the original full text very far into the computation...
david rush
On Fri, Jun 12, 2009 at 08:12:48AM +0100, David Rush wrote:
2009/6/12 Taylor Venable taylor@metasyntax.net:
I'm trying to write a parser combinator library, and part of that entails some rewinding of streams for ordered-choice operations (as illustrated above). ?A potential alternative would be to duplicate the port's contents and use a different port for each alternative, but I am not aware of any API to do this either. ?Any ideas on how to accomplish this objective?
I realize this is not what you are looking for, but when I hit this kind of problem in the lisp world, I found that life became much simpler by using a list of chars than by using string-ports (or ports of any kind for that matter). Yes it's expensive in terms of memory, but it's not that often that you need to keep the original full text very far into the computation...
Thanks for the idea; I hadn't thought of that one yet. I implemented it and it's working well for small things, so I think I'll implement a backend to fill a char list buffer from a port source, and let the functions that need to back-track (e.g. choice) decide when they can empty the buffer (e.g. on success of a child, for choice).
I'll have to examine the various stream implementations that have been proposed as well. Thanks to all for the pointers and advice.
It is convenient to use streams, which admit persistent updates, rather than ports, to which updates are destructive. For example, http://mumble.net/~campbell/darcs/parscheme/.