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