マクロツイーター

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

LaTeX でのレジスタ割当の話(1)

「LaTeX が新しくなった話」の記事を書くにあたって調べた、LaTeX(というか TeX on LaTeX)のレジスタ割当の実装についての情報をまとめておく。

レジスタ割当の命令

2014 年以前の LaTeX カーネルにおけるレジスタ割当のルーチンは、plain TeX のそれをほぼ継承したものである。新たにレジスタを確保したい場合には、\newナントカ という命令を用いる。

  • \newcount\XXX\newdimen\XXX\newskip\XXX\newmuskip\XXX\newtoks\XXX: これらの場合、\XXX は割り当てられたレジスタ自体を指す。
  • \newbox\XXX\newread\XXX\newwrite\XXX\newfam\XXX((LaTeX では \newfam\new@mathgroup という別名を与えてカーネルではそちらを使っている。何れにしても、パッケージレベルのコードで数式フォントを扱う場合は NFSS の命令を利用するので、直接 \newfam を使うことはない。))/\newlanguage\XXX\newinsert\XXX: これらの場合、\XXX は割り当てられたレジスタ*1の番号を表す定数を指す。
  • \allocationnumber [整数パラメタ]: 直前の \nweナントカ で割り当てられたレジスタの番号。

TeX エンジンは決まった個数(種別により 256 個または 16 個)のレジスタを持っていて、各レジスタは(0 から始まる整数の)番号で区別される。基本的に、割当ルーチンはこの中の“特定の番号範囲”(例えば toks の場合は 10〜255)にあるレジスタ群を“割当用”に予約している。“割当用”のレジスタは番号の昇順に使用され、例えば \newcount\XXX が実行されると、“割当用”の中で未使用の最小番号のレジスタ\XXX への割当に使われる。もし最後まで使い切っていた場合は、「レジスタ不足エラー」“No room for \count”が発生する。

レジスタ割当命令の中で、\newinsert は少し特殊である。*2insert は TeX 言語の文法要素ではなく、LaTeX(および plain TeX)のコード“実装”された概念である。単一の insert は「番号が同じ count、dimen、skip、box の 4 種のレジスタのセット」で構成される必要がある。このため、割当ルーチンでは、この 4 種のレジスタについて、insert 専用の割当領域を用意している。

カーネルでの追加機能

e-TeX 拡張などの拡張エンジンでは、一部種別のレジスタの数が「たくさん」(32768 個または 65536 個)に拡張されており、2015 年以降の LaTeX ではこの“拡張部分(256 番以降)”のレジスタも割当の対象となっている。開発者レベルの公開命令の仕様の互換性は保たれているので、特にこの件に関して対処する必要はない。((ただし、新しい割当ルーチンでは、“割当用”の領域が“基本領域(255 番以下)”と“拡張領域(256 番以上)”に分断して存在することになるので、\newナントカ で割り当てられるレジスタの番号が必ずしも 1 ずつ増加するとは限らないことになる(“基本”から“拡張”に移行する際に番号が飛んでしまう)。従って、「1 ずつ増加する」動作に依存するコードを書いていた場合は、新しいカーネルに対応させる改修が必要である。))

レジスタの割当に関連して、次のユーザ命令*3が追加されている。

  • \extrafloats{<整数>} [命令]: 未処理の浮動体の個数の許容上限を指定の数だけ増加させる。

LaTeX の文書中に記述された浮動体(フロート)は、それが実際に出力される((つまり出力(\shipout)されたページの一部になる。))までは一種の insert として保持されている。浮動体が現れるごとに insert を通常通り“割当”すると、実際に出力された後にそれが無駄になってしまう*4従って、浮動体の処理では、予め一定数(18 個)の insert を“浮動体用”に確保してそれを使い回している。従って、未処理の浮動体があまりに多くなるとこの在庫が枯渇してエラーが発生する。*5

\extrafloats 命令を実行すると、指定した個数の insert を“浮動体用”に新たに確保する。これにより、多数の未出力の浮動体が発生する場合でも処理を続行することが可能になる。

(続くはず)

*1:ここでは read、write、fam、language も「レジスタ」と呼ぶことにする。

*2:「インサート(insert)」というのは、「出力ルーチン中で版面に後から挿入されるボックス」(例えば脚注や浮動体など)を記憶するオブジェクトのこと。

*3:開発者レベルでなくて文書作成者レベル。

*4:割当ルーチンには「解放」する機能はないので。

*5:不足したらその場で新たに割り当てて補充すればよいような気もする。しかし、そもそも未処理の浮動体が多く残っているという時点で浮動体の配置ロジックが破綻してしまっている可能性が高い。なので無理に処理を続けるよりエラーにしてユーザに善処を求める方が合理的だと考えられたのかも知れない。