memo

ちょっとしたメモ書き(個別表示)

S式OCaml(Lisp風OCaml)トランスレータ : (2011/11/19)
前回の日記でちょっと書いてたSchemeもどきなLisp風言語からOCamlへのトランスレータの件
とりあえず数時間で適当に書いたものをば……

まだシンタックスがletとlambdaとifとかぐらいしか対応してないけどdefine-syntaxがあるから足りない分は頑張れば自前でマクロ実装できるはず
使い方はこんな感じで
s_exp_ocaml.scm
common.scm
sample.scm
こういうS式のLispっぽいコード(sample.scm)を以下のようなOCamlコードに変換する
gosh s_exp_ocaml.scm sample.scm > result.ml
result.ml

あとは適当にバイトコンパイルなら
ocamlc result.ml
とか、ネイティブコンパイルなら
ocamlopt result.ml
みたいな感じで実行ファイルを生成

なんか変換後のコードがあまり変わり映えがしないのがアレだけど
こんないい加減な手抜き実装でも上にあげたような簡単なサンプルが動くんだからCへのトランスレータを頑張って実装してる方々には申し訳なくなる
とりあえず動的型付け言語をお手軽に型推論付きの静的型付け言語にするならOCamlへの変換はなかなか良い選択肢かも、処理系も優秀でパフォーマンスも悪くないし
まあOCamlに限らず優秀な処理系を持つ言語へのトランスレータを前提とした言語設計も面白いかもしれない

ちなみに型エラーとか未定義の変数とかのエラーメッセージは
完全にocamlc(ocamlopt)にまかせてある。
なので元のLispソースとエラーメッセージは行数とか一致しないし微妙にわかりづらいかもしれない。
ただ、変数名とかはそのまんま変換してあるのでなんとなく見当はつく(はず……)

S式化することによる最大のメリットといえばLisp風のマクロを実装、利用する際の文法上の問題が無くなることかな、実際にこのサンプル中のcondはマクロで実装してある。

コード1をマクロ展開したものがコード2であり、最終的にはOCamlに変換されコード3となる

マクロ定義
(define-syntax cond
(syntax-rules ()
((_ (a1 a2 ...))
(if a1 (begin a2 ...)))
((_ (a1 a2 ...) (b1 b2 ...))
(if a1 (begin a2 ...) (if b1 (begin b2 ...))))
((_ (a1 a2 ...) b ...)
(if a1 (begin a2 ...) (cond b ...)))
))
コード1
(cond
((> foo 100)
(print_string "foo > 100!"))
((> foo 50)
(print_string "foo > 50!"))
(#t
(print_string "foo <= 50!")))
コード2
(if (> foo 100)
(begin (print_string "foo > 100!"))
(if (> foo 50)
(begin (print_string "foo > 50!"))
(if #t
(begin (print_string "foo <= 50!")))))
コード3
((if (foo > 100) then
(begin (); (print_string "foo > 100!"); end) else
((if (foo > 50) then
(begin (); (print_string "foo > 50!"); end) else
(if true then
(begin (); (print_string "foo <= 50!"); end))))));

: back