考虑以下 MWE:
\documentclass{memoir}
%% Create 123 box registers
\newcount\X
\X=1
\loop
\expandafter\newbox\csname mybox\the\X\endcsname
\advance \X by 1
\ifnum \X<124
\repeat
%% Create a box register and globally store ans empty hbox
\newcommand{\storebox}{%
\advance \X by 1
\expandafter\newbox\csname tempbox\the\X\endcsname
\expandafter\global\expandafter\setbox\csname tempbox\the\X\endcsname\hbox{}
}%
\begin{document}
%% Call \storebox 11 times in a group a total of 5 times
\begingroup
\storebox\storebox\storebox\storebox\storebox\storebox\storebox\storebox\storebox\storebox\storebox
\endgroup
\begingroup
\storebox\storebox\storebox\storebox\storebox\storebox\storebox\storebox\storebox\storebox\storebox
\endgroup
\begingroup
\storebox\storebox\storebox\storebox\storebox\storebox\storebox\storebox\storebox\storebox\storebox
\endgroup
\begingroup
\storebox\storebox\storebox\storebox\storebox\storebox\storebox\storebox\storebox\storebox\storebox
\endgroup
\begingroup
\storebox\storebox\storebox\storebox\storebox\storebox\storebox\storebox\storebox\storebox\storebox
\endgroup
%% Some text so the document isn't empty if it compiles
foo
\end{document}
使用当前的 TeX Live 2015 进行编译pdflatex
会lualatex
产生以下错误消息:
! Incompatible list can't be unboxed.
\sidecontents ... \z@ {\m@mwhich@margin {\m@msidebar@margin }\ifmemtortm \m@sideb@right \else \m@sideb@left \fi \vtop to0pt{\normalsize \normalfont \sidebarfont \vskip \topskip \vskip -\ht \strutbox \vskip \sidebartopsep \unvbox \sideins
\vss }\hss }
上述示例是更大(也更实用)的文档的简化版本,并且极其对变化很敏感。因此,例如,\newbox
在前导码中总共调用 122 或 124 次而不是 123 次可以消除错误。
查看日志,盒子寄存器在 195 左右表现异常,如下所示:
\tempbox132=\box192
\tempbox133=\box193
\tempbox134=\box194
\tempbox135=\box256
\tempbox125=\box196
\tempbox126=\box197
\tempbox127=\box198
\tempbox128=\box199
\tempbox129=\box200
\tempbox130=\box201
\tempbox131=\box202
\tempbox132=\box203
\tempbox133=\box204
\tempbox134=\box205
\tempbox135=\box206
! Incompatible list can't be unboxed.
\sidecontents ... \z@ {\m@mwhich@margin {\m@msidebar@margin }\ifmemtortm \m@sideb@right \else \m@sideb@left \fi \vtop to0pt{\normalsize \normalfont \sidebarfont \vskip \topskip \vskip -\ht \strutbox \vskip \sidebartopsep \unvbox \sideins
\vss }\hss }
我第一次注意到这个问题是在最近更新 LaTeX 内核(2015/10/01)之后,加载\usepackage[2015/01/01]{latexrelease}
生产文档确实允许原始文档进行编译。但是,上面的 MWE 显示内核更新与此无关,因为添加包latexrelease
没有效果。
那么,本例中此错误的根本原因是什么?我如何才能在类似情况下正确防止此错误发生?显然,我们可以通过对文档进行几乎任何更改来轻松消除错误,但这在原始生产文档上实际上并不是一个选项。
答案1
抱歉,这是 latex 的一个错误,在本地组中使用 是一种不好的做法\new...
,但如果你这样做,行为不应该那么糟糕,这增加了两个\global
,让事情回到正轨。我想我们会推出一个补丁版本。
\documentclass{memoir}
\makeatletter
\gdef\e@ch@ck#1#2#3#4{%
\ifnum#1<#2\else
\ifnum#1=#2\relax
\global#1\@cclvi
\ifx\count#4\global\advance#1 10 \fi
\fi
\ifnum#1<#3\relax
\else
\errmessage{No room for a new \string#4}%
\fi
\fi}%
\makeatother
%% Create 123 box registers
\newcount\X
\X=1
\loop
\expandafter\newbox\csname mybox\the\X\endcsname
\advance \X by 1
\ifnum \X<124
\repeat
%% Create a box register and globally store ans empty hbox
\newcommand{\storebox}{%
\advance \X by 1
\expandafter\newbox\csname tempbox\the\X\endcsname
\expandafter\global\expandafter\setbox\csname tempbox\the\X\endcsname\hbox{}
}%
\begin{document}
%% Call \storebox 11 times in a group a total of 5 times
\begingroup
\storebox\storebox\storebox\storebox\storebox\storebox\storebox\storebox\storebox\storebox\storebox
\endgroup
\begingroup
\storebox\storebox\storebox\storebox\storebox\storebox\storebox\storebox\storebox\storebox\storebox
\endgroup
\begingroup
\storebox\storebox\storebox\storebox\storebox\storebox\storebox\storebox\storebox\storebox\storebox
\endgroup
\begingroup
\storebox\storebox\storebox\storebox\storebox\storebox\storebox\storebox\storebox\storebox\storebox
\endgroup
\begingroup
\storebox\storebox\storebox\storebox\storebox\storebox\storebox\storebox\storebox\storebox\storebox
\endgroup
%% Some text so the document isn't empty if it compiles
foo
\end{document}
答案2
这似乎是由于更新回忆录。
我认为解决此问题的正确方法可能是使用\locbox
代替\newbox
,尽管我并不完全确定。如果我加载elocalloc.sty
并使用 ,\locbox
如下所示:
\documentclass{memoir}
\usepackage{elocalloc}
%% Create 123 box registers
\newcount\X
\X=1
\loop
\expandafter\locbox\csname mybox\the\X\endcsname
\advance \X by 1
\ifnum \X<124
\repeat
%% Create a box register and globally store ans empty hbox
\newcommand{\storebox}{%
\advance \X by 1
\expandafter\newbox\csname tempbox\the\X\endcsname
\expandafter\global\expandafter\setbox\csname tempbox\the\X\endcsname\hbox{}
}%
那么一切都会好起来。这不像什么约瑟夫·赖特的代码,但这个答案给了我这个想法。
希望您在此处序言中放置的代码实际上位于包或类中,可以对其进行更改而无需更改原始文档。
如果没有,如果您不能轻易改变现有文档的序言,以下内容可能会有用。
旧法典的汇编
有两个选择。
选项1
要在不更改代码的情况下编译原始文档,您可以使用存档副本回忆录并将包文件放在 TeX 首先能找到的地方。
我从工作目录创建了到包文件的符号链接,这可能是 GNU/Linux 或 OS X 上最简单的选项。
对于 Windows,您可以自行处理,但我相信它不能正确理解符号链接。在最坏的情况下,您只需将包文件复制到工作目录即可。
您应该有以下文件/链接:
mem10.clo mem12.clo mem17.clo mem25.clo mem36.clo mem60.clo memhfixc.sty mempatch.sty
mem11.clo mem14.clo mem20.clo mem30.clo mem48.clo mem9.clo memoir.cls
严格来说,有些可能不是必需的,但除非绝对必要,否则我不会冒险混合不同版本软件包中的文件。(目前,只有文件.cls
不同,但更新自然会改变这一点,因此对于给定文档的编译,我会坚持使用全部存档或全部当前版本。)
选项 2
如果您可以在文档中添加一行(在文件中*.tex
或命令行中),那么添加
\RequirePackage{etex}
before\documentclass
允许代码使用当前 TL 和当前回忆录。
解释
这是由于内核的改变造成的。
以供参考:
--- ../../2014/texmf-dist/tex/latex/memoir/memoir.cls 2015-03-06 22:27:23.000000000 +0000
+++ tex/latex/memoir/memoir.cls 2015-07-08 23:33:01.000000000 +0100
相关更改memoir.cls
可能是:
@@ -682,7 +682,9 @@
\fi
\ifmem@noetex\relax\else
- \IfFileExists{etex.sty}{\RequirePackage{etex}}{}
+ \ifx\e@alloc\@undefined
+ \IfFileExists{etex.sty}{\RequirePackage{etex}}{}
+ \fi
\fi
\providecommand*{\memoirpostopthook}{}
\memoirpostopthook
这是对 LaTeX 项目团队所做的旨在使其过时的更改的回应etex.sty
。理论上,现在不需要这个包了。以前使用的包埃泰克斯如果需要,则需要修改为加载。如果未定义elocalloc.sty
,则会加载。但在 TL 2015 中,它已定义,因此不会加载,因为它不是必需的。etex.sty
\e@alloc
etex.sty
我知道这一点是因为这个问题导致我犯了一个错误,我无法创建一个最小示例。无论我注释掉什么都可以解决问题,但取消注释所有内容会导致编译失败。什么都说不通。
你的描述听起来很熟悉——不仅 122 个盒子没问题,124 个盒子也没问题。我知道问题是否会出现取决于何时增加事物是需要的 - 也就是说,需要比 TeX 提供的更多的盒子或其他东西。如果你足够早地需要 124,那可能没问题。如果你只需要 122,那可能没问题。但如果你需要 123,那么在编译过程中其他东西可能需要更多,否则就没问题了。
然而,其他人需要提供详细的细节,因为我对此了解不够多。(事实上,我甚至对上面所说的内容都没有信心,尽管这种解释很肤浅。)