Cの.hからのトランスレータ

ある程度形になってきたためこっちに書きます。
http://panathenaia.halfmoon.jp/alang/headmaster/
Cの.hをAdaの宣言に直すトランスレータです。この間の愚痴はこれを作っていたのでした。

やっていることは、-fdump-ada-specの二番煎じ、SWIGの三番煎じ、CILの四番煎じです。とはいえ-fdump-ada-specはまだまだ実用には遠く、SWIGはAdaには対応していません*1ので、需要は一応あるはずです。

機能としては、少しだけ真面目にCの意味解析をしており、簡単なインライン関数であればそのままAdaのインライン関数にしたりします。インクリメントや条件演算子は関数内関数にしたり、引数が変更されている場合は(Adaの引数は変更できないので)一回ローカル変数に代入したりと、色々やってます。ある程度複雑なマクロも読み解いて、型として解釈可能ならsubtype、関数の別名ならrenames、式として解釈可能ならインライン関数にしたりします。ただ、現時点では関数型マクロはあきらめてます。関数型マクロをインライン関数に直すためには引数の型推論が必要ですから……その割には絶対無いと困る関数型マクロって意外と無くて……気合さえあればできそうな気はしているのですけどね……それよりもまだ基本的な部分に未実装なものが多すぎるため(演算子すら全部揃ってない)、とりあえず関数型マクロは抜きで、標準のヘッダーやwindows.hを扱えるようにしたいなあというのが当面の目標です。

Cのパーサは真面目に実装するとtypedef他色々特別扱いが必要なためパーサジェネレータは使えません。マクロもトランスレート対象にするためプリプロセス時の情報を残さないといけなかったため既存のプリプロセッサも使えません。CILすら使えません。全部手書きです。しくしく。
プリプロセッサについては、http://twitter.com/rui314/status/18821460437のようなドキュメントもあったのですが、それは無視して(というよりrui314さんに教えてもらう前に実装が終わってた)MCPPのpost-standardモード同等の処理をしています。要するに再帰による単純置換(手抜き)です。一部ヘッダーにそれではカバーし切れない(後続トークンの巻き込みが必要になる)部分がありましたので、展開後が引数付きマクロ名で次が"("で……みたいに判定して汚い処理をしてます。

……色々書こうとしていたのですが、実例見ていただいたほうがわかりやすいかな。現時点でもlibyamlのyaml.hぐらいは辛うじて実用になるかもしれないレベルで扱えており、The Village of Vampireのデータ保存部分をlibyamlに移行できて悦に入ってます。(これが需要の100%)

本当は一年半前のAda Hackathonのネタにしようと思ってたプロジェクトなんですよ……ここまで長かった……。まさにWhen I (yt) started to write headmaster I thought it was going to take two weeks. Exactly a year has passed since then and I am still fixing bugs in it.ですよ……。

さくっとAda以外にも対応して放棄してしまったwindows.h for DのリベンジやJEDIの独自色が強すぎるwin32ヘッダーを滅ぼしたりしようと野望を抱いていたのですが、私一人の労力では無理ということがわかってきました。コードはgithubに置いておきました(O'Caml 3.12.0以降が必要です)ので、物好きな方は弄ってやってください……。(でも実用にしようと思えばSWIG弄ったほうが早いだろうという二番煎じプロジェクトの弱点がっ)
個人的にはbzr派になりたいのです、が、いつまでたってもnested treeが使えるようにならないのとlaunchpad重すぎなので、とうとうgithubのアカウントを取ってしまいました……。