> For the complete documentation index, see [llms.txt](https://overleaf-pro.ayaka.space/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://overleaf-pro.ayaka.space/latex/zh-cn/geng-duo-zhu-ti/20-how-tex-macros-actually-work-part-2.md).

# TeX 宏究竟是如何工作的：第2部分

[第1部分](/latex/zh-cn/geng-duo-zhu-ti/19-how-tex-macros-actually-work-part-1.md) [第2部分](/latex/zh-cn/geng-duo-zhu-ti/20-how-tex-macros-actually-work-part-2.md) [第3部分](/latex/zh-cn/geng-duo-zhu-ti/21-how-tex-macros-actually-work-part-3.md) [第4部分](/latex/zh-cn/geng-duo-zhu-ti/22-how-tex-macros-actually-work-part-4.md) [第5部分](/latex/zh-cn/geng-duo-zhu-ti/23-how-tex-macros-actually-work-part-5.md) [第6部分](/latex/zh-cn/geng-duo-zhu-ti/24-how-tex-macros-actually-work-part-6.md)

## 引言：用图片讲故事

如第1部分所述，TeX必须“读取”你的 `.tex` 文件中的每一个字符，而这一读取过程更准确地称为 *扫描*。传统上，TeX 的输入处理（扫描）常被比作 TeX 拥有用来观察输入的“眼睛”，因此我们将在下面的图中沿用这一久经考验的类比。

### 图1：眼睛已准备就绪

我们假设 TeX 已经从一个 `.tex` 文件中获得了一些输入，正准备处理我们这串字符 `Hello World \jobname` ，这些字符包含在一段文本中。它会依次检查每个字符，并查看其类别码。

![TeX 的眼睛已准备好扫描一行文本](/files/fcdd7e6f1048de9c4f8bbc5870fcf57530f74ee6)

### 图2：处理类别码

在下一幅图中，我们将概览（更多细节见下文）TeX 对几种不同类别码的反应。请注意，总共有16种类别码，但为简便起见，我们这里只展示其中三种：11、10 和 0。其他字符码在 TeX 的排版过程中会变得很重要，例如构建表格、排版数学公式以及识别宏参数。

![TeX 对几种不同类别码的反应](/files/c8dd7f916100f648a6750dc11eea422a9b82edf3)

#### 图2说明

这里，我们讨论的是 TeX 在读取（扫描）构成一段文本的字符时的行为。TeX 会检查每个字符，查看其类别码，并根据类别码以及 TeX 的“模式”（一种基于其当前正在执行内容的状态）采取相应操作。

* **（绿色眼睛）** TeX 会看到这些字符中的每一个都具有类别码11（“字母”），并会将这些字符作为其正在构建的段落的一部分用于排版。然而，TeX 并不会仅仅转发（使用）字符码，而是会使用这两个数字的组合（字符码，类别码）来计算一个称为 *。通过计算这个会传递给 TeX 内部处理的记号值，该特定* （见下文）。一旦生成该字符记号，它就会进入 TeX 的内部排版过程/算法。
* **（蓝色眼睛）** TeX 看到一个空格字符（ASCII 32），其类别码为10（“空白符”）——请注意，如前所述，在 TeX 读取之前，空格（ASCII 32）或任何字符的类别码都可能已被改成其他值。

TeX 实际如何处理类别码10（“空白符”）的字符，确实会因 TeX 看到它的时间/位置而异——也就是 TeX 当前的“模式”。例如，有时 TeX 会直接跳过它们。这里，TeX 会知道自己在处理段落文本时检测到了一个类别码10的字符（恰好是一个空格，ASCII 32），因此最终会将其转换为所谓的词间胶：一种可以伸缩的弹性空白。

* **（红色眼睛）** 这里，TeX 观察到一个具有非常重要类别码的字符：0（转义字符）。

一个转义字符——*任何* 类别码为0的字符——都会告诉 TeX 切换到一种特殊的读取模式，并仔细扫描（读取）后续字符，因为它们标识的是一个 *命令*的名称，而不是要排版的文本。在 TeX 文献中，你也会看到“命令”一词被称为 *控制序列*。在看到转义字符之后，TeX 会检查紧随其后的字符的类别码 *紧接在它后面的那个字符*；这是因为 TeX 识别两种类型的命令：

* 称为 *控制字*的多字母命令：紧跟在转义字符之后的字符其类别码为11。随后所有类别码为11的字符都被视为命令名称的一部分。当 TeX 检测到任何一个 *不会* 不具有类别码11——例如一个类别码为10的空格字符时，它就会停止寻找构成命令名称的字符。
* 称为 *控制符号*的单字母命令：紧跟在转义字符之后的字符 *不会* 其类别码不为11。

你可以把转义字符理解为触发 TeX “跳出”其通常扫描行为并在接下来的几个字符上采用不同方式的信号——红色虚线框所示表明 TeX 将会 **开始扫描命令**.

### 图3：处理类别码11（“字母”）

在本系列的第1部分中，我们提到过 TeX 从输入中读取的每个字符都由两个整数来描述：

* 字符码：定义字符数值表示的整数；
* 类别码：TeX 为输入中可能出现的每个字符分配的0到15之间的一个值。

TeX 在其处理的下一阶段会使用这两条信息：创建字符记号。

图3在图2的基础上进行了扩展，展示 TeX 对这些类别码为11（字母）的输入字符会做什么：它会创建 *字符记号*——TeX 使用该字符的类别码与字符码的组合计算出的整数值。

**注意**：在这个例子中，我们只讨论类别码为11的字符，但你应当知道，TeX 也会为具有其他类别码的输入字符创建记号值——除了类别码0，因为它永远不会被转换成记号：转义字符只是充当一个“开关”，用来触发特殊处理。

![TeX 处理类别码11的字符](/files/33bd70977cc0c9845e91f7ef825a3f33986c0f1f)

下面的图5将展示 TeX 看到类别码0的字符（一个转义字符）时会做什么。

#### 图3说明：处理类别码11（“字母”）

这里，我们将重点关注 **绿色** 这一 *组合* 这两个数字，形成一个称为字符记号的单一整数：这些记号（整数）会被传递到 TeX 内部排版算法/处理的下一阶段。如前所述，TeX 也会为其他类别码（即非11）字符创建字符记号，这里我们只是以类别码11为例。

每个字符记号（一个整数）都会把一个输入字符与在该字符 **被 TeX 扫描（读入）时所分配的类别码**永久绑定：这一事实对于理解 TeX/LaTeX 宏的行为至关重要。当然，在后续处理中，TeX 有时需要拆分字符记号，以确定构造该记号时使用的是哪一对（字符码，类别码）。不过，一旦字符被 TeX 的输入（扫描）过程读入，TeX 计算出的字符记号值就会使该字符 *永久* 与分配给它的类别码耦合 *在读入时*.

**计算字符记号**

TeX 引擎使用一个简单公式来计算字符记号， $$T$$，由类别码为 $$C$$ 和字符码为 $$A$$:

$$T = \text{constant} \times C + A$$

像 pdfTeX 这样的8位引擎使用：

$$T = 256\times C + A$$

像 XeTeX 或 LuaTeX 这样的 Unicode 感知引擎必须使用不同的公式，因为在 Unicode 下，字符码可能远大于旧式8位 ASCII 编码世界中的最大值255。例如，XeTeX 使用：

$$T= 2^{21}\times C + A \hskip5mm \text{(where } A \text{ is a Unicode character code value)}$$

再一次值得注意的是，类别码0的字符不会被转换为字符记号：类别码0在 TeX 的输入过滤中占据非常特殊的位置，它纯粹用作一个“开关”，触发 TeX 进入对接下来几个字符的特殊扫描模式。图5将讨论这一点。

### 图4：处理类别码10（“空白符”）

TeX 对类别码10（“空白符”）字符的处理，取决于它在输入中检测到类别码10字符时当前正在处理什么。在我们的例子中，TeX 正在执行常规的段落处理，而类别码为10的空格字符将被转换为词间胶。

![TeX 处理类别码10的字符](/files/9933ead5eb4ff3f9d8b7649788044e07ca5d2008)

TeX 对空格的处理看起来可能相当特立独行，但对这一点的良好概述可见于 [《TeX by Topic》](http://www.eijkhout.net/texbytopic/texbytopic.html) 第1章和第2章——作者是 Victor Eijkhout——你可以 [下载一份免费的 PDF 版本](https://bitbucket.org/VictorEijkhout/tex-by-topic) 通过他的网站。

例如，当 TeX 看到类别码10的字符时，有时 TeX 会：

* 跳过（忽略）它们全部——例如，当 TeX 处于垂直模式时；
* 将多个空白符合并为一个空白符——在处理段落时会跳过多余空格；
* 吸收它们——例如，在命令名称后吸收一个空格；

另外请注意，有时 TeX 还会 *生成* 空格——通过将行尾字符转换为空格。空格字符（任何类别码为10的字符）的行为/处理方式是 TeX 的“特性”之一：要熟悉（并适应） TeX 的这一方面需要时间和练习。

### 图5a：处理类别码0（一个“转义字符”）

在这幅图中，TeX 已处理完直到 `\` 字符为止的所有字符，该字符的类别码为0：即“转义字符”——我们将使用一组后续图示来展示 TeX 如何处理转义字符并识别命令名称。

![TeX 处理类别码0的字符](/files/372fa6e5ef469e8102576606e1b8916435a144a4)

### 图5b：寻找命令名称

在这幅图中，我们查看红色虚线框部分（**开始扫描命令**），看看 TeX 在看到转义字符之后会做什么。

![TeX 在寻找命令名](/files/e4659b28300bfb769e171e68f27dd2d181a7aff6)

**图5b说明**

* 一旦被识别出来，转义字符就完成了它的工作：它充当了一个开关，不再参与任何进一步处理——具体来说，它 **不** 不会被转换成字符记号。
* 为了方便起见，我们再重复一下一些前面提到的细节。在看到转义字符后，TeX 会检查紧随其后的字符的类别码 *紧接在它后面的那个字符*；这是因为 TeX 识别两种类型的命令：
* * 称为 *控制字*：紧跟在转义字符之后的字符其类别码为11。随后所有类别码为11的字符都被视为构成命令名称（*控制词*）的一部分。当 TeX 检测到任何一个 *不会* 不具有类别码11——例如一个类别码为10的空格字符时，它就会停止寻找构成命令名称的字符。
  * 称为 *控制符号*的单字母命令：紧跟在转义字符之后的字符 *不会* 其类别码不为11。
* 在我们的例子中，位于 `\` 是一个 `j` 之后的第一个字符是（类别码11），这告诉 TeX 去寻找一个命令，它（可能）是由多个类别码为11的字符组成的多字母序列。
* TeX 会继续检查是否还有更多类别码为11的字符。一旦它检测到任何其他类别码的字符，例如类别码为10的空格，TeX 就知道自己已经到达命令名称的末尾。需要强调的是：这里是一个空格字符（类别码10）“终止”了命令的结束，但它也可能是任何一个 **没有** 其类别码不为11。

## 第3部分

在第3部分中，我们将从图5b继续，完成这一部分故事——TeX 如何识别一个命令——并继续讲述它接下来会做什么。我们还会更深入地了解 TeX 处理过程中的一些内部方面——其中一部分内容在第一次阅读时可以跳过，除非你真的喜欢这些细节。

[第1部分](/latex/zh-cn/geng-duo-zhu-ti/19-how-tex-macros-actually-work-part-1.md) [第2部分](/latex/zh-cn/geng-duo-zhu-ti/20-how-tex-macros-actually-work-part-2.md) [第3部分](/latex/zh-cn/geng-duo-zhu-ti/21-how-tex-macros-actually-work-part-3.md) [第4部分](/latex/zh-cn/geng-duo-zhu-ti/22-how-tex-macros-actually-work-part-4.md) [第5部分](/latex/zh-cn/geng-duo-zhu-ti/23-how-tex-macros-actually-work-part-5.md) [第6部分](/latex/zh-cn/geng-duo-zhu-ti/24-how-tex-macros-actually-work-part-6.md)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://overleaf-pro.ayaka.space/latex/zh-cn/geng-duo-zhu-ti/20-how-tex-macros-actually-work-part-2.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
