2017年2月10日

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による読み飛ばしは完了している.

3 件のコメント:

  1. 記述の中で \jlreq@ifendmark と \jlreq@endmark がゴッチャになってませんか?

    返信削除
  2. あ,最初の方ですね,ありがとうございます.

    返信削除

コメントの追加にはサードパーティーCookieの許可が必要です