C のヘッダをパースするライブラリを作りかけました。
http://shinh.skr.jp/chop/chop.tar.bz2
昔作った tccparser みたいな感じで、 Ruby/DL の宣言ヘルパみたいなのも作りました。
こんなのが動きます。
require 'chop' module LIBC extend Chop dlload 'libc.so.6' include 'stdio.h' include 'stdlib.h' include 'string.h' include 'ctype.h' include 'time.h' include 'sys/time.h' def my_compare(ptr1, ptr2) ptr1.ptr.to_s <=> ptr2.ptr.to_s end COMPARE = callback("int my_compare(char**, char**)") end p LIBC.atoi("10") p LIBC.isdigit(?1) p LIBC.isdigit(?a) p LIBC.strcat("a", "b") ary = ["a","c","b"] ptr = ary.to_ptr LIBC.qsort(ptr, ary.length, DL.sizeof('P'), LIBC::COMPARE) p ptr.to_a('S', ary.length) tv = LIBC::Timeval.malloc tz = LIBC::Timezone.malloc LIBC.gettimeofday(tv, tz) p Time.at(tv.tv_sec)
えーと作りかけってのは C ライブラリとしてのインターフェイスが終わってるとか、 Ruby の方が TODO だらけ(enum 無いとかマクロ無いとか)とかです。パーサとしてはそれなりにパースできてるような気がしますが定かではないです。
パーサは yacc 怖いので手で再帰下降っていうんでしょうかよくわかりませんで書きました。マクロも自前でやろうとしてたのですがあまりにしんどそうなので途中で投げ出してしまいましたヘタレめ。で急遽 GCC 内の libcpp 使うことになって libcpp の hash と CHoP 自体の hash で二つあるとかダメなことになってます。
現状は完全に GCC 依存。他の環境でも動くとは思うけどビルドの過程で色々と組込みマクロを抽出したりとかしてやがるわけです。あと cparser.c の
chop_add_include("/usr/lib/gcc/i486-linux-gnu/4.1.2/include");
ってとこは完全に環境依存だと思うので必要ならなんか書き換える必要がある気がしますが定かじゃありません。てか GCC の include パス一覧ってどう調べるんだっけという。
関連として c-wrapper 。 c-wrapper はもちろんすばらしいのですが、実行時に GCC 呼んだり Scheme でパースしたりするのはこうなんかイクないと思ったとか思わなかったとか。それと参考にしたソースコードは TCC 。あと libcpp よくわからんので GCC とかそのへんも。
あと、 CHoP は C Header \(^o^)/ Parser の略です。