Scheme Compiler の勉強(29) - app の実装と EXC_BAD_ACCESS

apply もどきの app を実装していなかったので実装。もどきと思うのは、(app f e1 e2 ..) は単に e1 e2 ... を評価して f を実行するだけで、リストでなくてもよいから。今までは先走って app を使わずに手続きを呼び出すような実装をしてた。

tests-1.8-req.scm にその app を使った深い関数呼び出しのテストコードがあったのでテスト。今の自分のトイコンパイラはちゃんと実行できないことが判明。(run-program はS式をLLVM IR にコンパイルして実行するだけ。)gdb で実行してみると EXC_BAD_ACCESS だと。

gosh> (run-program '(letrec ([e (lambda (x) (if ($fxzero? x) #t
						(o ($fxsub1 x))))]
			     [o (lambda (x) (if ($fxzero? x) #f
						(e ($fxsub1 x))))])
		      (e 5000000)))
*** ERROR: produced program exited abnormally

さあこれがちゃんと通るようにがんばろう。末尾再帰の最適化と関係していると想定。

ついでに。gauche, guile では実行できた。ひげぽんさん(id:higepon)の mosh (0.0.7) だと GC Warning: Out of Memory! Returning NIL! となった。お、と思ったけど、ふと letrec を手続きで包んだら普通に実行できた。これがどういう違いかは把握できていませんが一応idトラックバック->ひげぽんさん。ありそうなのはトップレベルだと最適化しないとかR5RSとR6RSでの仕様の違いとか。 mosh -t は passed になっています。

mosh>(define (fxzero? x) (= 0 x))
#<unspecified>
mosh>(define (fxsub1 x) (- x 1))
#<unspecified>
mosh>(define (f) (letrec ([e (lambda (x) (if (fxzero? x) #t (o (fxsub1 x))))] [o (lambda (x) (if (fxzero? x) #f (e (fxsub1 x))))]) (e 5000000)))
#<unspecified>
mosh>(f)
#t
mosh>(letrec ([e (lambda (x) (if (fxzero? x) #t (o (fxsub1 x))))] [o (lambda (x) (if (fxzero? x) #f (e (fxsub1 x))))]) (e 5000000))
#t
mosh>GC Warning: Out of Memory!  Returning NIL!

gosh> (define (fxzero? x) (= 0 x))
fxzero?
gosh> (define (fxsub1 x) (- x 1))
fxsub1
gosh> (define (f) (letrec ([e (lambda (x) (if (fxzero? x) #t (o (fxsub1 x))))] [o (lambda (x) (if (fxzero? x) #f (e (fxsub1 x))))]) (e 5000000)))
f
gosh> (f)
#t
gosh> (letrec ([e (lambda (x) (if (fxzero? x) #t (o (fxsub1 x))))] [o (lambda (x) (if (fxzero? x) #f (e (fxsub1 x))))]) (e 5000000))
#t