Skip to content

Instantly share code, notes, and snippets.

@aminophen
Last active October 29, 2022 03:27
Show Gist options
  • Save aminophen/422a3cb307cee901d963fcc2718f5121 to your computer and use it in GitHub Desktop.
Save aminophen/422a3cb307cee901d963fcc2718f5121 to your computer and use it in GitHub Desktop.
Brand new pTeX - brainstorming

仕様案

従来の (u)pTeX と「付かず離れず」のクリーンな設計を考える。

  • 可能な文字コードは全 Unicode 範囲とする。
  • 欧文・和文とは関係なく常に「1文字1トークン」とする。(変更)
    • これで「1文字1トークンの和文文字の UTF-8 → Unicode 変換結果」と「1バイト1トークンの欧文文字」が 0x80--0xFF で衝突することがなくなる。★
    • 文字トークンの区切りが変化することもなくなる=「バッククオートで Unicode 文字直書きからコード取得」は常に安全。
    • [TODO] TeX82 の「1文字コントロールシーケンスの特別扱い」(つまり \aa はバッククオートでのコード取得が同値)は 0--255 のままにできるか?
  • 内部バッファの文字コードは固定する。(pTeX の EUC/SJIS は廃止)
    • Unicode 値(XeTeX 方式)にするか,UTF-8(LuaTeX 方式)にするか → 元々 upTeX は Unicode 値なのでそのままで良さそう。
    • 補足:LuaTeX はソースファイル中の不正な UTF-8 バイト列を "! String contains an invalid utf-8 sequence." で弾くチェックを持つが,必須ではなさそう。(なぜか ^^ab 記法から生成する不正な UTF-8 バイト列は弾かれないし…)
    • 文字コードで都度トークンの和文or欧文が区別可能になれば ^^ab 記法を常に欧文扱いする必要もなくなるし,XeTeX/LuaTeX のように ^^^^^^^^^^ で4桁・6桁の Unicode スカラーを指定できると良さそう。(変更・拡張)
  • 全ての Unicode 文字は「和文か欧文か」「catcode」「kcatcode」の 3 つの属性を持つ。(変更)
    • これらの属性は eqtb テーブルの計 7bit の領域に格納され,「新しい入力文字がどれに当たるのか」を判断してトークン生成するために使われる。(※改行を空白とみなすかどうかもここで決定)
      • 下位 4bit : catcode: 0..15
      • 中位 2bit : kcatcode: 16..19(※15を引いて 0..3 で格納)
      • 最上位 1bit : is_cjk: 0..1(※和文(CJK)なら1,欧文なら0 / 改行の扱いにも影響)
    • 注意:従来 upTeX では 0--127 が常に欧文扱いだったが,和文扱いも許すこととする。☆
    • 注意:欧文の catcode 領域と和文の kcatcode 領域はもちろん,欧文の kcatcode 領域は \kansuji と \forcecjktoken での強制和文文字トークン生成でアクセスされうる。和文の catcode 領域がアクセスされることはない。
    • 補足:従来 upTeX では「\kcatcode=15(欧文扱い) の文字を \forcecjktoken で出すと自動的に \kcatcode=18 扱い」と固定だったが,このように属性を分離すれば固定を外せる。
  • 全ての文字トークンは計 29bit で表される。(upTeX の和文文字トークンと同じサイズ)
    • 和文文字トークン⇔欧文文字トークンの変化は起こらないので,先の eqtb と違って属性値はまとめてよい。
      • 下位 24bit : 文字コード U+0000..U+FFFFFF
      • 上位 5bit : catcode/kcatcode のどちらか(※16以上なら和文扱い,そうでなければ欧文扱い)
    • 注意:文字コードの最大を U+FFFFFF まで許しているが,これは現状 OTF パッケージの vf の文字コードの一時利用先として使われている。(=上限 U+10FFFF に落とすと OTF パッケージも改修必要)
  • トークンは自身の catcode/kcatcode に従って振る舞う。(従来どおり)
    • より詳細に書くと「和文文字トークンは kcatcode に従う」「それ以外は catcode に従う」。
    • 注意:トークンが持つ catcode/kcatcode はそのトークンの意味を固定する(eqtb テーブルとは無関係になる)とともに,和文文字トークンに格納された kcatcode の値は「\string による文字列化後トークンでも元の文字トークンの kcatcode を維持」「和文文字ノードにも和文文字トークンと同じ kcatcode を格納して \jcharwidowpenalty 決定に利用」にも波及する。
  • 属性値の eqtb テーブルへの更新と取得
    • 欧文/和文扱いの切替機能だけを持つ命令 \iscjk(仮称) を新設する。(upTeX の \kcatcode から機能分離)
    • \catcode は全 Unicode 文字に範囲拡大。(拡張)
    • \kcatcode は「その文字が仮に和文扱いされたら…」の属性変更に絞る。(pTeX に類似)
      • \catcode 代入 → catcode 更新と同時に is_cjk=0 に更新
      • \kcatcode 代入 → kcatcode 更新のみ(※このとき catcode=11,12 や is_cjk=1 への連動更新はしない:強制和文文字トークン生成用の値変更である可能性があるため)
      • \iscjk(仮称)=0 代入 → is_cjk=0 に更新(欧文扱いになる)のみ
      • \iscjk(仮称)=1 代入 → is_cjk=1 に更新(和文扱いになる)と同時に catcode≠11,12 なら補正(kcatcode=16/17/19→catcode=11, kcatcode=18→catcode=12)
      • \catcode 取得 → 欧文の場合は catcode 読出,和文の場合は kcatcode 読出から読替(18→12, 16/17/19→11)
      • \kcatcode 取得 → kcatcode 読出
      • \iscjk(仮称) 取得 → is_cjk 読出
      • ただし従来の upTeX との互換性目的で「\kcatcode=15」という文法を「\iscjk=0」と同義で扱う
    • 注意:これにより海外の LaTeX3 開発者にとっては「和文(CJK)トークン」という存在を知らなくても欧文トークン同様の値読み書きが支障なくできる。あとは日本側で「それが和文(CJK)トークンなら…」という分岐処理くらいを用意してあげれば,海外製の LaTeX3 内部処理にまでパッチする必要はないと期待。
    • [TODO] 設定は文字コード毎とするかブロック毎とするか?
    • [TODO] \lccode, \sfcode などは「仮に欧文扱いされたら…」の属性でよいか?
  • 条件文たち
    • TeX82 互換の \if では文字コードの値を見る。(維持: ただし★で和文と欧文の衝突は解消済み)
    • TeX82 互換の \ifcat では上記「\catcode の取得」と同じ値を見る。(変更: \kcatcode は見ない)
    • TeX82 互換の \ifx は文字コードと「欧文なら catcode / 和文なら kcatcode」の値の両方を見る。(従来どおり)
    • 従来の (u)pTeX の \ifcat に相当する機能として「欧文なら catcode / 和文なら kcatcode」の値を見る条件文プリミティブを新設する。(リネーム)
  • 文字列化
    • TeX82 互換の \number, \romannumeral および pTeX 互換の \jis, \euc, ... は常に欧文文字トークンを生成する。(従来どおりだが,☆のため仕様明記が必要)
    • TeX82 互換の \string, \meaning は「元が欧文→catcode=12」「元が和文→kcatcode=元の値」の文字トークンを生成する。(維持)
    • pTeX 互換の \kansuji は常に和文文字トークンを生成する。(変更: ☆のため 0--127 が和文化)
    • [TODO] \lowercase トリックで和文文字トークン生成を許すか?
  • 文字トークンから文字ノードへ
    • 最終的に欧文文字トークン (is_cjk=0 && catcode=11,12) は欧文文字ノードへ,和文文字トークン (is_cjk=1 && kcatcode=16..19) は和文文字ノードになる。
    • [TODO] 文字コード X ≧ 0x100 の欧文文字トークンをどうするか? → 欧文 TFM で未定義なので「ノードを作らない」と定めるか,OFM を使うか,別途 \usepackage[utf8]{inputenc} 並みに 8-bit な TFM の欧文フォントを使える仕組みか,何かしらの用意が必要。
  • 文字コードからの文字ノード直接生成
    • \char : eqtb テーブルの is_cjk に応じて欧文文字ノードまたは和文文字ノードを生成。和文文字ノードには eqtb テーブルの kcatcode を一緒に格納する。(維持)
    • \kchar : 常に和文文字ノードを生成し eqtb テーブルの kcatcode を一緒に格納する。(維持)
    • \achar(仮称) : 常に欧文文字ノードを生成する。(新規)

補足(1)

当初は「和欧文の区別・catcode・kcatcode という3つの属性が独立というところが肝」と考えていたが,議論を進めるうちに「catcode=13 かつ kcatcode=17」のようなものに違和感を感じてきたので,変更した。この変更後のほうがむしろ

  • 日本から見れば,任意の文字トークンの「和欧文の区別」と「\kcatcode」を好きにできる
  • しかし海外の LaTeX3 開発者から見れば「\catcode」だけに見える(つまり,日本で \kcatcode をどう変更しても欧文側の \catcode には何も起こらない)

に近づき,issue:150 のタイトル「欧文トークンに似せた CJK トークン」を突き詰め,見かけ上は文字トークンを欧文と同様のコードで扱える(実際には CJK トークンかもしれないが,全く意識せずに済む)と考え直した。

補足(2)

このように CJK トークンを隠しても,海外からも

  • 和文文字トークン (kcatcode=16,17,18) 直後の改行は空白にならない
  • 和文記号 (kcatcode=18) 一文字のコントロールシンボルの文字列化では空白が補われない (#37)

だけは見えてしまうのが避けられないと思うが,この程度なら問題ないと考える。

補足(3)

上記 [TODO] 文字コード X ≧ 0x100 の欧文文字トークンをどうするか? についての @h-kitagawa さん案:LaTeX の \DeclareUnicodeCharacter{00F6}{\"o} のように Unicode 値→出力命令へのマッピングを(アクティブ化を使わずに)定義できるように \tonoderecipe"xyzw={<token list>} のようなものを導入できないか。

参考:LuaTeX には「仮にその文字コードがアクティブ化 (catcode=13) されたら…」を定義する \letcharcode というプリミティブがあって \def\foo{bar}\letcharcode<文字コード>=\foo とすれば \meaning<文字コード>bar になる。(lowercase / uppercase トリックを使わずに済む)

% luatex
\show X         % > the letter X.
X               % => X
\char`X         % => X

\def\foo{Y}\letcharcode`X=\foo
\show X         % > the letter X.
X               % => X
\char`X         % => X

\catcode`X=13
\show X         % > X=macro:->Y.
X               % => Y
\char`X         % => X

\end

ここで \tonoderecipe"xyzw={<token list>} は「仮にその文字コードが is_cjk=0 だったら…」が欲しいのでちょっと似ていますが「アクティブ化は要しない(catcode=11,12 専用)」「そのトークン列を使うのは \meaning の時ではなく \char の時である」というのが異なる。

補足(4)

eqtb テーブルの実装は pTeX のソースの以下の部分。

@ Region 4 of |eqtb| contains the local quantities defined here. The
bulk of this region is taken up by five tables that are indexed by eight-bit
characters;
...
@d cat_code_base=auto_xspacing_code+1
  {table of 256 command codes (the ``catcodes'')}
@d kcat_code_base=cat_code_base+256
  {table of 256 command codes for the wchar's catcodes }

補足(5)

upTeX でのトークン表現は uptex-base/01uptex_doc_utf8.txt によると

  • 和文(CJK)トークンは 29bit (5bit:kcatcode, 24bit:charcode) で表現
    • 文字コード: U+0000..U+FFFFFF
    • カテゴリーコード: 15..19(※可能な値は5種類だが値をそのまま格納)
  • 欧文トークンは 12bit (4bit:catcode + 8bit:charcode) で表現 → ここは TeX82 と同じ
    • 文字コード: 0x00..0xFF
    • カテゴリーコード: 0..15
  • 文字トークンの和文(CJK)/欧文の区別は「最初に |max_cjk_val| で割って 16..19 なら和文(CJK),そうでなければ欧文」とみなす

である。

参考:仕様案の要件

目的は『和文(CJK)トークンを欧文トークンに似せる』こと。今の理解としては「見かけ上は文字トークンを欧文と同様のコードで扱えるようにする」(実際には CJK トークンかもしれないが,全く意識せずに自由な値の \catcode を設定でき,設定したとおりの値を読出せる)程度でよいのではないか。

項目「1文字1トークン」について (2022-10-24 @aminophen)

仕様選定の取っ掛かりは @h20y6m さんのコメントにしようと思います。

和文文字トークンのカテゴリコードとして何を返すべきか

こちらは上の仕様案「和文文字コード 0x100≦X からも \catcode の読出できるようにする」で(個別に \catcode, \kcatcode を指定可能に…であれ,機械的に11,12に読み替える…であれ)どうにかなりそうですが

0x80--0xFFの範囲で欧文と和文が区別できない

これは upTeX 開発当初からの問題と同じで

欧文については8-bitエンジンだけど和文文字トークンという異質なものが入ってくる

これは「欧文文字は1バイト1トークン」「和文文字は見た目の1文字で1トークン」で最初から解釈が分岐してしまう現在の仕様では解決困難なように思います。

じゃあどちらに寄せるのがいいかと考えると,(u)pTeX の資産を考えると「和文文字トークンを完全に廃止してしまう」のは \futurelet とか \prebreakpenalty などのバッククオートによる文字コード取得や LaTeX の \@tfor などを捨てることになるので,LuaTeX や XeTeX のように「見た目の1文字で1トークン」に寄せることで UTF-8 前提の 8-bit エンジン用のコードを使わないことにする方が自然だと思います。

  • LuaTeX は内部バッファが UTF-8
  • XeTeX は内部バッファは Unicode 値

どちらでも構いませんが,先の「0x80--0xFFの範囲で欧文と和文が区別できない」の根源は

「1文字1トークン」の和文文字を UTF-8 → Unicode 値に変換したときに 0x80--0xFF の文字コードになりうるのに,その行き先に「1バイト1トークン」の欧文文字トークンも存在すること

だと思うので,一律に「1文字1トークン」とすれば全て良い方向にむかうのではないでしょうか。

項目「3 つの属性」について

以下の 2 点を前提として「eqtb テーブルの和文/欧文文字コードには catcode/kcatcode は必要か」を議論する。

  • 海外の LaTeX3 開発者が和文(CJK)トークンの存在を意識せずに,自由な値の \catcode を設定でき,設定したとおりの値を読出せるような仕様設計が好ましい。
  • 同時に,従来の和文(CJK)トークンの仕様も極力維持したい。

まず 1 点目により「eqtb テーブルの和文文字コードに対して catcode が必要で,仮に同じ文字コードに kcatcode と共存することがあってもその影響は受けない」が必要と判断。

  • 別案「eqtb における catcode が kcatcode の値に連動する読替 (16,17,19→11 / 18→12)」では,\kcatcode 変更時に \catcode が書き換わってしまう恐れ
  • 別案「eqtb に格納可能な値の組み合わせ制約 {11,16,17,19}⇔{12,18}」では,自由な \catcode 設定が阻害される恐れ
  • いずれにせよ結局「最初に CJK トークンかどうかを判定しないと \catcode を読書できない」という状態が続いてしまい,LaTeX3 開発者が扱いづらいのではないか

次に 2 点目はどこまで維持するかが鍵となる。最初に upTeX において「欧文文字コードから 1 文字トークンを生成する命令」(具体的には \kansujichar, \Uchar, \forcecjktoken が該当)を考えたとき,何を生成すべきか?

  • [1] kcatcode=18 固定の和文文字トークン
    • これを選べば eqtb テーブルで欧文文字コードに対する kcatcode は不要。
    • 現在の upTeX の \kansuji, \forcecjktoken, \Uchar(≧ 0x100) はこれに該当。
  • [2] kcatcode=その時点での値の和文文字トークン
    • これを選べば eqtb テーブルで欧文文字コードに対する kcatcode が必要。
  • [3] 単に 1 文字トークンであって,欧文扱いなら catcode=12 / 和文扱いなら kcatcode=その時点での値
    • これを選べば eqtb テーブルで欧文文字コードに対する kcatcode は不要。

どれを選んでも良いと思うが

  • \Uchar は明らかに [3] が自然
    • 一律に「1文字1トークン」としたので XeTeX / LuaTeX と合わせられる。
  • \forcecjktoken は機能から [1]..[2] のいずれかに絞られるが,クリーンな設計案では [2] を選択
    • upTeX での主な使われ方は pTeX のエミュレーション「和文扱い可能な文字(= 0--127 以外)な文字を kcatcode によらず強制的に和文扱い」であったが,その状況で欧文文字コードを持つ和文文字トークンが一律に kcatcode=18 と固定されたことに疑問があったので…。
    • ちなみに upTeX でも(欧文の \string は catcode=12 固定に対し)和文文字トークンの \string は kcatcode=18 固定ではない。
  • \kansuji は [1]..[3] どれでも良いが,クリーンな設計案では [2] を選択
    • 理由は \forcecjktoken と同じ。

という考えにより一部に [2] を採用したため「eqtb テーブルでは欧文文字コードに対しても kcatcode が必要であり,catcode の影響は受けない」に至った。

→ 以上から「eqtb テーブルでは全文字コードに対して catcode と kcatcode が独立に格納される必要がある」と考えた。この状況でどちらが有効かを判定するために is_cjk も必要となる。

さらに @h-kitagawa さんの 2022-10-27 付コメント

内部バッファからのトークン生成や \Uchar などでは,和文欧文の判定で何を最初に見るのが良いか?

  • 例えば kcatcode→catcode→is_cjk の順番で設定すると,(catcode,kcatcode,is_cjk)=(13,17,1) という状況が生まれるが,「catcode=13 を優先して(= is_cjk は catcode=11,12 のときしか効力がなく)アクティブ文字」か「is_cjk を優先して和文文字トークン」か?

を受けて is_cjk=1 の状況に限り eqtb における可能な catcode の値を 11,12 に制限するようにした。なお「catcode=11 かつ kcatcode=18」あるいは「catcode=12 かつ kcatcode=16,17,19」の組み合わせが発生することは許容しているが,これは例えば (c,k,j)=(12,18,1) の状態から \catcode=11 を指定された場合,仮に (11,18,0) 不可としても (11,16,0) (11,17,0) (11,19,0) のどれに補正すればよいか自明ではないためである。

項目「文字トークンの 29bit 表現」について

同じ前提で「和文/欧文文字トークンには catcode/kcatcode は必要か」を議論する。

和文文字トークンにも欧文互換の \ifcat が機能するためには

  • [A] 和文文字トークンにも catcode の情報を格納
  • [B] 和文文字トークンは catcode を持たないが kcatcode から値を読替 (16,17,19→11 / 18→12)

の2通りの実装が考えられる。最初は [A] を選択したが,必須とはいえないし「catcode=13 かつ kcatcode=17」のようなものに違和感があるという意見にも納得したので [B] に転換した。

@aminophen
Copy link
Author

texjporg/tex-jp-build#150 の仕様案と実装案をまとめ始めてみる。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment