oreore_lisp(1)
先日から、cdr 作業、正確には、CD-R 作業をしている。CD+R でも、CD-RWでもCD-RAMでもCD+RW でも良かったんだけど、一番コストパフォーマンスが良さそうな、CD-Rである。
そろそろヤバくなりつつあるWindows機をバックアップしておこうと思って、DVD Writer を買ってきたのだ。DVDの事なんて良く知らないおいらは、山田君に相談したよ。そしたら彼は BuffaloのDVSM-X20U2Vを勧めてくれた。6980円也。
生DVDは、日本製がいいよとの事だったので、Made in Japan なSONY製にした。(特価だったので) タイマー発動は 無いだろうな。まあ、DVD(にしろCDでも)は、何処のやつを使っても、いずれ発動しちゃう から、気にしてもしょうがないか。
買ってきたWriterは、X20倍速対応のUSB接続のやつだ。付属のユーティリティを使うとX20で 使えるようになるらしいけど、面倒なので止めた。ドライブ自身は、Optiarc DVD RW AD-7240Sと 名乗ってたよ。
実際にコピーを始めると、結構な率で、Write fail で失敗する事がある。ドライブとメディアの 相性が有るって話を聞いてはいたけど、実際に経験してみると腹だたしい。 Buffaloでは、推奨メディアとして、(CD-Rの場合)太陽誘電、マクセル、三菱、SONYを上げて いたけど、自分で調べてみる鹿。
CD-R実験室にOptiarc AD-7240S というのが出ていた。よくもまあ、いろいろと調べてますなあ。感心するやら呆れるやら。 と、このページからドライブのメーカーへ飛んで行くとSONY製だった。SONYと仲の良いメディア メーカーって何処だろう? 中立性を取って、太陽誘電かなあ。
DVD Writerなんかをチョイスするより、割り切って、外付けHDDにでもしておいた方が良かった かしらん。
Lispの解説見つけたよ
吉田さんが書かれた、ちょっと変わったLisp入門を見つけたので、忘れないうちにメモ。 これって、今やってる oreore_lisp の解説記事でもあるんだ。
興味深げに読ませていただきました。読んだ後は、手を動かそうとソースを見始めた んだけど、ちとおかしな所を発見。附属してる、base.lispを読み込む部分だ。ちょっと 見直しついでに、oreore に改造してみたよ。
[sakae@fb ~/oreore_lisp]$ diff -u oreore_lisp.c.org oreore_lisp.c --- oreore_lisp.c.org 2009-11-11 12:42:14.000000000 +0900 +++ oreore_lisp.c 2009-11-11 12:44:36.000000000 +0900 @@ -22,7 +22,7 @@ #define UNDEF ((cell)2) #define SPECIAL_TOKENS "().'" -#define LOAD_FILE_ESCAPE "\\f " +#define LOAD_FILE_ESCAPE ":l " #define DEFAULT_FILE_EXT ".lisp" #define IS_INT(n) (((int)n & 0x00000001) != 0) @@ -150,7 +150,7 @@ if (input_stream == NULL) { if (get_one_line("lisp> ")) exit(1); - if (strncmp(read_buffer, LOAD_FILE_ESCAPE"\\f ", strlen(LOAD_FILE_ESCAPE)) == 0) { + if (strncmp(read_buffer, LOAD_FILE_ESCAPE, strlen(LOAD_FILE_ESCAPE)) == 0) { open_load_file(strtok(&read_buffer[strlen(LOAD_FILE_ESCAPE)], "\r\n")); continue; }
typoが残っていたのと、ファイルを指定する接頭語を、acl っぽくしたのだ。この結果 lispのプロンプトが出てる所で、次のようにして、ファイルをロード出来る。
lisp> :l base def defmacro if % null apply mapcar lisp>
嗚呼、ついでに、defun も、ちと近代風にしちゃった。defって、rubyでもpythonでも お馴染みだもの!
on gdb
また、懲りもせずgdbを使って動きを追ってみたいんだけど、ソース上では、CAR(e)のように マクロが多用されていて、gdbのpコマンドを使う時ちと不便だ。みなさんは、こういう時どうしてる んですかね?
私は、馬鹿の一つ覚えで、.gdbinitに次のように定義した。
define car print ((cons_t *)$arg0)->car_e end define cdr print ((cons_t *)$arg0)->cdr_e end define atom print ((symbol_t *)$arg0)->name end
最後の atomと言うのは、Lisp 1.5風に言うと、印字名を表示する意図なので pname の方が 適切かと思ったけど、何となく、atomってのを使ってみたかったので。。
lisp> (cons 123 ()) Breakpoint 1, eval (e=0x804e328, env=0x0) at oreore_lisp.c:548 548 if (e == NIL || IS_INT(e)) return e; (gdb) n 549 if (IS_SYMBOL(e)) { (gdb) 556 return apply(CAR(e), CDR(e), env); (gdb) p e $2 = 0x804e328 (gdb) car e $3 = 0x8088a80 (gdb) cdr e $4 = 0x804e330 (gdb) n Breakpoint 1, eval (e=0x8088a80, env=0x0) at oreore_lisp.c:548 548 if (e == NIL || IS_INT(e)) return e; (gdb) atom e $5 = "cons", '\0' <repeats 27 times>
もう少し、便利なgdbコマンドを増やしておいた方がいいな。
oreore改造
前回やった、時間計測マクロに再び挑戦してみる。まずはプリミティブな手続きの追加だな。 このLispは設計上の都合から、32Bitのintは扱えない。cellにintの即値を格納する都合上 intとポインターを区別出来るようにしてるからだ。
具体的には、格納したいintを1ビット左にシフトし、LSBに1をセットしてる。 (この結果、CELL値で奇数になってるのは、intと判定出来る)すなわち、31Bitのintが 扱えるのだ。
困った事に、EPOC秒も折り返し点を過ぎているので、そのまま格納すると、結果がオーバーフローして マイナス表示になる。だったら、格納する前に適当な値を引いてしまえと。
どんな値を引いてもいいんだけど、区切りよく、21世紀の始まりをEPOCの0秒としよう。 えっと、2001年1月1日が21世紀の始まりだったよな。EPOC秒にすると、
sakae@nil ~/oreore_lisp]$ irb irb(main):001:0> Time.local(2001).to_i => 978274800 [sakae@nil ~/oreore_lisp]$ date -r 978274800 Mon Jan 1 00:00:00 JST 2001
この数値を引いて、oreore時間にしちゃえ。
cell gtod() { struct timeval tv; int s,u; gettimeofday(&tv, NULL); s = tv.tv_sec - 978274800; // diff from 2001/01/01 u = tv.tv_usec; return cons(INT2CELL(s), INT2CELL(u)); }
嗚呼、init()の所へ、この関数を登録を忘れないようにしなければ。で、試運転。
isp> (gtod) (279738516.695681) lisp> (gtod) (279738544.139247)
何となく、浮動小数点表示してるのは、Lispのマジックっつう事ですんで、間違い無きように。
時間の引き算
上記で、まがいものの時間情報を得られるようになったので、それ用の時間差を計算する コードを書いてみる。実験台は、fib に決まってるので、実験出来るようについでに準備を整えておく。
(def < (a b) (cond ((> a b) nil) ((= a b) nil) (t t))) (def fib(n) (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2))))) (def diff(a b) (cond ((> (cdr a) (cdr b)) (cons (- (car a) (car b)) (- (cdr a) (cdr b)))) ((= (cdr a) (cdr b)) (cons (- (car a) (car b)) 0)) (t (cons (- (- (car a) (car b)) 1) (- (+ (cdr a) 1000000) (cdr b))))))
少なりの < は、> の論理を反転させる if を書けばいいかと思ってたけど、ちゃんと場合分け しないと、おかしな事になるね。危ない、危ない。 そんじゃ、ちょっと、diffの試験をば。
lisp> (setq old (gtod)) old lisp> (setq new (gtod)) new lisp> new (279745591.203011) lisp> old (279745577.178021) lisp> (diff new old) (14.24990)
ははは、紛い物ゆえにボロが出ましたなあ。小数点以下の表示が6桁に満たない場合、頭の中で 小数点のすぐ右隣に"0"を補ってください。(うん、我ながら酷い仕様だ事。printルーチンを いじって、%06d しちゃうかな。微妙だ。) そんじゃ、気を取り直して、もう一丁。
lisp> new (279746091.355922) lisp> old (279746081.949215) lisp> (diff new old) (9.406707) lisp> [sakae@nil ~/oreore_lisp]$ bc 279746091.355922 - 279746081.949215 9.406707
どうやら、借りのある計算もOKのようです。
マクロへの下実験
道具立ては揃ったようなので、下実験してみます。
lisp> (def test () lisp> (setq old (gtod)) lisp> (fib 15) lisp> (diff (gtod) old)) ** ERROR : Wrong number of arguments 'def' requires 3, but 5
はて、どうしますかね。begin or progn or let ? 何がいいのだろう。