マクロツイーター

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

TeX プログラムのデバッグで絶望する前に知るべきこと (2)

前回の続き)
その他のデバッグ用のモノ

tracingナントカ や showナントカ 以外にも、次のようなものがデバッグ用機能として用意されている。(☆ 印は e-TeX 拡張で追加されたもの。)

  • \errorcontextlines 〔整数パラメタ〕: エラーや showナントカ で実行停止した際に表示される実行コンテキストの“量”。LaTeX での初期値は −1 であり、この場合は最低限、すなわちマクロ呼出スタックの最上段と最下段のみの表示になる。このパラメタの値を n(≧ 0)にすると、その途中のレベルのコンテキストが、上から n 段を限度にして表示され、それより多くのレベルがあった場合は ... で省略があったことが示される。((つまり 0 と −1 の違いは省略の ... の表示の有無。))
  • \currentgrouplevel 〔整数パラメタ・読取専用〕☆: 現在のグルーピングのネストのレベル。
  • \currentgrouptype 〔整数パラメタ・読取専用〕☆: 最内のグルーピングの種別。定数の意味は e-TeX のマニュアルを参照されたい。
  • \currentiflevel 〔整数パラメタ・読取専用〕☆: 現在の条件分岐のネストのレベル。
  • \currentiftype 〔整数パラメタ・読取専用〕☆: 最内の条件分岐の種別。定数の意味は e-TeX のマニュアルを参照されたい。
  • \currentifbranch 〔整数パラメタ・読取専用〕☆: 最内の条件分岐の結果。1 = 真、−1 = 偽、0 = 未決。
print デバッグするためのモノ

他のプログラム言語と同じく、いわゆる「print デバッグ」、すなわち「臨時に現在の変数等の内容を端末やログに出力させる」という手段はデバッグの際によく用いられる。端末やログに出力するには以下の命令が利用できる。

  • \message{トークン列〉} : 端末とログに“メッセージ形式で”出力する。
  • \immediate\write16{トークン列〉} : 端末とログに出力する。
  • \immediate\write-1{トークン列〉} : ログにのみ出力する。
  • \wlog{トークン列〉} 〔plain TeX のマクロ〕: ログにのみ出力する。(前項と同じ((\wlog は単に \immediate\write\m@ne に展開されるマクロである。)))
  • \typeout{トークン列〉}LaTeX の命令〕: LaTeX 保護付で端末とログにのみ出力する。

このうち、\message は「ユーザへの処理メッセージを出力する」ための専用の命令で、前後に改行を伴わずに((TeX がページを DVI ファイルに送出した際に出る [1] やファイルを読み込んだ時に出る (./foo.sty) のようなメッセージと同じ様式になる。))出力が行われる。残りのものは TeX の入出力機能を利用していて、こちらは独立した行として*1出力される。((ちなみに、\write の後の整数値はストリーム番号であり、0〜15 が普通のファイル、18 がアレ、それ以外の正値が「端末とログ」、負値が「ログのみ」を表す。))

注意すべき点として、引数のトークン列には完全展開(\edef と同じもの)が適用される(その後で“文字列化”される)。従って、完全展開可能でないものが入っていると予期せぬ事態が起こりうる。入力のトークン列を展開せずに(文字列化して)出力するには、\noexpand\unexpanded を適宜使う必要がある。ただし、\typeout に関しては“LaTeX 式の保護”が有効になるので、保護(\protect)が付いたマクロ((あるいは、最初から保護付で定義(\DeclareRobustCommand)されたマクロ。))は展開が抑止される。

逆に、引数のトークン列は展開されるので、例えばマクロを“文字列変数”のように使っている場合は、それを引数に入れると、その“現在の値”を出力することができる。その他のタイプの“変数”の値を調べるには、以下に挙げるようなプリミティブ命令(何れも展開可能)を利用すればよい。

  • \the〈内部値〉 : その内部値(パラメタ、レジスタ)の現在の値を表す \the-文字列。
  • \theトークン列レジスタ〉 : そのレジスタの現在の内容のトークン列。
  • \meaningトークン〉 : そのトークンの意味を説明した \the-文字列。
    ※例えば \meaning$ は「math shift character $」、\meaning\@firstoftwo は「\long macro:#1#2->#1」に展開される。
  • \noexpandトークン〉 : 引数のトークンそのもの(展開抑止)。
  • \unexpanded{トークン列〉} ☆: 引数のトークン列そのもの(展開抑止)。
  • \stringトークン〉 : トークンを“文字列化”した結果の \the-文字列。
    ※制御語(英字の制御綴)を文字列化する場合、\string は他と異なり区切りの空白を入れない。((例えば「\detokenize{\foo!}」は「\foo !」に展開されるが、「\string\foo!」は「\foo!」となる。))
  • \detokenize{〈トークン列〉} ☆: 引数のトークン列を“文字列化”した結果の \the-文字列。

これらのプリミティブの展開結果は「\the-文字列((「\the-文字列」というのは、粗く言うと「ほとんど単なる“文字列”と見做してよいトークン列」のこと。厳密にいうと、ある文字列に対して、「各文字をそれ対するカテゴリコード 12(但し空白文字は例外的にカテゴリモード 10)の文字トークンで表したもの(トークン列)」が \the-文字列である。TeX では構文解析のレベルでは「トークン列」しか扱えないので、「単なる文字列を返す関数」の働きをするプリミティブは、実際には、\the-文字列に展開されるという形で実装される。))」のものと「一般のトークン列」のものがあるが、\write\message が出力するものは当然「文字列」なので、結局最後に“文字列化”が行われている。((従って、\write 等の中で使う分には \unexpanded\detokenize は等価である。\noexpand\string は「区切りの空白」の有無が異なるので等価ではない。))

*1:前は行の途中であれば改行する。後ろは無条件に改行する。