読者です 読者をやめる 読者になる 読者になる

m4のifelseをプリミティブでなく定義する

ifelseマクロ

マクロプロセッサm4にはifelseというプリミティブがあり、次のようにして条件分岐(条件式)をマクロとして書くことができます。

$ cat sample.txt
define(`foo',``hoge'')dnl
define(`bar',``hoge'')dnl
ifelse(foo,bar,`true',`false')
define(`foo',``hoge'')dnl
define(`bar',``piyo'')dnl
ifelse(foo,bar,`true',`false')

$ m4 < sample.txt
true
false

ユーザー定義マクロによる実現

一見、このifelseはプリミティブでないと困るように思えますが、簡単な展開であれば、実は以下のようなマクロで代用できます(本物は多段分岐とかもできる)。

$ cat sample2.txt
define(`IFELSE',`define(`$1',``dummy'')$1(define(`$1',`$4')define(`$2',`$3'))')dnl
define(`foo',``hoge'')dnl
define(`bar',``hoge'')dnl
IFELSE(foo,bar,`true',`false')
define(`foo',``hoge'')dnl
define(`bar',``piyo'')dnl
IFELSE(foo,bar,`true',`false')

$ m4 < sample2.txt
true
false

仕組みですが、IFELSEがどのように展開されているかを見れば簡単にわかります。IFELSEを定義しているdefineの2個目の実引数をもう一段クウォートしてみると次のようになります。

$ cat sample3.txt
define(`IFELSE',``define(`$1',``dummy'')$1(define(`$1',`$4')define(`$2',`$3'))'')dnl
define(`foo',``hoge'')dnl
define(`bar',``hoge'')dnl
IFELSE(foo,bar,`true',`false')
define(`foo',``hoge'')dnl
define(`bar',``piyo'')dnl
IFELSE(foo,bar,`true',`false')

$ m4 < sample3.txt
define(`hoge',``dummy'')hoge(define(`hoge',`false')define(`hoge',`true'))
define(`hoge',``dummy'')hoge(define(`hoge',`false')define(`piyo',`true'))

先頭の定義は、そこにある通りダミーです。m4では(cpp等でも同様ですが)、トークンをマクロ名として見てその時点で定義されてないと素通りしてしまうため、まずとにかく一旦定義します。続いてカッコの狭間にあるhogeがマクロの呼び出しですが、マクロの実際の置換えは、実引数の処理が全部終わった後に行われるのでまずは何もせず、m4は実引数の処理に進みます。ここで実引数がdefine、すなわちマクロ定義マクロであるため、実引数が処理されることによってhogeの再定義が起きます。展開結果を見ればわかりますが、1行目では1個目の定義が2個目の定義でさらに上書きされます。一方2行目では1個目の定義が有効です。このようにhogeが(再)定義された後に、hogeの置換えが起きるので、最終的に条件分岐が実現できる、ということになります。

余談(本題)

m4は名前を見てマクロ呼出しか否かを決める、という仕様であるためダミーの定義が必要でしたが、拙作のマクロプロセッサMacr055(m55)ではマクロ呼出しは明示的ですので、ダミーの定義は必要ありません。(2014/Dec/14 追記 バージョンアップで動作を修正したため、以下の変更は最新版では必要ありません。パッチも当たりません)が、Software Tools(『ソフトウェア作法』)の実装にならって、マクロ名を読んだ時点で定義を引っ張るようになっているため、ここで示したようなことはそのままでは出来ません。以下のパッチを当てる必要があります(仕様を変更しようか考慮中)。

以上の話の元ネタは、GPMというマクロプロセッサを詳解している次の論文

の中にあるのですが(m4ではマクロ名の名前空間を汚染してしまうが、GPMにはマクロローカルの名前空間があるので汚染が起きない)、GPMについては、今月28日(金曜日)が申込み〆切りの「第56回プログラミング・シンポジウム」( http://www.ipsj.or.jp/prosym/56/56CFA.html )にある和田先生の「GPMとそのプログラム」で深い話があるのではないか、と思われます。