こんにちは、高木です。
C言語ではプリプロセッサを使って前処理を行います。プリプロセッサは比較的単純なことならできるのですが、ちょっと凝ったことをしようとすると力不足です。たとえば、事前に配列をソートするとか、静的に二分木や三角関数表を作るとかは、C言語のプロセッサには荷が重すぎます。
通常、こうしたことを行うには、別途何らかのコードジェネレータを作って、それに C/C+ のソースコードを生成させることになります。ですが、もっと簡単な方法があればそれに越したことはありません。今回は、埋め込み型のスクリプト言語である PHP を使ってこれを実現することを試みます。
PHPというと、Web専用の言語だと誤解している人もいるかもしれません。しかし、実際のPHPはコマンドラインでも使うことができますので、通常のスクリプト言語として扱うこともできます。しかも、同じソースファイルにPHPのコードと他の言語のコードを混在できますから、今回の目的にはぴったりです。
しかも、PHPはC言語の影響を受けたプログラミング言語ですので、ifやforなどの基本的な文法はC言語とそっくりです。普段C言語を使っているプログラマーにとっては、PHPは非常に習得しやすい言語だといえます。
なお、m4のような強力なマクロプロセッサを使うという方法もありますが、m4だと、C言語のキーワードと衝突する組み込みマクロがあるなど、いろいろ気を使う部分が少なくありません。その点、<?php と ?> で囲んだ部分だけが対象になる PHP は便利です。
今回は、固定小数点を用いた静的な三角関数表を作る前処理を PHP で記述する例を挙げます。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// isin.c - 1.14固定小数点による正弦関数 int isin(int angle) { static const short table[] = { <?php for ($angle = 0; $angle < 360; ++$angle) { printf("%d,\n", (int)(sin($angle * pi() / 180) * (1 << 14))); } ?> }; return table[angle % 360]; } |
上のコードの5行目から10行目に書かれた<?phpから?>までがPHPのコードです。PHPのコードは同じファイルの中で何度でも登場させることができますので、C言語のソースコードに簡単に埋め込むことができます。
これをどうやってコンパイルするかを見ていきましょう。このソースファイルが仮にisin.pcだった場合、以下のコマンドで前処理を行うことができます。
0 1 2 |
php isin.pc > isin.c |
PHPが前処理した結果は標準出力に書き込まれますので、上の例ではisin.cというファイルにリダイレクトしています。あとは、isin.cを普通にコンパイルすればOKです。
この方法を使えば、C言語に限らず、C++でもJavaでもC#でもJavaScriptでも前処理することができます。それどころか、ちょっと工夫すればPHP自体を前処理することさえできます。Makefileを書く場合は問題ないのですが、統合開発環境で前処理を行わせる場合はちょっと面倒かもしれませんね。また、インテリセンスなどの入力補完が正しく動作しない可能性がありますし、常時警告が出続ける可能性もあります。なので、PHPで前処理させるコードを書くときは、私はあまり高機能な統合開発環境よりシンプルなエディタを使っています。
ちなみに、1.14固定小数点というのは、整数部に1ビット、小数部に14ビットを持つ形式です。最上位ビットは符号ビットになりますので、計16ビットで範囲[0, 1]の値を表現することができます。isin関数が返した結果を(1 << 14)で割ってあげれば(そのままでは整数除算になってしまいますので、floatやdoubleにキャストしてから割ります)、元の値を求めることができます。