; Copyright (c) 1994 by Richard Kelsey. See file COPYING. ; write s-expressions ; Memory (define *memory*) (define *hp*) (define (initialize-memory! size) (set! *memory* (allocate-memory size)) ;(if (null-pointer? *memory*) ; (error "out of memory, unable to continue")) (set! *hp* *memory*)) (define (allocate size) (let ((p *hp*)) (set! *hp* (address+ *hp* size)) p)) (define (words->a-units x) (* x 4)) ; Data (define tag-bits 1) (define tag-mask (- (shift-left 1 tag-bits) 1)) (define tag/fixnum 0) (define tag/pair 1) (define (enter-fixnum x) (+ (shift-left x tag-bits) tag/fixnum)) (define (extract-fixnum x) (arithmetic-shift-right x tag-bits)) (define (make-predicate tag) (lambda (x) (= tag (bitwise-and x tag-mask)))) (define fixnum? (make-predicate tag/fixnum)) (define my-pair? (make-predicate tag/pair)) (define (make-accessor tag offset) (lambda (x) (word-ref (address+ (integer->address (+ x (- 0 tag))) (words->a-units offset))))) (define (make-setter tag offset) (lambda (x v) (word-set! (address+ (integer->address (+ x (- 0 tag))) (words->a-units offset)) v))) (define pair-size 16) ; bytes (define head (make-accessor tag/pair 0)) (define tail (make-accessor tag/pair 1)) (define set-head! (make-setter tag/pair 0)) (define set-tail! (make-setter tag/pair 1)) (define (make-pair x y) (let ((p (+ tag/pair (address->integer (allocate pair-size))))) (set-head! p x) (set-tail! p y) p)) (define null tag/pair) (define (my-null? x) (= x null)) (define (print-s-exp x out) (cond ((fixnum? x) (write-number-no-newline (extract-fixnum x) out)) ((my-null? x) (write-char #\( out) (write-char #\) out)) ((my-pair? x) (write-char #\( out) (print-s-exp (head x) out) (let loop ((x (tail x))) (cond ((my-null? x) (write-char #\) out)) ((my-pair? x) (write-char #\space out) (print-s-exp (head x) out) (loop (tail x))) (else (write-char #\space out) (write-char #\. out) (write-char #\space out) (print-s-exp x out) (write-char #\) out))))))) (define *input-port*) (define *peeked-char?* #f) (define *peeked-char*) (define (readc) (cond (*peeked-char?* (set! *peeked-char?* #f) *peeked-char*) (else (call-with-values (lambda () (read-char *input-port*)) (lambda (ch eof? status) (if eof? (ascii->char 0) ch)))))) (define (peekc) (if *peeked-char?* *peeked-char* (call-with-values (lambda () (read-char *input-port*)) (lambda (ch eof? status) (if eof? (ascii->char 0) (begin (set! *peeked-char?* #t) (set! *peeked-char* ch) ch)))))) (define (digit? ch) (let ((ch (char->ascii ch))) (and (>= ch (char->ascii #\0)) (<= ch (char->ascii #\9))))) (define (read-number) (let loop () (case (peekc) ((#\-) (readc) (- 0 (really-read-number))) ((#\+) (readc) (really-read-number)) (else (really-read-number))))) (define (really-read-number) (let loop ((r 0)) (let ((ch (peekc))) (cond ((digit? ch) (readc) (loop (+ (- (char->ascii ch) (char->ascii #\0)) (* r 10)))) (else r))))) (define (read-s-exp) (case (peekc) ((#\space #\newline) (readc) (read-s-exp)) ((#\- #\+) (enter-fixnum (read-number))) ((#\() (readc) (read-list)) (else (if (digit? (peekc)) (enter-fixnum (read-number)) -1)))) (define (read-list) (case (peekc) ((#\space #\newline) (readc) (read-list)) ((#\)) (readc) null) ((#\.) (readc) ; eat the dot (let ((res (read-s-exp))) (if (read-r-paren) res -1))) (else (let ((head (read-s-exp))) (make-pair head (read-list)))))) (define (read-r-paren) (case (peekc) ((#\space #\newline) (readc) (read-r-paren)) ((#\)) #t) (else #f))) ; Printing integers ; Return 10**n such that 10**n <= x < 10**(n+1) (define (integer-mask x) (do ((x x (quotient x 10)) (mask 1 (* mask 10))) ((< x 10) mask))) ; Write positive integer X out to PORT (define (write-number x port) (write-number-no-newline x port) (write-char '#\newline port)) (define (write-number-no-newline x port) (let ((x (cond ((< x 0) (write-char '#\- port) (- 0 x)) (else x)))) (let loop ((x x) (mask (integer-mask x))) (let ((digit (quotient x mask))) (write-char (ascii->char (+ digit (char->ascii '#\0))) port) (if (> mask 1) (loop (remainder x mask) (quotient mask 10))))))) (define (test size) (initialize-memory! size) (let ((s-exp (make-pair (enter-fixnum 1) (make-pair (enter-fixnum 2) (make-pair (make-pair (enter-fixnum 3) (enter-fixnum 4)) null)))) (out (current-output-port))) (print-s-exp s-exp out) (newline out) (set! *input-port* (current-input-port)) (print-s-exp (read-s-exp) out) (newline out)))