> For the complete documentation index, see [llms.txt](https://ayakaleaf-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://ayakaleaf-pro.ayaka.space/latex/zh-cn/shen-du-wen-zhang/21-how-does-expandafter-work-tex-uses-temporary-token-lists.md).

# \expandafter 是如何工作的：TeX 使用临时 token 列表

[第 1 部分](/latex/zh-cn/shen-du-wen-zhang/19-how-does-expandafter-work-an-introduction-to-tex-tokens.md) [第 2 部分](/latex/zh-cn/shen-du-wen-zhang/22-how-does-expandafter-work-the-meaning-of-expansion.md) [第 3 部分](/latex/zh-cn/shen-du-wen-zhang/21-how-does-expandafter-work-tex-uses-temporary-token-lists.md) [第 4 部分](/latex/zh-cn/shen-du-wen-zhang/20-how-does-expandafter-work-from-basic-principles-to-exploring-tex-s-source-code.md) [第 5 部分](/latex/zh-cn/shen-du-wen-zhang/17-how-does-expandafter-work-a-detailed-macro-case-study.md) [第 6 部分](/latex/zh-cn/shen-du-wen-zhang/18-how-does-expandafter-work-a-detailed-study-of-consecutive-expandafter-commands.md)

## 展开与内部记号列表

到目前为止，我们已经探讨了记号、记号列表以及 TeX 中“展开”概念背后的核心原理。在本节中，我们将使用 TeX 原语 `\jobname` 来介绍展开处理的一个重要方面：TeX 对……的使用 *临时记号列表*——它们是一种 *基本* ……工作方式的一个方面 `\expandafter` ，正如我们将在本系列文章的后文中看到的那样。

`\jobname` 是一个可展开的 TeX 原语，其展开会生成一系列字符记号，这些记号表示主输入 `.tex` 文件的名称。例如，假设我们有以下文本，作为 `.tex` 名为 `mycode.tex`:

```
    我的文件名是 \jobname .tex % 注意 \jobname 后面的空格
```

这将排版出

```
    我的文件名是 mycode.tex
```

当我们使用 `\jobname` 命令时，最终排版出的字符并不是从你的物理 `.tex` 文件中读取的，那么它们来自哪里：TeX 在哪里存储/读取这些记号？对用户不可见（即，在 TeX 内部深处）， `\jobname` 会创建一个临时记号列表，该列表由表示你的文件名的一系列字符记号构成。一旦 `\jobname` 已经创建了该记号列表，TeX 便会暂时将“视线”从当前输入源（此处为我们的 `.tex` 文件）转而从该临时记号列表中读取记号（字符记号）。当 TeX 需要下一个输入记号时，它会从该内部列表中读取下一个记号，并一直这样做，直到读到列表末尾；此时 TeX 会恢复从先前的输入源读取记号，而在这里，那将是从我们的 `.tex` 输入文件中读取的文本。

如下面的图示所示，TeX 会恢复读取 `.tex` 输入文件中它在处理完 `\jobname`——即在读取空格字符之后、但在读取“.”字符之前。实际上，句点（.）正等待从 TeX 的输入缓冲区中读取——这是 TeX 内存中的一小块区域，用于保存从 `.tex` 文件中读入的一行文本——TeX 会逐行读取并处理你的 `.tex` 文件，它不会将整个文件读入内存。

在阅读下图时，请从底部向上看，以跟随处理流程。

![TeX 如何展开 \jobname](/files/dbd99ec16d3b153eaab1f7edf209df158072096f)

回到我们关于展开的讨论，我们可以观察到， `\jobname` 的展开导致 `\jobname` 命令（记号）被 *移除* 从输入中 *替换* 被展开生成的记号所取代：生成的临时记号列表用于保存 `.tex` 文件中使用的

可展开命令（例如 `\jobname`）并不是唯一会“悄悄”创建并使用记号列表来实现其效果的 TeX 原语。例如，命令 `\uppercase` 和 `\lowercase` 都会创建内部记号列表来改变其参数的字母大小写。完成大小写转换后，TeX 会切换为从这些命令生成的记号列表中读取字符记号。记号列表是 TeX 唯一的“记号数据存储”机制——除了将数据写入物理磁盘文件之外。

### 记号的来源：TeX 是一位杂技高手

当 TeX 处理一份典型文档时，它必须管理 *许多* 多个记号来源：来自众多物理磁盘文件的输入，以及处理过程中创建的无数内部记号列表。在本节中，我们将非常简要地探讨 TeX 如何设法“同时驾驭”这些输入源。

假设我们想要一个简单的宏，用来排版我们的 `.tex` 文件：

```
    \def\myfile{The name of my file is \jobname .tex}
```

后来，在我们 `.tex` 文件中的某个时刻，我们调用宏 `\myfile`：暂时地，TeX 会从通过你文本中的文本（`.tex`）文件创建/读取记号，切换为从 `\myfile` 存储在其内存中的定义（记号列表）中读取记号。当 TeX 执行该 `\myfile` 宏（处理其记号）时，它会检测到一个表示 `\jobname` 命令的记号，而其展开又会创建另一个临时记号列表，TeX 必须从中读取记号。即使在这个简单场景中，TeX 也必须管理三个输入来源：

1. 该 `.tex` 包含该 `\myfile` 宏的文本文件；
2. 存储……定义的记号列表 `\myfile` 宏的文本文件；
3. 由……创建的记号列表 `\jobname` 命令在……内部 `\myfile` 宏中。

当 TeX 处理文档时，它会不断在输入源之间切换：物理文件和记号列表，那么 TeX 是如何跟踪这一点的呢？答案是，在内部，TeX 引擎维护着一个所谓的 [输入栈](https://en.wikipedia.org/wiki/Stack_\(abstract_data_type\)) 它充当一种“记忆”，使 TeX 在切换输入源时能够记住自己当时正在做什么（正在从哪里读取）。

不深入细节，TeX 引擎内部的代码使用一个名为 `curinput` （当前输入）的全局变量，除其他作用外，它会告诉 TeX 当前是在从物理文件还是从记号列表中读取。 `curinput` 它还会指示 TeX 下一个记号应从何处获取（在当前记号列表或其文本缓冲区中）。如果 TeX 正在从记号列表中读取， `curinput` 它还会记录正在处理的是哪种类型的记号列表——例如，作为宏存储的记号列表，或者这些记号是否来自不同的源。

在需要时， `curinput` 变量会被更改以指向新的输入源，而 TeX 当前的“输入状态”（源和位置）会被保存在输入栈中，以便 TeX 之后能够返回到那个确切位置（在某个 `.tex` 文件中的位置，或记号列表中的下一个记号）。一旦新的输入源耗尽（例如，记号列表中不再有记号，或文件已到达末尾），它就会从栈中弹出，并且 `curinput` 会更新以确保 TeX 恢复从先前的源获取记号。

## 深入探究（可选阅读）

以下各节为喜欢细节的读者提供更多背景信息。

### 真实的记号列表

下图使用的是 Overleaf 定制构建的 Knuth TeX 生成的，它可以访问 TeX 的内部数据和数据结构。这个记号列表示意图是在上面简化版的基础上构建的，并包含了额外的数据，例如显示由 `\jobname` 其类别码为 12，而不是通常的 11 类别码。在这张图中，“node”只是 TeX 用来表示一个内存存储单元的名称。

![TeX 记号列表内部](/files/085b8a2c0fdea49d2170592ac5c9f2a7877e272a)

### TeX 如何读取并处理 \jobname

另外，为了完整起见，这里给出 TeX 在检测到时的“思考过程”概览 `\jobname` 在我们的输入中 `.tex` 文件中的情况。在这张图中，我们可以看到 TeX 如何检测转义字符（`\` 其类别码为 0），处理字符序列 `jobname`，生成一个记号，并查找该 `\jobname` 命令的含义；TeX 会发现它的命令码 > 100，这表明它是一个可展开命令。

![TeX 如何扫描并处理 \jobname](/files/f8767592bc6a809a160faba3734389744f643af6)

[第 1 部分](/latex/zh-cn/shen-du-wen-zhang/19-how-does-expandafter-work-an-introduction-to-tex-tokens.md) [第 2 部分](/latex/zh-cn/shen-du-wen-zhang/22-how-does-expandafter-work-the-meaning-of-expansion.md) [第 3 部分](/latex/zh-cn/shen-du-wen-zhang/21-how-does-expandafter-work-tex-uses-temporary-token-lists.md) [第 4 部分](/latex/zh-cn/shen-du-wen-zhang/20-how-does-expandafter-work-from-basic-principles-to-exploring-tex-s-source-code.md) [第 5 部分](/latex/zh-cn/shen-du-wen-zhang/17-how-does-expandafter-work-a-detailed-macro-case-study.md) [第 6 部分](/latex/zh-cn/shen-du-wen-zhang/18-how-does-expandafter-work-a-detailed-study-of-consecutive-expandafter-commands.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://ayakaleaf-pro.ayaka.space/latex/zh-cn/shen-du-wen-zhang/21-how-does-expandafter-work-tex-uses-temporary-token-lists.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.
