LaTeXのマクロを学ぼうとしていたときに、この定義:
\x@protect
は、" " で表される 1 つの引数を持つマクロです#1
。\@typeset@protect
は としても定義される\relax
ため、 の最初の分岐\ifx
が実行され、何も行われません。 ( は\ifx
2 つのマクロの意味を比較します。) したがって、 の唯一の結果は、の定義の\x@protect
最初の " " である引数が破棄されることです。これにより、何も実行されないコマンド \protect と自体が残ります。これは循環定義のように見えます。実際はそうではありません。これは、LaTeX の作者が痕跡を隠そうとする卑劣なトリックです。 のリストをもう一度、非常に疑わしい目で見てください。最後の " " とピリオドの間には 2 つのスペースがありますが、他のリストの最後の制御シーケンスの後には 1 つしかありません。実際、すべてのリストで末尾のスペースは 1 つだけです。 のリストの最後から 2 番目のスペースは、スペースを含めて最後の制御シーケンスの名前の一部であり、" " です。`\\
\\
\\
\\
\\
\\
\\
なぜ循環参照なのでしょうか?
循環参照に遭遇してもなぜエラーにならないのでしょうか?
答え1
との対話型セッションを始めましょうpdflatex test
。test.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 {}
名前とルールの末尾にスペースがあるためです。補助ファイルが読み込まれるとき、二重スペースは無視されます。
\\
またはなどの制御記号の場合は若干異なります\?
が、基本的な考え方は同じです。