`\unrestored@protected@xdef` 的功能?

`\unrestored@protected@xdef` 的功能?

     所以,我正在读texdoc tamethebeast驯服 BeaST:BibTeX 的 B 到 X) 时,我偶然发现了一个我从未见过的宏,它讨论了的实现\thebibliography;这就是宏\@mkboth这个答案针对这个问题“\@mkboth 和 \markboth 起什么作用?”解释了它的作用,但后来我发现其他宏内命令的定义,我已经从未见过;宏是\unrestored@protected@xdef。无论是LaTeX2e 非官方参考手册(2017 年 8 月)也不此网页列表记录TeX 基本控制序列包含任何关于其功能的提及。这让我想知道它的作用是什么,所以有人能回答这个问题和/或给我指出一个参考资料吗?解释一下它是如何工作的?

答案1

该命令是关于使用扩展定义宏的。TeX 原语\edef定义一个宏\def,但它会扩展定义文本。例如:

\def\Who{World}
\edef\Hello{Hello \Who}

该宏\Who被展开,并且的定义文本\HelloHello World

\xdef只是\edef\xdef=的全局变体\global\edef

\edef在许多情况下,如果扩展了脆弱的宏,则或的硬扩展\xdef将失败。例如,以下宏不健壮:

\def\FragileMacro{%
  \def\MyMacro{...}%
  ...
}

如果在或\FragileMacro中使用,则不是可扩展标记,只是保留而不进行进一步处理,即它不定义任何内容。然后尝试扩展 。如果它未定义,则会抛出由于命令未定义而导致的错误消息。或者,它会扩展为一些非活动字符。然后,稍后的 执行将失败,因为无法定义非活动字符。\edef\xdef\def\MyMacro\FragileMacro\def

LaTeX 的方式是保护:

  • \protect在脆弱的宏阻止其扩展之前。
  • 可以通过 定义宏为健壮命令\DeclareRobustCommand。它会偷偷地\protect将包含可能脆弱的命令文本的内部宏放进去。

有几个有问题的上下文,例如在 .log 文件/控制台中显示某些内容、写入文件,或者在这种情况下扩展\edef\xdef。 的正确定义取决于这些上下文。在或 的\protect情况下,它是:\edef\xdef\@unexpandable@protect

\def\@unexpandable@protect{\noexpand\protect\noexpand}

然后

\let\protect\@unexpandable@protect
\edef\FooBar{\protect\FragileCommand}

在第一次扩展\protect

\edef\FooBar{\noexpand\protect\noexpand\FragileCommand}

\noexpand阻止下一个标记的扩展,并且定义相当于

\def\FooBar{\protect\FragileCommand}

\protect被保留并\FragileCommand阻止其扩展。

内部 LaTeX 宏\@protected@edef\@protected@xdef是纯 TeX\edef和的LaTeX 对应项\xdef

\def\protected@edef{%
   \let\@@protect\protect
   \let\protect\@unexpandable@protect
   \afterassignment\restore@protect
   \edef
}
\def\protected@xdef{%
   \let\@@protect\protect
   \let\protect\@unexpandable@protect
   \afterassignment\restore@protect
   \xdef
}

首先\@@protect获取 的当前含义\protect。然后\protect根据上下文重新定义(扩展定义)。\protect获取 的含义\@unexpandable@protect。 的重新定义\protect由 恢复\afterassignment。它\restore@protect在下一个赋值\edef或之后立即调用\xdef。使用先前定义的\restore@protect恢复 的定义:\protect\@@protect

\def\restore@protect{\let\protect\@@protect}

该版本\unrestored@protected@xdef是的优化版本\@protected@edef,仍然重新定义\protect,但省略了的恢复\protect

\def\unrestored@protected@xdef{%
   \let\protect\@unexpandable@protect
   \xdef
}

宏定义更小更快,避免了宏扩展和两次赋值。但是,它只能在特殊情况下使用,通常在组的末尾:

\begingroup
  ...
  \@unrestored@protected@xdef\FooBar{\protect\FragileMacro}%
\endgroup

在组结束时,任何本地更改(此处为 的重新定义)都会被恢复。无需\protect显式恢复。\protect

典型用例latex.ltx

\def\@xfootnote[#1]{%
   \begingroup
     \csname c@\@mpfn\endcsname #1\relax
     \unrestored@protected@xdef\@thefnmark{\thempfn}%
   \endgroup
   \@footnotemark\@footnotetext
}
\def\@xfootnotemark[#1]{%
   \begingroup
      \c@footnote #1\relax
      \unrestored@protected@xdef\@thefnmark{\thefootnote}%
   \endgroup
   \@footnotemark
}
\def\@xfootnotenext[#1]{%
  \begingroup
     \csname c@\@mpfn\endcsname #1\relax
     \unrestored@protected@xdef\@thefnmark{\thempfn}%
  \endgroup
  \@footnotetext
}

该小组还出现在\markboth

\def\markboth#1#2{%
  \begingroup
    \let\label\relax \let\index\relax \let\glossary\relax
    \unrestored@protected@xdef\@themark {{#1}{#2}}%
    \@temptokena \expandafter{\@themark}%
    \mark{\the\@temptokena}%
  \endgroup
  \if@nobreak\ifvmode\nobreak\fi\fi
}

该小组似乎缺少以下内容\@markright

\def\@markright#1#2#3{\@temptokena {#1}%
  \unrestored@protected@xdef\@themark{{\the\@temptokena}{#3}}%
}

但是\@markright它本身在一个组内被调用:

\def\markright#1{%
  \begingroup
    \let\label\relax \let\index\relax \let\glossary\relax
    \expandafter\@markright\@themark {#1}%
    \@temptokena \expandafter{\@themark}%
    \mark{\the\@temptokena}%
  \endgroup
  \if@nobreak\ifvmode\nobreak\fi\fi
}

\@themark在定义 之后\@markright,需要将标记寄存器的新内容添加到\mark。但是,\mark再次扩展参数(\@themark已经被 扩展)。因此,使用\@unrestored@protected@xdef临时令牌寄存器作为技巧。在令牌寄存器仅扩展令牌寄存器一次之前,内容不会进一步扩展。\@temptokena\the

相关内容