Scheme Compiler の勉強(37) - printer

ちょっと脱線して、scheme のオブジェクトを出力する機能をコンパイラに組み込む。じかに LLVM で書くのではなくて、Scheme で書いてコンパイルした結果を runtime に組み込むことにした。
リストの外部表現にはドット対(dotted notation)の他、 list notation というのがある。Scheme じゃないけど CLHS 22.1.3.5 http://www.lispworks.com/documentation/HyperSpec/Body/22_ace.htm に丁寧に書かれている。というのを随分前に調べたのだった。

Scheme で20行くらいの $display-pair は、コンパイルされて 130行くらいの LLVM プログラムになる。これを LLVM で最適化すると 50 行くらいになり、PowerPCアセンブラになると 70 行くらいになった。Scheme 以外はちょっと手で書くのも読むのも嫌になる分量で、これを可能にするのが"コンパイラ"というアイディアなのだなぁと思う。

;; gauche
gosh> (cons (cons 1 2) (cons 3 ()))
((1 . 2) 3)
;; 自作コンパイラもどき
gosh> (run-program '(cons (cons 1 2) (cons 3 ())))
"((1 . 2) 3)\n"
;; 定義はこんな感じ。
(code (obj top)
          (if top
              ($display-char #\())
          ($display-obj (car obj))
          (if (pair? (cdr obj))
              (begin
                ($display-char #\Space)
                ($display-pair (cdr obj) #f))
              (if (not (null? (cdr obj)))
                  (begin
                    ($display-char #\Space)
                    ($display-char #\.)
                    ($display-char #\Space)
                    ($display-obj (cdr obj)))))
          (if top
              ($display-char #\))))
;; 

バグ発覚

vector 周りのバグが分かった。

gosh> (run-program
        '(let ([v (make-vector 1)] [y (cons 1 2)] )
           (vector-set! v 0 3)
	   y))
"(196609 . 2)\n"

vector を作った後にコンスセルを作るとデータが破壊される。make-vector に2以上を与えると生じない。これは fix するのに時間が掛かりそう、、