LaTeX 宏中的循环引用

LaTeX 宏中的循环引用

在尝试学习 LaTeX 中的宏时,我遇到了这个定义

\x@protect是一个带有一个参数的宏,用“ ”表示#1\@typeset@protect也被定义为\relax,因此\ifx执行 的第一个分支,它不执行任何操作。 (\ifx比较两个宏的含义。)所以 的唯一结果是它的参数,即 的定义中的\x@protect第一个“ ”被丢弃。 这样就剩下命令 \protect(一个无操作)和它自己。 这似乎是一个循环定义。 事实上,它不是。 这是 LaTeX 作者试图掩盖其踪迹的卑鄙伎俩。 再仔细看看 的列表,非常可疑。 最后一个“ ”和句点之间有两个空格,而其他列表中的最后一个控制序列后只有一个! 事实上,所有列表中只有一个尾随空格。 列表中的倒数第二个空格是其最后一个控制序列名称的一部分,即“ ”,包括空格!`\\\\\\\\\\\\\\

为什么会出现循环引用?

为什么遇到循环引用它不会崩溃?

答案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\?

\?处理时会发生什么?有两种情况:如果与(即)\protect的含义不同,则遵循错误分支。因此输入流将具有\@typeset@protect\relax

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

而的扩展\@x@protect将删除最后两个标记,剩下\protect\?\fi(并\fi最终消失)。

例如,在\protected@edef或中\protected@write,当\protect被赋予与 不同的含义时,就会发生这种情况\@typeset@protect

如果有,则条件为真,因此输入流在跳过错误分支后将具有,

\protect\?

现在\protect消失了,我们似乎和之前一样。但事实并非如此,因为后面跟着一个\protecttoken不同的\?测试文档中输入。

仔细查看第一个命令的输出\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  {}

因为名称和规则中的尾随空格。读入辅助文件时将忽略双倍空格。

\\对于控制符号(例如或 )稍有不同\?,但总体思路是相同的。

相关内容