マクロツイーター

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

LaTeX が新しくなった話(補足1)

レジスタ 65536 個」

e-(u)pTeX 上の LaTeX を「レジスタ 65536 個」に対応させることについては、「あまり重要ではない」としたが、ここではそれを実現する際の課題について考える。ここで問題になるのは「\chardef による整数定数定義の限界」である。

LaTeX\newcount で制御綴にレジスタを割り当てた場合、その制御綴は countdef トークンになる。

\newcount\mycountA
\show\countA %==>「\mycount123」(例えば)
% 以下の2つが同等になる
\mycountA=42
\count123=42

\newdimen\newtoks 等にういても同様である。ところが、\newbox に関しては事情が異なる。この場合、割当の対象となる制御綴は「ボックス型の変数」の代わりになるのではなく、常に \setbox\copy 等の「添字」として使われる。

\newbox\myboxA
% 以下の2つが同等になる
\setbox\myboxA\hbox{Hello}\copy\myboxA
\setbox123\hbox{Hello}\copy123

すなわち、この \myboxA は実は単なる整数定数なのである。\newbox の他に、\newread\newwrite\newfam\newlanguage で定義される制御綴も整数定数である。

ところで、TeX において整数定数を定義するには \chardef が流用される。例えば、\newbox マクロが \myboxA を定義する時は次のコードを実行している。

\chardef\myboxA=123 % 整数定数を定義

(ちなみに、\newcount の場合は \countdef プリミティブが用いられる。)

ところが、「\chardef で定数を定義する」というのは(よく利用されるが)「裏技」であるゆえ、少し不合理な制限をもつ。つまり、「本来の目的」を考えると \chardef の定義式の右辺にとれる値の範囲、すなわち「\chardef の定数が作れる範囲」は「有効な文字符号値の範囲」に限られることが判る。\newbox 等がちゃんと機能するためには、この範囲が「レジスタ番号の範囲」をカバーできていなければならない。

「定数を作る」問題

両者の具体的な範囲はエンジンによって異なり、以下のようになっている。

エンジン有効な符号値レジスタ番号
TeX0〜2550〜255
pdfTeX0〜2550〜32767
Aleph0〜655350〜65535
XeTeX0〜11141110〜32767
LuaTeX0〜11141110〜65535
e-pTeX0〜255 + 和文0〜65535
e-upTeX0〜231−10〜65535
※ 1114111 = 0x10FFFF は Unicode スカラー値の最大値。

e-pTeX の「有効な符号値の範囲」は少し複雑で、欧文の符号値(0〜255)と和文の符号値の両方が有効であり、後者の範囲は「現在の内部漢字コード(EUC または SJIS)の有効な“スカラー値”*1の集合」となっている。

これを見ると、pdfTeX では「\chardef の範囲」でレジスタ番号の範囲をカバーできていないことが判る。また、e-pTeX の「和文符号値」は不連続で特に 256〜33087 の値を含まないため、e-pTeX も必要な範囲をカバーできていない。

このうち、pdfTeX に関しては問題を回避する方法がある。「整数定数」を作るのに \chardef の代わりに \mathchardef を使うこともできて、この場合は(エンジンに依らずに)0〜32767 の範囲の定数が作れるので、これを利用して必要なレジスタ番号の範囲をカバーできる。実際に、LaTeX の新カーネルでは pdfTeX のときは定数定義に \mathchardef を使っている((t定数定義の命令として \e@alloc@chardef を用意し、それがエンジンによって \chardef\mathchardef に等値されるようになっている。))。(なお、割当の制御綴を整数定数でなく \def\myboxA{50000 })のような“整数値マクロ”で定義する、というのは、従来の方法と互換がないので無理である。((例えば、\the\myboxA のように使われる可能性が絶対無いとはいえない。\protected\myboxA{\numexpr50000\relax} とでもすれば失敗するか可能性は減らせるが、確実ではない。)))

では全く同じ方法が e-pTeX に使えるかというと、それは無理である。何故なら、こちらでは必要な「レジスタ番号の範囲」が 0〜65535 であり、\mathchardef でもカバーできないからである。結局、e-pTeX の場合はどうしようもないのではないか……。

またアレなことを考えてみた

いや、実は解決方法は存在する。そもそも今考えている(レジスタが 65536 個ある)のは FAM256 適用の e-pTeX である。ということは、Omega 互換の「\mathchardef の拡張版」である \omathchardef というプリミティブが使用できる。この命令も整数定数定義に使用できて、しかも、Omega 拡張の omathcode は 27 ビット(クラス 3 + ファミリ 8 + 文字コード 16)の値をとる。ということは \omathchardef を使うと、0〜65535 の範囲の整数定数が作れる!

ただ少し注意すべき点がある。FAM256 適用の e-pTeX では数式ファミリは 256 個(8 ビット)に拡張されているが、欧文符号空間は 8 ビットのままである(Omega は符号空間が 16 ビットである)。従って、omathcode の下位 16 ビット(文字コード)が 255 を超える場合(例えば 0x2021306)は e-pTeX にとっては「無意味な値」となってしまうはずである。

しかし実際に試してみた限りでは、そのような「無意味な」値をもつ \omathchardef でエラーが生じることはなく、また定数定義としては想定通りの動作をするようである。

\omathchardef\foo="2021306
\show\foo %==>「\foo=\omathchar"2021306」
\showthe\foo %==>「33690374」(= 0x2021306)

というわけで、この現状の動作を仕様と定めてしまえばいい。すると、「FAM256 適用の e-pTeX では(あるいは e-upTeX を含めてしまってもよく、また『\omathchar がある場合』でもよい)定数定義(\e@alloc@chardef)に \omathchardef を使う」ということで無事に問題を解決できる。

*1:つまり、SJISEUC で符号化した結果の 2 バイトの列を big-endian 16 ビットの整数値として解釈した値。例えば〈亜〉なら SJIS で 0x889F、EUC で 0xB0A1。