944 lines
26 KiB
Scheme
944 lines
26 KiB
Scheme
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;
|
|
; Copyright 2006 William D Clinger.
|
|
;
|
|
; Permission to copy this software, in whole or in part, to use this
|
|
; software for any lawful purpose, and to redistribute this software
|
|
; is granted subject to the restriction that all copies made of this
|
|
; software must include this copyright notice in full.
|
|
;
|
|
; I also request that you send me a copy of any improvements that you
|
|
; make to this software so that they may be incorporated within it to
|
|
; the benefit of the Scheme community.
|
|
;
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;
|
|
; 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".
|
|
;
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
(import (scheme base)
|
|
(scheme read)
|
|
(scheme write)
|
|
(scheme file)
|
|
(scheme char))
|
|
|
|
(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)))
|
|
(let loop ((i 0) (result #f))
|
|
(if (= i n)
|
|
result
|
|
(loop (+ i 1) (parse-string input-string))))))
|
|
|
|
(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")))
|
|
(error #f (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)
|
|
(error #f "Syntax error"))))
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;
|
|
; Parses repeatedly, returning the last <datum> parsed.
|
|
;
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
(do ((x (parse-datum) (parse-datum))
|
|
(y 'eof x))
|
|
((eq? x 'eof)
|
|
y))))
|
|
|
|
(define (main)
|
|
(let* ((count (read))
|
|
(input1 (read))
|
|
(output (read))
|
|
(s2 (number->string count))
|
|
(s1 input1)
|
|
(name "parsing"))
|
|
(run-r7rs-benchmark
|
|
(string-append name ":" s2)
|
|
1
|
|
(lambda () (parsing-benchmark (hide count count) (hide count input1)))
|
|
(lambda (result) (equal? result output)))))
|
|
|
|
(include "src/common.sch")
|