jlreq.cls話……というよりはTeXマクロな話.jlreq.clsの中で次のようなマクロを用意している.
\jlreq@ifendmark{<トークン列>}{<実行1>}{<実行2>}
これは<トークン列>が\jlreq@endmark
ならば<実行1>を,そうでなければ<実行2>になるfully expandableなマクロ.ただし,<トークン列>は\jlreq@endmark
のみか\jlreq@endmark
を全く含まないと仮定する.
使うのは次のような時.\cmd{{A}{B}…}
みたいなマクロを作りたい時に,まず\def\cmd#1{\cmdA#1\jlreq@endmark}
として,一引数ごとに解釈していく\cmdA
を定義することで実装する.\cmdA
内では#1
が\jlreq@endmark
であるか否かの判定をすることになる.
最初は何も考えずに,マクロとか使わず直に
\ifx\jlreq@endmark#1\relax……\else……\fi
と書いていた.#1
が\jlreq@endmark
と等しければ明らかによく,そうでなければ#1
の最初のトークンが\jlreq@endmark
と一致せずに読み飛ばされる,というわけである.#1
の二つ目以降のトークンは読み飛ばし対象となる.
大概これで良いのだが,#1
が\iftrue\fi
とかで破綻する.\ifx\jlreq@endmark\iftrue\fi\relax\else\fi
となってしまい,\ifx
により\iftrue
が食われてしまう.その結果,\fi
が\if***
より一つ大きくなって破綻する.
実際に使っていてこれで破綻してしまった(先頭に\if***
が来る引数を与えなくてはならなくなった)ので,今のでは次のように書いている.
\long\def\jlreq@helper@ifendmark@getfirsttoken#1#2\jlreq@endmark{#1}
\long\def\jlreq@ifendmark#1{%
\expandafter\ifx\jlreq@helper@ifendmark@getfirsttoken#1\jlreq@endmark\jlreq@endmark\@empty
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi}
これは次の例で破綻する:\jlreq@ifendmark{{AA}}
.\jlreq@helper@ifendmark@getfirsttoken
とかいうマクロで一つ目のトークンだけ取り出した気になっているが,これは一つ目のトークンを取り出すとは限らないわけである.まぁ,jlreq.cls内ではこれで困ることはないのだが.
というわけで,改めてこんな風に手元でしてみた.
\long\def\jlreq@ifendmark#1{%
\expandafter\expandafter\expandafter\ifx\jlreq@ifendmark@#1{}\jlreq@endmark\jlreq@endmark
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi}
\long\def\jlreq@ifendmark@#1#{\jlreq@ifendmark@@#1\@empty\jlreq@endmark}
\long\def\jlreq@ifendmark@@#1#2\jlreq@endmark#3\jlreq@endmark{#1}
つまり,まずグルーピングの始まる{
の前までを取得し,更にその一つ目のトークン(これは{}
によるグルーピングを含まないはず)をとって比較する.{
の前が空っぽだと面倒なので,\@empty
を挟んでいる.すると,\jlreq@ifendmark#1{}\jlrqe@endmark
を二回展開すると,
#1
における{
の前までが空ならば\@empty
に,- そうでなければ
{
の前までの一つ目のトークン(つまり#1
の一つ目のトークン)に
\jlreq@endmark
と比較すれば良い.これならば大丈夫だと思うのだが.
ちなみに
\def\jlreq@ifendmark#1#2#3{\ifx**** #2\else #3\fi}
ではなく\@firstoftwo
や\@secondoftwo
は(TeXあるあるだけど)#2
や#3
の\if***\fi
が対応がとれていなくても大丈夫にするため.上の定義ならば,#2
や#3
の部分が解釈される時には\ifx
による読み飛ばしは完了している.
記述の中で \jlreq@ifendmark と \jlreq@endmark がゴッチャになってませんか?
返信削除あれ?どこですか?
返信削除あ,最初の方ですね,ありがとうございます.
返信削除