本来の \romannumeral
さて、これまでの \romannumeral の話を見て、きっと誰もが「どうしていつも後ろにゴチャゴチャしたものがくっついているのだ」と疑問に思うであろう。これには少し複雑な事情がある。
\romannumeral プリミティブを用いると先頭完全展開ができることを解説したが、実は、このプリミティブの本来の目的はそれではなく、\romannumeral は \number と同様の「整数を文字列化する」ためのプリミティブだったのである。つまり、次のような書式で使われる。
\romannumeral<整数n>
そして、n が非正(0 以下)の場合、これの一回展開の結果は空列になる。これがポイントである。(なお、n が正の時は展開結果に何やらアルファベットが混ざってくるので、それほど有用ではない。)もう一度「\romannumeral トリック」の書式を見てみよう。
\romannumeral-`0<トークン列S>
\romannumeral の直後には整数の表現が続くはずである。そう思ってみると、`0 は〈0〉の文字コードである 48 を表すので、この \romannumeral は引数に −48 を取っていて展開すると空になる。それはいいのだが、じゃあ「トークン列 S が先頭完全展開される」という性質はどこからくるのだろう?
TeX が整数を読む
そのポイントは「TeX がコード中にある整数値を読む」時の挙動にある。
- TeX が「整数を読み取る状況にある」ときは、一つの「整数を表現する、展開不能なトークンの列」が得られるまで何度でも展開を繰り返す。
`aは、123、'123、"123と同じく「数字表記による整数」であり、原則的に直後に空白トークンを置いて終結する。終結の空白は無いかもしれないが、とにかく数字表記の直後にある展開不能トークンを得てそれが空白であるか調べる必要がある。
最初の項目について例を挙げて説明しよう。
\def\Q{"}\def\T{3}\def\QT{\Q\T}
\number\QT\T\T\QT1 行目のマクロ定義がある状態で、2 行目のトークン列の 1 回展開はどうなるか。\number の引数を得るために TeX は引き続くトークン列をどんどん展開していく。
\QT\T\T\QT → \Q\T\T\T\QT → "\T\T\T\QT 〔" なので16進数字表記である〕 → "3\T\T\QT 〔16進数字以外に当たるまで進む〕 → "33\T\QT → "333\QT → "333\Q\T → "333"\T 〔数字表記 "333 が終結した〕
この結果、引数は "333 すなわち 819 と判る。従って、この \number の一回展開は以下のようになる。
\number\QT\T\T\QT → 819"\T
\romannumeral トリックができるワケ
ここまで来れば \romannumeral トリックの原理の理解も容易である。例えば次のようなトークン列の一回展開を考えてみる。
\romannumeral-`0\QT
\romannumeral の引数として、TeX は「数字表記」の「-`0」を読み取る。実は、文字コード表記(`a)の“数字”は常に 1 桁しかないのであるが、飽くまで文法上は「数字表記」なので、直後の展開不能トークンを調べて、それが空白であれば除去する必要がある。
-`0\QT → -`0\Q\T → -`0"\T 〔終結する〕
\romannumeral の引数は負数の −48 である。従って、\romannumeral の一回展開は次のようになる。
\romannumeral-`0\QT → "\T
結果的に、「\romannumeral-`0」に続くトークン列を先頭完全展開する動作になっている。
\romannumeral の挙動の例外
前回の記事で、\romannumeral の動作には「一つだけ例外」があると書いた。トリックの原理を解っている人なら、例外が何かも判るだろう。「対象のトークン列の先頭完全展開の先頭が空白トークンである場合は、展開結果からはそれが消滅する」ということである。
\def\A{\B\B}
\edef\B{\space\space}% \B は"␣␣"に展開される
この定義の下では、「\A\A」の先頭完全展開の結果は「␣␣\B\A」である。一方、「\A\A」に \romannumeral トリックを適用した結果は次のようになる。
\romannumeral-`-\A\A → ␣\B\A
つまり、先頭の空白トークンが 1 つ(だけ)消えてしまう。
ZR さんの流儀
ちなみに、某 ZR 氏は、自分の書く TeX コードの中で \romannumeral トリックを使う場合は以下のような書き方をしている。
%% \xx@burst-`>(トークン列)
% いわゆる"\romannumeral トリック".
\let\xx@burst\romannumeral
%%<*> \choptwo{<文字列>}
% 2文字切り落とす.
\newcommand*\choptwo[1]{%
\expandafter\chop\expandafter{\xx@burst-`>\chop{#1}}}すなわち、「\romannumeral-`0」の部分の見かけを「\xx@burst-`>」(“xx@”は適当な名前空間識別子)としている。“0”でなくて“>”を使う((もちろん、-`0(= -48)も -`>(= -62)も負の値だから動作は同じである。))のは、「-`>」を矢の形に見立てているからである。