在 `\hbox` 中取消装箱时出现奇怪的错误

在 `\hbox` 中取消装箱时出现奇怪的错误

圣诞快乐!

我在 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或 之后\unvboxTeX 会扩展标记,直到找到 ⟨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

相关内容