この章ではm4
への入力を制御するための、さまざまな組み込みマクロを
説明します。
組み込みマクロdnl
は最初の改行文字までにある文字をすべて読み込んでから
改行文字も含めてそれらを捨てます。
dnl
次の例のようにdefine
の呼び出しの後に続く改行を取り除くために、
define
と一緒によく使います。
define(`foo', `Macro `foo'.')dnl A very simple macro, indeed. foo =>Macro foo.
コメントの扱かわれ方とは対照的に(see section コメント)、 次の改行までの入力が改行を含めて捨てられます。
通常dnl
の後ろには、行末もしくはその他の空白(whitespace)が続きます。
GNU m4
はdnl
に続いて開きカッコがあるとき、
それを警告する診断メッセージを出します。
この場合dnl
は閉じカッコを探しながら、すべての引数を集め処理します。
この引数の収集が原因となる予想可能な副作用はすべて起こります。
このときdnl
は何も出力しません。
閉じカッコのあとに続く次の改行までの入力は、
それがどの行にあっても、改行を含めてやはり捨てられます。
デフォルトの引用符は組み込みマクロchangequote
によって変更できます。
changequote(opt start, opt end)
startは新しい開始引用符でendは新しい終了引用符です。
もし欠けている引数があるときは、デフォルトの引用符(`
と '
)
がその欠けている引数の代わりに使用されます。
changequote
は展開されると消滅します。
changequote([, ]) => define([foo], [Macro [foo].]) => foo =>Macro foo.
適切な文字がないときはstartやendを好きな長さにしてかまいません。
changequote([[, ]]) => define([[foo]], [[Macro [[[foo]]].]]) => foo =>Macro [foo].
引用符を両方とも空文字列にすると、事実上クォート機構が無効になり、 テキストをクォートする方法が無くなります。
define(`foo', `Macro `FOO'.') => changequote(, ) => foo =>Macro `FOO'. `foo' =>`Macro `FOO'.'
changequote
を使って現在の引用符を替えない限り、
終了引用符と対になっていない開始引用符を含む文字列をクォートする
方法はm4
には存在しません。
入力に含まれる名前と混同されてしまうので、 どちらの引用符も記号でない普通の文字や`_' (アンダースコア)で 始めるべきではありません。そうした場合はクォート機構が無効になります。
デフォルトのコメントデリミタ(comment delimiters)は
組み込みマクロchangecom
で変更できます。
changecom(opt start, opt end)
startが新しいコメント開始デリミタ(start-comment delimiter)で、
endが新しいコメント終了デリミタ(end-comment delimiter)です。
欠けている引数があるときは、デフォルトのコメント区切り記号
(#
と 改行文字)がその欠けている引数の代わりに使用されます。
コメント区切り記号は任意の長さにすることができます。
changecom
は展開されると消滅します。
define(`comment', `COMMENT') => # A normal comment =># A normal comment changecom(`/*', `*/') => # Not a comment anymore =># Not a COMMENT anymore But: /* this is a comment now */ while this is not a comment =>But: /* this is a comment now */ while this is not a COMMENT
クォートされた文字列であるかのようにコメントが出力にコピーされている 様子に注目しましょう。 コメント内部のテキストが展開されるようにしたいときは、 コメント開始デリミタをクォートしてください。
引数なしでchangecom
を呼ぶとコメント機構が完全に無効になります。
define(`comment', `COMMENT') => changecom => # Not a comment anymore =># Not a COMMENT anymore
マクロ
changeword
とそれに関連する機能すべてが実験段階にあります。 GNUm4
をインストールする際configure
に--enable-changeword
オプションを与えたときだけ この機能を使用することができます。 これから先、この機能が変更されたり、削除されてしまうことさえありえます。 したがって、この機能に依存した使い方はしないで下さい。 この機能について意見を寄せていただくときは バグを報告するときと同じ方法で行ってください。
m4
によって処理されるファイルは、クォートされた文字列、
単語(潜在的なマクロ名)、そして単純なトークン(その他の単一の文字すべて)
に分割されます。
初めに単語は次の正規表現によって定義されています。
[_a-zA-Z][_a-zA-Z0-9]*
changeword
を使えばこの正規表現を変更できます。
たとえば数字が含まれているファイルに置換をかけたい場合など、
m4
の字句構成規則を緩めると便利なときもあるでしょう。
changeword(`[_a-zA-Z0-9]+') define(1, 0) =>1
字句構成規則を厳しくすると 組み込みマクロのうちいくつかが使えなくなってしまうことが多いので、 緩める場合ほど便利にはなりません。 次の例のように、間違って組み込みマクロを呼んでしまうのを避けるために 使うことはできるでしょう。
define(`_indir', defn(`indir')) changeword(`_[_a-zA-Z0-9]*') esyscmd(foo) _indir(`esyscmd', `ls')
m4
は単語を一度に一文字ずつ構築するので、
changeword
に渡すことができる正規表現には制限があります。
これは、もし指定した正規表現が`foo'を受理するなら
`f'と`fo'も受理しなければならないというものです。
changeword
には、もう一つ機能があります。
指定した正規表現に角括弧でくくられた部分が1つ以上存在する場合、
最初の角括弧でくくられた部分の外側にあるテキストが、
シンボルを表引きする前に捨てられます。
changecom(`/*', `*/') changeword(`#\([_a-zA-Z0-9]*\)') #esyscmd(ls)
こうすると、m4
はすべてのマクロの呼び出しの先頭に
`#'記号を必要とするようになるので、
m4
でシェル・スクリプトを処理するときに
shift
コマンドがm4
に飲み込まれてしまわないようにできます。
また種々の一般的な単語を失うことなくプレーン・テキストを
処理できるようになります。
m4
のマクロ置換はテキストに基づいていますが、
TeXのものはトークンに基づいています。
changeword
によって、この違いを浮き彫りにすることができます。
たとえば次の例は同じアイデアをTeXとm4
で表現したものです。
初めはTeX バージョンからです。
\def\a{\message{Hello}} \catcode`\@=0 \catcode`\\=12 =>@a =>@bye
つぎにm4
バージョンです。
define(a, `errprint(`Hello')') changeword(`@\([_a-zA-Z0-9]*\)') =>@a
TeXの例において、最初の行はマクロa
が`Hello'メッセージを
表示するように定義しています。
2行目は\の代わりに@をエスケープ文字として使えるように
定義しています。
3行目は\をエスケープ文字ではなく通常の表示可能文字として
定義しています。
4行目はマクロa
を呼び出しています。
したがって、このファイルに対してTeXを走らせると
`Hello'メッセージを表示します。
m4
の例をm4
に与えると`errprint(Hello)'を表示します。
この理由はTeXはマクロが定義されたときにマクロ定義の字句解析
を行うのに対し、m4
は単純にテキストを保存しておき、
字句解析は実際にマクロが使われるまで後回しにするからです。
changeword
を使用すると、
m4
の速度が7倍ほど遅くなることに注意してください。
通常の入力が終りになるまで、テキストを`保存(save)'しておくことができます。
保存されたテキストは通常の入力が終った段階でm4
に再び読み込まれます。
通常この機能は一時ファイルの削除など正常終了前に行うクリーンアップ動作を
開始するために使われます。
入力テキストを保存するためには組み込みマクロm4wrap
を使います。
m4wrap(string, ...)
stringと残りの引数は入力が終端に達したときに再び読み込まれるように 安全な場所に保存されます。
define(`cleanup', `This is the `cleanup' actions. ') => m4wrap(`cleanup') => This is the first and last normal input line. =>This is the first and last normal input line. ^D =>This is the cleanup actions.
保存されている入力は通常の入力が終端に達したときだけ再び読み込まれます。
m4
を終了するためにm4exit
が使われたときは再読み込みは行われません。
保存されたテキストの中でm4wrap
を呼びだしても差し支えありませんが、
そのとき保存されたテキストが再読み込みされる順番は決まっていません。
m4wrap
が再帰的に使われていない場合、
保存された各テキストはそれぞれが保存されたのと逆の順番(LIFO--last in, first out)で再読み込みが行われます。
Go to the first, previous, next, last section, table of contents.