LaTeX マクロの循環参照

LaTeX マクロの循環参照

LaTeXのマクロを学ぼうとしていたときに、この定義:

\x@protectは、" " で表される 1 つの引数を持つマクロです#1\@typeset@protectは としても定義される\relaxため、 の最初の分岐\ifxが実行され、何も行われません。 ( は\ifx2 つのマクロの意味を比較します。) したがって、 の唯一の結果は、の定義の\x@protect最初の " " である引数が破棄されることです。これにより、何も実行されないコマンド \protect と自体が残ります。これは循環定義のように見えます。実際はそうではありません。これは、LaTeX の作者が痕跡を隠そうとする卑劣なトリックです。 のリストをもう一度、非常に疑わしい目で見てください。最後の " " とピリオドの間には 2 つのスペースがありますが、他のリストの最後の制御シーケンスの後には 1 つしかありません。実際、すべてのリストで末尾のスペースは 1 つだけです。 のリストの最後から 2 番目のスペースは、スペースを含めて最後の制御シーケンスの名前の一部であり、" " です。`\\\\\\\\\\\\\\

なぜ循環参照なのでしょうか?

循環参照に遭遇してもなぜエラーにならないのでしょうか?

答え1

との対話型セッションを始めましょうpdflatex testtest.tex

\documentclass{article}

\DeclareRobustCommand{\?}{js bibra}

\makeatletter

\show\?

この\showコマンドは実行を停止し、さらにコマンドを発行できるようになります。

This is pdfTeX, Version 3.14159265-2.6-1.40.20 (TeX Live 2019) (preloaded format=pdflatex)
 restricted \write18 enabled.
entering extended mode
(./test.tex
LaTeX2e <2019-10-01> patch level 3
(/usr/local/texlive/2019/texmf-dist/tex/latex/base/article.cls
Document Class: article 2019/10/25 v1.4k Standard LaTeX document class
(/usr/local/texlive/2019/texmf-dist/tex/latex/base/size10.clo))
> \?=macro:
->\x@protect \?\protect \?  .
l.7 \show\?

? i\show\x@protect
> \x@protect=macro:
#1->\ifx \protect \@typeset@protect \else \@x@protect #1\fi .
<insert>   \show\x@protect

l.7 \show\?

? i\show\@x@protect
> \@x@protect=macro:
#1\fi #2#3->\fi \protect #1.
<insert>   \show\@x@protect

l.7 \show\?

が処理されると何が起こるでしょうか\??2つのケースがあります。 が( )\protectと同じ意味を持たない場合、偽の分岐が続きます。したがって、入力ストリームは\@typeset@protect\relax

\@x@protect\?\fi\protect\?

の展開により、\@x@protect最後の 2 つのトークンが削除され、\protect\?\fi(そして\fi最終的には消えます) が残ります。

これは、たとえば\protected@edefまたは で\protected@write\protectに とは異なる意味が割り当てられている場合に発生します\@typeset@protect

もしそうなら、条件は真なので、入力ストリームは偽の分岐をスキップした後、

\protect\?

今は\protect消えて私たちは思われる以前と同じ場所にいるはずだった。しかし、次のトークン\protect違うそこから\?テスト文書に入力されました。

最初のコマンドの出力をよく見てください\show

->\x@protect \?\protect \?  .

と末尾のピリオドの間に->、TeX はマクロの置換テキストを表します。この表現のルールは、制御語の後にはスペースが続くのに対し、制御記号の後にはスペースが続かないというものです。これは、 と の後にスペースがあり\x@protect\protectの後にスペースがないことを説明しています\?。しかし、末尾のピリオドの前にはスペース!どこから来るのでしょうか?

すると\DeclareRobustCommand{\?}{js bibra}、LaTeXはいくつかのことを行いますが、主なものは次のとおりです。

\expandafter\def\csname ? \endcsname{js bibra}

そして、このマクロを非常に非標準的な名前で使用して、 の「ユーザー レベル バージョン」を定義します\?。 の前のスペースが\endcsnameマクロ名になっていることに注意してください。

詳細は他にもありますが、補助ファイルの書き方を簡単にするというのが目的です。LaTeXの古いバージョンでは、次のようなものがありました。

\def\LaTeX{\protect\pLaTeX}
\def\pLaTeX{<the real definition>}

LaTeX2eがリリースされると、以前のコードは

\DeclareRobustCommand{\LaTeX}{<the real definition>}

新しい抽象化レベルを活用する。以前のバージョンでは、\LaTeX{}セクションのタイトルに次のように書かれていた。

\protect\pLaTeX {}

補助ファイルに書き込む。

\LaTeX  {}

名前とルールの末尾にスペースがあるためです。補助ファイルが読み込まれるとき、二重スペースは無視されます。

\\またはなどの制御記号の場合は若干異なります\?が、基本的な考え方は同じです。

関連情報