Beim Versuch, Makros in LaTeX zu lernen, stieß ich aufdiese Definition:
\x@protect
ist ein Makro mit einem Argument, dargestellt durch "#1
".\@typeset@protect
ist auch definiert als\relax
und daher wird der erste Zweig von\ifx
ausgeführt, der nichts tut. (\ifx
vergleicht die Bedeutung zweier Makros.) Das einzige Ergebnis von\x@protect
ist also, dass sein Argument, das erste "\\
" in der Definition von\\
, verworfen wird. Übrig bleiben der Befehl \protect, der eine Nicht-Operation ist, und\\
es selbst. Dies scheint eine zirkuläre Definition zu sein. Tatsächlich ist es das nicht. Es ist ein fieser Trick der LaTeX-Autoren, die versuchen, ihre Spuren zu verwischen. Werfen Sie einen zweiten, äußerst misstrauischen Blick auf die Auflistung von\\
. Zwischen dem letzten " " und dem Punkt stehen zwei Leerzeichen\\
, während nach der letzten Steuersequenz in anderen Auflistungen nur eins steht! Tatsächlich steht in allen Auflistungen nur ein Leerzeichen am Ende. Das vorletzte Leerzeichen in der Auflistung von\\
ist Teil des Namens seiner letzten Steuersequenz, die "\\
" ist, einschließlich des Leerzeichens!`
Warum der zirkuläre Verweis?
Warum bricht es nicht ab, wenn ein Zirkelverweis auftritt?
Antwort1
Beginnen wir eine interaktive Sitzung mit pdflatex test
, wo test.tex
ist
\documentclass{article}
\DeclareRobustCommand{\?}{js bibra}
\makeatletter
\show\?
Der \show
Befehl stoppt den Lauf, sodass wir weitere Befehle ausgeben können
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\?
Was passiert, wenn \?
verarbeitet wird? Es gibt zwei Fälle: Wenn \protect
nicht die gleiche Bedeutung hat wie \@typeset@protect
(was ist \relax
), dann wird der falsche Zweig verfolgt. Somit hat der Eingabestrom
\@x@protect\?\fi\protect\?
und die Erweiterung von \@x@protect
entfernt die letzten beiden Token, sodass übrig bleibt \protect\?\fi
(und \fi
schließlich verschwindet).
Dies geschieht beispielsweise in \protected@edef
oder \protected@write
, wenn \protect
eine andere Bedeutung als zugewiesen wird \@typeset@protect
.
Wenn dies der Fall ist, ist die Bedingung wahr, so dass der Eingabestrom nach dem Überspringen des falschen Zweigs Folgendes aufweist:
\protect\?
Jetzt \protect
verschwindet und wirerscheinenan der gleichen Stelle zu sein wie vorher. Aber das sind wir nicht, denn das folgende Token \protect
istandersdavon \?
wurde in das Testdokument eingetragen.
Schauen Sie sich die Ausgabe des ersten \show
Befehls genau an. Wir erhalten
->\x@protect \?\protect \? .
Zwischen ->
und dem abschließenden Punkt stellt TeX den Ersatztext des Makros dar. Die Regeln für diese Darstellung sind, dass auf Steuerwörter ein Leerzeichen folgt, während dies bei Steuersymbolen nicht der Fall ist. Dies erklärt das Leerzeichen nach \x@protect
und \protect
sowie das Fehlen eines Leerzeichens nach \?
. Aber dem abschließenden Punkt geht ein Leerzeichen vorauszweiRäume! Woher kommen sie?
Wenn Sie dies tun \DeclareRobustCommand{\?}{js bibra}
, führt LaTeX mehrere Aktionen aus. Die wichtigste davon ist etwa
\expandafter\def\csname ? \endcsname{js bibra}
und verwenden Sie dann dieses Makro mit einem sehr unüblichen Namen, um die „Benutzerversion“ von zu definieren \?
. Beachten Sie das Leerzeichen vor \endcsname
, das im Makronamen endet.
Es gibt noch ein paar weitere Details, aber die Idee ist, das Schreiben von Hilfsdateien zu erleichtern. In den älteren Versionen von LaTeX sahen wir so etwas wie
\def\LaTeX{\protect\pLaTeX}
\def\pLaTeX{<the real definition>}
Als LaTeX2e veröffentlicht wurde, wurde der bisherige Code
\DeclareRobustCommand{\LaTeX}{<the real definition>}
Nutzung einer neuen Abstraktionsebene. In den älteren Versionen \LaTeX{}
hätte ein Abschnittstitel lauten müssen:
\protect\pLaTeX {}
in den Hilfsdateien. Jetzt schreibt es
\LaTeX {}
wegen des abschließenden Leerzeichens im Namen und in der Regel. Das doppelte Leerzeichen wird beim Einlesen der Hilfsdatei ignoriert.
Bei Steuersymbolen wie \\
oder verhält es sich etwas anders \?
, die Grundidee ist jedoch dieselbe.