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


入力制御

この章ではm4への入力を制御するための、さまざまな組み込みマクロを 説明します。

入力中の空白(whitespace)を削除する

組み込みマクロdnlは最初の改行文字までにある文字をすべて読み込んでから 改行文字も含めてそれらを捨てます。

dnl

次の例のようにdefineの呼び出しの後に続く改行を取り除くために、 defineと一緒によく使います。

define(`foo', `Macro `foo'.')dnl A very simple macro, indeed.
foo
=>Macro foo.

コメントの扱かわれ方とは対照的に(see section コメント)、 次の改行までの入力が改行を含めて捨てられます。

通常dnlの後ろには、行末もしくはその他の空白(whitespace)が続きます。 GNU m4dnlに続いて開きカッコがあるとき、 それを警告する診断メッセージを出します。 この場合dnlは閉じカッコを探しながら、すべての引数を集め処理します。 この引数の収集が原因となる予想可能な副作用はすべて起こります。 このときdnlは何も出力しません。 閉じカッコのあとに続く次の改行までの入力は、 それがどの行にあっても、改行を含めてやはり捨てられます。

引用符(quote characters)を変更する

デフォルトの引用符は組み込みマクロchangequoteによって変更できます。

changequote(opt start, opt end)

startは新しい開始引用符でendは新しい終了引用符です。 もし欠けている引数があるときは、デフォルトの引用符(`') がその欠けている引数の代わりに使用されます。

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

changequote([, ])
=>
define([foo], [Macro [foo].])
=>
foo
=>Macro foo.

適切な文字がないときはstartendを好きな長さにしてかまいません。

changequote([[, ]])
=>
define([[foo]], [[Macro [[[foo]]].]])
=>
foo
=>Macro [foo].

引用符を両方とも空文字列にすると、事実上クォート機構が無効になり、 テキストをクォートする方法が無くなります。

define(`foo', `Macro `FOO'.')
=>
changequote(, )
=>
foo
=>Macro `FOO'.
`foo'
=>`Macro `FOO'.'

changequoteを使って現在の引用符を替えない限り、 終了引用符と対になっていない開始引用符を含む文字列をクォートする 方法はm4には存在しません。

入力に含まれる名前と混同されてしまうので、 どちらの引用符も記号でない普通の文字や`_' (アンダースコア)で 始めるべきではありません。そうした場合はクォート機構が無効になります。

コメントデリミタ(comment delimiters)を変更する

デフォルトのコメントデリミタ(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

単語(word)の字句構造を変更する

マクロchangewordとそれに関連する機能すべてが実験段階にあります。 GNU m4をインストールする際 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)

通常の入力が終りになるまで、テキストを`保存(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.