海野秀之(うんのひでゆき)の外部記憶
Twitter (twilog) / RSS / アンテナ / ぶくま
record-case.scm, rec-recur.scm は昨日のをそのまま。
compiler2.scm:
;; compiler2.scm
; Translater shown in 3.5.1 of 3imp.
(load "record-case")
(load "rec-recur")
; tail: 3imp p.59
(define tail?
(lambda (next)
(eq? (car next) 'return)))
; extend: p.65
(define extend
(lambda (e r)
(cons r e)))
; extend: p.65
(define compile-lookup
(lambda (var e)
(recur nxtrib ((e e) (rib 0))
(recur nxtelt ((vars (car e)) (elt 0))
(cond
((null? vars) (nxtrib (cdr e) (+ rib 1)))
((eq? (car vars) var) (cons rib elt))
(else (nxtelt (cdr vars) (+ elt 1))))))))
; compile: p.64
(define compile
(lambda (x e next)
(cond
((symbol? x)
(list 'refer (compile-lookup x e) next))
((pair? x)
(record-case x
(quote (obj)
(list 'constant obj next))
(lambda (vars body)
(list 'close
(compile body (extend e vars) '(return))
next))
(if (test then else)
(let ((thenc (compile then e next))
(elsec (compile else e next)))
(compile test e (list 'test thenc elsec))))
(set! (var x)
(let ((access (compile-lookup var e)))
(compile x e (list 'assign access next))))
(call/cc (x)
(let ((c (list 'conti
(list 'argument
(compile x e '(apply))))))
(if (tail? next)
c
(list 'frame next c))))
(else
(recur loop ((args (cdr x))
(c (compile (car x) e '(apply))))
(if (null? args)
(if (tail? next)
c
(list 'frame next c))
(loop (cdr args)
(compile (car args)
e
(list 'argument c))))))))
(else
(list 'constant x next)))))
vm2.scm:
;; vm2.scm
; 3imp 3.5.2 Evaluation
(load "record-case")
(load "rec-recur")
(load "compiler2")
(define call-frame
(lambda (x e r s)
(list x e r s)))
(define closure
(lambda (body e)
(list body e)))
(define continuation
(lambda (s)
(closure (list 'nuate s '(0 . 0)) '())))
(define lookup
(lambda (access e)
(recur nxtrib ((e e) (rib (car access)))
(if (= rib 0)
(recur nxtelt ((r (car e)) (elt (cdr access)))
(if (= elt 0)
r
(nxtelt (cdr r) (- elt 1))))
(nxtrib (cdr e) (- rib 1))))))
(define VM
(lambda (a x e r s)
(record-case x
(halt () a)
(refer (var x)
(VM (car (lookup var e)) x e r s))
(constant (obj x)
(VM obj x e r s))
(close (body x)
(VM (closure body e) x e r s))
(test (then else)
(VM a (if a then else) e r s))
(assign (var x)
(set-car! (lookup var e) a)
(VM a x e r s))
(conti (x)
(VM (continuation s) x e r s))
(nuate (s var)
(VM (car (lookup var e)) '(return) e r s))
(frame (ret x)
(VM a x e '() (call-frame ret e r s)))
(argument (x)
(VM a x e (cons a r) s))
(apply ()
(record (body e) a
(VM a body (extend e r) '() s)))
(return ()
(record (x e r s) s
(VM a x e r s))))))
repl2.scm:
#!/usr/local/bin/gosh
(add-load-path ".")
(load "vm2")
(define banner
(lambda ()
(display "3imp Heap-Based Compiler and VM")))
(define evaluate
(lambda (x)
(VM '() (compile x '() '(halt)) '() '() '())))
(define (repl)
(let loop ((s '()))
(display "\n>>> ")
(set! s (read))
(display (compile s '() '(halt)))
(newline)
(display "\n==> ")
(display (evaluate s))
(newline)
(loop '())))
(define (main args)
(banner)
(repl))
% ./repl2.scm 3imp Heap-Based Compiler and VM >>> 100 (constant 100 (halt)) ==> 100 >>> ((lambda (x) x) 1) (frame (halt) (constant 1 (argument (close (refer (0 . 0) (return)) (apply))))) ==> 1 >>> (if #f 1 2) (constant #f (test (constant 1 (halt)) (constant 2 (halt)))) ==> 2 >>> ((lambda (x) (set! x (call/cc (lambda (cont) (cont 20))))) '()) (frame (halt) (constant () (argument (close (frame (assign (0 . 0) (return)) (conti (argument (close (constant 20 (argument (refer (0 . 0) (apply)))) (apply))))) (apply))))) ==> 20
拡張したりするのは、Stack-Based のやつを元にしたいので、ささーと逃げるように 4 章にすすむよ!