TeX言語🤮でよくネタにされるものとして\expandafter
や\aftergroup
といった“変態的なプリミティブ”がある。今回のテーマである\futurelet
もその“変態的なプリミティブ”の一種として紹介されることが多い。
ところが実は\futurelet
は「その動作を理解するだけ」であればそんなに難しいものではない。特に「他人が書いた\futurelet
を含むコードの動作を把握したい」という場合は、\futurelet
の定義さえ知っていれば「とにかく定義に愚直に従って動作を把握する」ことができる。\futurelet
が“読める”ことはそれだけでも大きなメリットになるだろう。
そういうわけで、本記事では\futurelet
の動作を理解したうえで、その知識を使って実際に\futurelet
を“読む”ことを目標とする。
前提知識
とにかく \futurelet の規則を知ろう
\futurelet
の動作を把握するには「TeXのコードを“トークンの列”として見る」ことが大事である。\futurelet
が実行される場面において、実際に\futurelet
以降のコードを“トークンの列”と考えてみよう。
\futurelet‹トークン1›‹トークン2›‹トークン3›‹トークン4›……
この前提の下で、「\futurelet‹トークン1›
」という文は、以下の動作を行う。
注意として、(少なくとも本記事の定義では2)\futurelet
の“引数”に相当するのは‹トークン1›
だけであるので、文を実行した後も‹トークン2›
と‹トークン3›
はそのまま残っている。従って、この文の次には‹トークン2›
が実行されることになる。
補足
\futurelet
は代入文の一種である。従って、一般の代入文についての諸々の注意事項(\global
修飾や\afterassignment
など)は\futurelet
についても当てはまる。
とにかく \futurelet するコードを読もう
\futurelet
の規則を把握したので、次はその規則を使って\futurelet
を使った簡単なコードを“読む”練習をしてみよう。以下のコードにおいて、マクロ\Check
が何をするものなのかを言葉で説明してほしい。
\def\Check{\futurelet\my@tok\my@check@a} \let\my@bgroup={ %←暗黙文字トークン \def\my@check@a{% % \my@tokが'{'であるなら... \ifx\my@tok\my@bgroup \message{Yes}% \else \message{No}% \fi}
読んでみる
パッと見たところでは\Check
は引数を取らないようなので、\Check
単体で展開を追ってみる。
\Check ↓(展開) \futurelet\my@tok\my@check@a
\futurelet
の規則を愚直に適用すると、\futurelet\my@tok
が実行されるとその文の2つ先にあるトークンを見ることになるが、今考えている範囲では、文の後にあるトークンは1つしかない。結局、\Check
の直後に何かトークンがある状態を考える必要があったようである。\Check
の直後のトークンを‹トークンA›
とする。
\Check‹トークンA›…
\Check
を展開すると以下のようになる。
\futurelet\my@tok\my@check@a‹トークンA›…
改めて\futurelet
の規則を適用すると、\futurelet\my@tok
を実行すると、2つ先にある‹トークンA›
が\my@tok
に\let
される3。その後の入力バッファは以下のようになる。
\my@check@a‹トークンA›…
これ以降は\my@check@a
の展開・実行となる。\my@check@a
は単純なコードなので、以下の動作をすることは容易に理解できるであろう。
\my@tok
の意味が(カテゴリコード1の){
に等しいかを調べて、そうであればYes
、なければNo
を端末に出力する。
ここで\futurelet
の実行により「\my@tok
の意味」は「‹トークンA›
の意味」と等しくなっている。従って、\my@check@a
は実質的には‹トークンA›
の意味を調べていることになる。
これで\Check
のコードを完全に“読む”ことができた。結局、\Check
の動作を言葉で説明すると以下のようになる。
- 自身の直後にあるトークン(の意味)が(カテゴリコード1の)
{
に等しいかを調べて、そうであればYes
、なければNo
を端末に出力する。
まとめ
もうこれで、読んでいるコードの中に\futurelet
が出てきてもコワくありません! どんどんTeX言語🤮のコードを読んでいきましょう💁