CHoP

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 の略です。

なにかあれば下記メールアドレスへ。
shinichiro.hamaji _at_ gmail.com
shinichiro.h