UNIX/Linuxの部屋 fileppコマンドの使い方

TOP UNIX/Linuxの部屋 UNIX/Linuxコマンド一覧 用語集 新版 由来/読み方辞書 環境変数マニュアル Cシェル変数 システム設定ファイル システムコール・ライブラリ ネットワークプログラミングの基礎知識 クラウドサービス徹底比較・徹底解説




コマンド filepp 独自拡張プリプロセッサ このエントリーをはてなブックマークに追加

filepp は文字列を前処理する cpp と似たようなプリプロセッサである。以下のように使用する。
% filepp 入力ファイル > 出力ファイル


filepp コマンドの使いみち
まず、filepp を cpp の代替として C 言語のソースを処理するために使用するのは避けた方がよい。理由は、インクルードファイルが存在しなかった場合の処理や、文字列リテラル ("hoge" のような文字列定数) を書き換えてしまうという仕様の違いがあるからである。

となると使いどころが難しいのだが、例えば
複数ホストの /etc/hosts などの設定ファイルを管理する際、元ネタとなるファイルをひとつだけ作っておき、filepp で各ホストの hosts を生成する
など、「静的データに対してちょっとした制御を行いたい」というときに使うとよいのではないかと思う。また、Java のようにプリプロセッサが存在しない環境で、プリプロセッサが必要になったときに filepp を使うのもよいかもしれない。

filepp コマンドの基本的な使い方
filepp は下記のようにして使用する。入力ファイル内の #include・#define・#ifdef などの構文を filepp が適切に処理する。
% filepp 入力ファイル > 出力ファイル

プリプロセッサの基本的な構文 (#include・#define・#ifdef など) は cpp の項を参照。同様に、cpp で使用できるオプションは filepp でも使用可能なことが多い。

filepp では一般的な cpp を拡張し、独自の機能を持っている。デフォルトのままで使用できる拡張機能もあるが、多くの機能はモジュールを組み込まないと使用できない。モジュールを有効にするには -m オプションを使う。例えば for.pm モジュールを使う場合は
% filepp -m for.pm 入力ファイル > 出力ファイル
とする。以下、filepp 独自の拡張機能と、注意点を説明する。

文字列比較の拡張
通常のプリプロセッサでは文字列の比較はできない。
#if HOGE = 1
⇒ 数値の比較は OK だが…
#if HOGE = "hoge"
⇒ 文字列の比較はエラーとなる

一方、filepp では eq を使うことで文字列を比較が可能で、さらに「=~」でパターンマッチを使うことができる。
#if HOGE eq "string"
⇒ 文字列の比較には eq を使う
#if HOGE =~ /regexp/
⇒ パターンマッチは「=~」で

ループ (for.pm モジュール)
#for COUNTER 1 < 4 +1
printf("%d\n", COUNTER);
⇒ COUNTER は 1〜3 まで増分 +1 でループする
#endfor

ループ (foreach.pm モジュール)
#foreach FILE "file1.dat", "file2.dat", "file99.dat"
printf("%s\n", FILE);
#endfor
⇒ カンマ区切り記述した各要素を、ループ内で使用できる。

#foreachdelim / /
#foreach FILE "file1.dat" "file2.dat" "file99.dat"
printf("%s\n", FILE);
#endfor
⇒ foreachdelim を使うことで、foreach の区切り文字を変更できる。

#foreachdelim /\s+/
⇒ 区切り文字は正規表現で指定することも可能。

インクルードパス
cpp は /usr/include を標準のインクルードファイルパスとして特別扱いしている。一方、filepp はインクルードファイルパスは全て自分で -I オプションで指定する必要がある (/usr/include は特別扱いされない)。また、インクルードファイルが見つからなかった場合でもエラーとはならず、その行を削除して処理は続行される。

定義済マクロ
cpp と同様に、__FILE__・__LINE__ などが定義済マクロとして用意されているが、
printf("%s\n", __FILE__);
と書くと
printf("%s\n", foo.c);
というふうに文字列がダブルクォートで囲まれない形で置換されてしまう。もし一般的な cpp のような出力が欲しければ、cmacros.pm モジュールを使うこと。

コメント削除 (c-comment.pm モジュール)
C 言語・C++ 形式のコメント、「/* 〜 */」「//〜」を削除する。通常はコメントは出力ファイルに残るが、
% filepp -m c-comment.pm 入力ファイル > 出力ファイル
とすることで、コメントが削除されたものが出力ファイルに出力される。

複数行の define (bigdef.pm モジュール)
普通のプリプロセッサで複数行に渡る置換を行う場合、
#define foo(x,y,z) printf(\ 
   "x is %d\n"\ 
   "y is %s\n"\ 
   "z is %s\n",\ 
   x, y, z);
などと行末にエスケープを付ける必要があり、面倒で可読性が低くなる。しかし bigdef.pm モジュールを組み込むことで、
#bigdef foo(x,y,z)
   printf("x is %d\n"
          "y is %s\n"
          "z is %s\n",
          x, y, z);
#endbigdef
と #bigdef〜#endbigdef を使って読みやすい形で記述できる。

文字列リテラル内の文字列置換抑止 (literal.pm モジュール)
デフォルトでは filepp は文字列リテラルも置換対象とする (というより、filepp は「ここからここまでが文字列リテラル」などという解析は行っていない)。つまり、
#define hoge FUGA
printf("This is hoge.\n");
の出力結果は、
printf("This is FUGA.\n");
となる。しかし literal.pm モジュールを使用すると文字列リテラルかどうかを判断し、文字列リテラル内の文字列置換が抑止されるようになる。

数学関数 (maths.pm モジュール)
加減乗除算のほか、abs・tan・sin・cos・exp・log・rand などが使用可能。どういうときに使うと便利なんだろうか。
printf("1+2=%d\n", add(1, 2));
printf("1+2+3+4=%d\n", add(1, 2, 3, 4));
printf("5-2=%d\n", sub(5, 2));
printf("3*4=%d\n", mul(3, 4));
printf("8/2=%d\n", div(8, 2));
printf("pi=%d\n", M_PI);
printf("e=%d\n", M_EI);