マクロツイーター

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

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

前回の続き。今回が最終回で、LuaTeXについて。

\U~の系列についてはXeTeXの記事を参照。

LuaTeX関連の注意事項

※一般の注意事項については初回の記事を参照。

  • だめだ LuaTeXなにもわからない😭

LuaTeXのやつ

  • \begincsname‹トークン列›\endcsname ★:「‹トークン列›を完全展開して得られる文字トークン列を脱トークン化した文字列を名前とする制御綴」について、その制御綴が定義済ならそのトークン、未定義なら空に展開される。

    • \csnameと同様に、完全展開の結果に制御綴が含まれる場合はエラーになる。
    • \csnameと異なり“\relax化”の副作用を決して起こさない。
  • \csstring‹トークン›トークンが文字トークンの場合は、その文字。制御綴の場合はその名前。

    • \stringと異なり制御綴名の前に\escapecharの文字は前置されない
  • \directlua[‹整数:名前番号›]{‹文字列›} ☆:引数の文字列をLuaコードとして実行する。

    • 名前番号を指定した場合は、チャンク名*1lua.name[‹名前番号›]の値が指定される。
    • 実行後、「LuaライブラリのTeXバッファ出力機能によって出力された文字列」を内容とする仮想的な入力ファイルを作って、以降はこの仮想的なファイルから読み込むようにする。
      Luaプログラムを実行する他のプリミティブについても実行後の処理方式は同様である*2
    • LuaライブラリでTeXトークンを出力することも可能なはずだけど、その扱いの詳細については未調査。
    • なお\lateluaは展開不能である。
  • \dvifeedback何これ?

    • 多分\pdffeedbackと同じ使用法だろうが、マニュアルに未記載。
  • \dvivariable何これ?

    • 多分\pdfvariableと同じ使用法だろうが、マニュアルに未記載。。
  • \fontid‹フォント›:そのフォントを一意に指定する番号(整数)。

    • 実装上は\pdffontname(LuaTeXでは\pdffeedback fontname)と同等なのかもしれない。
  • \formatname:使用中のフォーマットについて、フォーマット作成時(ダンプ実行時)の\jobnameの値。

    • INIモードにおいては空になる。
  • \ifcondition:展開しても何も起こらず、また「条件判断に関する内部状態」も変化させないが、「条件不成立による読み飛ばし」の際にはこのプリミティブは「if-トークンの一種である」と見なされる。

    • 要するに「if-均衡を回復させるための\@gobble\if」と同じ役割のはず。
  • \immediateassigned{‹トークン列›} ☆:引数のトークン列に書かれた「TeXの代入文」(複数可)を実行する。

    • つまり普通のTeXの代入を展開限定文脈で実行できる
    • 引数は「TeXの代入文」のみからなる*3必要がある。
    • 代入文の種類には制限がある(例えばボックスの代入は不可)らしい。
  • \immediateassignment‹代入文› ☆:直後に続く単一の「TeXの代入文」を実行する。

    • 実行される代入文が1つであることを除いて\immediateassignedと同じ。
  • \lastnamedcs ★:最後の\csname\ifcsname\begincsnameの実行で生成された制御綴のトークン。

    • \ifcsname\begincsnameを用いて当該制御綴が未定義だった場合は「無効な制御綴を表す特殊なトークン」になる。
    • 従って厳密にいうとLuaTeXでは\ifcsname\begincsnameは副作用をもつ。
  • \luabytecode‹整数› ☆:その番号のLuaバイトコードレジスタが保持するLua関数を実行する。

  • \luaescapestring{‹文字列›}:その文字列に対して「Luaの文字列リテラル」用のエスケープを適用した結果の文字列。

    • 外側のクオート""は付かない。
  • \luafunction‹整数› ☆:Lua関数テーブルのその番号の項目が保持するLua関数を実行する。

    • Lua関数テーブルの値(Lua関数)はフォーマットに保存されない*4
  • \luatexbanner:エンジンのバナー文字列。

  • \luatexrevision:エンジンのリビジョン番号。

    • なお\luatexversionは読取専用整数パラメタである。
    • 例えばバージョン番号が「1.9.2」の場合、\luatexrevision2に展開される(ドットは付かない)。\luatexversionは109になる。
  • \mathstyle:現在の数式スタイルを表す整数。

    • 値:0=D、1=D′、2=T、3=T′、4=S、5=S′、6=SS、7=SS′、-1=数式外。
    • TeXの数式読取の仕組に起因する制限のため、実用するには\Ustackと組み合わせる必要がある(参照)
  • \pdffeedback‹名前›:指定の名前の「PDFフィードバック」の値を返す。

    • 「PDFフィードバック」は何らかの「PDF機能に関する読取専用のパラメタ」を表し、名前によって互いに区別される。
    • これらはpdfTeXにおいては「読取専用のパラメタである」または「値に展開される」ような個別のプリミティブとして提供されていた。例えば、「\pdffeedback creationdate」はpdfTeXの\pdfcreationdateに相当する。
    • \pdffeedbackはその引数を含めて一回の展開で「値を表す文字列」に展開される。例えば、\pdffeedback pageref‹整数›は(pdfTeXの\pdfpageref‹整数›と同じく)一回展開すると整数値の文字列になる。
    • 引数の‹名前›の読取が独特である。
      • \pdffeedbackの後に続くトークン列を順次展開していって、それまでに得た文字トークン列が「有効な名前の一つに一致する」か「有効な名前のどの接頭辞とも一致しなくなる(制御綴に当たった場合も含む)」時点で終結する*5
      • 従ってこの引数については「終結用に吸収されるトークン」という規定が存在せず、直後に続く空白トークンや\relaxは常に有効になる。
  • \pdfvariable‹名前› ★:指定の名前の「PDF変数」を意味とする単一トークン。

    • 「PDF変数」は何らかの「PDF機能に関する読書可のパラメタ」を表し、名前によって互いに区別される。
    • これらはpdfTeXにおいては「読書可のパラメタ」である個別のプリミティブとして提供されていた。例えば、「\pdfvariable compresslevel」はpdfTeXの\pdfcompresslevel(整数パラメタ)に相当する。
    • \pdfvariableを一回展開すると「当該のパラメタ(データ型はPDF変数の種類により異なる)を意味とする単一のトーク*6」になる。例えば「\pdfvariable compresslevel」の一回展開は整数パラメタとなる。
    • 引数の‹名前›の読取の挙動は\pdffeedbackと同じ。
  • \scantextokens{‹トークン列›} ☆:「引数のトークン列を(展開せずに)脱トークン化した結果の文字列」を内容とする仮想的な入力ファイルを作って、以降はこの仮想的なファイルから読み込むようにする。

    • \scantokensの変種で、より「マクロの展開」に近い動作になるようにしたもので、以下の点が異なる:
      • 末尾に\endlincharの文字が付かない。
      • 「入力ファイル境界検査」が抑止される。

*1:Luaチャンク名は、Luaインタプリタからの情報表示の際に用いられる。

*2:つまり厳密にいうと「Luaから吐かれたもの」は展開結果ではない。展開結果は空であることになるので☆印を付けた。

*3:厳密にいうと:普通にトークン列を実行していった際に、展開不能であるトークンは「代入文を開始するもの」でなければならない。

*4:従って通常の(非INIの)使用においては、Luaバイトコードレジスタは「フォーマット作成時(INIモード)に登録された関数」を読み出すのに専ら利用され、それ以外の用途ではLua関数テーブルが利用される。

*5:後者の場合、警告を出した上で、\pdffeedbackを無かったことにして引数として読んだトークン列をバッファに返す。

*6:ここでいう「パラメタを意味とするトークン」というのは\dayや\parindentの類(TeXbookでは“parameter”と呼ばれている)のことであり「パラメタトークン」(TeXbookでは“parameter token”)のことではない。

画期的なバリアブルフォントを作ってみた

「某I◯Cが人類に打ち克った証」たる某近代ナンチャラが最終日を迎える中、東京では……(中略)……ゆきだるま☃!

というわけで、コロナ禍にも負けず、某I◯Cにも負けず、今年も普段通りの「ゆきだるま☃の日」がやってきました!

フォントについて語ってみる

さて☃といえばフォントですが、5年ほど前に、「ヒラギノ角ゴシック」の☃がチョット話題になりました。

nlab.itmedia.co.jp

ヒラギノフォントといえば「☃が無表情」なことで有名ですが、後から追加された「W0」だけ、なぜか☃がチョット笑顔で、しかも帽子が黒いのです。この件が話題になったときのツイッタァーの反応がまとめられています。

togetter.com

……おや、一人だけ、変なことを言ってますね……。

f:id:zrbabbler:20210808155437p:plain
アレな人(ざんねん🙃)

バリアブルフォントについて語ってみる

バリアブルフォント(variable font)というのは、2016年にOpenTypeの仕様に追加された「Font Variation」という機能を利用したフォントのことで、粗くいうと「一つのファミリの中の変種を“無限に”作る」ことを可能としています。例えば、先の話にあったようにヒラギノフォントにはW0・W1・……・W8・W9の10個のウェイト(字の太さ)が用意されていますが(これはこれでスゴイわけですが)、ウェイトを”バリアブル”にしたフォントでは、ユーザは「W5.5」とか「W3.14159」とかに相当する中間のウェイトを利用できます。いわば、ウェイトの種類が“無限”に増やせるわけです1

欧文のバリアブルフォントは既に数多く発表されていましたが、今年(2021年)の4月に、フリーの和文フォント「源ノ角ゴシック」について、そのバリアブルフォント版が公開されました。

blog.adobe.com

これを機にして日本でもバリアブルフォントの技術に注目が集まっているようです。先月には、「全角ダーシの太さ・長さが自由に調節できるフォント」が公開されました。

欧文フォントに続いて和文フォントの世界にもバリアブルフォントの時代が到来したとなれば、☃文フォントの世界にもバリアブルフォントが求められるのは必然の流れでしょう。

☃文バリアブルフォントについて検討してみる

☃について「“無限に”変えたいもの」といえば、やっぱり帽子やマフラーの色でしょう。(カラー絵文字のフォントがあることからわかるように、現在のOpenTypeの仕様では「色付きのグリフ」がサポートされています。)

f:id:zrbabbler:20210808161322p:plain
さっきのツイートにある画像

しかし残念ながら現状では、Font Variationの仕組で変化させる対象となるのは、グリフの輪郭線の点の座標に限られるようです2

一方で、「笑顔と無表情の間で“無限の”バリエーションを作る」ことであれば、これは輪郭線の変化なので実現できそうです。

☃文バリアブルフォントを作ってみる

というわけで、さっそく作ってみました

github.com

※詳しい話はまた後日🙃

まとめ

というわけで、笑顔の☃も、無表情の☃も、不機嫌な☃も、すべて素敵!

f:id:zrbabbler:20210808205032p:plain


  1. バリアブルフォントの技術が最もよく用いられるのは「ウェイト(太さ)の変化」に対してですが、その他に「字幅の変化」「傾きの変化」に対してもよく使われます。

  2. 一応「variationの軸の値と連動してグリフ置換を行う」みたいな仕組はあるようなので、色の違うグリフを多数用意して“疑似的に”実現するという手段はありえますが、それだとそもそもバリアブルフォントである意味があまりなさそうです。

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

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

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で名前を共通にすることを意図している。とはいっても必ずしも両方のエンジンで実装されているとは限らない。

  • \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が指定できて、カテゴリコードが和文か欧文かに応じて文字コードの有効範囲も異なることに注意。
  • \Umathcharclass‹整数:文字コード›:その文字に対する数式クラス*3の値(整数)。
    ※LuaTeXで利用可能。

  • \Umathcharfam‹整数:文字コード›:その文字に対する数式ファミリの値(整数)。
    ※LuaTeXで利用可能。

  • \Umathcharslot‹整数:文字コード›:その文字に対する数式スロット(数式フォント中の文字コード)の値(整数)。
    ※LuaTeXで利用可能。

(続く)

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

*2:具体的には\XeTeXinputencoding、\XeTeXdefaultencoding、\XeTeXlinebreaklocaleの3つ。

*3:「文字に対する数式クラス・数式ファミリ・数式スロット」というのは元祖TeXの数式コードに対応する概念である。例えば、文字Xに対する数式コード(\mathcode`\X)が"7158だとすると「数式クラスは7、数式ファミリは1、数式スロットは"58」ということになる。

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

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

pdfTeX関連の注意事項

※一般の注意事項については初回の記事を参照。

  • 整数・寸法・グルー値の情報を返すプリミティブは、他のエンジンでは「読取専用のパラメタ」として提供される(例えば\lastkern)ことが多いが、pdfTeXでは「その値を表す\the-文字列に展開する展開可能プリミティブ」であることが多い。
  • pdfTeXのマニュアルでは\pdfincludecharsが展開可能プリミティブとして挙げられているが、実際には展開不能であるようだ。恐らくこれは単純な記述ミス……?

pdfTeXのやつ

  • 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の場合(プリミティブ名は\strcmp)、文字列をUTF-16のユニット列に変換した上で比較する。従って、BMP外の文字が含まれる場合は必ずしもUnicode符号値の順にはならない。
  • \pdftexbanner:エンジンのバナー文字列。

    • 「バナー文字列」とは起動時に端末に出力される「This is pdfTeX, …」のような文字列。
  • \pdftexrevision:エンジンのリビジョン番号。

    • なお\pdftexversionは読取専用整数パラメタである。
    • 例えばバージョン番号が「1.40.21」の場合、\pdftexrevision21に展開される(ドットは付かない)。\pdftexversionは140になる。
  • \pdfunescapehex{‹文字列:16進ダンプ›}:その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だったら、アレなこと*1になる。
  • “フォント”の引数には、\jfont\tfontも使える。

pTeXのやつ

  • pTeXの追加のif-トークン ☆:

    • \ifdbox‹整数:ボックス番号›
    • \ifddir
    • \ifjfont‹フォント›
    • \ifmbox‹整数:ボックス番号›
    • \ifmdir
    • \iftbox‹整数:ボックス番号›
    • \iftdir
    • \iftfont‹フォント›
    • \ifybox‹整数:ボックス番号›
    • \ifydir
  • “漢字コード変換子”、すなわち\euc‹整数›\jis‹整数›\kuten‹整数›\sjis‹整数›:「当該の漢字コードでの符号値が引数の整数に等しい和文文字の、内部漢字コードでの符号値」の十進表記文字列。

  • \ptexrevisionpTeXのリビジョン番号の文字列。

    • なお\ptexversion\ptexminorversionは読取専用整数パラメタである。
  • \kansuji‹整数›:その整数の(一〇方式の)漢数字表記の文字列。負数の場合は空になる。

    • \kansujicharで漢数字として使用する文字を変更できる。

upTeXのやつ

  • upTeXの追加の“漢字コード変換子”:
    • \ucs‹整数›
      ※将来にはpTeXでもサポートされる予定。

e-pTeXのやつ

e-pTeX独自(つまり、“非eのpTeX系”にも“非pTeX系”にもない)のプリミティブは存在する*2のだが、その中には展開可能のものはなさそう。

\Uchar\UcharcatについてはXeTeXの記事を参照。

(続く)

*1:「欧文扱い」が適用されるので、UTF-8のバイト列を表す欧文文字トークン列(カテゴリコード12)に変換される。

*2:例えば\epTeXinputencodingなど。なお「e-upTeX独自」、つまり「e-upTeXにあるがupTeXにもe-pTeXにもない」プリミティブは存在しない。

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

まとめてみた。

注意事項

  • 多くのプリミティブは展開結果が必ず\the-文字列になる。そうでないものについて注意のため印を付けている。
    • 無印:(状態変化無しで)展開結果が必ず\the-文字列になる。
    • ★印:(状態変化無しで)展開結果が\the-文字列以外になりえる。
    • ☆印:展開に付随して内部状態が変化し、展開結果が必ず空になる。
    • ◇印:展開に付随して内部状態が変化し、展開結果が非空になりえる。
  • 各項目の説明には「そのプリミティブの一回展開結果のトークン列が何か」を記した。ただし☆・◇印のものは“動作”を記した。
  • 展開結果の記述に関する注意:
    • 展開結果が“文字列”として述べられている場合、それは実際には\the-文字列*1を指す。
    • 数値・寸法・グルー値を\the-文字列として表す場合の書式は「そのデータ型のパラメタを\theで出力する場合」と同じである。※例えば寸法値10ptは10.0ptという\the-文字列で表される。
  • 引数の記述に関する注意:
    • 角括弧 [ ] は省略可能であることを示す。角括弧自体は入力しない。
    • 引数が“文字列”として述べられている場合、それは「与えられたトークン列を完全展開して脱トークン化した結果の文字列」が使われることを示す。
    • 引数に現れる“フォント”は「fontdefトークン」「\font」「\textfont‹整数›」「\scriptfont‹整数›」「\scriptscriptfont‹整数›」の何れか*2を指す。

元祖TeXのやつ

  • “条件トークン”☆:TeXの内部の「条件判断に関する内部状態」を変化させる。

    • “条件トークン”とは「if-トークン」「\else」「\or」「\fi」を指す。元祖TeXがもつif-トークンは以下の通り:
      • \if‹トークン1›‹トークン2›
      • \ifcase‹整数›
      • \ifcat‹トークン1›‹トークン2›
      • \ifdim‹寸法比較›
      • \ifeof‹整数:ストリーム番号›
      • \iffalse
      • \ifhbox‹整数:ボックス番号›
      • \ifhmode
      • \ifinner
      • \ifmmode
      • \ifnum‹整数比較›
      • \ifodd‹整数›
      • \iftrue
      • \ifvbox‹整数:ボックス番号›
      • \ifvmode
      • \ifvoid‹整数:ボックス番号›
      • \ifx‹トークン1›‹トークン2›
    • 詳細は以下の記事を参照。
  • “マーク変数” ★:現在の状況で(各々のマーク変数の機能に即して)該当するマークのトークン列。

    • ここで“マーク変数”は以下のものを指す:
      • \botmark
      • \firstmark
      • \splitbotmark
      • \splitfirstmark
      • \topmark
  • \csname‹トークン列›\endcsname ◇:「‹トークン列›を完全展開して得られる文字トークン列を脱トークン化した文字列を名前とする制御綴」のトークンに展開される。

    • 当該の制御綴が未定義の場合は、「その制御綴がローカルに\relaxに等値される」という副作用をもつ。
    • 完全展開の結果に制御綴が含まれる場合はエラーになる。
    • \endcsname自体は展開不能である。
  • \endinput ☆:現在のファイルからの読込を「既に読んだ行」までで停止する。

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

  • \fontname‹フォント›:そのフォントの定義を表す文字列。

    • 書式は「‹TFM名› at ‹寸法:使用サイズ›」だが、使用サイズがデザインサイズに等しい場合は「‹TFM名›」のみになる。
  • \input‹ファイル名› ☆:以降は指定のファイルから入力を読むようになる。

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

    • 「ジョブ名」はコマンドオプションの-jobnameの値。既定値はシステム依存だが、多くの場合は「最初に読んだファイルのベース名」になる。
  • \meaning‹トークン›:そのトークンの意味を説明した文字列。

    • 例えば、\meaning$は「math shift character $」、\meaning\quadは「macro:->\hskip 1em\relax」に展開される。
  • \noexpand‹トークン› ★:引数のトークンを展開不能にしたトークン。

    • 通常は展開限定文脈において「引数のトークン自身に展開されそれ以上展開されない」という挙動のために用いられる。
    • 引数のトークンが元々展開不能だった場合は単純にそれ自身になる。展開可能だった場合は「一時的に意味を\relaxに置き換えた」トークン(なので、展開限定文脈外においてそれが実行されたとしても何も起こらない)になる。厳密な仕様は結構ヤヤコシイ。
  • \number‹整数›:その整数の(典型の)十進表記の文字列。

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

  • \string‹トークン›トークンが文字トークンの場合は、その文字。制御綴の場合はそれを文字列化したもの(後続の空白は無し)。

    • 「制御綴の文字列化」は、制御綴名の前に\escapecharの文字を前置した形の文字列。ただし\escapecharが(欧文)文字コードの範囲外の値の場合は何も前置されない。
  • \the‹内部値›:その内部値(レジスタ・パラメタ)の現在の値を表すトークン列。普通は\the-文字列であるが、以下の場合は例外となる:

    • \the‹トークン列レジスタ・パラメタ› ★:そのレジスタ・パラメタが現在保持するトークン列そのもの。※展開限定文脈である場合はそれ以上展開されない。
    • \the‹フォント› ★:そのフォントを選択するためのfontdefトークン。
      • ここで生じるトークンの“外形”については少しヤヤコシイことになっている。

e-TeXのやつ

  • e-TeX拡張のif-トークン ☆:

    • \ifdefined‹トークン›
    • \ifcsname‹トークン列›\endcsname
      \csnameと異なり“\relax化”の副作用を決して起こさない。
    • \iffontchar‹フォント›‹整数:文字コード›
  • e-TeX拡張の“マーク変数”★:

    • \botmarks‹整数:マーク番号›
    • \firstmarks‹整数:マーク番号›
    • \splitbotmarks‹整数:マーク番号›
    • \splitfirstmarks‹整数:マーク番号›
    • \topmarks‹整数:マーク番号›
  • \detokenize{‹トークン列›}:引数のトークン列を(展開せずに)脱トークン化した結果の文字列。

    • 結果は\the-文字列であることに注意。実質的に「(字句解析前の)文字列に戻す」働きをもつのは\scantokensの方である。
  • \eTeXrevision:e-TeXのリビジョン番号の文字列。

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

  • \unexpanded{‹トークン列›} ★:引数のトークン列自身。※展開限定文脈である場合はそれ以上展開されない。

    • 展開限定文脈以外では普通に展開される。\the‹トークン列レジスタ・パラメタ›の展開と同じ規則である。
  • \unless‹ifトークン›… ☆:後続の条件部の真偽を反転させた条件文を開始する。

    • \unlessの直後に真偽型のif-トークンそのものが続く必要がある。条件部を含めて一回で展開されることに注意。

(続く)

*1:「\the-文字列」は「TeXの文字トークン列によって文字列を表現する」際の規約で、ASCII空白(文字コード32)についてはカテゴリコード10、それ以外の文字についてはカテゴリコード12の文字トークンを用いる。

*2:\textfont・\scriptfont・\scriptscriptfontの引数の整数は数式ファミリ番号を指す。

\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