ikarus/benchmarks/rnrs-benchmarks/parsing.ss

955 lines
29 KiB
Scheme

; Hacked to change error to fatal-error.
; (One of the benchmarked systems has a problem with calls to error.)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Parsing benchmark.
;
; Reads nboyer.sch into a string before timing begins.
;
; The timed portion of the benchmark parses the string
; representation of nboyer.sch 1000 times.
;
; The output of that parse is checked by comparing it
; the the value returned by the read procedure.
;
; Usage:
; (parsing-benchmark n input)
;
; n defaults to 1000, and input defaults to "nboyer.sch".
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(library (rnrs-benchmarks parsing)
(export main)
(import (rnrs) (rnrs mutable-strings) (rnrs-benchmarks))
(define (parsing-benchmark . rest)
(let* ((n (if (null? rest) 1000 (car rest)))
(input (if (or (null? rest) (null? (cdr rest)))
"nboyer.sch"
(cadr rest)))
(input-string (read-file-as-string input))
(answer (call-with-input-file
input
(lambda (in)
(do ((x (read in) (read in))
(answer '() x))
((eof-object? x)
answer)))))
(benchmark-name
(string-append "parsing:" input ":" (number->string n))))
(run-benchmark benchmark-name
n
(lambda (x) (equal? x answer))
(lambda (input-string)
(lambda () (parse-string input-string)))
input-string)))
(define (read-from-string-port-benchmark . rest)
(let* ((n (if (null? rest) 1000 (car rest)))
(input (if (or (null? rest) (null? (cdr rest)))
"nboyer.sch"
(cadr rest)))
(input-string (read-file-as-string input))
(answer (call-with-input-file
input
(lambda (in)
(do ((x (read in) (read in))
(answer '() x))
((eof-object? x)
answer)))))
(benchmark-name
(string-append "reading:" input ":" (number->string n))))
(run-benchmark benchmark-name
n
(lambda ()
(let ((in (open-string-input-port input-string)))
(do ((x (read in) (read in))
(y #f x))
((eof-object? x) y))))
(lambda (x) (equal? x answer)))))
(define (read-file-as-string name)
(call-with-input-file
name
(lambda (in)
(do ((x (read-char in) (read-char in))
(chars '() (cons x chars)))
((eof-object? x)
(list->string (reverse chars)))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; The parser used for benchmarking.
;
; Given a string containing Scheme code, parses the entire
; string and returns the last <datum> read from the string.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (parse-string input-string)
; Constants and local variables.
(let* (; Constants.
; Any character that doesn't appear within nboyer.sch
; (or the input file, if different) can be used to
; represent end-of-file.
(eof #\~)
; length of longest token allowed
; (this allows static allocation in C)
(max_token_size 1024)
; Encodings of error messages.
(errLongToken 1) ; extremely long token
(errincompletetoken 2) ; any lexical error, really
(errLexGenBug 3) ; can't happen
; State for one-token buffering in lexical analyzer.
(kindOfNextToken 'z1) ; valid iff nextTokenIsReady
(nextTokenIsReady #f)
(tokenValue "") ; string associated with current token
(totalErrors 0) ; errors so far
(lineNumber 1) ; rudimentary source code location
(lineNumberOfLastError 0) ; ditto
; A string buffer for the characters of the current token.
(string_accumulator (make-string max_token_size))
; Number of characters in string_accumulator.
(string_accumulator_length 0)
; A single character of buffering.
; nextCharacter is valid iff nextCharacterIsReady
(nextCharacter #\space)
(nextCharacterIsReady #f)
; Index of next character to be read from input-string.
(input-index 0)
(input-length (string-length input-string))
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; LexGen generated the code for the state machine.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (scanner0)
(let loop ((c (scanchar)))
(if (char-whitespace? c)
(begin
(consumechar)
(set! string_accumulator_length 0)
(loop (scanchar)))))
(let ((c (scanchar)))
(if (char=? c eof) (accept 'eof) (state0 c))))
(define (state0 c)
(case c
((#\`) (consumechar) (accept 'backquote))
((#\') (consumechar) (accept 'quote))
((#\)) (consumechar) (accept 'rparen))
((#\() (consumechar) (accept 'lparen))
((#\;) (consumechar) (state29 (scanchar)))
((#\+ #\-) (consumechar) (state28 (scanchar)))
((#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9)
(consumechar)
(state27 (scanchar)))
((#\.) (consumechar) (state16 (scanchar)))
((#\a
#\b
#\c
#\d
#\e
#\f
#\g
#\h
#\i
#\j
#\k
#\l
#\m
#\n
#\o
#\p
#\q
#\r
#\s
#\t
#\u
#\v
#\w
#\x
#\y
#\z
#\A
#\B
#\C
#\D
#\E
#\F
#\G
#\H
#\I
#\J
#\K
#\L
#\M
#\N
#\O
#\P
#\Q
#\R
#\S
#\T
#\U
#\V
#\W
#\X
#\Y
#\Z
#\!
#\$
#\%
#\&
#\*
#\/
#\:
#\<
#\=
#\>
#\?
#\^
#\_
#\~)
(consumechar)
(state14 (scanchar)))
((#\#) (consumechar) (state13 (scanchar)))
((#\") (consumechar) (state2 (scanchar)))
((#\,) (consumechar) (state1 (scanchar)))
(else
(if (char-whitespace? c)
(begin (consumechar) (state30 (scanchar)))
(scannererror errincompletetoken)))))
(define (state1 c)
(case c
((#\@) (consumechar) (accept 'splicing))
(else (accept 'comma))))
(define (state2 c)
(case c
((#\") (consumechar) (accept 'string))
(else
(if (isnotdoublequote? c)
(begin (consumechar) (state2 (scanchar)))
(scannererror errincompletetoken)))))
(define (state3 c)
(case c
((#\n) (consumechar) (state8 (scanchar)))
(else (scannererror errincompletetoken))))
(define (state4 c)
(case c
((#\i) (consumechar) (state3 (scanchar)))
(else (scannererror errincompletetoken))))
(define (state5 c)
(case c
((#\l) (consumechar) (state4 (scanchar)))
(else (scannererror errincompletetoken))))
(define (state6 c)
(case c
((#\w) (consumechar) (state5 (scanchar)))
(else (scannererror errincompletetoken))))
(define (state7 c)
(case c
((#\e) (consumechar) (state6 (scanchar)))
(else (scannererror errincompletetoken))))
(define (state8 c)
(case c
((#\e) (consumechar) (accept 'character))
(else (scannererror errincompletetoken))))
(define (state9 c)
(case c
((#\c) (consumechar) (state8 (scanchar)))
(else (scannererror errincompletetoken))))
(define (state10 c)
(case c
((#\a) (consumechar) (state9 (scanchar)))
(else (scannererror errincompletetoken))))
(define (state11 c)
(case c
((#\p) (consumechar) (state10 (scanchar)))
(else (scannererror errincompletetoken))))
(define (state12 c)
(case c
((#\s) (consumechar) (state11 (scanchar)))
((#\n) (consumechar) (state7 (scanchar)))
(else
(if (char? c)
(begin (consumechar) (accept 'character))
(scannererror errincompletetoken)))))
(define (state13 c)
(case c
((#\() (consumechar) (accept 'vecstart))
((#\t #\f) (consumechar) (accept 'boolean))
((#\\) (consumechar) (state12 (scanchar)))
(else (scannererror errincompletetoken))))
(define (state14 c)
(case c
((#\a
#\b
#\c
#\d
#\e
#\f
#\g
#\h
#\i
#\j
#\k
#\l
#\m
#\n
#\o
#\p
#\q
#\r
#\s
#\t
#\u
#\v
#\w
#\x
#\y
#\z
#\A
#\B
#\C
#\D
#\E
#\F
#\G
#\H
#\I
#\J
#\K
#\L
#\M
#\N
#\O
#\P
#\Q
#\R
#\S
#\T
#\U
#\V
#\W
#\X
#\Y
#\Z
#\!
#\$
#\%
#\&
#\*
#\/
#\:
#\<
#\=
#\>
#\?
#\^
#\_
#\~
#\0
#\1
#\2
#\3
#\4
#\5
#\6
#\7
#\8
#\9
#\+
#\-
#\.
#\@)
(consumechar)
(state14 (scanchar)))
(else (accept 'id))))
(define (state15 c)
(case c
((#\.) (consumechar) (accept 'id))
(else (scannererror errincompletetoken))))
(define (state16 c)
(case c
((#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9)
(consumechar)
(state18 (scanchar)))
((#\.) (consumechar) (state15 (scanchar)))
(else (accept 'period))))
(define (state17 c)
(case c
((#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9)
(consumechar)
(state18 (scanchar)))
(else (scannererror errincompletetoken))))
(define (state18 c)
(case c
((#\e #\s #\f #\d #\l)
(consumechar)
(state22 (scanchar)))
((#\#) (consumechar) (state19 (scanchar)))
((#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9)
(consumechar)
(state18 (scanchar)))
(else (accept 'number))))
(define (state19 c)
(case c
((#\e #\s #\f #\d #\l)
(consumechar)
(state22 (scanchar)))
((#\#) (consumechar) (state19 (scanchar)))
(else (accept 'number))))
(define (state20 c)
(case c
((#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9)
(consumechar)
(state20 (scanchar)))
(else (accept 'number))))
(define (state21 c)
(case c
((#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9)
(consumechar)
(state20 (scanchar)))
(else (scannererror errincompletetoken))))
(define (state22 c)
(case c
((#\+ #\-) (consumechar) (state21 (scanchar)))
((#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9)
(consumechar)
(state20 (scanchar)))
(else (scannererror errincompletetoken))))
(define (state23 c)
(case c
((#\#) (consumechar) (state23 (scanchar)))
(else (accept 'number))))
(define (state24 c)
(case c
((#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9)
(consumechar)
(state24 (scanchar)))
((#\#) (consumechar) (state23 (scanchar)))
(else (accept 'number))))
(define (state25 c)
(case c
((#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9)
(consumechar)
(state24 (scanchar)))
(else (scannererror errincompletetoken))))
(define (state26 c)
(case c
((#\#) (consumechar) (state26 (scanchar)))
((#\/) (consumechar) (state25 (scanchar)))
((#\e #\s #\f #\d #\l)
(consumechar)
(state22 (scanchar)))
((#\.) (consumechar) (state19 (scanchar)))
(else (accept 'number))))
(define (state27 c)
(case c
((#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9)
(consumechar)
(state27 (scanchar)))
((#\#) (consumechar) (state26 (scanchar)))
((#\/) (consumechar) (state25 (scanchar)))
((#\e #\s #\f #\d #\l)
(consumechar)
(state22 (scanchar)))
((#\.) (consumechar) (state18 (scanchar)))
(else (accept 'number))))
(define (state28 c)
(case c
((#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9)
(consumechar)
(state27 (scanchar)))
((#\.) (consumechar) (state17 (scanchar)))
(else (accept 'id))))
(define (state29 c)
(case c
((#\newline)
(consumechar)
(begin
(set! string_accumulator_length 0)
(state0 (scanchar))))
(else
(if (isnotnewline? c)
(begin (consumechar) (state29 (scanchar)))
(scannererror errincompletetoken)))))
(define (state30 c)
(case c
(else
(if (char-whitespace? c)
(begin (consumechar) (state30 (scanchar)))
(begin
(set! string_accumulator_length 0)
(state0 (scanchar)))))))
(define (state31 c)
(case c
(else
(begin
(set! string_accumulator_length 0)
(state0 (scanchar))))))
(define (state32 c) (case c (else (accept 'id))))
(define (state33 c)
(case c (else (accept 'boolean))))
(define (state34 c)
(case c (else (accept 'character))))
(define (state35 c)
(case c (else (accept 'vecstart))))
(define (state36 c)
(case c (else (accept 'string))))
(define (state37 c)
(case c (else (accept 'lparen))))
(define (state38 c)
(case c (else (accept 'rparen))))
(define (state39 c)
(case c (else (accept 'quote))))
(define (state40 c)
(case c (else (accept 'backquote))))
(define (state41 c)
(case c (else (accept 'splicing))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; End of state machine generated by LexGen.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; ParseGen generated the code for the strong LL(1) parser.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (parse-datum)
(case (next-token)
((splicing comma backquote quote lparen vecstart)
(let ((ast1 (parse-compound-datum)))
(identity ast1)))
((boolean number character string id)
(let ((ast1 (parse-simple-datum)))
(identity ast1)))
(else
(parse-error
'<datum>
'(backquote
boolean
character
comma
id
lparen
number
quote
splicing
string
vecstart)))))
(define (parse-simple-datum)
(case (next-token)
((id)
(let ((ast1 (parse-symbol))) (identity ast1)))
((string) (begin (consume-token!) (makeString)))
((character) (begin (consume-token!) (makeChar)))
((number) (begin (consume-token!) (makeNum)))
((boolean) (begin (consume-token!) (makeBool)))
(else
(parse-error
'<simple-datum>
'(boolean character id number string)))))
(define (parse-symbol)
(case (next-token)
((id) (begin (consume-token!) (makeSym)))
(else (parse-error '<symbol> '(id)))))
(define (parse-compound-datum)
(case (next-token)
((vecstart)
(let ((ast1 (parse-vector))) (identity ast1)))
((lparen quote backquote comma splicing)
(let ((ast1 (parse-list))) (identity ast1)))
(else
(parse-error
'<compound-datum>
'(backquote comma lparen quote splicing vecstart)))))
(define (parse-list)
(case (next-token)
((splicing comma backquote quote)
(let ((ast1 (parse-abbreviation)))
(identity ast1)))
((lparen)
(begin
(consume-token!)
(let ((ast1 (parse-list2))) (identity ast1))))
(else
(parse-error
'<list>
'(backquote comma lparen quote splicing)))))
(define (parse-list2)
(case (next-token)
((id string
character
number
boolean
vecstart
lparen
quote
backquote
comma
splicing)
(let ((ast1 (parse-datum)))
(let ((ast2 (parse-list3))) (cons ast1 ast2))))
((rparen) (begin (consume-token!) (emptyList)))
(else
(parse-error
'<list2>
'(backquote
boolean
character
comma
id
lparen
number
quote
rparen
splicing
string
vecstart)))))
(define (parse-list3)
(case (next-token)
((rparen
period
splicing
comma
backquote
quote
lparen
vecstart
boolean
number
character
string
id)
(let ((ast1 (parse-data)))
(let ((ast2 (parse-list4)))
(pseudoAppend ast1 ast2))))
(else
(parse-error
'<list3>
'(backquote
boolean
character
comma
id
lparen
number
period
quote
rparen
splicing
string
vecstart)))))
(define (parse-list4)
(case (next-token)
((period)
(begin
(consume-token!)
(let ((ast1 (parse-datum)))
(if (eq? (next-token) 'rparen)
(begin (consume-token!) (identity ast1))
(parse-error '<list4> '(rparen))))))
((rparen) (begin (consume-token!) (emptyList)))
(else (parse-error '<list4> '(period rparen)))))
(define (parse-abbreviation)
(case (next-token)
((quote backquote comma splicing)
(let ((ast1 (parse-abbrev-prefix)))
(let ((ast2 (parse-datum))) (list ast1 ast2))))
(else
(parse-error
'<abbreviation>
'(backquote comma quote splicing)))))
(define (parse-abbrev-prefix)
(case (next-token)
((splicing)
(begin (consume-token!) (symSplicing)))
((comma) (begin (consume-token!) (symUnquote)))
((backquote)
(begin (consume-token!) (symBackquote)))
((quote) (begin (consume-token!) (symQuote)))
(else
(parse-error
'<abbrev-prefix>
'(backquote comma quote splicing)))))
(define (parse-vector)
(case (next-token)
((vecstart)
(begin
(consume-token!)
(let ((ast1 (parse-data)))
(if (eq? (next-token) 'rparen)
(begin (consume-token!) (list2vector ast1))
(parse-error '<vector> '(rparen))))))
(else (parse-error '<vector> '(vecstart)))))
(define (parse-data)
(case (next-token)
((id string
character
number
boolean
vecstart
lparen
quote
backquote
comma
splicing)
(let ((ast1 (parse-datum)))
(let ((ast2 (parse-data))) (cons ast1 ast2))))
((rparen period) (emptyList))
(else
(parse-error
'<data>
'(backquote
boolean
character
comma
id
lparen
number
period
quote
rparen
splicing
string
vecstart)))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; End of LL(1) parser generated by ParseGen.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Help predicates used by the lexical analyzer's state machine.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (isnotdoublequote? c) (not (char=? c #\")))
(define (isnotnewline? c) (not (char=? c #\newline)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Lexical analyzer.
;
; This code is adapted from the quirk23 lexical analyzer written
; by Will Clinger for a compiler course.
;
; The scanner and parser were generated automatically and then
; printed using an R5RS Scheme pretty-printer, so they do not
; preserve case. In preparation for the case-sensitivity of
; R6RS Scheme, several identifiers and constants have been
; lower-cased in the hand-written code to match the generated
; code.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; next-token and consume-token! are called by the parser.
; Returns the current token.
(define (next-token)
(if nextTokenIsReady
kindOfNextToken
(begin (set! string_accumulator_length 0)
(scanner0))))
; Consumes the current token.
(define (consume-token!)
(set! nextTokenIsReady #f))
; Called by the lexical analyzer's state machine,
; hence the unfortunate lower case.
(define (scannererror msg)
(define msgtxt
(cond ((= msg errLongToken)
"Amazingly long token")
((= msg errincompletetoken)
"in line ")
((= msg errLexGenBug)
"Bug in lexical analyzer (generated)")
(else "Bug in lexical analyzer")))
(fatal-error (string-append "Lexical Error: " msgtxt) lineNumber)
(set! nextTokenIsReady #f)
(set! nextCharacterIsReady #f)
(next-token))
; Accepts a token of the given kind, returning that kind.
;
; For some kinds of tokens, a value for the token must also be
; recorded in tokenValue.
(define (accept t)
(if (memq t '(boolean character id number string))
(set! tokenValue
(substring string_accumulator 0 string_accumulator_length)))
(set! kindOfNextToken t)
(set! nextTokenIsReady #t)
t)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Character i/o, so to speak.
; Uses the input-string as input.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Returns the current character from the input.
(define (scanchar)
(if nextCharacterIsReady
nextCharacter
(begin (if (< input-index input-length)
(begin (set! nextCharacter
(string-ref input-string input-index))
(set! input-index (+ input-index 1)))
(set! nextCharacter eof))
(set! nextCharacterIsReady #t)
; For debugging, change #f to #t below.
(if #f
(write-char nextCharacter))
(scanchar))))
; Consumes the current character, and returns the next.
(define (consumechar)
(if (not nextCharacterIsReady)
(scanchar))
(if (< string_accumulator_length max_token_size)
(begin (set! nextCharacterIsReady #f)
(if (char=? nextCharacter #\newline)
(set! lineNumber (+ lineNumber 1)))
(string-set! string_accumulator
string_accumulator_length
nextCharacter)
(set! string_accumulator_length
(+ string_accumulator_length 1)))
(scannererror errLongToken)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Action procedures called by the parser.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (emptyList) '())
(define (identity x) x)
(define (list2vector vals) (list->vector vals))
(define (makeBool)
(string=? tokenValue "#t"))
(define (makeChar)
(string-ref tokenValue 0))
(define (makeNum)
(string->number tokenValue))
(define (makeString)
; Must strip off outer double quotes.
; Ought to process escape characters also, but we won't.
(substring tokenValue 1 (- (string-length tokenValue) 1)))
(define (makeSym)
(string->symbol tokenValue))
; Like append, but allows the last argument to be a non-list.
(define (pseudoAppend vals terminus)
(if (null? vals)
terminus
(cons (car vals)
(pseudoAppend (cdr vals) terminus))))
(define (symBackquote) 'quasiquote)
(define (symQuote) 'quote)
(define (symSplicing) 'unquote-splicing)
(define (symUnquote) 'unquote)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Error procedure called by the parser.
; As a hack, this error procedure recovers from end-of-file.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (parse-error nonterminal expected-terminals)
(if (eq? 'eof (next-token))
'eof
(begin
(display "Syntax error in line ")
(display lineNumber)
(display " while parsing a ")
(write nonterminal)
(newline)
(display " Encountered a ")
(display (next-token))
(display " while expecting something in")
(newline)
(display " ")
(write expected-terminals)
(newline)
(fatal-error "Syntax error"))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Parses repeatedly, returning the last <datum> parsed.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(do ((x (parse-datum) (parse-datum))
(y 'eof x))
((eq? x 'eof)
y))))
(define (main . args)
(parsing-benchmark parsing-iters "parsing-data.ss")))