在rotating
包示例中,文档类之前包含一个命令。
\errorcontextlines32
\documentclass[twoside]{report}
当我应用\meaning\errorcontextlines
它时,它没有显示任何定义。它有什么用处?
答案1
\errorcontextlines
指 TeX 发现错误时输出的行数,这些行应该为用户提供一些有关错误发生原因的背景信息。
摘自 TeX Book(第 34 页):
如果您使用其他人设计的 TeX 格式包,您的错误消息可能会涉及许多难以捉摸的两行级别的宏上下文。通过
\errorcontextlines=0
在文件开头设置,您可以减少报告的信息量;TeX 将只显示顶部和底部的上下文行对以及最多\errorcontextlines
两行附加项目。(如果因此省略了任何内容,您还会看到“...
”。)即使大部分大型上下文都被抑制,您也很有可能发现错误来源;如果没有,您可以说“I\errorcontextlines=100\oops
”并重试。(这通常会给您一个未定义的控制序列错误和大量上下文。)纯 TeX 设置\errorcontextlines=5
。
在上面的讨论中假设\oops
未定义。
答案2
这个答案展示了如何使用\errorcontextlines
/如何解释结果上下文,以及为什么该功能有用以及何时该功能无用以及您可以做什么。
也可以看看:编译 - 如何有效地追踪 LaTeX 错误? - TeX - LaTeX Stack Exchange
TeX 没有调用堆栈,但是这是宏扩展语言中最接近的。
如何使用此功能
考虑这个程序(带有适当的序言)
\errorcontextlines=10000
\def\c{1 \errorerror 2}
\def\b #1 {7 #1 8}
\def\a{5 \b {3 \c 4} 6}
7 \a 8
相关输出是
! Undefined control sequence.
\c ->1 \errorerror
2
<argument> 3 \c
4
\b #1 ->7 #1
8
\a ->5 \b {3 \c 4}
6
l.7 7 \a
8
(然后 TeX 进入提示符(该行以 开头?
)。)
错误信息的含义:
- 某个文件第 7 行的内容(查看此文件以了解它是哪个文件)是
7 \a 8
,而 TeX 刚刚读取了\a
。(3) \a
扩展为5 \b {3 \c 4} 6
。\b
扩展为7 #1 8
。#1
“扩展”为3 \c 4
。 (实际上更像是“#1
具有的值”)\c
扩展为1 \errorerror 2
。7 {expands \a} 5 {expands \b {3 \c 4}} 7 3 {expands \c} 1 \errorerror
执行(3)之后,发生错误,2 4 8 6 8
接下来将执行。
通常,底线就是代码中的位置。
与查找错误一样,大多数时候您要查找的地方是包含代码的最顶层. (例如,如果a
和c
是库/包函数,并且\b
是您的函数,您可能想要修改的定义\b
)
限制
扫描参数时出错
在这种情况下,TeX 将无法正确报告行号。请参阅 LaTeX 调试策略和括号不匹配更多细节。
未显示宏的行号
这个问题无法解决(除非重新编译 TeX/以某种方式修改执行),TeX 不会存储宏的定义位置。
线太短
...
要查看行首/行末的内容,请参阅这个答案。
缺少中间上下文行
引擎执行明确的“尾部调用优化”以避免在循环中建立内存,因此如果某个命令(加上它的参数)位于其他命令的末尾,那么它将在上下文中隐藏。
除了重新编译 TeX 之外,没有其他方法可以禁用此功能。(与 C 相比,编译器可以执行尾部递归,但在调试模式下不能执行此操作)
例如,如果代码修改为
\errorcontextlines=10000
\def\c{1 \errorerror}
\def\b#1{7 #1}
\def\a{5 \b{3 \c}}
7 \a 8
\def\a#1{1 #1}
\a{3 4 \errorerror 5 6}
错误信息将只是
\c ->1 \errorerror
l.13 7 \a
8
所有中间错误上下文行均缺失。
尽管如此,在这种情况下你知道原因是尾部调用优化,无需重新编译 TeX,您可以查看宏的定义(\show
或latexdef
)来找出缺失的宏(它始终是最后一个。对于除“宏”之外的上下文行类型,这有点困难,但对于<argument>
类型有\tracingmacros
)。
这种行为导致问题很难调试的例子:参见问题。
缺少底部上下文行
还有一种情况是你无法获取代码的最顶层:\usepackage
。
请参阅链接的评论为什么这个错误信息行号是错误的? - TeX - LaTeX Stack Exchange。
要寻求解决方法,请参见下面的评论。
错误的令牌列表?
(3): 实际上,\a
(第一行中的最后一个标记)是 TeX 最后“读取”的内容,不一定是当前正在扩展的内容。
此外,如果上下文来自文件,TeX 将显示行内容,而不是实际的待处理的下一个标记。如果上下文来自宏,TeX 将显示宏定义(即使 TeX 有能力从解析的标记列表中“重建”代码)
某些操作可能会让 TeX 读取一些更多的命令,包含错误定义的命令不是第一行最后一个命令。
例如:
\def\a{1 \errorerror 2}
7 \expandafter \a \a 8
错误信息:
\a ->1 \errorerror
2
\a ->
1 \errorerror 2
l.12 7 \expandafter \a \a
8
注意:
- 该错误是由于扩展第一的
\a
宏观,而不是第二个, - 第二个
\a
以未展开的形式出现,而不是以曾经展开的形式出现。
缺少箭头 ( ->
) / 参数
这是一个相对简单的问题,但请注意,如果宏体太长,箭头->
可能会被省略。
./a.tex:11: Undefined control sequence.
\aaaaaaaaaaaaaaaaaaaa ...lax \relax \relax \ERROR
\relax \relax \relax \rela...
l.11 \aaaaaaaaaaaaaaaaaaaa
在这种情况下,仍然应该理解宏名称是\aaaaaaaaaaaaaaaaaaaa
,并且它可能有一些参数等。请参阅下面的代码。
\documentclass{article}
\errorcontextlines=100
\def\aaaaaaaaaaaaaaaaaaaa #1#2#3{
\relax \relax \relax \relax \relax \relax \relax \relax \relax \relax
\ERROR
\relax \relax \relax \relax \relax \relax \relax \relax \relax \relax
}
\aaaaaaaaaaaaaaaaaaaa {} {} {}
丢失的\
这也可能发生。代码
\escapechar=-1
\def\aaaaaaaaaaaaaaaaaaaa #1#2#3{
\relax \relax \relax \relax \relax \relax \relax \relax \relax \relax
\ERROR
\relax \relax \relax \relax \relax \relax \relax \relax \relax \relax
}
\aaaaaaaaaaaaaaaaaaaa {} {} {}
创建与上面类似的消息,但是没有 \
s。
./a.tex:12: Undefined control sequence.
aaaaaaaaaaaaaaaaaaaa ...x relax relax relax ERROR
relax relax relax relax re...
l.12 \aaaaaaaaaaaaaaaaaaaa {} {} {}
标记列表来源的宏名称错误
这有时会发生在 expl3 代码或类似代码的“回调”中。
例如
\cs_new_protected:Npn \mymacro {
\peek_analysis_map_inline:n {ab \error cd}
}
\mymacro 1
那么回溯将具有以下形式
\__tl_analysis_map_1:nnN #1#2#3->\group_end: ab\error
cd\__tl_peek_analysis_loop:NNn \prg_break_point:Nn \peek_analysis_map_break: {}
l.9 \mymacro 1
而不是你所期望的,那就是
\mymacro->\peek_analysis_map_inline:n {ab \error
cd}
l.9 \mymacro 1
尽管错误的标记\error
最初来自\mymacro
,但回溯显示它来自\__tl_analysis_map_1:nnN
(
因为内部参数
{\peek_analysis_map_inline:n {ab \error cd}}
存储在该宏中,然后从那里执行)。
类似的情况也发生在简单的条件下,例如
\cs_new_protected:Npn \mymacro {
\bool_if:NT \c_true_bool {
ab \error cd
}
}
\mymacro
这给出了回溯
<argument> ab\error
cd
\use:n #1->#1
l.11 \mymacro
缩进错误
由于某种原因,如果第一个例子是用 LuaLaTeX 而不是 PDFLaTeX 编译的,下面这一行的缩进<argument>
将是错误的:
! Undefined control sequence.
\c ->1 \errorerror
2
<argument> 3 \c
4
\b #1 ->7 #1
8
\a ->5 \b {3 \c 4}
6
l.7 7 \a
8
幸运的是,这个问题不是很严重,仍然可以分辨出哪条线是哪条。
输出中的 CR/LF 字符
通常会有 2 行,但有时可能会有更多,因为标记列表本身包含一些 CR/LF 字符。
我不知道如何解决这个问题。
边注
在这种情况下,您可以看到
\c →
、l.13
、<argument>
“上下文类型”。有关其他类型,请参阅tex core - TeX 错误消息中的 <recently read> 等是什么意思 - TeX - LaTeX Stack Exchange因为 TeX 是一种宏扩展语言,所以循环的唯一方法(如果它不是原始命令)是递归扩展宏。当然,可以只扩展到
O(log n)
步骤,其中n
是迭代次数,但扩展到深度的实现n
更加直接,并且运行速度也更快。即使
\errorcontextlines
程序中尚未存在,您也可以I\errorcontextlines=10000\show1
在控制台上键入以“打印出”内容。然而I\errorcontextlines=10000\MARK
不起作用。