% -*- coding: utf-8 -*- % This is part of the book TeX for the Impatient. % Copyright (C) 2003 Paul W. Abrahams, Kathryn A. Hargreaves, Karl Berry. % See file fdl.tex for copying conditions. \input macros %\chapter{Making sense \linebreak of error messages} \chapter{理解错误信息} \chapterdef{errors} %\codefuzz = 4pc % for this chapter only (in scope of \chapter) %\bix^^{error messages} %Interpreting \TeX's error messages can sometimes %be like going to your physician %with a complaint that you're feeling fatigued and being handed, %in response, %a breakdown of your blood chemistry. The explanation of your distress %is probably there, but it's not easy to figure out what it is. %A few simple rules will go a long way in helping you to understand \TeX's %error messages and get the most benefit from them. \codefuzz = 4pc % for this chapter only (in scope of \chapter) \bix^^{错误信息} 解释 \TeX\ 的错误信息有时候就像, 你跟医生抱怨你感觉疲乏无力,医生却递给你一份血生化细目表。 对你的痛苦的解释也许就在那里,但却不容易弄清楚它是什么。 掌握一些简单规则对你理解 \TeX\ 错误信息并从中受益将大有帮助。 %Your first goal should be %to understand what you did that caused \TeX\ to complain. %Your second goal (if you're working interactively) %should be to catch as many errors as you can in a single run. 你的第一个目标应当是理解什么东西导致 \TeX\ 报错。 第二个目标(如果是交互式使用 \TeX )应当是在一次运行中捕获尽可能多的错误。% \footnote{译注:本章的各个节标题为译者所加。} \section{第一个例子} %Let's look at an example. Suppose that your input %contains the line: %\csdisplay %We skip \quid a little bit. %| %You meant to type `|\quad|', but you typed `|\quid|' instead. %Here's what you'll get from \TeX\ in response: %\csdisplay %!! Undefined control sequence. %l.291 We skip \quid % a little bit. %? %| %This message will appear both at your terminal and in your log file. %^^{log file//error messages} %The first line, which always starts with an exclamation point (|!!|), %tells you what the problem is. The last two lines before the `|?|' prompt %(which in this case are also %the next two lines) tell you how far \TeX\ has gotten %when it found the error. %It found the error on line $291$ of the current input file, %and the break between the two message lines indicates %\TeX's precise position within line $291$, namely, just after |\quid|. %The current input file is the one just after the most recent unclosed %left parenthesis in the terminal output of your run (see \xref{infiles}). 我们来看一个例子。假设你的输入中包含下面这行: \csdisplay We skip \quid a little bit. | 你本想输入 `|\quad|',却输入成 `|\quid|'。 此时 \TeX\ 将给出下面的信息: \csdisplay !! Undefined control sequence. l.291 We skip \quid a little bit. ? | 此信息将同时出现在终端上和日志文件中。 ^^{日志文件//错误信息} 第一行始终以感叹号(|!!|)开头,告诉你出现了什么问题。 在 `|?|' 提示符之前的最后两行(在此例子中同样也是接下来的两行)% 告诉你 \TeX\ 在何处发现此错误。 它在当前输入文件的第 $291$ 行发现了错误, 两个信息行之间的断行表示 \TeX\ 在第 $291$ 行的精确位置,即在 |\quid| 后面。 当前输入文件是指,在运行时的终端输出上, 最接近的非闭合左圆括号后显示的文件(见\xref{infiles})。 %This particular error, an undefined control %sequence, is one of the most common ones you can get. %If you respond to the prompt with another~`|?|', %\TeX\ will display the following message: %{\hfuzz = 2in %\csdisplay %Type to proceed, S to scroll future error messages, %R to run without stopping, Q to run quietly, %I to insert something, E to edit your file, %1 or ... or 9 to ignore the next 1 to 9 tokens of input, %H for help, X to quit. %| %}% 这种错误,即控制序列未定义,是你最常出现的错误之一。 如果你在提示符后键入另一个 `|?|',\TeX\ 将显示下列信息: {\hfuzz = 2in \csdisplay Type to proceed, S to scroll future error messages, R to run without stopping, Q to run quietly, I to insert something, E to edit your file, 1 or ... or 9 to ignore the next 1 to 9 tokens of input, H for help, X to quit. | }% %Here's what these alternatives mean: %\ulist %\li If you type \asciichar{return}, %\TeX\ will continue processing your document. %In this case it will just ignore the |\quid|. %\li If you type `|S|' (or `|s|'---uppercase and lowercase are equivalent %here), \TeX\ will process your document without stopping \emph{except} %if it encounters a missing file. Error messages will still appear at your %terminal and in the log file. %\li If you type `|R|' or `|r|', %you'll get the same effect as `|S|' except that %\TeX\ won't even stop for missing files. %\li If you type `|Q|' or `|q|', %\TeX\ will continue processing your document but %will neither stop for errors nor display them at your terminal. The %errors will still show up in the log file. %\li If you type `|X|' or `|x|', %\TeX\ will clean up as best it can, discard the page %it's working on, and quit. You can still print or view the %pages that \TeX\ has already processed. %\li If you type `|E|' or `|e|', \TeX\ will clean up and terminate %as it would for `|X|' or `|x|' and then enter your text editor, %positioning you at the erroneous line. %(Not all systems support this option.) %\li If you type `|H|' or `|h|', %you'll get a further explanation of the error displayed %at your terminal and %possibly some advice about what to do about it. This explanation will also %appear in your log file. For the undefined control sequence above, %you'll get: %{\hfuzz = 2in %\csdisplay %The control sequence at the end of the top line %of your error message was never \def'ed. If you have %misspelled it (e.g., `\hobx'), type `I' and the correct %spelling (e.g., `I\hbox'). Otherwise just continue, %and I'll forget about whatever was undefined. %| %} %\li If you type `|?|', you'll get this same message again. %\endulist 这些选择各自的含义如下: \ulist \li 如果你键入 \asciichar{return}, \TeX\ 将继续处理你的文档。在此例子中它就忽略了 |\quid|。 \li 如果你键入 `|S|'(或者 `|s|'——这时候大小写是等价的), \TeX\ 将继续处理你的文档且不再暂停,\emph{除非}找不到某文件。 但错误信息还是会出现在终端上和日志文件中。 \li 如果你键入 `|R|' 或 `|r|', 你将得到与 `|S|' 相同的结果,但此时 \TeX\ 即使找不到文件也不会暂停。 \li 如果你键入 `|Q|' 或 `|q|', \TeX\ 将继续处理你的文档,且遇到错误后将不会再暂停,也不会在终端上显示。 错误信息还是会记录到日志文件中。 \li 如果你键入 `|X|' 或 `|x|', \TeX\ 将尽力清理干净,丢弃正在构造的页面,并退出。 你仍然可以打印或查看 \TeX\ 已经生成的页面。 \li 如果你键入 `|E|' 或 `|e|', \TeX\ 将如同 `|X|' 或 `|x|' 那样清理并中止,然后打开文本编辑器,跳转到错误所在的行。% (并非所有系统都支持此选项。) \li 如果你键入 `|H|' 或 `|h|', 你将在终端上看到对此错误的进一步解释,可能还有对此错误的一些建议。 这些信息同样会记录到你的日志文件中。 对于上述例子的未定义控制序列,你将得到下列信息: {\hfuzz = 2in \csdisplay The control sequence at the end of the top line of your error message was never \def'ed. If you have misspelled it (e.g., `\hobx'), type `I' and the correct spelling (e.g., `I\hbox'). Otherwise just continue, and I'll forget about whatever was undefined. | } \li 如果你键入 `|?|',你将得到和上面相同的信息。 \endulist %\noindent %The other two alternatives, typing `|I|' or a small integer, provide ways of %getting \TeX\ back on the track so that your error won't cause further errors %later in your document: %\ulist %\li If you type `|I|' or `|i|' %followed by some text, then \TeX\ will insert %that text as though it had occurred just after the point of the error, %at the innermost level where \TeX\ is working. %In the case of the example above, that means at \TeX's %position in your original input, namely, just after `|\quid|'. %Later you'll see an example that shows %the difference between inserting something at the innermost level and %inserting it into your original input. In the example above of the undefined %control sequence, if you type: %\csdisplay %I\quad %| %\TeX\ will carry out the |\quad| command and produce a quad space %where you intended to have one. %\li If you type a positive integer less than $100$ (not less than $10$ as the %message misleadingly suggests), %\TeX\ will delete that number of tokens from the innermost %level where it is working. %(If you type an integer greater than or equal to $100$, \TeX\ will %delete $10$ tokens!) %\endulist \noindent 另外两个选择,即键入 `|I|' 或一个小整数, 提供一种让 \TeX\ 回到正常轨道上的方法, 使得该错误不会在文档后面导致更多的错误: \ulist \li 如果你键入 `|I|' 或 `|i|' 并加上一些文本, \TeX\ 将把文本插入错误位置之后,放在 \TeX\ 处理的最内层级。 在上面这个例子中,这表示在 \TeX\ 的原始输入的位置,即在 `|\quid|' 之后。 稍后我们将给出一个例子,说明把某些东西插入到最内层级与插入到原始输入的区别。 在上面这个控制序列未定义的例子中,如果你键入: \csdisplay I\quad | \TeX\ 将执行 |\quad| 命令并在你需要的地方生成一个全方间隔。 \li 如果你键入一个小于 $100$(错误信息让人误解为小于 $10$)的正整数, \TeX\ 将从它处理的最内层级删除该数目的记号。% (如果你键入大于或等于 $100$ 的整数,\TeX\ 将只删除 $10$ 个记号!) \endulist \section{第二个例子} %Here's an example of another common error: %\csdisplay %Skip across \hskip 3cn by 3 centimeters. %| %The error message for this is: %\csdisplay %!! Illegal unit of measure (pt inserted). % % c % % n %l.340 Skip across \hskip 3cn % by 3 centimeters. %| %^^|| %In this case \TeX\ has observed that `|3|' is followed by something that %isn't a proper unit of measure, and so it's assumed the unit of measure to be %points. \TeX\ will read the tokens of `|cn|' again and insert them into %your input, which is not what you want. In this case you can get a better %result by first typing `|2|' to bypass the `|cn|'. %You'll get the message: %\csdisplay % n % %l.340 Skip across \hskip 3cn % by 3 centimeters. %| 这里是另一种常见错误的例子: \csdisplay Skip across \hskip 3cn by 3 centimeters. | 这个例子的错误信息为: \csdisplay !! Illegal unit of measure (pt inserted). c n l.340 Skip across \hskip 3cn by 3 centimeters. | ^^|| 这里 \TeX\ 注意到 `|3|' 后面不是一个正确的度量单位,因此它假设该度量单位为点。 \TeX\ 将重新读取 `|cn|' 的记号并将它们插入你的输入中,而这并不是你想要的。 在这种情形下若想得到更好的结果,你可以先键入 `|2|' 以跳过 `|cn|'。 这样你将得到如下信息: \csdisplay n l.340 Skip across \hskip 3cn by 3 centimeters. | %Now you can type %`|I\hskip 3cm|' to get the skip you wanted (in addition to the |3pt| skip %that you've already gotten).\footnote %{By typing `|I\unskip\hskip 3cm|' you can get rid of the |3pt| skip.} 现在你可以键入 `|I\hskip 3cm|' 以得到你所要的间距(加上你已经得到的 |3pt| 间距)。% \footnote{若改为键入 `|I\unskip\hskip 3cm|',你就可以去掉这个 |3pt| 的间距。} \section{第三个例子} %If you type something that's only valid in math mode, \TeX\ will switch over %to math mode for you whether or not that's what you really wanted. %For example: %\csdisplay %So \spadesuit s are trumps. %| %Here's \TeX's error message: %\csdisplay %!! Missing $ inserted. % % $ % % \spadesuit %l.330 So \spadesuit % s are trumps. %| %Since the |\spadesuit| symbol is only allowed in math mode, %\TeX\ has inserted a `|$|' in front of it. %After \TeX\ inserts a token, it's positioned in \emph{front} of %that token, in this case the `|$|', ready to read it. %Typing `|2|' will cause \TeX\ to skip both the `|$|' %and the `|\spadesuit|' tokens, leaving it ready to process the `|s|' %in `|s are trumps.|'. %(If you just let \TeX\ continue, it will typeset `|s are trumps|' %in math mode.) 如果你输入某些仅可用于数学模式的内容,\TeX\ 将帮你切换到数学模式, 不管这是否你真正想要的。例如: \csdisplay So \spadesuit s are trumps. | 下面是 \TeX\ 的错误信息: \csdisplay !! Missing $ inserted. $ \spadesuit l.330 So \spadesuit s are trumps. | 由于 |\spadesuit| 符号仅可在数学模式中使用, \TeX\ 已经在它前面插入一个 `|$|'。 在插入某个记号之后,\TeX\ 位于该记号的\emph{前面}, 在此情形中就是位于 `|$|' 前面,并准备读取输入。 键入 `|2|' 将让 \TeX\ 跳过 `|$|' 和 `|\spadesuit|' 记号, 让它准备处理 `|s are trumps.|' 中的 `|s|'。% (若你只是让 \TeX\ 继续,它将在数学模式中排版 `|s are trumps|'。) \section{第四个例子} %Here's an example where \TeX's error diagnostic is downright wrong: %\csdisplay %\hbox{One \vskip 1in two.} %| %The error message is: %\csdisplay %!! Missing } inserted. % % } % % \vskip %l.29 \hbox{One \vskip % 1in two.} %| %^^|| %The problem is that you can't use |\vskip| when \TeX\ is in %restricted horizontal mode, i.e, constructing an hbox. %But instead of rejecting the |\vskip|, \TeX\ has inserted a right brace %in front of it in an attempt to close out the hbox. %If you accept \TeX's correction, \TeX\ will complain again %when it gets to the correct right brace later on. It will also complain %about anything before that right brace that isn't allowed in vertical mode. %These additional complaints will be particularly confusing %because the errors they indicate are bogus, a %result of the propagated effects of the inappropriate %insertion of the right brace. %Your best bet is to type `|5|', skipping past all the tokens %in `|}\vskip 1in|'. 在下面这个例子中,\TeX\ 对错误的诊断是完全不正确的: \csdisplay \hbox{One \vskip 1in two.} | 它给出的错误信息如下: \csdisplay !! Missing } inserted. } \vskip l.29 \hbox{One \vskip 1in two.} | ^^|| 问题在于,当 \TeX\ 位于受限水平模式中,即正在构建水平盒子时,不能使用 |\vskip|。 但 \TeX\ 不是丢掉 |\vskip|,而是在它前面插入一个右花括号,以结束该水平盒子。 如果你接受 \TeX\ 的修改,\TeX\ 遇到稍后的正确右花括号时将再次报错。 它还将对该右花括号之前的任何不能出现在竖直模式的东西报错。 这些额外的错误将是特别让人迷惑的,因为这些错误所说的都是假的, 它们是不恰当插入右花括号后产生的结果。 你的最佳做法是键入 `|5|' 以跳过在 `|}\vskip 1in|' 中的所有记号。 \section{第五个例子} %Here's a similar example in which the error message is longer %than any we've seen so far: %\csdisplay %\leftline{Skip \smallskip a little further.} But no more. %| %The mistake here is that |\smallskip| only works in a vertical mode. %The error message is something like: %\csdisplay %!! Missing } inserted. % % } % % \vskip %\smallskip ->\vskip % \smallskipamount % Skip \smallskip % a little further. %\leftline #1->\line {#1 % \hss } %l.93 ...Skip \smallskip a little further.} % But no more. %| %The error messages here give you a tour through the macros that are used in %\plainTeX's implementation of |\leftline|---macros %that you probably don't care about. %The first line tells you that \TeX\ intends to cure the problem by %inserting a right brace. %\TeX\ hasn't actually read the %right brace yet, so you can delete it if you choose to. %Each component of the message after the first line %(the one with the `!') occupies a pair of lines. %Here's what the successive pairs of lines mean: 这里还有个相似的例子,它的错误信息比你之前看到的都要长: \csdisplay \leftline{Skip \smallskip a little further.} But no more. | 错误在于 |\smallskip| 只能在竖直模式中使用。给出的错误信息如下: \csdisplay !! Missing } inserted. } \vskip \smallskip ->\vskip \smallskipamount Skip \smallskip a little further. \leftline #1->\line {#1 \hss } l.93 ...Skip \smallskip a little further.} But no more. | 这些错误信息带你巡视了在 \plainTeX\ 中用于实现 |\leftline| 的各个宏——% 这些宏也许是你并不在乎的。 第一行告诉你 \TeX\ 试图通过插入右花括号解决此问题。 \TeX\ 还未读到右花括号,因此若你想的话你可以删除它。 第一行(带 `!' 的那行)之后的信息每部分都由两行组成。 下面是各部分的两行信息的含义: %\olist %\li The first pair indicates that \TeX\ has inserted, but not yet read, %a right brace. %\li The next pair indicates that after reading the right brace, \TeX\ will %again read a `|\vskip|' command (gotten from the macro definition %of |\smallskip|). %\li The third pair indicates that \TeX\ was expanding the |\smallskip| %macro when it found the error. The pair also displays the definition of %|\smallskip| and indicates how far \TeX\ has gotten in expanding and %executing that definition. Specifically, it's just attempted %unsuccessfully to execute the |\vskip| command. In general, a %diagnostic line that starts with a control sequence followed by `|->|' %indicates that \TeX\ has been expanding and executing a macro by that %name. %\li The fourth pair indicates that \TeX\ was processing a macro argument %when it found the |\smallskip| and also indicates \TeX's position in that %argument, i.e., it's just processed the |\smallskip| (unsuccessfully). %By looking ahead to the next pair of lines %we can see that the argument was passed to %|\leftline|. %\li The fifth pair indicates that \TeX\ was expanding %the |\leftline| %macro when it found the error. %(In this example the error occurred while \TeX\ was %in the middle of interpreting several %macro definitions at different levels of expansion.) %Its position after |#1| indicates that the last thing it saw was the %first (and in this case the only) argument to |\leftline|. %\li The last pair indicates where \TeX\ is positioned in your input file. %Note that this position is well beyond the position where it's %inserting the right brace and reading `|\vskip|' again. %That's because \TeX\ has already read the entire argument to |\leftline| %from your input file, even though it's only processed part of that argument. %The dots at the beginning of the pair indicate a preceding part of the %input line that isn't shown. This preceding part, in fact, includes %the |\leftline| control sequence that made the |\vskip| illegal. %\endolist \olist \li 第一对双行表示 \TeX\ 已经插入,但尚未读到的右花括号。 \li 第二对双行表示在读取右花括号后, \TeX\ 将重新读取 `|\vskip|' 命令(它来自 |\smallskip| 宏的定义中)。 \li 第三对双行表示 \TeX\ 是在展开 |\smallskip| 时发现的错误。 此部分也显示 |\smallskip| 的定义,并表示在展开和执行该定义时已经读到哪里。 具体地说,它是在执行|\vskip| 命令时失败的。 一般地,以控制序列加 `|->|' 开始的信息行表示 \TeX\ 已展开执行的宏的名称。 \li 第四对双行表示 \TeX\ 在处理宏参量时发现了 |\smallskip|, 同时也表示 \TeX\ 在该参量中的位置,即它正在处理 |\smallskip|(失败了)。 通过往前查找接下来两行,你可以看到此参量是传递给 |\leftline| 的。 \li 第五对双行表示 \TeX\ 是在展开 |\leftline| 宏是发现的错误。% (在这个例子中,错误发生在 \TeX\ 解释多个不同层级的宏定义的中间。)% 在 |#1| 后面的位置表示它最后读取到的是 |\leftline| 的第一个(在这里也是唯一的)参量。 \li 最后对双行表示 \TeX\ 在你的输入文件的位置。 注意此位置远远超出它插入右花括号并重新读取 `|\vskip|' 的位置。 这是因为 \TeX\ 已经从输入文件读取了 |\leftline| 的完整参量, 即使它仅仅处理该参量的一部分。 这两行信息开头的圆点表示输入行前面一部分内容没显示出来。 前面那部分内容实际上就包括让 |\vskip| 变得不合法的 |\leftline| 控制序列。 \endolist %\noindent %In a long message like this, you'll generally find only the first line and the %last pair of lines to be useful; but it sometimes helps to know what the other %lines are about. Any text that you insert or delete will be %inserted or deleted at the %innermost level. In this example the insertion or deletion would occur %just before the %inserted right brace. %Note in particular that in this case \TeX\ puts any text you might insert %\emph{not} into your input text but into a macro definition %several levels down. (The original macro definition is of course not modified.) \noindent 在类似这样的长篇信息中,你通常发现只有第一行和最后两行是有用的; 但知道其他行是怎么回事有时候也有益处。 任何你插入或删除的文本将在最内层级中插入或删除。 在这里例子中,插入或删除将出现在 \TeX\ 插入的右花括号前。 特别要注意,在此情形中 \TeX\ 将\emph{不会}把你可能插入的文本放在你的输入文本中, 而是放在多层宏定义的最里面。% (原始的宏定义当然并不会被改动。) %You can use the ^|\errorcontextlines| command \ctsref{\errorcontextlines} %to limit the %number of pairs of error context lines that \TeX\ produces. %If you're not interested in all the information that \TeX\ is giving you, %you can set |\error!-contextlines| to $0$. That will give you just the first %and last pairs of lines. 你可以用 ^|\errorcontextlines|\ctsref{\errorcontextlines}命令限制 \TeX\ 生成的错误信息双行的数目。 如果你并非对 \TeX\ 给你的所有信息都感兴趣, 你可以设定 |\error!-contextlines| 为 $0$。 这样错误信息将只有最前面两行和最后面两行。 %Finally, %we'll mention two other indicators that can appear at the start of a pair %of error message lines: %\ulist %\li ^|| indicates that \TeX\ was in the middle of its output routine %when this error occurred. %\li ^|| indicates that \TeX\ was in the middle of executing a %|\write| command when this error occurred. %\TeX\ will detect such an error when it is actually doing the |\write| %(during a |\shipout|), rather than when it first encounters the |\write|. %\endulist 最后,我们提及可能出现在错误信息行对开头的另外两个指示词: \ulist \li ^|| 表示 \TeX\ 在它的输出例行程序中间遇到此错误。 \li ^|| 表示 \TeX\ 在执行 |\write| 命令时遇到此错误。 \TeX\ 将在实际执行 |\write| 时才检测这样的错误(在 |\shipout| 时), 而不是在刚遇到 |\write| 命令时。 \endulist %\eix^^{error messages} %\endchapter %\byebye \eix^^{错误信息} \ifoldeplain\else\ifcompletebook\else \vskip4em{\sectionfonts\leftline{本章索引}} \readindexfile{i} \fi\fi \endchapter \byebye