9.5. Scheme Printer


9.5. Scheme Printer

Printing Scheme objects may seem like a complicated process, but in fact a rudimentary printer is quite straightforward, as this example demonstrates. Both write and display are supported by the same code. Sophisticated Scheme implementations often support various printer controls and handle printing of cyclic objects, but the one given here is completely basic.

The main driver for the program is a procedure wr, which takes an object to print x, a ag d?, and a port p. The ag d? is #t if the code is to display the object, #f if it is to write the object. The d? ag is important only for characters and strings. Recall from Section 7.2 that display prints strings without the enclosing quote marks and characters without the #\ syntax.

The entry points write and display handle the optionality of the second (port) argument, passing the value of current-output-port when no port argument is provided.

Procedures, ports, and end-of-file objects are printed as #<procedure>, #<port>, and #<eof>. The tests for the end-of-file objects and ports are made early, since implementations are permitted to implement these object types as special cases of other object types. Objects of types not recognized by the printer are printed as #<unknown>; this can occur if the Scheme implementation provides extensions to the standard set of object types.

The code follows the module structure outlined in Section 3.5.

 (define write #f) (define display #f) (let ()   ;; wr is the driver, dispatching on the type of x   (define wr     (lambda (x d? p)       (cond         ((eof-object? x) (write-string "#<eof>" p))         ((port? x) (write-string "#<port>" p))         ((symbol? x) (write-string (symbol->string x) p))         ((pair? x) (wrpair x d? p))         ((number? x) (write-string (number->string x) p))         ((null? x) (write-string "()" p))         ((boolean? x) (write-string (if x "#t" "#f") p))         ((char? x) (if d? (write-char x p) (wrchar x p)))         ((string? x) (if d? (write-string x p) (wrstring x p)))         ((vector? x) (wrvector x d? p))         ((procedure? x) (write-string "#<procedure>" p))         (else (write-string "#<unknown>" p))))) ;; write-string writes each character of s to p (define write-string   (lambda (s p)     (let ((n (string-length s)))       (do ((i 0 (+ i 1)))           ((= i n)) (write-char (string-ref s i) p))))) ;; wrpair handles pairs and nonempty lists (define wrpair   (lambda (x d? p)     (write-char #\( p)     (let loop ((x x))       (wr (car x) d? p)       (cond          ((pair? (cdr x))           (write-char #\space p)           (loop (cdr x)))          ((null? (cdr x)))          (else           (write-string " . " p)           (wr (cdr x) d? p))))   (write-char #\) p))) ;; wrchar handles characters, recognizing and printing the ;; special syntaxes for #\space and #\newline. Used only when ;; d? is #f. (define wrchar   (lambda (x p)     (case x       ((#\newline) (write-string "#\\newline" p))       ((#\space) (write-string "#\\space" p))       (else (write-string "#\\" p)             (write-char x p))))) ;; wrstring handles strings, inserting slashes where ;; necessary. Used only when d? is #f. (define wrstring   (lambda (x p)     (write-char #\" p)     (let ((n (string-length x)))       (do ((i 0 (+ i 1)))           ((= i n))           (let ((c (string-ref x i)))             (if (or (char=? c #\") (char=? c #\\))                 (write-char #\\ p))             (write-char c p))))     (write-char #\" p))) ;; wrvector handles vectors (define wrvector   (lambda (x d? p)     (write-string "#(" p)     (let ((size (vector-length x)))       (if (not (= size 0))         (let ((last (- size 1)))           (let loop ((i 0))             (wr (vector-ref x i) d? p)             (if (not (= i last))                 (begin                   (write-char #\space p)                   (loop (+ i 1))))))))     (write-char #\) p))) ;; write calls wr with d? set to #f (set! write   (lambda (x . rest)     (if (null? rest)         (wr x #f (current-output-port))         (wr x #f (car rest))))) ;; display calls wr with d? set to #t (set! display   (lambda (x . rest)     (if (null? rest)         (wr x #t (current-output-port))         (wr x #t (car rest)))))) 

Exercise 9.5.1.

start example

Numbers are printed with the help of number->string. Correct printing of all Scheme numeric types, especially inexact numbers, is a complicated task. Handling exact integers and rational numbers is fairly straightforward, however. Modify the code to print exact integers and rational numbers directly (without number->string), but continue to use number->string for inexact and complex numbers.

end example

Exercise 9.5.2.

start example

Modify wr and its helpers to direct their output to an internal buffer rather than to a port. Use the modified versions to implement a procedure object->string that, like number->string, returns a string containing a printed representation of its input. For example:

 (object->string '(a b c))  "(a b c)" (object->string "hello")  "\"hello\"" 

You may be surprised just how easy this change is to make.

end example




The Scheme Programming Language
The Scheme Programming Language
ISBN: 026251298X
EAN: 2147483647
Year: 2003
Pages: 98

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net