圣诞快乐!
我在 TeX 级别遇到了一个奇怪的错误消息,它花了我相当多的时间才解开,因为它实在是太没用了……
这是一个最简单的纯 TeX 示例:
\newbox\tempbox
\hbox{%
\begingroup
\setbox\tempbox=\vbox{foo}
\unvbox\tempbox
\endgroup
}
\bye
输出:
! Missing \endgroup inserted.
<inserted text>
\endgroup
<to be read again>
\unvbox
l.5 \unvbox
\tempbox
! Missing } inserted.
<inserted text>
}
<to be read again>
\unvbox
l.5 \unvbox
\tempbox
! Extra \endgroup.
l.6 \endgroup
! Too many }'s.
l.7 }
它确实有一种扭曲的意义,就像\unvbox
哭喊着“让我离开这里”并插入组关闭命令直到它逃离了水平盒子......
但当然在现实世界中,所有这些都被深埋在宏构造的几个层次中,而调试的主要问题是我完全不记得我是在一个里面\hbox
。
此外,这个疯子插入的结束小组的命令\unvbox
完全搞乱了小组结构,最终整个混乱局面以紧急休息而告终。
在这个 MWE 中,盒子没有通过插入来定义\endgroup
,因此\unvbox
对空盒子进行操作。
一个简单的“你不能在水平盒子中取消垂直盒子;被忽略”将会更有帮助。
这种行为有理由吗?
答案1
在 TeXbook 第 286 页我们发现
某些命令与水平模式不兼容,因为它们本质上是垂直的。当以下命令出现在不受限制的水平模式下时,它们会导致 TeX 结束当前段落:
⟨垂直命令⟩ →
\unvbox
|\unvcopy
|\halign
|\hrule
|
\vskip
|\vfil
|\vfill
|\vss
|\vfilneg
|\end
|\dump
在受限水平模式下,禁止出现 ⟨vertical command⟩,但在常规水平模式下,它会导致 TEX 插入标记平价进入输入;阅读并扩展此内容后平价标记,TeX 将再次看到 ⟨vertical command⟩ 标记。(
\par
将使用控制序列的当前含义;平价可能不再代表 TeX 的\par
原语。)
您会得到与 完全相同的错误\hbox{a\vfil}
。
模块 1062tex.web
可能会有帮助
许多与框制作相关的操作都是由输入中的括号触发的。例如,当用户
\hbox to 100pt{⟨hlist⟩}
在垂直模式下说“ ”时,框大小的信息(100pt,确切地) 被放入保存堆栈,其上方有一个级别边界字,并且当前组←调整后的水平框组;TeX 进入受限水平模式来处理 hlist。右括号最终导致保存堆栈恢复到原来的状态,此时有关框大小的信息(100pt,确切地)再次可用;一个盒子被打包,我们离开受限水平模式,将新盒子附加到封闭模式的当前列表中(在本例中是垂直模式的当前列表),然后进行从盒子中删除的任何垂直调整打包。
读平价如同一个盒装的par
。
那里可能可能是“在受限水平模式中发现垂直命令”之类的错误,补充“缺失}
插入”(在您的例子中,\endgroup
首先还需要提供)。有一类错误消息You can’t use x in y mode
(模块 1049),但它在这里不是很有用,因为无论如何都需要插入适当的标记来结束受限水平模式,而忽略命令\unvbox
将需要进一步处理,并且可能比您在此处找到的错误更多。
现在,由于\unvbox
只有在不受限制的水平模式下才合法,因此您可以将代码修复为
\relax\ifhmode
\ifinner
% possibly issue a warning
\box
\else
\unvbox % will trigger insertion of \par
\fi
\else
\unvbox
\fi
警告应该指出输出可能与预期不符。无需\expandafter
删除\fi
或\else
,因为在\box
或 之后\unvbox
TeX 会扩展标记,直到找到 ⟨number⟩。
答案2
很多问题都归结于 TeX 程序的结构。摘自 tex.web 的 §1064:
我们必须处理括号和类似符号嵌套不正确的错误。有时用户会犯插入多余符号的错误,但有时用户会犯遗漏错误。TeX 无法总是区分两者,因此它会进行猜测并尽量避免陷入循环。
在这种情况下,TeX 的最佳猜测是应该在}
the 之前有一个\unvbox
,因为 the\unvbox
不属于那里。值得记住的是,TeX 主要是用 20 世纪 70 年代的技术编写的,因此存在局限性。
答案3
这种行为有理由吗?
正如其他人所说的,你可以争辩说这是由于 TeX 的年代久远了,但我认为强制结束内部 hmode 从而允许输出垂直列表的行为即使是现在也是相当合理的,尽管它在遇到组的“真正”结尾时经常会导致或多或少的虚假错误。
出现任何错误后,PDF 应该被视为潜在的调试目标,合理的 PDF 输出不是目标。建议的替代回退方法是跳过 unvbox,这将隐藏 PDF 的大部分输出,并且(可能)使查看问题的位置变得更加困难。
这与 TeX 中的其他错误恢复一致。如果您alpha
在 tex 模式下使用,它会强制启动数学模式,并将 a 放在$
前面,尽管这几乎总是会破坏段落的其余部分,因为它没有很好的方法来停止数学模式。它不会删除\alpha
。