考虑以下 MWE,重现以下问题这个问题:
\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage{kotex}
\usepackage{amsmath}
\newtheorem{Cvičení}{Cvičení}
\begin{document}
\tracingmacros2\tracingcommands2
\begin{align*}
a = b
\end{align*}
\end{document}
这里的问题是使用特殊字符作为环境名称\newtheorem
。虽然很快就发现了这一点,但我发现出现的警告和错误有些模糊:
! Missing \endcsname inserted.
<to be read again>
\protect
l.16 \end{align*}
The control sequence marked <to be read again> should
not appear between \csname and \endcsname.
和
! TeX capacity exceeded, sorry [input stack size=5000].
\@spaces ->\space
\space \space \space
l.16 \end{align*}
If you really absolutely need more capacity,
you can ask a wizard to enlarge me.
即使没有使用\begin{Cvičení}
,这些错误也会出现,只有kotex
加载 时才会出现。
我使用\tracing
上面 MWE 中的命令进行了调查,发现日志文件的相关部分是第 5038 行及以下:
\@elt #1->\global \csname c@#1\endcsname \the \csname c@#1\endcsname
#1<-CviÄenÃ
{\csname}
Ä#1->\ifcsname u8:\string Ä\string #1\endcsname \csname u8:\string Ä\string #1\
expandafter \endcsname \else \expandafter \unihangul@two@octets \expandafter Ä\
expandafter #1\fi
#1<-
{\ifcsname}
{\string}
{\string}
{true}
{\csname}
{\string}
{\string}
{\expandafter}
{\else}
\u8:Ä ->\IeC {\v c}
\IeC ->\ifx \protect \@typeset@protect \expandafter \@firstofone \else \noexpan
d \IeC \fi
{\ifx}
{true}
{\expandafter}
{\else}
\@firstofone #1->#1
#1<-\v c
\v ->\T1-cmd \v \T1\v
\T1-cmd #1->\ifx \protect \@typeset@protect \@inmathwarn #1\else \noexpand #1\e
xpandafter \@gobble \fi
#1<-\v
{\ifx}
{true}
\@inmathwarn #1->\ifmmode \@latex@warning {Command \protect #1 invalid in math
mode}\fi
#1<-\v
{\ifmmode}
{true}
\@latex@warning #1->\GenericWarning {\space \space \space \@spaces \@spaces \@s
paces }{LaTeX Warning: #1}
#1<-Command \protect \v invalid in math mode
\GenericWarning ->\csname m@gobble\iffirstchoice@ \else 4\fi \endcsname \protec
t \GenericWarning
{\csname}
{\iftrue}
{true}
{\else}
\m@gobble ->
! Missing \endcsname inserted.
<to be read again>
\protect
l.16 \end{align*}
The control sequence marked <to be read again> should
not appear between \csname and \endcsname.
\GenericWarning #1#2->\begingroup \def \MessageBreak {
#1}\set@display@protect \immediate \write \@unused {
#2\on@line .
}\endgroup
#1<-\space \space \space \@spaces \@spaces \@spaces
#2<-LaTeX Warning: Command \protect \v invalid in math mode
\space ->
\space ->
\space ->
\@spaces ->\space \space \space \space
\space ->
\space ->
\space ->
\space ->
\@spaces ->\space \space \space \space
\space ->
\space ->
\space ->
\space ->
\@spaces ->\space \space \space \space
\space ->
\space ->
\space ->
\space ->
\set@display@protect ->\let \protect \string
{\string}
\v ->\T1-cmd \v \T1\v
我从中得到的信息如下:
环境
align*
导致许多计数器使用进行全局更新\@elt
,包括(在日志文件中\c@Cvičení
显示为)。\c@CviÄenÃ
Ä
是一个主动的角色(这似乎是负责的部分kotex
)并最终导致被\v
扩大。由于
\v
不能在数学模式下使用,LaTeX 会尝试就此发出警告。然后就出错了。
\csname m@gobble\iffirstchoice@ \else 4\fi \endcsname \protect \GenericWarning
导致\m@gobble
扩展为无(尽管它的名字没有吞噬任何东西),但 TeX 似乎仍然想读取\csname
并抱怨\protect
(导致我们看到的警告)。- 尽管同一行代码在接下来的循环中被一次又一次地扩展,但这种情况只会发生一次。
LaTeX 现在继续扩展
\GenericWarning
,并最终尝试将“命令 \v 在数学模式下无效”写入日志文件,本质上是说出来\let\protect\string
然后写入Command \protect \v invalid in math mode
日志文件。根据日志文件 ({string}
),这应该有效,但随后还是\v
被扩展了。这会导致无限循环,直到超出 TeX 的内存容量,导致最终的错误。
所以我的问题是
为什么 4. 中的问题只出现一次,而不是在同一行代码的后续扩展中出现?
为什么
\let\protect\string \protect\v
5.基本执行没有达到预期的效果呢?
答案1
第一个问题:为什么 4. 中的问题只出现一次,而不是在同一行代码的后续扩展中出现?
警告说“缺少插入的 \endcsname。... 标记的控制序列不应出现在 \csname 和 \endcsname 之间。”所以问题是 LaTeX 仍在等待\endcsname
,因为第一个从未到达,但\endcsname
(隐藏在这里的名称下)不允许出现在 csname 中。这不再是问题,因为就像消息所说的那样,TeX 实际上在显示错误之前插入了一个,所以在稍后我们不再处于 csname 中,所以(或)是有效的。\@elt
\relax
\protect
\endcsname
\relax
\protect
第二个问题:为什么\let\protect\string \protect\v
5.基本执行没有起到预期的效果?
为此,您必须进一步查看日志文件:在展开第一个 之前大约 10 行\@elt
,有一行{\xdef}
。因此,我们处于 的\xdef
定义中\@gtempa
。在 的扩展值中\xdef
(或\edef
),允许使用诸如 之类的不可展开命令\let
,但保持原样,不进行评估。
因此,在这种情况下\let\protect\string\protect\v
不会评估\let
或\protect
,但会尝试扩展可扩展命令\string
,\v
从而导致无限递归。