読者です 読者をやめる 読者になる 読者になる

もしTeX芸人が遠藤侑介の『あなたの知らない超絶技巧プログラミングの世界』を読んだら

Quine書きますよね。

というわけで、TeXでQuineを書く話。ただし、前例(TeX de Quine!! - 0番染色体)にあるように、dviやpdfに書き出す例は多いみたいなので、私はコンソール出力結果がQuineになるようにしてみた。コードはこちら。

gist.github.com

これをquine.texとし、

max_print_line=10000 etex -no-shell-escape quine.tex

なんていう風に実行すると、そのコンソール出力がソースコードと一致する。これを書くための技法を紹介しよう。

基本的なQuineの書き方

まずは『あなたの知らない超絶技巧プログラミングの世界』(Amazon.co.jp: あなたの知らない超絶技巧プログラミングの世界: 遠藤 侑介: 本)を読もう。その第3章の技術を使っただけである。なお、その技術をTeXで再現するに際し、e-TeX拡張の\unexpandedを用いて展開制御している*1

TeXでやるにあたっての工夫

TeXのコンソール出力は使いづらいことで有名である[要出典]。まず、バージョン情報や読み込んだファイル、実行結果のサイズなどを勝手に出力する。しかも抑制できない。また、長い文字列を出そうとすると勝手に改行する。これらを解決する必要があった。

ユーザの意図しない出力への対応

まずは、ユーザの意図しない出力への対応である。今回のQuineではdviやpdf側の出力は一切気にする必要がないので,どんな文字列が出力されようが問題ないだろう,と思う読者もいるかもしれない.しかし,それは大きな間違いである.etexを起動したときの文字列を見てもらいたい.

$ etex
This is pdfTeX, Version 3.14159265-2.6-1.40.15 (TeX Live 2014/W32TeX) (preloaded format=etex)
 restricted \write18 enabled.
**

TeXエンジンのバージョン情報などとともに,restricted \write18が有効になっている旨の出力がある.この「\write18」という文字列がQuineでは邪魔になる.そのままソースコードにこれを書くとエラーになるためである.これを回避するために,いささか邪道ではあるが-no-shell-escapeオプションをつけて回避した.\write18さえ禁止してしまえば,出力は

$ etex -no-shell-escape
This is pdfTeX, Version 3.14159265-2.6-1.40.15 (TeX Live 2014/W32TeX) (preloaded format=etex)

となり,無害な出力が得られる.なお,この出力を見てもらえばわかるが,TeXエンジンの情報が入るので,Quineのソースコードは実行するTeXエンジンに(バージョンなども含めて)依存する.

長い出力の強制改行対策

この問題を認識してもらうために,次のコードを考える.

\message{wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww}\bye

これをsample.texとして実行してみる.

$ etex sample
This is pdfTeX, Version 3.14159265-2.6-1.40.15 (TeX Live 2014/W32TeX) (preloaded format=etex)
 restricted \write18 enabled.
entering extended mode
(./sample.tex
wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
wwwwwwwwwwwwwwwww )
No pages of output.
Transcript written on sample.log.

なぜか改行される.これは,このツイート


にあるように,TeXの設定ファイルで規定されるものらしい.TeX側からこれを変更するのはつらい.そこで,その設定自体は環境変数を使えば動的に書き換えられることを利用し,これも邪道ではあるが,max_print_line=10000と環境変数を設定して実行することにより,これを回避した.

まとめ

TeXのコンソール出力は扱いづらい.

*1:別に使わなくてもできる