マクロツイーター

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

100万回ハローワールドするTeX言語的な方法

とあるプログラミング言語1が超絶アレなためムシャクシャしたので、チョットTeX芸してみた。

[↓お題]

[↓結果🙃]

※上記のプログラムはplain TeX用のものである。texコマンドでコンパイルするとDVIファイル、pdftexコンパイルするとPDFファイルが得られる。以下、この記事で扱うコードはplain TeXを前提とする。

とりあえず

なるべくTeX言語特有の変態な方法を使う

という方向性にこだわってみた。

参考:フツー(?)の方法

なお、元ネタで使っている方針はもちろんTeX言語でも使える。TeX言語チョットデキル人であれば思いつくであろう2

\let\z.\def~{\z}\def\y{\edef~{~~~~~~~~~~}}\y\y\y\y\y\y
\def\z{Hello world!\par}~\bye

TeXを対話モードで使っていて「反復処理を書きたい」という場合に、このパターンを実際に使うことがたまにある。(TeXでループを書くのは面倒なので。)

変態な方法

{\catcode`\m=\active\gdefm{\hbox{Hello world!}$\par$}}
\mathcode`m="8000$\romannumeral1000000000\relax$\bye

ポイントは\romannumeral1000000000である。ローマ数字で“10億”を出力しようとしているが、(TeXの)ローマ数字で最大の数字は“m=1000”なので、結果的にTeXはこのコードをmを100万個並べた文字列に展開する。これでループ的な実行制御なしで“同じトークン100万個”を得ることに成功した🙃

ただしこのmのカテゴリコードは123なので、このままでは“m”以外のテキストを出力するのには使えない。カテゴリコードが12の文字トーク4でマクロを実行させたい……となると、math-acriveを使うことが考えられる。

文字のmath codeを"8000に設定することを“math-active”という5。文字をmath-activeにすると、数式モード中で当該の文字の(カテゴリコードが11または12の)文字トークンが実行されたときに「代わりにその文字のアクティブ(カテゴリコード13)な文字トークンが実行される」という動作になる。標準のplain TeX(やLaTeX)では数式モード中での'の入力でプライム記号(\prime)が上添字として出力されるが、この挙動は'をmath-activeにすることで実現している。

今の場合はmの入力で“Hello world!”を出力させたいので、アクティブなmにマクロを定義した上で\mathcode`\m="8000を設定する。その上で、数式モードに入って\romannumeral1000000000を実行すればよいことになる。ただし数式モードに入るのは飽くまでmath-activeのためで文字列自体は非数式で出力したいなので\hboxを使う。さらに「数式モード中では改段落ができない」のを回避するために「一旦数式モードを終結してから改段落してまた数式モードに入る」という対策をとった。

まとめ

新しいテフライブが無事にリリースできるといいですね😊(まとめろ)


  1. ただしTeX言語以外😲
  2. 先頭の\let\z.は「\zを(一時的に)展開不能にする」ために入れている。1行目を実行した時点で~の意味は「\zを100万個並べたもの」に展開されるマクロになる。
  3. \romannumeralの展開結果は\the文字列なのでこのmのカテゴリコードは11ではなく12である。
  4. e-TeXを前提するなら\scantokensを使うという手段もありそうだが、これは実際にやってみると\scantokensのバッファが100万文字に耐えられずに失敗した。
  5. もしかしたら“math-active”はオレ用語なのかもしれない🙃