(define number-char? (let ((special (list #\/ #\e #\.))) (lambda (ch) (or (char-numeric? ch) (member ch special))))) (define string->value ; Helper procedures all take three parameters: (1) A string, ; (2) a starting position for the expected kind of value, ; (3) the length of the string (so that we don't need to ; recompute it). Some helpers also take a fourth parameter, ; which accumulates the portions of the string needed. ; All return a pair of (1) the value read and (2) the ; position immediately after the end of the value. (letrec ( ; Convert a string to any kind of value (str->value (lambda (str pos len) (let ((ch (string-ref str pos))) (cond ((char-whitespace? ch) (str->value (str (+ 1 pos) len))) ((char-numeric? ch) (str->number str (+ 1 pos) len pos)) ((eq? ch #\() (str->sublist str (+ 1 pos) len null)) ((eq? ch #\") (str->str str (+ 1 pos) len (+ 1 pos))) )))) ; Convert a portion of a string to a number. ; Works by stepping through the string until it hits ; a value clearly not in the number. (str->number (lambda (str pos len start) (if (and (< pos len) (number-char? (string-ref str pos))) (str->number str (+ 1 pos) len start) (cons (string->number (substring str start pos)) pos)))) ; Convert a portion of a string to a sublist, assuming ; we've read the open paren and some portion already. ; The "stuff" parameter contains values in list in ; reverse order. (str->sublist (lambda (str pos len stuff) (let ((ch (string-ref str pos))) (cond ((char-whitespace? ch) (str->sublist str (+ 1 pos) len stuff)) ((eq? ch #\)) (cons (reverse stuff) (+ 1 pos))) (else (let ((valandnewpos (str->value str pos len))) (str->sublist str (cdr valandnewpos) len (cons (car valandnewpos) stuff)))))))) ; Convert a string to a string, assuming we've read the ; first quotation mark (str->str (lambda (str pos len start) (let ((ch (string-ref str pos))) (cond ((eq? ch #\") ; End of string (cons (substring str start pos) (+ pos 1))) ((eq? ch #\\) ; Escape (str->str str (+ pos 2) len start)) (else (str->str str (+ pos 1) len start)))))) ) (lambda (str) (car (str->value str 0 (string-length str))))))