在嘗試學習 LaTeX 中的巨集時,我遇到了這個定義:
\x@protect
是一個帶有一個參數的宏,用「#1
」表示。\@typeset@protect
也被定義為\relax
,因此執行第一個分支\ifx
,它不執行任何操作。 (\ifx
比較兩個巨集的意義。)因此 的唯一結果是它的參數,即 定義中的\x@protect
第一個「 」被丟棄。這留下了命令 \protect (這是一個無操作)及其本身。這似乎是一個循環定義。事實上,事實並非如此。這是 LaTeX 作者試圖掩蓋自己蹤跡的卑鄙伎倆。再仔細看看 的列表,非常可疑。最後一個「 」和句點之間有兩個空格,而其他清單中最後一個控制序列之後只有一個!事實上,所有清單中只有一個尾隨空格。清單中的最後一個空格是其最後一個控制序列名稱的一部分,即“ ”,包括空格!\\
\\
\\
\\
\\
\\
\\
為什麼要循環引用?
為什麼遇到循環引用時它不會崩潰?
答案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\?
\?
處理時會發生什麼事?有兩種情況:如果與(which is )\protect
的意思不同,則遵循錯誤分支。因此輸入流將有\@typeset@protect
\relax
\@x@protect\?\fi\protect\?
的擴展\@x@protect
將刪除最後兩個標記,留下\protect\?\fi
(並\fi
最終消失)。
例如,當被賦予與 不同的意義時,\protected@edef
就會發生這種情況。\protected@write
\protect
\@typeset@protect
如果有,則條件為 true,因此輸入流在跳過 false 分支後將具有:
\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 {}
因為名稱和規則中的尾隨空格。讀入輔助檔案時,雙倍空格將被忽略。
\\
對於諸如或 之類的控制符號來說,它略有不同\?
,但總體思路是相同的。