プリプロセッサデバッガ

昨日のことを適当にまとめてみる。


始まりはこのつぶやきから。

【急募】このコードがうまく動く理由 http://codepad.org/IwJ4sqA9

http://twitter.com/DecimalBloat/status/9965596581

これを見て、そういえば id:y-hamigaki さんが Boost.Wave を使ってプリプロセス時デバッグする方法を書いていたことを思い出したので、実際に wave.exe を使ってみました。

wave.exe を使おう

まず wave.exe がどこにあるかわからず苦戦。
調べてみると boost/tools/wave にあるみたいなので、そこからソースを持ってきて適当にビルド。


で、最初の頭のおかしいソースをコピペして、

#pragma wave trace(enable)

をどこかに追加して、

wave.exe -S"C:\Program Files\boost\boost_1_42" -ttrace.txt --timer --variadics crazy.h

とか実行してみると・・・

warning: PP_IS_EMPTY_VIII: too few macro arguments

とか怒られました。
PP_IS_EMPTY_VIII の定義は

#define PP_IS_EMPTY_VIII(a, ...) PP_IS_EMPTY_IX((HELPER_IV_ ## a))

となっていて、これに対して引数1つで呼び出してみるとエラーになるようです。


念のため以下のようなコードも試してみました。

#define HOGE(...)
HOGE() // OK
#define HOGE2(a, ...)
HOGE2(A) // エラー

これ Boost.Wave のバグじゃね?と思ったのですが、一応 C99 の規格を開いてみることに。
すると・・・

there shall be more arguments in the invocation than there are parameters in the macro definition (excluding the ...).

N1256 §6.10.3¶4

とか書いてました。 ... を除いた引数の数より呼び出し時の引数の数の方が多くないといけないようです。
HOGE2 は ... を除いた引数の数が 1 個、呼び出し時の引数が 1 個なのでエラーになっていると。
HOGE が OK なのは、空トークンを一つの引数と認識しているかららしいです。
疑ってごめんなさい Boost.Wave。あなたは正しかった。


ということでそれを id:DigitalGhost さんに報告したところ、PP_IS_EMPTY_V を以下のように修正すればいけそうということです。

#define PP_IS_EMPTY_V(a, ...) PP_IS_EMPTY_VI((a __VA_ARGS__ (), NIL))

で、再度 wave.exe に掛けてみると、1 と 6 が出力されて、ログも取れました。


結果はこちら。


これだけ詳細にログが出ていれば、うまく動く理由分かりますよね!自分は見る気がしませんが。

wave.exe をもっと使ってみる

調子に乗って、DigitalGhost さんの Preprocessor の記事も wave.exe に掛けてみました。
いくつかは結果見て面白い面白いとかって言ってたのですが、プリプロセス時 FizzBuzz のソースをやってみると、すごいことに。


最初はデバッグモードで VS 上から処理を掛けていたのですが、そうすると Stack overflow で wave.exe が落ちました
仕方ないのでリリースビルドしてコマンドラインから直接叩いたのですが、処理が戻ってきません
それでも延々と待ち続けること20分。ようやく処理が戻ってきて、正しく出力されました。
で、ログファイルを見ると 15,092,097,953 byte
このログさえ読めばあなたもきっとコンパイルFizzBuzz の仕組みが分かるように!ふざけんな。

まとめ

Boost.PP あたりを使いまくっているでかいコードを追っていくとログが膨大なことになるので、これは wave.exe のソースを弄って BOOST_* のログを出さないようにしたり、これのログビューワを作って特定の部分だけ隠すとかの対策をしないとまともに読めそうにないです。
ただ小さいコードでのプリプロセスを追うのであれば、wave.exe はかなり使えそうです。
例えば 1から10まで足すんだって、プリプロセッサで - デ-mk6 なんかはログのサイズが 1.3MB 程度なので、まあ読めないことも無いと思います。


ということでプリプロセス時デバッグなら wave.exe を使うといいよ!というお話でした。