Next: parser logic operators, Up: parser logic [Index]
As first usage example, let’s see a simple parser using a full Scheme
string as argument and accepting lexemes being the empty string or
strings of characters ‘#\a’ and ‘\#b’; the result of a call to
the parser is the list of characters or #f
if the input is
invalid:
#!r6rs (import (vicare) (vicare parser-logic)) (module (parse-abba) (define (parse-abba input-string) (assert (string? input-string)) (%parse-string input-string (string-length input-string) 0 ;start index '() ;start value for ACCUMULATOR )) (define-parser-logic define-string->abba-parser ch next fail (%parse-string (accumulator) ((:end-of-input) (reverse accumulator)) ((#\a #\b) (next %parse-string (cons ch accumulator))))) (define-string->abba-parser string->token-or-false (%parse-string)) #| end of module |# ) (parse-abba "") ⇒ () (parse-abba "a") ⇒ (#\a) (parse-abba "b") ⇒ (#\b) (parse-abba "1") ⇒ #f) (parse-abba "ciao") ⇒ #f) (parse-abba "abb") ⇒ (#\a #\b #\b)
notice the use of next
to recursively tail–call
parse-string
.
The macro string->token-or-false
is exported by (vicare
parser-logic)
; it implements the device logic for a full input Scheme
string representing a lexeme; it is to be used in a parser returning
#f
when the input is invalid.
The macros in the module combine their output and expand to the
definition of a function %parse-string
equivalent to the
following:
(define (%parse-string input.string input.length input.index accumulator) (if (fx=? input.index input.length) (reverse accumulator) (let ((ch (string-ref input.string input.index))) (cond ((or (char=? #\a ch) (char=? #\b ch)) (%parse-string input.string input.length (fx+ 1 input.index) (cons ch accumulator))) (else #f)))))
Let’s see a parser using a full Scheme string as argument and accepting lexemes being the empty string or strings of characters ‘#\a’ and ‘\#b’:
the result of a call to the parser is the list of characters or #f
if the input is invalid:
#!r6rs (import (vicare) (vicare parser-logic)) (module (parse-abab) (define (parse-abab input-string) (assert (string? input-string)) (%parse-string input-string (string-length input-string) 0 ;start index '() ;start value for ACCUMULATOR )) ;;Parser logic to convert a string of intermixed ;;#\a and #\b into a list of characters. (define-parser-logic define-string->abab-parser ch next fail (%parse-string (accumulator) ((:end-of-input) (reverse accumulator)) ((#\a #\b) (if (or (null? accumulator) (case ch ((#\a) (char=? #\b (car accumulator))) ((#\b) (char=? #\a (car accumulator))))) (next %parse-string (cons ch accumulator)) (fail))))) ;;Actual parser drawing characters from an input string. (define-string->abab-parser string->token-or-false (%parse-string)) #| end of module |# ) (parse-abab "") ⇒ () (parse-abab "a") ⇒ (#\a) (parse-abab "b") ⇒ (#\b) (parse-abab "1") ⇒ #f (parse-abab "ciao") ⇒ #f (parse-abab "abb") ⇒ #f (parse-abab "baa") ⇒ #f (parse-abab "abab") ⇒ (#\a #\b #\a #\b) (parse-abab "baba") ⇒ (#\b #\a #\b #\a)
notice the use of fail
to signal an input error from inside an
operator clause.
The macros in the module combine their output and expand to the
definition of a function %parse-string
equivalent to the
following:
(define (%parse-string input.string input.length input.index accumulator) (if (fx=? input.index input.length) (reverse accumulator) (let ((ch (string-ref input.string input.index))) (cond ((or (char=? #\a ch) (char=? #\b ch)) (if (or (null? accumulator) (case ch ((#\a) (char=? #\b (car accumulator))) ((#\b) (char=? #\a (car accumulator))))) (%parse-string input.string input.length (fx+ 1 input.index) (cons ch accumulator)) #f)) (else #f)))))
Let’s see a parser using a full Scheme string as argument and accepting
lexemes representing exact integers in base 10; the result of a
call to the parser is the exact integer object or #f
if the input
is invalid:
#!r6rs (import (vicare) (vicare parser-logic)) (define (parse-integer input-string) (define (%digit ch) ;;Given a character argument: return the corresponding ;;fixnum if the character is between #\0 and #\9, else ;;return false. ;; (let ((N (fx- (char->integer ch) (char->integer #\0)))) (and (fx>= N 0) (fx< N 10) N))) ;;Parser logic to convert a string into an exact integer ;;in base 10. (define-parser-logic define-string->integer-parser ch next fail (%parse-integer () ((%digit) => D (next %parse-digit+ D))) (%parse-digit+ (accumulator) ((:end-of-input) accumulator) ((%digit) => D (next %parse-digit+ (+ D (* 10 accumulator)))))) ;;Actual parser drawing characters from an input string. (define-string->integer-parser string->token-or-false (%parse-integer)) (assert (string? input-string)) (%parse-integer input-string (string-length input-string) 0)) (parse-integer "") ⇒ #f (parse-integer "1") ⇒ 1 (parse-integer "123") ⇒ 123 (parse-integer "ciao") ⇒ #f (parse-integer "123ciao") ⇒ #f
The macros in the body of parse-integer
combine their output and
expand to the definition of two functions %parse-integer
and
%parse-digit+
equivalent to the following:
(define (%parse-integer input.string input.length input.index) (if (fx=? input.index input.length) #f (let ((ch (string-ref input.string input.index))) (cond ((%digit ch) => (lambda (D) (%parse-digit+ input.string input.length (fx+ 1 input.index) D))) (else #f))))) (define (%parse-digit+ input.string input.length input.index accumulator) (if (fx=? input.index input.length) accumulator (let ((ch (string-ref input.string input.index))) (cond ((%digit ch) => (lambda (D) (%parse-digit+ input.string input.length (fx+ 1 input.index) (+ D (* 10 accumulator))))) (else #f)))))
Next: parser logic operators, Up: parser logic [Index]