2011-03-31 の記事の続き。
その記事では、任意の非負整数を「読み飛ばす」(空に展開する)方法を述べた。これを読んで「じゃあ負数を含めた任意の整数を読み飛ばすことはできないの?」と思った人がいるかも知れない。ここではそれを考えてみる。
これを行うには「展開可能なプリミティブで整数を引数にして結果何も出さない」ものが必要となるが、残念ながら TeX にそういうプリミティブは存在しないようだ。というかそんな命令は普通は何の役にも立たないからなくても当然だ。
ただ 1 つ可能性があるのは \if-トークンの利用である。\if-トークンは挙動が複雑で普通の「展開可能プリミティブ」とは訳が異なるが、展開可能であることは間違いない。すなわち
\edef\foo{\ifnum0=12345 \fi} % \foo の展開は空になる
を実行すると、12345 の部分が他の値であっても \foo
の展開テキストは空になる。ということは、展開制御(\expandafter
)を駆使して次の手順を踏めば良さそうである。
残念ながら、この方法は次の理由で上手くいかない。
\ifnum
の条件判断が偽だった場合、(実質的に)その時点で、「対応する」\fi
(今の場合存在しないかも知れない)まで読み飛ばされてしまい、新たな\fi
を割り込ませてもそれは先の\fi
の後にしか来ない。
つまり、(現在 \ifx
の有効な分岐の中だとして)
\ifnum0=100 \foo...\fi \bar
のように \ifnum0=
を割り込ませて \ifnum
を展開して直後に \fi
を割り込ませても、その結果は
\ifnum0=100 \foo...\fi\fi \bar
と同値なもの(これでは \foo
は処理されない)になってしまい、所望の
\ifnum0=100 \fi\foo...\fi \bar
(\foo
は処理されるべき)にならないのである。
ところで、上の例で判断が真(つまり 100 を 0 に変えた場合)は、そもそも読み飛ばしが発生しないため、所望の位置に \fi
が入る。ということは、「整数を読んで、常に真となる条件文」があれば好都合である。しかし残念ながら TeX の条件文には該当するものがない。「最も安全(偽になる可能性が最も低い)」なのが、「\ifnum-"7FFFFFFF<〈n〉
」でこれは n が -"7FFFFFFF
(TeX で扱える最小の整数値)でない限り成立する。TeX には ≦、≧ の比較がないのである。((「e-TeX だったら \unless\ifnum-"7FFFFFFF>〈n〉
で実現できる」と考えたかも知れない。確かにそうである。ただし、後で触れるように、e-TeX ではもっと安全な方法がある。))
取りあえず、「n = -"7FFFFFFF
の時に破綻する」ことは諦めて、今の方法で、後続の任意の整数を読み飛ばすマクロ \xx@gobblenum
を実装すると以下のようになる。
\def\xx@gobblenum{%
\expandafter\fi \ifnum-"7FFFFFFF<%
}
これで、(n ≠ -"7FFFFFFF
の時)\xx@gobblenum〈n〉
は 3 回展開すると空になる。
\edef\xx@test{\xx@gobblenum 12345ABC} % \xx@test は「ABC」になる
\edef\xx@test{\xx@gobblenum\year\space ABC} % \xx@test は「 ABC」になる
実は、この \xx@gobblenum
の定義は、もう 1 つ失敗する場合がある。次のように「該当の整数が数字表記でかつ終端に達しない内に \fi
がある」場合、展開結果に何故か出所不明の \relax
が出現する。
\edef\xx@test{\iftrue\xx@gobblenum 12345\fi X} % \xx@test は「\relax X」になる
これは TeX の仕様である。次のような場合が解りやすい。
\count9=1\iffalse2\else3\fi4 % \count9 は 134 になる
\edef\xx@test{\ifnum 22<11\else 3\fi X} % \xx@test は「\relax X」になる
上の行の例から解るように、数字表記の整数を読み込む場合、if 文自体は数字列を終結させない。ところが同じ理屈で下の行を処理しようとすると、「条件判断を決定するために 11 の次の文字を読む必要があるが、条件判断が決定しないため次の文字が判らない」というジレンマに陥ってしまう。従って、「条件部が終結しないまま \else
や \fi
に達した」場合、TeX は \else
/\fi
の前に \relax
を自動挿入して「条件部を終結させる」処理を行う。展開結果に \relax
が入るのはそのためである。