Go to the first, previous, next, last section, table of contents.


新たにマクロを定義する方法

マクロはいくつかの異なる方法で定義、再定義、削除することができます。 また現在の定義を失うことなく一時的にマクロを再定義しておいて、 後で元の定義に戻すこともできます。

マクロの定義方法

通常はマクロを定義したり再定義するときは、 組み込みマクロdefineを使います。

define(name [, expansion])

これはnameexpansionに展開されるように定義します。 もしexpansionが与えられなかったときは、空文字列だと見なされます。

defineは展開されると消滅します。

次の例では、マクロfoo`Hello World.'に展開されるように 定義しています。

define(`foo', `Hello world.')
=>
foo
=>Hello world.

出力に空行がある理由は、マクロ定義の直後にある改行文字が 定義の一部ではなく、従って出力にそのままコピーされるためです。 これはdnlマクロを使うことで避けることができます。 詳しくはSee section 入力中の空白(whitespace)を削除するを参照してください。

マクロdefineは引数が与えられたときだけ認識されます。

マクロの引数

マクロは引数を取ることができます。n番目の引数は$nとして 展開用テキストの中で示し、マクロが展開されるときにn番目の 実引数(actual argument)に置き換えられます。 次の例は2つの引数を取るマクロです。2つの引数の順番を単純に交換します。

define(`exch', `$2, $1')
=>
exch(arg1, arg2)
=>arg2, arg1

これはdefineへの引数の順番を逆にしたいときなどに使えます。

define(`exch', `$2, $1')
=>
define(exch(``expansion text'', ``macro''))
=>
macro
=>expansion text

二重になった引用符の説明についてはSee section マクロの引数をクォートするを参照してください。

GNU m4では`$'に続く数字は複数の桁でもよいので、 マクロはいくつでも引数を取ることができます。 これと違いUNIXのm4では1桁の数字しか認識されません。

特殊なケースとして、0番目の引数$0は常に現在展開されているマクロの名前 となります。

define(`test', ``Macro name: $0'')
=>
test
=>Macro name: test

クォートされたテキストを展開後のテキストに含めたい時は、 クォートは入れ子にできることを思い出しましょう。したがって、

define(`foo', `This is macro `foo'.')
=>
foo
=>This is macro foo.

展開されたテキストに含まれる`foo'は、 クォートされた文字列(quoted string)であり名前(name)ではないので、 再走査によって展開はされず、 引用符がはぎ取られるだけです(see section 字句・構文解析の規則)。

マクロの特殊な引数

与えられた実引数(actual arguments)の個数や全ての実引数をまとめて表すための 特別な表記方法があります。

マクロを呼び出すときに与えられた実引数の個数は、 展開用テキストの中で$#として表します。 したがって与えられた実引数の個数を表示するマクロは次のようになります。

define(`nargs', `$#')
=>
nargs
=>0
nargs()
=>1
nargs(arg1, arg2, arg3)
=>3

展開用テキストの中で$*という表記をすることで、 全ての実引数を(クォートはせずに)コンマで区切ったものを表すことができます。

define(`echo', `$*')
=>
echo(arg1,    arg2, arg3 , arg4)
=>arg1,arg2,arg3 ,arg4

引数をそれぞれクォートしなければならないことがよくありますが、 そんなときは$@という表記を使います。 これは各引数がクォートされることを除けば$*と同じです。

define(`echo', `$@')
=>
echo(arg1,    arg2, arg3 , arg4)
=>arg1,arg2,arg3 ,arg4

引用符はどこに行ったのでしょうか? もちろん展開後のテキストを 再走査したときにm4が食べてしまったのです。 違いを見るために、次のようにしてみましょう。

define(`echo1', `$*')
=>
define(`echo2', `$@')
=>
define(`foo', `This is macro `foo'.')
=>
echo1(foo)
=>This is macro This is macro foo..
echo2(foo)
=>This is macro foo.

これが理解できないときはSee section マクロの呼び出しをトレースするを参照してください。

展開用テキストに記号`$'が存在し、それに続く部分がm4に理解できる ものでないときは、`$'は他のテキストと同じように マクロ展開後のテキストへ単にコピーされます。

define(`foo', `$$$ hello $$$')
=>
foo
=>$$$ hello $$$

マクロを`$12'などに展開させたいときは、 $の後に一組の引用符を置きます。 これによって、m4がその$記号を引数への参照だと解釈してまうのを 防ぐことができます。

マクロの削除

undefineを使えばマクロの定義を削除することができます。

undefine(name)

これによってマクロnameが削除されます。 展開されてしまうのを防ぐためにマクロの名前は必ずクォートしなくてはなりません。

undefineは展開されると消滅します。

foo
=>foo
define(`foo', `expansion text')
=>
foo
=>expansion text
undefine(`foo')
=>
foo
=>foo

nameがマクロとして定義されていなくても問題はありません。 その場合はundefineが何もしないだけです。

undefineは引数が与えられたときだけ認識されます。

マクロ名の変更

すでに定義済みのマクロの名前を替えることができます。 それには組み込みマクロdefnが必要となります。

defn(name)

これはname定義をクォートしたものに展開されます。 引数が定義済みのマクロでないときは展開されると消滅します。

nameがユーザ定義マクロの場合、 クォートされた定義とは単にクォートされた展開用テキストのことです。 nameが組み込みマクロの場合、 展開後のテキストは、m4の内部にある組み込みマクロの定義を指す 特殊なトークンとなります。 このトークンは、define (および pushdef) の第2引数としてのみ意味を持ち、その他の文脈では無視されます。

通常の使用方法は、次の例でundefineの名前をzapに換える方法を 見るのが一番分かりやすいでしょう。

define(`zap', defn(`undefine'))
=>
zap(`undefine')
=>
undefine(`zap')
=>undefine(zap)

このようにdefnはユーザ定義マクロの定義や 組み込みマクロの定義をコピーするために使うことができます。 たとえ元のマクロが削除されても、もう一方の名前を使って 定義にアクセスすることができます。

defnは引数が与えられたときだけ認識されます。

マクロの一時的な再定義

あるマクロを一時的に再定義しておき、後で元の定義に戻すことができます。 それにはdefineundefineに良く似た、 組み込みマクロpushdefpopdefを使います。

pushdef(name [, expansion])
popdef(name)

これらのマクロはスタック(stack)に似た仕組みで機能します。 pushdefは、あるマクロを一時的に再定義します。 このときnameの前の定義は、新しい定義によって置き換えられる前に 保存されます。もし前の定義が存在しない場合は、 pushdefdefineとまったく同じように機能します。

あるマクロに複数の定義が存在する場合(その中の一つだけがアクセス可能です)、 popdefを使って一番上の定義を削除することができます。 前の定義が無い場合、popdefundefineのように機能します。

define(`foo', `Expansion one.')
=>
foo
=>Expansion one.
pushdef(`foo', `Expansion two.')
=>
foo
=>Expansion two.
popdef(`foo')
=>
foo
=>Expansion one.
popdef(`foo')
=>
foo
=>foo

defineによって、複数の定義を持つマクロを再定義したときは、 一番上の定義が新しい定義で置き換えられます。 undefineによって定義を削除するときは、 一番上のもの一つだけではなく、すべての定義が削除されます。

define(`foo', `Expansion one.')
=>
foo
=>Expansion one.
pushdef(`foo', `Expansion two.')
=>
foo
=>Expansion two.
define(`foo', `Second expansion two.')
=>
foo
=>Second expansion two.
undefine(`foo')
=>
foo
=>foo

pushdefdefnを使えば、組み込みマクロを一時的に再定義することが できます。

マクロpushdefpopdefは引数が与えられたときだけ認識されます。

マクロの間接的な呼び出し

indirを使うと、どんなマクロでも間接的に呼び出すことができます。

indir(name, ...)

indirはマクロnameを残りの引数と共に呼び出します。 これを"不正な"名前を持つマクロを呼ぶのに使うことができます(define はそういう名前でも定義できます。)

define(`$$internal$macro', `Internal macro (name `$0')')
=>
$$internal$macro
=>$$internal$macro
indir(`$$internal$macro')
=>Internal macro (name $$internal$macro)

ここでの要点は、大きなマクロ・パッケージで、 間違って呼ばれてしまうことのないマクロを定義できるということです。 それらは組み込みマクロindirによってだけ呼びだすことができます。

組み込みマクロの間接的な呼び出し

builtinを使えば、組み込みマクロを間接的に呼び出すことができます。

builtin(name, ...)

これは組み込みマクロnameを、残りの引数と共に呼び出します。 たとえnameに本来の定義を隠している別の定義が与えられていても、 本来の定義を呼び出します。

マクロbuiltinは引数が与えられたときだけ認識されます。


Go to the first, previous, next, last section, table of contents.