% -*- 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 <return> 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 <return> 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).
%<to be read again>
%                   c
%<to be read again>
%                   n
%l.340 Skip across \hskip 3cn
%                             by 3 centimeters.
%|
%^^|<to be read again>|
%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
%<recently read> 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).
<to be read again>
                   c
<to be read again>
                   n
l.340 Skip across \hskip 3cn
                             by 3 centimeters.
|
^^|<to be read again>|
这里 \TeX\ 注意到 `|3|' 后面不是一个正确的度量单位，因此它假设该度量单位为点。
\TeX\ 将重新读取 `|cn|' 的记号并将它们插入你的输入中，而这并不是你想要的。
在这种情形下若想得到更好的结果，你可以先键入 `|2|' 以跳过 `|cn|'。
这样你将得到如下信息：
\csdisplay
<recently read> 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.
%<inserted text>
%                $
%<to be read again>
%                   \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.
<inserted text>
                $
<to be read again>
                   \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.
%<inserted text>
%                }
%<to be read again>
%                   \vskip
%l.29 \hbox{One \vskip
%                     1in two.}
%|
%^^|<inserted text>|
%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.
<inserted text>
                }
<to be read again>
                   \vskip
l.29 \hbox{One \vskip
                     1in two.}
|
^^|<inserted text>|
问题在于，当 \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.
%<inserted text>
%                }
%<to be read again>
%                   \vskip
%\smallskip ->\vskip
%                    \smallskipamount
%<argument> 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.
<inserted text>
                }
<to be read again>
                   \vskip
\smallskip ->\vskip
                    \smallskipamount
<argument> 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 ^|<output>| indicates that \TeX\ was in the middle of its output routine
%when this error occurred.
%\li ^|<write>| 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 ^|<output>| 表示 \TeX\ 在它的输出例行程序中间遇到此错误。
\li ^|<write>| 表示 \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
