……いや、別に全然怖くなんかないですよ!
いきなり問題。次の TeX のソースを解析すると何個のトークンからなると見做されるか。ただし、カテゴリコードの設定は LaTeX の通常通りであると仮定する。
\someproc A {B C\relax } {`\\}\nil %?
……いえ、別に「ひっかけ」はないので、素直に答えて大丈夫です…。そう、「15」ですね。やっぱり何も怖くなかった。めでたしめでたし。
* * *
しかし、恐らくは答えが「5」とか「7」とかの全然違う数になった人がいるだろう。そういう人はトークンの定義を誤解している可能性が高い。
粗く言うと、1 つのトークンとは、1 つの制御綴である、または字句解析で無視されない部分の文字(空白文字を含む)の 1 つのことである。今の問題の場合、「複数の空白文字は 1 つと見做される」「制御綴の直後の空白文字は無視される」「コメントは無視される」という規則に従うと、無視されない制御綴と文字は以下のようになり、これらの各々がトークンであるということになる。
「\someproc
」「A
」「空白」「{
」「B
」「空白」「C
」「\relax
」「}
」「空白」「{
」「`
」「\\
」「}
」「\nil
」
よくある誤解は、トークン化のルールを「区切り無しマクロの引数対応」と混同することであろう。例えば、上の例でもし \someproc
が
\def\someproc#1#2#3#4{...}
のように定義されたマクロだとすると、引数の対応は以下のようになる。
#1 -> A #2 -> B C\relax #3 -> `\\ #4 -> \nil
つまり、空白トークンは読み飛ばされ、グループ { ... }
は単一の引数と扱われる。しかし、これは「マクロの引数のルール」であり、トークン化とは関係がない。つまり、
グループはトークンではない
のである。もしこれを誤解していたなら、本当に恐ろしいことになる。なぜなら、トークンの定義の理解は、他の様々な TeX の機能の理解のための前提知識となっているからである。いくつか例を挙げてみる。
\ifx{foo}{#1}...\fi
{foo}
とか foo
とかはトークンではない。{
とか f
とかがトークンである。従って、この if 文は {
と f
を比較するので、#1 の内容に関わらず常に偽となる。
\expandafter\xx@process\expandafter{\xx@args\xx@nil}\xx@postproc
{\xx@args\xx@nil}
はトークンではない。{
がトークンである。従って、このトークン列を 1 回展開した時に展開されるのは \xx@postproc
ではなく \xx@args
である。
\futurelet\xx@token\xx@inspect{x}
\xx@token
は {
に let される。x
ではない。
無論大抵の場合はトークンの理解が誤っているとプログラムが思うように動かないので、デバッグの過程で誤解に気づくだろう。だから、これまである程度の量の TeX 言語のコードを書いている人が、この記事を見た後で、青ざめた顔で自分の今まで書いたコードを片端から読み返している、なんて本当に恐ろしいことは幸いにも起こらない……はず……である。
ちなみに、LaTeX ではトークンの概念は表立って必要となることがほとんどなく、それゆえ LaTeX の参考書では「トークン」の言葉を使わないことが多い。一方で、命令(= TeX 言語のマクロ)の引数の規則は大概は説明がある。したがって、その状態で TeX 言語の学習を始めた時に混同が起きやすいのだと思う。