The read
procedure only reads a single datum from the input port; the extra parenth does not raise an error in your code because it is never reached. One solution is to write a procedure that reads from the input port until the end is reached, collecting the resulting forms in a list:
(define (read-from-string s)
(let ((input (open-input-string s)))
(let loop ((expr (read input))
(result '()))
(if (eof-object? expr)
(reverse result)
(loop (read input) (cons expr result))))))
If read
can successfully parse all of the expressions, a list of those expressions will be returned; otherwise an error will be signaled.
Sample interactions:
scratch.rkt> (read-from-string "(1 (b 1))")
'((1 (b 1)))
scratch.rkt> (read-from-string "(+ 1 2)")
'((+ 1 2))
scratch.rkt> (read-from-string "(+ 1 2) (+ 3 4)")
'((+ 1 2) (+ 3 4))
scratch.rkt> (read-from-string "()")
'(())
scratch.rkt> (read-from-string "(+ 1 1))")
; string::8: read: unexpected `)`
scratch.rkt> (read-from-string "(+ 1 1)(")
; string::8: read: expected a `)` to close `(`
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…