m4 マクロ・プロセッサーの概要

このトピックでは、オペレーティング・システム環境で使用されている、任意のプログラミング言語用のフロントエンド・プロセッサーである、m4 マクロ・プロセッサーについての情報を提供します。

プログラムの先頭で、シンボル名またはシンボリック定数を特殊な文字列として定義することができます。 次に、m4 マクロ・プロセッサーを使用して、 引用符のないシンボル名のオカレンスを対応する文字列に置き換えることができます。 あるテキストの文字列を他の文字列に置き換えるだけでなく、m4 マクロ・プロセッサーには以下の機能があります。

  • 演算機能
  • ファイル操作
  • 条件付きマクロ展開
  • 文字列およびサブストリング関数

m4 マクロ・プロセッサーは、トークン と呼ばれる英字と数字の文字列を処理します。 m4 マクロ・プロセッサーは、それぞれの英数字のトークンを読んで、 それがマクロの名前かどうかを判別します。 次に、マクロを定義するテキストでマクロ名を置き換え、 その結果の文字列を元の入力にプッシュし、再スキャンします。 マクロは引数で呼び出せますが、 引数は定義テキストが再スキャンされる前に収集されて、右側の場所に置き換えられます。

m4 マクロ・プロセッサーは、define などの組み込みマクロを提供します。 新規マクロを作成することもできます。 組み込みマクロとユーザー定義マクロの働きは同じです。

m4 マクロ・プロセッサーの使用

m4 マクロ・プロセッサーを使用するには、 次のコマンドを入力します。

m4 [file]

m4 マクロ・プロセッサーは、各引数を順に処理します。 引数がないか、または引数が - (ダッシュ) である場合、m4 マクロ・プロセッサーはその入力ファイルとして標準入力を読み取ります。 m4 マクロ・プロセッサーは、その結果を標準出力に書き込みます。 したがって、後で使用するために出力をファイルにリダイレクトするには、 次のようなコマンドを使用します。

m4 [file] >outputfile

ユーザー定義マクロの作成

マクロ 説明
define ( MacroName, Replacement) Replacement の値を持つ新しいマクロ MacroName を定義します。

例えば、プログラムに次のステートメントがあるとします。

define(name, stuff)

m4 マクロ・プロセッサーは、 文字列stuff と定義しています。 文字列がプログラム・ファイル内に存在する場合、m4 マクロ・プロセッサーはそれを文字列 stuff に置き換えます。 文字列 name は、ASCII 英数字であり、 しかも英字または下線で始まっていなければなりません。 文字列 stuff は任意のテキストですが、 テキスト中に括弧が使われている場合、 開き括弧 (左括弧) の数は閉じ括弧 (右括弧) の数と同じでなければなりません。 stuff のテキストを複数行に広げるには、/ (スラッシュ) を使用します。

開き括弧 (左括弧) は、ワード define のすぐ後に続けます。 次に例を示します。

define(N, 100)
 . . . 
if (i > N)

これは、N100 であると定義し、 シンボリック定数 N を後の if ステートメントで使用します。

プログラム中のマクロ・コールは、次の形式です。

name(arg1,arg2, . . . argn)
マクロ名は、英数字以外の文字で囲んだ場合にかぎり認識されます。 以下の例では、変数 NNN は、 定義されたマクロ N と関連付けられません。
define(N, 100)
 . . . 
if (NNN > 100)

他の名前に関してマクロを定義することができます。 次に例を示します。

define(N, 100)
define(M, N)

これは、MN が両方とも 100 であると定義します。 後で N の定義を変更して、 それに新しい値を割り当てた場合、M は、N ではなく 100 の値を保存します。

m4 マクロ・プロセッサーは、 マクロ名をできるかぎり早くその定義テキストに展開します。 文字列 N は、100 で置き換えられます。 次に、文字列 M100 で置き換えられます。 全体としての結果は、最初の場所に次のように入力した場合と同じです。

define(M, 100)

定義の順序は、次のように交換できます。

define(M, N)
define(N, 100)

ここで、M は文字列 N であると定義されているので、 後で M の値が要求されたとき、 結果はその時点での N の値になります (M が N によって置き換えられ、 それが 100 によって置き換えられるためです)。

引用文字の使用

define の引数の展開を遅らせるには、それを引用文字で囲みます。 引数を変更しない場合の引用文字は ` および ' (左右の単一引用符) です。 引用文字によって囲まれたテキストは、いずれもすぐには展開されませんが、 引用文字は除去されます。 引用符付き文字列の値は、引用文字を除去した文字列になります。 次の例を参照してください。

define(N, 100)
define(M, `N')

N を囲む引用文字は、引数が収集されるときに除去されます。 引用文字を使用した結果、M は、100 でなく文字列 N になります。 一般的規則では、m4 マクロ・プロセッサーは、何かを評価するときに、 常に 1 レベルの引用文字を取り去ります。 これは、マクロの外側でも同じです。 define という語を出力に表示させるには、 その語を次のように引用文字で囲んで入力します。

`define' = 1;

引用文字の別の使用例は、N の再定義です。 N を再定義する場合は、N を引用文字の中に入れて評価を遅らせます。 次に例を示します。

define(N, 100)
. . . 
define(`N', 200)

問題が発生するのを防ぐために、マクロの最初の引数を引用します。 例えば、次のフラグメントは N を再定義しません。

define(N, 100)
. . . 
define(N, 200)

2 番目の定義の N は、100 で置き換えられます。 結果は、次のステートメントと同じです。

define(100, 200)

m4 マクロ・プロセッサーは、 名前を定義できるだけで数字は定義できないので、 このステートメントを無視します。

引用文字の変更

引用文字は普通は ` および ' (左または右の単一引用符) です。 それらの文字が適切ではない場合は、次の組み込みマクロで引用文字を変更できます。

マクロ 説明
changequote (l, r ) 左右の引用文字を、l 変数と r 変数で表される文字に変更します。

元の引用文字に復元するには、changequote を次のように引数なしで使用します。

changequote

引数

マクロ処理の最も簡単な形式は、 ある文字列の他の文字列 (固定) 文字列による置き換えです。 ただし、マクロでも引数を使用できるので、 マクロを異なる場所で使用して、異なる結果を得ることができます。 引数をマクロの置換テキスト (その定義の 2 番目の引数) の中のどこで使用するかを示すには、 シンボル $n を使用して、n 番目の引数を示します。 マクロが使用されるとき、m4 マクロ・プロセッサーがシンボルを指示された引数の値で置き換えます。 例えば、次のシンボルがあるとします。

$2

これは、マクロの 2 番目の引数を参照します。 したがって、bump と呼ばれるマクロを次のように定義したとします。

define(bump, $1 = $1 + 1)

m4 マクロ・プロセッサーは、 最初の引数を 1 ずつ増分するコードを生成します。 bump(x) ステートメントは、x = x + 1 と同じです。

マクロでは、必要なだけの引数を使用することができます。 ただし、$n シンボルを使用してアクセスできる引数は 9 個だけです ($1 から $9)。 9 番目を超える引数をアクセスするには、shift マクロを使用します。

マクロ 説明
shift ( ParameterList) リストの復元不能な左シフトを実行するために、ParameterList の最初のエレメントを除くすべてを戻します。

このマクロは 1 番目の引数を除去し、 残りの引数を $n シンボルに再び割り当てます (2 番目の引数を $1 に、3 番目の引数を $2 に、 10 番目の引数を $9 に)。 shift マクロを複数回使用すると、 そのマクロで使用するすべての引数にアクセスすることができます。

$0 マクロはマクロの名前を戻します。 提供されていない引数は null 文字列に置き換えられるので、 引数を次のように連結したマクロを定義することができます。

define(cat, $1$2$3$4$5$6$7$8$9)

したがって

cat(x, y, z)

これは次の場合と同じです。

xyz

この例の引数 $4 から $9 は、 対応する引数が提供されていないので null です。

m4 マクロ・プロセッサーは、先行する引数で囲まれていないブランク、 タブ、または改行の文字を破棄しますが、他のすべてのホワイト・スペースは保持します。 したがって

define(a, b c)

これは、ab c であると定義します。

引数はコンマで分離します。 コンマで引数が終わらないようにするには、 括弧を使用してコンマの入った引数を囲みます。 次に例を示します。

define(a, (b,c))

この引数は 2 つだけです。 最初の引数は a で、2 番目は (b,c) です。 コンマまたは単一括弧を使用するには、 それを引用文字で囲みます。

事前定義 m4 マクロの使用

m4 マクロ・プロセッサーは、1 組の事前定義マクロを提供します。 この項では、多数のマクロとその使用法について説明します。

マクロ定義の除去

マクロ 説明
undefine (` MacroName') ユーザー定義マクロまたは組み込みマクロ (`MacroName ') の定義を除去します。

次に例を示します。

undefine(`N')

これは、N の定義を除去します。 例えば次のように、undefine マクロで組み込みマクロを除去するとします。

undefine(`define')

組み込みマクロの定義を再び使用できなくなります。

この場合は、置き換えを防ぐために単一引用符が必須です。

定義済みマクロの検査

マクロ 説明
ifdef (`MacroName', Argument1, Argument2 ) マクロ MacroName が定義済みで、 ゼロに定義されていない場合、Argument1 の値を戻します。 それ以外の場合、Argument2 を戻します。

ifdef マクロでは、3 つの引数を使用することができます。 最初の引数が定義されている場合、ifdef の値は 2 番目の引数です。 最初の引数が定義されていない場合、ifdef の値は 3 番目の引数です。 3 番目の引数がない場合、ifdef の値は null です。

整数演算の使用

m4 マクロ・プロセッサーは、整数のみの演算を行うために、 以下の組み込み関数を用意しています。

マクロ 説明
incr ( Number) Number + 1 の値を戻す。
decr ( Number) Number - 1 の値を戻す。
eval 算術式を評価する。

したがって、変数を Number 値より 1 大きく定義するには、 次のものを使用します。

define(Number, 100)
define(Number1, `incr(Number)')

これは、Number1Number の現行値より 1 大きく定義します。

eval 関数は、 次の演算子 (優先度に関して降順にリストされている) を使った式を評価することができます。
  • 単項 + および -
  • ** または ^ (べき乗)
  • * / % (モジュラス)
  • + -
  • == != < <= > >=
  • !(not)
  • & または && (論理 AND)
  • | または || (論理 OR)

必要に応じて操作をグループ化するには、括弧を使用します。 式のオペランドは、すべて数字でなければなりません。 真の関係の数値 (例えば、1 > 0) は 1、 偽は 0 です。eval 関数の精度は 32 ビットです。

例えば、次に示すように、eval を使用して M2==N+1 であると定義します。

define(N, 3)
define(M, `eval(2==N+1)')

テキストが非常に簡潔でないかぎり、マクロを定義するテキストを引用文字で囲みます。

ファイルの操作

新しいファイルを入力に組み合わせるには、 組み込みの include 関数を使用します。

マクロ 説明
include ( File) ファイル File の内容を戻します。

次に例を示します。

include(FileName)

これは、FileName の内容を include コマンドの位置に挿入します。

include マクロで指定されたファイルにアクセスできない場合、 致命的エラーが発生します。 致命的エラーを避けるには、 代替形式の sinclude マクロ (サイレントの組み込み) を使用します。

マクロ 説明
sinclude ( File ) ファイル File の内容を戻しますが、File へアクセスできない場合にエラーを報告しません。

sinclude (silent include) マクロはメッセージを書きませんが、 指定されたファイルにアクセスできない場合は継続します。

出力のリダイレクト

m4 マクロ・プロセッサーの出力は、 処理時に一時ファイルに再びリダイレクトし、 収集された材料をコマンドで出力することができます。 組み込みの divert マクロを使用している場合、 m4 マクロ・プロセッサーは、 1 から 9 の番号を付けられた 9 個までの一時ファイルを保守します。

マクロ 説明
divert ( Number) 出力ストリームを一時ファイル Number に変更します。

m4 マクロ・プロセッサーは、 プログラムからのすべての出力を、divert 関数の後で一時ファイル Number の終わりに書き込みます。 出力をディスプレイ・スクリーンに戻すには、 通常の出力処理を再開する divert 関数か divert(0) 関数のどちらかを使用します。

m4 マクロ・プロセッサーは、すべてのリダイレクトされた出力を、 処理の最後に、 一時ファイルに数値順に書き込みます。 m4 マクロ・プロセッサーは、 出力が 0 から 9 以外の一時ファイルにリダイレクトされると、出力を破棄します。

データをすべての一時ファイルから数値順に戻すには、 組み込みの undivert マクロを使用します。

マクロ 説明
undivert ( Number1, Number2... ) 指示された一時ファイルの内容を、現在の一時ファイルに追加します。

選択された一時ファイルを指定された順序で戻すには、 組み込みの undivert マクロを引数付きで使用します。 undivert マクロの使用時に、m4 マクロ・プロセッサーは、 リカバリーされた一時ファイルを破棄し、 リカバリーされたデータをマクロのために検索することはありません。

undivert マクロの値は、方向転換されたテキストではありません。

divnum マクロを使って、どの一時ファイルが現在使用中かを判別することができます。

マクロ 説明
divnum 現在アクティブな一時ファイルの値を戻します。

divert マクロで出力ファイルを変更しない場合、m4 マクロ・プロセッサーは全出力を 0 という名前の一時ファイルに書き込みます。

プログラム内でのシステム・プログラムの使用

組み込まれた syscmd マクロを使用すると、 プログラムから任意のプログラムをオペレーティング・システムで実行することができます。 例えば、次のステートメントは date プログラムを実行します。

syscmd(date)

固有ファイル Nnames の使用

maketemp マクロを使用して、 プログラムから固有ファイル名を作成することができます。

マクロ 説明
maketemp ( String...nnnnn...String) 引数文字列内の文字 nnnnn を現在のプロセス ID で置き換えることによって、 固有ファイル名を作成します。

例えば、次のステートメントがあるとします。

maketemp(myfilennnnn)

m4 マクロ・プロセッサーは、myfile にプロセス ID を連結した文字列を戻します。 この文字列は、一時ファイルの指定に使用します。

条件式の使用

条件式の評価を使えば、マクロ式の処理時間を判別することができます。

説明
ifelse (String1, String2, Argument1, Argument2) String1String2 と一致する場合、Argument1 を戻します。 それ以外の場合は、Argument2 を戻します。

組み込まれた ifelse マクロは、条件テストを行います。 最も簡単な形式では、次のようになります。

ifelse(a, b, c, d)

これは、2 つの文字列 ab を比較します。

ab が同一の場合、 組み込まれた ifelse マクロは 文字列 c を戻します。 同一でない場合は、文字列 d を戻します。 例えば、2 つの文字列を比較して、同じ場合は yes を、 異なる場合は no を戻す、compare と呼ばれるマクロを定義することができます。

define(compare, `ifelse($1, $2, yes, no)')

引用文字によって、ifelse マクロの評価が早く行われすぎるのを防止することができます。 4 番目の引数が欠落している場合、空として扱われます。

ifelse マクロでは任意の数の引数を使用でき、 したがって、限定形式のマルチパスの決定能力を提供します。 次に例を示します。

ifelse(a, b, c, d, e, f, g)

このステートメントは、次に示すフラグメントと論理的に同じです。

if(a == b) x = c;
else if(d == e) x = f;
else x = g;
return(x);

最終引数を省略すると、結果は null になります。

ifelse(a, b, c)

そのため、これは ab と一致する場合は c に、 それ以外の場合は null になります。

文字列の操作

この項で述べているマクロを使えば、入力文字列を出力文字列に変換することができます。

マクロ 説明
len その引数を構成する文字列のバイト長を戻します。

したがって

len(abcdef)

これは 6 です。

len((a,b))

これは 5 です。

マクロ 説明
dlen 文字列内の表示可能文字の長さを戻します。

2 バイト・コードで構成される文字は、1 文字として表示されます。 したがって、文字列に何らかの 2 バイトの、 各国文字サポート文字が使われている場合、dlen の結果は len の結果とは異なります。

マクロ 説明
substr ( String, Position , Length) 文字番号 Position から始まり、Length 文字長の String のサブストリングを戻します。

入力を使用すると、substr (s, i, n) は、i 番目の位置 (原点は 0) から始まり、n 文字長の s のサブストリングを戻します。 n を省略すると、文字列の残りの部分が戻されます。 例えば、次の関数を参照してください。

substr(`now is the time',1)

これは、次の文字列を戻します。

ow is the time
マクロ 説明
index( String1, String2 ) String1 の中の、String2 が始まる文字位置 ( 文字番号 0 から始まる)、 または String1String2 が入っていない場合は -1 を戻します。

組み込まれた substr マクロの場合と同様、 文字列の起点は 0 です。

マクロ 説明
translit ( String, Set1 , Set2) Set1 の中にある文字を求めて、String を検索します。 見つかった場合は、それらの文字を Set2 の中の対応する文字に変更します (文字変換)。

この一般的形式は、次のようになります。

translit(s, f, t)

これは、f で見つかった任意の文字を t の対応する文字によって置き換えることによって s を変更します。 例えば、次の関数を参照してください。

translit(`little', aeiou, 12345)
これは、母音をそれに対応する数字に置き換えて、以下を戻します。
l3ttl2

t の方が f より短い場合は、t の中のエントリーを持たない文字は削除されます。 t がまったく存在しない場合、f の文字は s から削除されます。 次の関数を参照してください。

translit(`little', aeiou)
これは、文字列 little から母音を削除して、以下を戻します。
lttl
マクロ 説明
dnl その後に続くすべての文字を、改行文字まで (これを含む) 削除します。

このマクロは、空の行を除去するために使用します。 例えば、次の関数を参照してください。

define(N, 100)
define(M, 200)
define(L, 300)

この結果、定義の一部でない各行の最後に改行が置かれます。 これらの改行文字は、出力に渡されます。 改行を除去するには、 各行に組み込みの dnl マクロを追加します。

define(N, 100) dnl
define(M, 200) dnl
define(L, 300) dnl

m4 マクロのデバッグ

この項で説明しているマクロを使えば、エラーと処理情報をレポートすることができます。

マクロ 説明
errprint ( String) その引数 (String) を標準エラー・ファイルに書き出す

次に例を示します。

errprint (`error')
マクロ 説明
dumpdef (` MacroName'... ) 引数として指定された項目の現在の名前と定義 (`MacroName '...) をダンプする

引数を指定しないと、dumpdef マクロは現在の名前と定義をすべて出力します。 名前を引用符で囲むことを忘れないでください。

その他の m4 マクロ

それぞれの簡単な説明を付けた追加 m4 マクロのリストを、 次に示します。

マクロ 説明
changecom ( l, r ) 左右のコメント文字を l 変数と r 変数で表される文字に変更します。
defn ( MacroName) 引用符で囲まれた MacroName の定義を戻します。
en (String ) String 内の文字数を戻します。
m4exit ( Code) m4 マクロ・プロセッサーを Code の戻りコードで終了します。
m4wrap ( MacroName) m4 マクロ・プロセッサーの終了時にマクロ MacroName を実行します。
popdef ( MacroName) MacroName の現在の定義を pushdef マクロによって保管された直前の定義で置き換えます。
pushdef ( MacroName, Replacement) MacroName の現在の定義を保管してから、MacroNameReplacement であると定義します。
sysval syscmd マクロを最後に使用したときの戻りコードを取得します。
traceoff ( MacroList) MacroList 内の任意のマクロのトレースをオフにします。 MacroList が null の場合、すべてのトレースをオフにします。
traceon ( MacroName) マクロ MacroName のトレースをオンにします。 MacroName が null の場合、すべてのマクロのトレースをオンにします。