マクロツイーター

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

完全解説! TeX言語のプリミティブな制御記号全部まとめ

せっかくの「TeX言語GW特別キャンペーン🍀」であるが、誰も「完全解説! TeX言語のプリミティブな制御記号全部まとめ」の記事を書かないので、仕方がなく自分で書くことにした(ざんねん🙃)

必要な前提知識

  • TeX言語の「プリミティブ」「制御綴」とは何かを知っている。

「プリミティブな制御記号」の定義

制御記号(control symbol)というのは「英字(カテゴリコード11)以外の文字1つからなる名前1の制御綴」のことであり、従って「プリミティブな制御記号」とは「制御記号で表されるプリミティブ」を指すことになるだろうが、そもそもカテゴリコードの設定や制御綴の意味は可変であるためこれをそのまま定義とするのは都合が悪い。INIモードの初期状態を前提にするのも一つの手であるが、LuaTeXのように「初期状態で制御綴に割り当てられていないプリミティブがある」ようなエンジンもある。

そこで、まず条件を緩めて文字の種類は問わないことにする。さらに「制御綴名」の代わりに「プリミティブ名」を考えることにする。「プリミティブ名」というのは「意味がプリミティブであるトークンに\meaningを適用して得られる文字列2」のことであり、例えば「\expandafterプリミティブ」などと説明する場合の「expandafter」がプリミティブ名である。この名前はプリミティブごとに決まっていて不変である。そこで、「プリミティブな制御記号」の定義を「プリミティブ名が1文字のプリミティブ」と定めることにしよう。

「プリミティブな制御記号」の一覧

というわけで、TeXの「名前が1文字のプリミティブ」を全て列挙すると以下のようになる。

プリミティブ説明
\␣(U+0020)通常の欧文空白
\-任意(discretionary)のハイフン
\/イタリック補正

この結果は(メジャーエンジンの範囲3では)どのエンジンでも変わらない。ここで現れる文字(空白、- /)はどれも(一般的なフォーマットで)カテゴリコードが11以外であるので、結果的に「名前が1文字」のプリミティブは制御記号的なものしかないことがわかる。

「プリミティブな制御記号」の解説

本記事の目的は恐らく「一覧がどうなるか」であったはずで、そうすると記事はもう完成していることになるが、せっかくなので各プリミティブについて「具体的な動作の詳細」を解説をしてみる。

なおこの3つのプリミティブは「そのまま4LaTeXカーネルの命令になっている」くらい有名なので、基本的な使い方については周知であるとする(ざんねん🙃)

\␣:通常の欧文空白

名前がASCII空白1文字であるプリミティブ5は「段落に欧文空白としての水平空きを出力する」機能を持つ。

  • 現在が垂直モードである場合は水平モードに移行する6
  • 現在の「欧文空白グルー値」を以下の要領で取得する:
    • グルー値パラメタ\spaceskipの値がゼロ(0pt)である場合は現在のフォントのfontdimenを調べる。「‹fontdimen2の値› plus ‹fontdimen3の値› minus ‹fontdimen4の値›」が「欧文空白グルー値」である。
    • \spaceskipが非ゼロの場合はその値が「欧文空白グルー値」である。
  • 大きさが「欧文空白グルー値」の水平空きを出力する。

\-:任意のハイフン

\-は「普段は何も出ないが、行分割時には現在のhyphencharの文字を行末に出す」ようなdiscretionaryを出力する。

  • \hyphenchar\fontの値を取得し「hyphencharの値」とする。
  • \discretionary{\char‹hyphencharの値›}{}{}を行う。
    • ただし「hyphencharの値」が有効な文字コードの範囲7の外であれば第1引数を空にする。

ただしLuaTeXでは手順が少し異なる。

  • 現在の言語の\prehyphencharの値を取得し「prehyphencharの値」とする。
  • 現在の言語の\posthyphencharの値を取得し「posthyphencharの値」とする。
  • \discretionary{\char‹prehyphencharの値›}{\char‹posthyphencharの値›}{}を行う。
    • ただし「prehyphencharの値」が有効な文字コードの範囲外であれば第1引数を空にし、「posthyphencharの値」が有効な文字コードの範囲外であれば第2引数を空にする。

\/:イタリック補正

\/は直前の文字に対するイタリック補正の水平カーンを出力する。

  • 垂直モードではエラーになる。
  • 数式モードでは常にゼロの水平カーンを出力する。
    ※数式モードでは文字のイタリック補正の分のカーンが原則常に出力される8のでそれ以上空ける必要がない。
  • 水平モードの場合は実際にイタリック補正のカーンを出力する:
    • 直前に出力したものが文字でない場合は何もせず終了。
    • 直前に出力した(フォントの)文字のイタリック補正の値を取得する。
      ※TFMに記録されている9
    • 取得した値の水平カーンをイタリック補正として出力する。

まとめ

というわけで皆さん、もっともっとTeX言語🤮の記事を書きましょう!💁


  1. 制御綴の「名前」にはエスケープ文字は含めない。
  2. ここで得られる文字列自体は\expandafterのような制御綴の形の文字列であり、正確にはここからエスケープ文字を除いたものをプリミティブ名とする。なお、少なくとも元祖TeXではINIモードの初期状態において「全てのプリミティブについて、それと同名の制御綴にプリミティブが紐づけられている」(例えば\expandafter制御綴の意味はexpandafterプリミティブである)が成立している。
  3. 元祖TeX、pdfTeX、XeTeX、LuaTeX、(e-)(u)pTeX。
  4. \-についてはLaTeXカーネルで再定義が行われていて少し挙動が異なる。
  5. ちなみに「名前がASCII空白1文字である制御綴」のことは「制御空白(control space)」と呼ばれる。
  6. ちなみに「空白トークンを実行した」場合は、現在が水平モード以外(垂直モードまたは数式モード)である場合は何も起こらない。
  7. LuaTeXでは1~0x10FFFF(0は無効扱い)、XeTeXでは0~0x10FFFF、イマドキのe-upTeXでは0~0x2E7F、それ以外は0~255。
  8. OpenTypeの数式フォントを利用する場合は「数式イタリック補正」のデータに基づいて自動的に(常に)補正が行われる。
  9. XeTeX・LuaTeXでOpenTypeを使う場合もそれに相当するデータが存在する。