マクロツイーター

はてダから移行した記事の表示が崩れてますが、そのうちに直せればいいのに(えっ)

TeXのプリミティブで展開可能なやつ(4)

XeTeX関連の補足事項

  • 各プリミティブの“種別”が何であるかについてのマニュアルの記述がかなりアレ。例えば、読取専用パラメタ(だから展開不能)なのに“Expands to …”と書いてあったり*1、読書可パラメタなのに一般命令であるかのように書かれていたり。大体は「機能から自然に予想される種別」になっているようである。例えば:
    • \XeTeXgenerateactualtextは(読書可の)整数パラメタ。
    • \XeTeXglyphbounds‹フォント›‹位置›は読取専用の寸法値パラメタ。
  • 従って、情報読取系のプリミティブで展開可能なのは、「文字列を返すもの」に限られる。
  • ちなみに、XeTeXには「文字列を設定するパラメタ」のようなプリミティブ(\XeTeXinputencodingなど*2)があるが、(恐らくTeXにそういう概念がないため)実際にはこれはパラメタでなく一般命令である。つまり、これらのプリミティブで設定した値を読みだすことはできない。
  • OpenTypeの各種タグは整数値として扱われている(例えばfeature tagの“ital”は0x76657274という整数値)。なので、\XeTeXOTfeaturetagは読取専用整数パラメタであり展開不能である。
  • \XeTeXinterchartoks‹クラス1›‹クラス2›トークン列パラメタである。

XeTeXのやつ

  • \XeTeXglyphname‹フォント›‹グリフ番号›:そのフォントの指定のグリフ番号(GID)に対応するグリフ名。
  • \XeTeXfeaturename‹フォント›‹featureコード›:AATのfeatureの名前。
  • \XeTeXvariationname‹フォント›‹variationコード›:AATのvariationの名前。

以下のものはpdfTeXのプリミティブを名前を変えて採用したもの。

  • \ifprimitive ☆:pdfTeXの\ifpdfprimitiveと同じ。
  • \normaldeviate:pdfTeXの\pdfnormaldeviateと同じ。
  • \strcmp{‹文字列1›}{‹文字列2›}:pdfTeXの\pdfstrcmpと同じ、ただしUnicode対応になっている。
    ※文字列の比較は「UTF-16のユニット列」として(あるいは「UTF-16BEのバイト列」と考えても同値)行われる。従って、BMP外の文字が含まれる場合は必ずしもUnicode符号値の順にはならない。
  • \uniformdeviate:pdfTeXの\pdfuniformdeviateと同じ。

“U~”なやつ

名前がUで始まる拡張プリミティブはUnicodeに関するもので、この命名法はXeTeXとLuaTeXで名前を共通にすることを意図している。とはいっても必ずしも両方のエンジンで実装されているとは限らない。

※「LuaTeXにしかないやつ」は未調査。

  • \Uchar‹文字コード›:その文字コードをもち、\the-文字列のときと同じカテゴリコードをもった文字トークン。言い換えると、その文字コードの文字1つだけからなる\the-文字列。
    ※XeTeX・LuaTeX・e-(u)pTeXで利用可能。
    ※e-(u)pTeXの場合、文字コードが256以上の場合は和文文字トークンが生成される。e-upTeXでの和文カテゴリコードは\the-文字列の規則に従うが、例外的に、その文字の和文カテゴリコードが15のときは、代わりに和文カテゴリコードが18の和文文字トークンを生成する。
  • \Ucharcat‹文字コード›‹カテゴリコード›:指定の文字コードとカテゴリコードをもつ文字トークン。 ※XeTeX・e-(u)pTeXで利用可能。
    ※e-upTeXの場合、カテゴリコードが16以上の場合には(文字コードとカテゴリコードを和文のものと見なして)和文文字トークンが生成される。なお、文字コードが0~127の範囲の和文文字トークンは生成できない。
    ※e-pTeX和文文字トークンが和文カテゴリコードを保持しないため、\Ucharcatは欧文専用になる。
    ※カテゴリコードとして有効な値は、欧文では1~4、6~8、10~13で、(e-upTeXの)和文では16~19である。文字コードの有効範囲は欧文と和文で異なることに注意。

*1:もちろんパラメタだから\theを付ければ展開されるのであるが。

*2:\XeTeXinputencoding、XeTeXdefaultencoding、\XeTeXlinebreaklocaleの3つ。

TeXのプリミティブで展開可能なやつ(3)

前回の続き。今回はpdfTeXについて。

pdfTeX関連の補足事項

  • 「文字列」の引数については、与えられたトークン列を完全展開して脱トークン化した結果の文字列が使われる。
  • 整数・寸法値・グルー値の情報を返すプリミティブは、他のエンジンでは「読取専用のパラメタ」(例えば\lastkern)として提供されることが多いが、pdfTeXは「その値を表す\the-文字列に展開する展開可能プリミティブ」であることが多い。その場合、値を表す書式は「その型のパラメタの値を\theで出力する場合」と同じになる。
    ※例えば寸法値10ptは10.0ptという\the-文字列で表される。
  • ◇印は、内部状態の変化を行った上で空でないトークン列に展開されるもの。
    ※なお★・☆印の意味はシリーズ初回と同じ。
  • pdfTeXのマニュアルでは\pdfincludecharsが展開可能プリミティブとして挙げられているが、実際には展開不能であるようだ。恐らくこれは単純な記述ミス……?

pdfTeXのやつ

  • 追加のif-トークン(\ifincsname\ifpdfabsdim\ifpdfabsnum\ifpdfprimitive)☆
  • \expanded{‹トークン列›} ★:そのトークン列の完全展開の結果。
    ※つまり“展開の加速”(一回展開で完全展開をひき起こす)ができる。
    ※「pdfTeX拡張プリミティブ」という扱いなのであるが、事情があって、一番先にLuaTeXで実装された。pdfTeXで実装されたのはずっと後になってからである(参考)
  • \leftmarginkern‹ボックス番号›: ボックスの左側マージンカーンの幅(寸法値)。
  • \pdfcolorstackinit[page] [direct]{‹PDF命令列›} ◇: 色スタックを新規作成した上で、その色スタック番号の整数に展開される。
  • \pdfcreationdate:処理開始日時をPDF日時形式で現した文字列。
    ※「PDF日時形式」はD:20060102150405+07'00'のような形式。
  • \pdfescapehex{‹文字列›}:その文字列の16進ダンプの文字列。
    ※「16進ダンプ」は各文字の符号値の16進表記(0埋め、大文字)を並べたもの。
  • \pdfescapename{‹文字列›}`:その文字列に対して「PDF名前」用のエスケープを適用した結果の文字列。
  • \pdfescapestring{‹文字列›}:その文字列に対して「PDF文字列」用のエスケープを適用した結果の文字列。
    ※PDF文字列を現す外側の丸括弧()は付かない。
  • \pdffiledump[offset‹開始位置›] [length‹長さ›]{‹ファイル名›}:そのファイルの指定の位置の内容(バイト列)の16進ダンプの文字列。
  • \pdffilemoddate{‹ファイル名›}:そのファイルの更新日時をPDF日時形式で現した文字列。
  • \pdffilesize{‹ファイル名›}:そのファイルのサイズ(整数)。
  • \pdffontname‹フォント›:そのフォントを一意に指定する番号(整数)。
    ※PDF中でF‹番号›という名前がそのフォントに対応する。
  • \pdffontobjnum‹フォント›:そのフォントに対応するPDFのFontオブジェクトの番号(整数)。
  • \pdffontsize‹フォント›:そのフォントのサイズ(寸法値)。
  • \pdfinsertht‹insert番号›:そのinsertの現状での高さ(寸法値)。
  • \pdflastmatch‹番号›:最後に実行した正規表現検索(\pdfmatch)の指定番号のマッチの情報で、「‹位置›->‹文字列›」という形式の文字列。
    ※位置は0起点。指定番号のマッチが無効の時は「-1->」となる。
    ※一般の正規表現検索の慣習に従い、番号0は全体のマッチを表す。もし最後の検索が失敗だった場合は0も含めて全てのマッチが無効になる。
  • \pdfmatch[icase] [subcount‹グループ数上限›]{‹パターン›}{‹検索対象›} ◇:正規表現検索を行った上で、結果を表す整数に展開される:-1=不正パターンエラー、0=失敗、1=成功。icaseオプションは大小文字同一視指定。
    POSIX拡張正規表現、らしい(多分egrepのものと同じ)。
  • \pdfmdfivesum[file]{‹文字列›}:その文字列のMD5ハッシュ値の16進ダンプの文字列。fileオプション付きの場合は、引数の名前のファイルのハッシュ値になる。
  • \pdfnormaldeviate:平均0、標準偏差65536の正規分布に従う乱数(整数)。
  • \pdfpageref‹ページ番号›:そのページ番号に対するPDFのPageオブジェクトの番号(整数)。
  • \pdfstrcmp{‹文字列1›}{‹文字列2›}:2つの文字列を比較した結果を表す整数:-1=文字列1が小、0=等しい、1=文字列1が大。
    ※e-(u)pTeXの場合、和文文字はUTF-8のバイト列に変換した上で比較される。(※内部漢字コードは無関係)
    ※なお、XeTeXの\strcmpUTF-16のユニット列として比較する。
  • \pdftexbanner:エンジンのバナー文字列。
    ※「バナー文字列」とは起動時に端末に出力される「This is pdfTeX, …」のような文字列。
  • \pdftexrevision:エンジンのリビジョン番号。
    \pdftexversionは読取専用整数パラメタ。
    ※例えばバージョン番号が「1.40.21」の場合、pdftexrevision21に展開される(ドットは付かない)。\pdftexversionは140になる。
  • \pdfunescapehex{‹16進数字列›}:その16進ダンプが表す文字列。
    ※英字は大文字でも小文字でもよい。16進数字以外の文字は無視される。
  • \pdfuniformdeviate‹上限›:0以上‹上限›未満の一葉乱数(整数)。
  • \pdfxformname‹番号›:その番号のFormオブジェクトを一意に指定するTeX内で使用される番号(整数)。
    ※PDF中でFm‹番号›という名前が当該のFormオブジェクトに対応する。
  • \pdfximagebbox‹Image番号›‹位置番号›:その番号のImageオブジェクトのバウンディングボックスの大きさの情報で、‹位置番号›に応じて以下の値を返す:1=左下隅x、2=左下隅y、3=右上隅x、4=右上隅y。
  • rightmarginkern‹ボックス番号›: ボックスの右側マージンカーンの幅(寸法値)。

そして最後に特殊なもの。

  • \pdfprimitiveは「直後の制御綴を、それが現在保持している値とは無関係に、同名のpdfTeXのプリミティブを保持するものと見なす」という、やや特殊な働きを持つ。\pdfprimitive\制御綴…が展開可能であるかは、「\制御綴と同名のプリミティブ」が展開可能であるかに依存する。
    • プリミティブが展開可能ならば、\pdfprimitive\制御綴…全体が展開可能であり、その展開結果は「プリミティブの\制御綴…の展開結果」となる。
    • プリミティブが展開不能ならば、\pdfprimitive\制御綴…全体も展開可能である。
    • 何れにしても、「プリミティブを保持する特殊な制御綴(あるいはトークン)に展開される」という仕様ではないことに注意。

TeXのプリミティブで展開可能なやつ(2)

前回の続き。今回はpTeX系列について。

pTeX関連の補足事項

  • upTeXで「和文文字を含む\the-文字列」が生成される場合、和文文字トークンの和文カテゴリコードは、その時点における当該の和文文字に対する和文カテゴリコード(\kcatcodeの値)になる。もし和文カテゴリコードが15だったら、なんかアレなことになる。
    pTeXでは和文文字トークンは和文カテゴリコードを持っていない。
  • “フォント”の引数には、\jfont\tfontも使える。

pTeXのやつ

  • 追加のif-トークン(\ifdbox\ifddir\ifjfont\ifmbox\ifmdir\iftbox\iftdir\iftfont\ifybox\ifydir)☆

  • “漢字コード変換子”、すなわち\euc\jis\kuten\sjis:直後に整数を続ける。展開結果は「当該の漢字コードで引数の整数を符号値に対応する和文文字を内部漢字コードに変換した結果の符号値」の十進表記。

  • \ptexrevisionpTeXのリビジョン番号の文字列。
    \ptexversion\ptexminorversionは読取専用整数パラメタ。

  • \kansuji<整数>:その整数の(一〇方式の)漢数字表記。
    \kansujicharで漢数字として使用する文字を変更できる。

upTeXのやつ

  • 追加の漢字コード変換子(\ucs

e-(u)pTeXのやつ

該当なし……かな?

※オリジナルではないが、最近のe-(u)pTeXでは\Uchar\Ucharcatが使えることに注意。

(続く)

TeXのプリミティブで展開可能なやつ(1)

まとめてみた。

注意

  • 多くのプリミティブは展開結果が必ず\the-文字列になる。展開結果が必ず空になる(付随して内部状態が変化する)ものについては☆印、以上のどれにも当てはまらないものには★印を付けた。
  • 各項目の説明には、そのプリミティブの(一回)展開結果のトークン列が何かを記した(無印のものは文字列として述べているが、実際には\the-文字列であることに注意)。ただし☆印のものは”動作”を記した(展開結果は常に空である)。

元祖TeXのやつ

  • “条件トークン”、すなわち各種if-トークンと\else\or\fi ☆:TeXの内部の「条件判断に関する内部状態」を変化させる。詳細は以下の記事を参照。

  • “マーク変数”、すなわち\topmark\firstmark\botmark\splitfirstmark\splitbotmark ★:現在の状況で(各々のマーク変数の機能に即して)該当するマークのトークン列。

  • \csname‹トークン列›\endcsname ★:「‹トークン列›を完全展開して得られる文字トークン列を脱トークン化した文字列を名前とする制御綴」のトークン。
    ※完全展開の結果に制御綴が含まれる場合はエラーになる。
    ※当該の制御綴が未定義の場合は、「その制御綴がローカルに\relaxに等値される」という副作用をもつ。
    ※このパターン以外で現れる\endcsnameは展開不能である。

  • \endinput ☆:現在のファイルからの読込を「既に読んだ行」までで停止する。

  • \expandafter‹トークン1›‹トークン2›… ★:‹トークン1›の後に「‹トークン2›以降のトークン列を一回展開した結果」を続けたトークン列。

  • \fontname‹フォント›:そのフォントの定義で「‹TFM名› at ‹使用サイズ›pt」の形(使用サイズがデザインサイズに等しい場合は‹TFM名›のみ)の文字列。
    ‹フォント›は「fontdefトークン」「\font」「\textfont\scriptfont\scriptscriptfontの後に数式ファミリ番号を続けたもの」の何れか。

  • \input‹ファイル名› ☆:以降は指定のファイルから入力を読むようになる。
    ‹ファイル名›は空白トークン(これは吸収される)または展開不能の制御綴で終結する。ファイル名が終結するまで完全展開が起こる。
    ※ただし最近の処理系だと文字列をクオートする("…"で囲う)ことで「空白を含むファイル名」を引数にとれる(参照)
    ※もっと最近の処理系だと\input{‹ファイル名›}のように引数を波括弧で囲う書式も可能である。この場合は、引数のトークン列を完全展開した結果(制御綴を含んでもよい)を脱トークン化した文字列がファイル名として用いられる。

  • \jobname:ジョブ名の文字列。
    ※「ジョブ名」はコマンドオプションの-jobnameの値。省略時の既定値は(システム依存だが多くの場合)「最初に読んだファイルのベース名」になる。

  • \meaning‹トークン›:そのトークンの意味を説明した文字列。
    ※例えば、\meaning$は「math shift character $」、\meaning\quadは「macro:->\hskip 1em\relax」に展開される。

  • \noexpand‹トークン› ★:【展開限定文脈で】そのトークン自身に展開され、それ以上展開されない。
    ※通常は展開限定文脈以外で使われることはない。

  • \number‹整数›:その整数の(典型の)十進表記。

  • \romannumeral‹整数›:その整数の小文字ローマ数字表記。ゼロ以下の場合は空になる。

  • \string‹トークン›トークンが文字トークンの場合は、その文字。制御綴の場合はそれを文字列化したもの(後続の空白は無し)。
    ※「制御綴の文字列化」は、制御綴名の前に\escapecharの文字を前置した形の文字列。ただし\escapecharが(欧文)文字コードの範囲外の値の場合は何も前置されない。

  • \the‹内部値›:その内部値(パラメタ、レジスタ)の現在の値を表すトークン列。普通は\the-文字列であるが、以下の場合は例外となる:

    • \the‹トークン列レジスタ・パラメタ› ★:そのレジスタ・パラメタが現在保持するトークン列そのもの。
    • \the‹フォント› ★:そのフォントを選択するためのfontdefトークン。
      ※この中の‹フォント›\fontnameの項の説明と同じ。

e-TeXのやつ

  • 拡張“マーク変数”、すなわち\topmarks‹番号›\firstmarks‹番号›\botmarks‹番号›\splitfirstmarks‹番号›\splitbotmarks‹番号› ★:現在の状況で該当するマークのトークン列。

  • \detokenize{‹トークン列›}:引数のトークン列を(展開せずに)脱トークン化した結果の文字列。
    ※結果は\the-文字列であることに注意。実質的に「(字句解析前の)文字列に戻す」働きをもつのは\scantokensの方である。

  • \eTeXrevision:e-TeXのリビジョン番号の文字列。
    \eTeXversionは読取専用整数パラメタ。

  • \scantokens{‹トークン列›} ☆:引数のトークン列を(展開せずに)脱トークン化した結果の文字列を内容とする仮想的な入力ファイルを作って、以降はこの仮想的なファイルから読み込むようにする。

  • \unexpanded{‹トークン列›} ★:【展開限定文脈で】引数のトークン列自身に展開され、それ以上展開されない。

  • \unless‹ifトークン›… ☆:後続の条件文の真偽を反転させた条件文を開始する。
    \unlessの直後に真偽型のif-トークンそのものが続く必要がある。条件部を含めて一度で展開されることに注意。

(続く)

\index 命令中の”\”の機能がヤヤコシイ話

LaTeXでMakeIndex(mendexやupmendexも含む)を利用して索引を作る場合の、\index命令中の「エスケープ処理」について。具体的には、quote(")とescape(\)の違いについて。

※実はMakeIndexは「LaTeX専用」でも「TeX専用」でもないのであるが、ここではLaTeXとの併用を前提とする。

\index にイロイロ書ける件

\index命令の「実際のテキスト」の部分(@の右側に相当する部分)には「索引中でその項目を実際に出力するためのLaTeXコード」を書く。このLaTeXコードはその場では実行されず、コードの文字列が.idxファイル(MakeIndexの入力)を経由して.indファイル(同じく出力)にそのまま書き出されて、それがLaTeXで読み込まれる際に実行されることになる。従って、\verbなどの「呪われた命令」を書くこともできる。

\index{%@\verb+%+ (comment)}

※つまり、\index命令の引数はverbatimなものとして解釈されている。なので、引数中に「呪われた命令」を書ける代わりに、\index自体が「呪われた命令」になってしまう。この辺りの「実際の仕様」については以下の記事を参照されたい。

\index でquoteする件

ただし、\indexの引数の書式では、幾つかの文字に特別な意味を持たせている。例えば、@は「『キー』と『実際のテキスト』の区切り文字」であり、!は「階層の区切り文字」として使われる。従って、「実際のテキスト」の内容にこれらの文字を含めたい場合は“エスケープ”をする必要がある。もちろん、これはMakeIndexのレベルのもので、LaTeXにおけるエスケープとは別物である。(LaTeXエスケープ文字\は寧ろそのまま出力されてほしい。)MakeIndex(の既定)では、“エスケープ”の役割を"に割り当てていて、これを“quote”と呼んでいる。

例えば、MakeIndexの特殊文字である!を「実際のテキスト」(および「キー」)に書くには、これをquoteして"!と書く必要がある。

% ! を " でquoteした
\index{Happy TeXing"!@Happy {\TeX}ing"!}
%→"実際のテキスト"は Happy {\TeX}ing!

※quoteを付けた文字列は.idxにはそのまま書き出される。.idxを読み込み“引数を解析する”際に「quoteの解釈」が行われる。

注意として、MakeIndexの処理においては原則的に(La)TeXの文法は考慮されない。(前述の通り、そもそもMakeIndexは(La)TeX専用ではない。)従って、例えば\verbが絡む場合でも「MakeIndexの特殊文字をquoteする("を前置する)」という規則は変わらない。

% ! を " でquoteした
\index{"!@\verb+"!+ (level operator)}
%→"実際のテキスト"は \verb+!+

% もし \verb の区切りを | にしたい場合は,
% | も特殊文字なのでquoteする必要がある.
\index{"!@\verb"|"!"| (level operator)}
%→"実際のテキスト"は \verb|!|

quoteをquoteする件

"がquoteに使われるということは、"自身もMakeIndexの特殊文字の一種ということになる。もし"を「実際のテキスト」に含みたい場合は""と書く必要がある。

% " を " でquoteした
\index{""@\verb+""+ (quote)}
%→"実際のテキスト"は \verb+"+

\index で“\”も特殊な件

これまでの話から考えると、(La)TeXエスケープ文字である\はMakeIndexにおいては特殊文字ではないように思える。事実、\!を「実際のテキスト」に書いた場合、!エスケープされることなく「階層の区切り文字」として働く。

% 失敗: ! で階層が分けられるので不正な入力になる
\index{\!@\verb+\!+ (negative thin space)}

ところが実は\もMakeIndexの特殊文字なのである。実際、MakeIndexの索引スタイルの中には“escape”という項目がありこれの既定値が\になっている。(恐らくLaTeX以外でMakeIndexを使う場合は別の文字を指定するのであろう。)といってもMakeIndexで\(つまりescape)が特殊な働きをする場面は限られていて、それは\"という文字列の扱いである。

\index{Godel@G\"odel}

この例では「実際のテキスト」の中でLaTeXのアクセント命令\"を使おうとしている。一見すると、"はquote文字であるためoを(無意味に)quoteするのに使われてしまって、結果的にG\odelと解釈されてしまうように思える。しかし実はMakeIndexでは「quoteはescapeでエスケープされる」ということになっているのである((\"命令を使うために\""oと書く必要が生じるのをMakeIndexの作者が嫌ったらしい。TeX Liveに含まれるind.pdfという文書にその旨が書かれている。))。従って、先ほどの例はこのままで正しい。

% \" の " はquoteにならない
\index{Godel@G\"odel}
%→"実際のテキスト"は G\"odel

\index の規則がさらにややこしくなる件

ただこのように\を特殊扱いしたせいで、MakeIndexの規則が不用意に複雑になっている感じもする。例えば以前に出した\!を書く例を考える。単純にquoteだけ考えると、!"!に変えればよさそうに見える。

% 実はこれでもダメ: " はquoteにならない
\index{\"!@\verb+\"!+ (negative thin space)}

ところがこれだと\"という形になっているため、"がquoteにならないのである。正しい解決策は何かというと、\の特殊性を消すために\"でquoteすればよい。

% \ と ! の両方をquoteした
\index{"\"!@\verb+"\"!+ (negative thin space)}
%→"実際のテキスト"は \verb+\"+

本の種類によっては、索引のテキストでLaTeX命令を多用することもあるだろうから、\に注意を払わないといけないのは少し不便であると感じる。

escapeをescapeする件

LaTeXの規則で、\"はアクセント命令であるが、その前にさらに\がある場合は\\が命令になるため\"の部分は命令にならない。これに合わせる形で、MakeIndexの規則でも「escapeはescapeでエスケープされる」、つまり\\は(結果的に)通常の文字の\\と解釈される。

% \\ の \ はescapeにならない
\index{bogus@bo\\"!gus}
%→"実際のテキスト"は bo\\!gus

波括弧をescapeする件

MakeIndexの入力において波括弧({})は特に特殊な役割をもつわけではないが、「{}は均衡する必要がある」ことになっている。LaTeX文書中の\index命令では「均衡していないとそもそも\indexの引数が正しく読み取れない」ので当然であるが、.idxファイルの入力でも同じ規則が適用される。

自分が調べた限りだと、前にescapeのついた\{\}については「波括弧の均衡の判定」からは除外されるようである。従って、この場合もescapeは特殊な役割をもつことになる。

% \{ の波括弧は気にしない
\index{\{@$\{$ (left brace)}
%→"実際のテキスト"は $\{$

※ただしMakeIndexのマニュアル(makeindex.pdf、日付が1987年であり古い)では逆に「例外にならない」と書いてある。どこかの時点で仕様が変わったのかもしれない。

なお、\verb絡みで単独の(\のない){を入力に含めようとして"{と書くと、\index命令の引数の読取が失敗してしまう。(\index命令は波括弧はverbatim扱いしないので。)

% 失敗: \index が実行できない
\index{"{@\verb+"{+ (left brace)}

これについては簡単な解決策はないので「単独の{」は避けるしかなさそうである。それにしても、「実際のテキスト」では諸々の回避策をとれても、「キー」の部分では対処は極めて難しいように思う。

.idxファイルの入力としては「quoteされた単独の{」を含む形は許される。そのため、「ビルドのワークフローの中で.idxアドホックに書き換える」という手段で一応解決できる。

% .idxファイルの中でこの行はOK
\indexentry{"{@\verb+"{+ (left brace)}{8}   
%→"実際のテキスト"は \verb+{+

まとめ

f:id:zrbabbler:20210504102004p:plain

某ZR流パラメタトークン思考法

課題

次のTeXコードを実行したときのTeXの動作を、字句解析を中心にして述べよ。

LaTeXフォーマットで\makeatletterの状態のカテゴリコードを仮定する。

\toks@{\def\xx@#1}\the\toks@{!#1}

某ZR氏の解答

表記

  • 制御綴のトークンを“[def]”等で表す。
  • 文字トークンを“‹A›₁₁”等で表す。
  • パラメタトークンを“①”等で表す。

動作の解説

  • \toks@を読み [toks@] と解釈する。\toks@(0番のtoksレジスタ)に対する代入文を開始する。
  • {を読み ‹{›₁ と解釈する。これ以降は代入すべきトークン列の内容であり、展開抑止の状態に入る。
  • \def\xx@#1を読み、[def] [xx@] ‹#›₆ ‹1›₁₂ と解釈する。
  • }を読み ‹}›₂ と解釈する。代入すべきトークン列が確定し、展開抑止が終わる。\tokS@に“[def] [xx@] ‹#›₆ ‹1›₁₂”が代入される。
  • \theを読み、[the] と解釈する。プリミティブ\theの引数を待つ状態になる。
  • \toks@を読み [toks@] と解釈する。\theの展開を行う。\theプリミティブの引数がtoksレジスタなので、そのレジスタの内容の“[def] [xx@] ‹#›₆ ‹1›₁₂”をバッファに吐き出し、以降はここからトークンを読み出す。
  • [def] を読む。\def文を開始し、展開抑止の状態に入る。以降に続く「代入先トークン」「パラメタテキスト」「置換テキスト」を待つ。
  • [xx@] を読む。これが「代入先トークン」である。
  • ‹#›₆ ‹1›₁₂ を読む。パラメタテキストの読取の途中に“‹#›₆ ‹1›₁₂”が現れたので、パラメタトークン“①”に置き換える。
  • (バッファのトークンが尽きたので再びソース文字列から読む。)
  • {を読み ‹{›₁ と解釈する。ここでパラメタテキストが終わり、“①”と確定する。
  • !#1を読み、‹!›₁₂ ‹#›₆ ‹1›₁₂ と解釈する。置換テキストの読取の途中に“‹#›₆ ‹1›₁₂”が現れたので、パラメタトークン“①”に置き換える。
  • }を読み ‹}›₂ と解釈する。ここで置換テキストが終わり、“‹!›₁₂ ①”と確定する。
  • すなわち、以下の引数を以て、\def文が実行される。展開抑止が終わる。`
    • 代入先=[xx@]
    • パラメタテキスト=①
    • 置換テキスト=‹!›₁₂ ①

補足

つまり、某ZRのモデルでは、パラメタトークン(① など)は「パラメタテキスト」や「置換テキスト」のトークン列の内容には現れるが、入力バッファの中には決して現れない。

もしこの後、\xx@?を実行したとすると、[xx@] ‹?›₁₂ の展開結果として、置換テキストの ① を ‹?›₁₂ に置き換えたトークン列である“‹!›₁₂ ‹?›₁₂”がバッファに吐き出される。この場合もパラメタトークン自体はバッファには現れない。