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]