> 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-tw/geng-duo-zhu-ti/23-how-tex-macros-actually-work-part-5.md).

# TeX 巨集實際上如何運作：第 5 部分

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

## 簡介與概述

在第 4 部分中，我們回顧了 TeX 巨集的一些基本屬性，為接下來兩篇文章做準備；在那兩篇文章中，我們會仔細檢視 TeX 巨集的底層機制：專門的 token list。在這最後兩篇文章中，我們使用稱為 node list 的圖示，這些圖示是根據使用經過特別修改的 Knuth 原始 TeX 軟體所產生的資料製作而成——那些修改是為了存取一般使用者無法取得的 TeX 內部資料結構。透過「接入」TeX 的內部巨集處理與執行常式，我們得以輸出圖形資料，進而更詳細、更準確地討論 TeX 的巨集處理行為。Overleaf 希望這些圖示能幫助讀者更深入理解 TeX 巨集實際的運作方式。

### 可能的補充背景閱讀

Overleaf 已經發表了兩篇與 token 相關的文章，提供關於 TeX token 與 TeX token list 的額外背景資訊。如果你需要補足任何理解上的缺口，並希望充分掌握本系列第 5 與第 6 部分的內容，請務必花點時間看看。

* [什麼是「TeX token」？](/latex/zh-tw/shen-ru-wen-zhang/53-what-is-a-tex-token.md)
* [什麼是 TeX token list？](/latex/zh-tw/shen-ru-wen-zhang/54-what-is-a-tex-token-list.md)

## 作為 token list 的巨集

當 TeX 偵測到一個建立巨集的指令（`\def`, `\edef`, `\gdef` 或 `\xdef`）出現在輸入串流中時，它會觸發一個程序，將這兩個部分都轉換為 `<parameter text><replacement text>` 我們的巨集定義，轉換成一長串 token list——而且是非常特定的一種 token list。

巨集所使用的 token list 與 TeX 中其他類型的 token list 略有不同，因為它們包含了「特殊」的 token 值，而這些值只有 TeX 內部的程序才能建立／產生：那些特殊 token 無法直接由你在 .tex 檔中加入的任何指令建立。TeX 會建立並使用這些「特殊」token 值，來協助處理你的巨集呼叫，這一點我們會在下文中探討並說明。

### 簡述 token list 的儲存方式：節點

為了儲存一串 tokens（整數值），TeX 使用一種稱為 [linked list](https://en.wikipedia.org/wiki/Linked_list)的資料結構，在 TeX 的情況中，它包含一個所謂的 *節點*。你可以把節點想成一小包電腦記憶體，用來儲存一組資料項目。若要儲存巨集，這些節點會像鏈條一樣串在一起，其中每個節點（鏈中的一環）都可以儲存數個資訊項目——包括一個 token 值，以及清單中下一個節點的記憶體位址。如需進一步資訊，你可以閱讀文章 [什麼是 TeX token list](/latex/zh-tw/shen-ru-wen-zhang/54-what-is-a-tex-token-list.md) ，但下方圖示總結了以 token list 儲存的巨集之主要特徵：

![以鏈結節點 node list 儲存的 TeX 巨集 token list 圖](/files/36a8491474060d34b4a31ebc27241d64e625e902)

### 提醒：巨集定義的 4 個部分

如第 4 部分所述，任何巨集的結構都可以寫成：

```
<TeX 巨集原語><巨集名稱><參數文字>{<取代文字>}
```

其中：

* `<TeX 巨集原語>` ＝ 其中之一 `\def`, `\edef`, `\gdef` 或 `\xdef`;
* `<巨集名稱>`＝ 你的巨集名稱，例如 `\foo`;
* `<參數文字>` 可以是「null」（不存在），也可以是一串分隔符 token 與巨集參數 token；
* `<取代文字>` 是你的巨集實際的主體：也就是在呼叫該巨集時會被「執行」的部分。

**注意**：（如同在第 4 部分也曾指出的）在整段討論中，我們都假設 `<巨集名稱>` 之後會接著一個類別代碼 10 的空白字元，作為分隔符來終止 `<巨集名稱>`。 *沒有* 在我們的文字／討論中明確顯示該空白字元，但我們假定它存在。嚴格來說，我們應該像這樣表示：

```
<TeX 巨集原語><巨集名稱><空白><參數文字>{<取代文字>}
```

然而，我們將省略明確加入 `<空格>` 字元，並隱含假設它存在。

**注意**：這些字元 `{` 和 `}` *不會* 成為巨集 token list 的一部分：它們的作用只是告訴 TeX 的輸入掃描器（負責建立 tokens）何處 `<取代文字>` 開始與結束。

當 TeX 定義一個巨集時，這些部分 `<parameter text><replacement text>` 會被轉換成一個連續的長 token list——該 list 中 token 的總數取決於巨集的複雜度。如我們所見，這個部分有特定用途，作為 TeX 用來挑選構成實際巨集之引數（值）的 tokens 的「token 模板」或「藍圖」：也就是要送入 `<取代文字>`.

為了把這些概念釐清，讓我們以一個範例巨集來說明，但把它保持得簡短一些，避免後續圖示過於雜亂：

```
\def\foo A#1\fake{123 #1}
```

對於我們的巨集， `\foo`

* `<參數文字>` = `A#1\fake`
* `<取代文字>` = `123 #1`

雖然這個範例是一個簡單的巨集，但它包含了我們需要探討的所有特徵。

如前所述，TeX 會將 `<parameter text><replacement text>` 轉換成一個長 token list，你可以在下方圖示中看到。在我們的範例中，由 `A#1\fake{123 #1}` 所形成的 tokens 已轉換為一串連續的 tokens，並儲存在一個 token list 中（作為一個節點的 linked list）。

## 顯示真實巨集 token list 的圖示

下列圖示展示巨集如何 `\def\foo A#1\fake{123 #1}` 被儲存，並使用來自 TeX 引擎內部的真實資料。它是使用 [Knuth 的 TeX 的自訂版本](/latex/zh-tw/shen-ru-wen-zhang/01-a-new-series-of-articles-tex-tokens-and-related-concepts-but-why-and-how.md#how-can-you-study-tex-tokens3f) 製作的，並加上額外程式碼以攔截巨集呼叫、檢查 TeX 的內部資料，並將其匯出成可由一個名為 [Graphviz](https://www.graphviz.org/).

你可以以下列格式下載此圖示： [PDF 檔](https://assets.ctfassets.net/nrgyaltdicpt/N6gT757eXCxRV3FtdPPga/7ce120dc05ed05962bb911ff1124734b/annotatednodelist-plain.pdf) （675 KB）或 [SVG 檔](https://images.ctfassets.net/nrgyaltdicpt/4PkmtHDhO8KF892ZDWuLHP/2c9c8385c6948fd122b228c5c780a3a6/annotatednodelist-plain.svg) （1.8 MB）。

![註解過的 TeX token list 圖](/files/f7bad9b0717ddd0e5e83442e66d0844153564acd)

#### 理解節點

在上方圖示中，你會看到每個節點都包含兩個資料項目，稱為 **下一個節點** 以及 **目前節點**。這些只是表示 TeX 內部記憶體位置的整數值——也就是其他節點儲存的位置。 **下一個節點** 和 **目前節點** 的值並不重要，它們只是儲存位置（記憶體位址），使節點能夠串連成一個列表。

![下一個節點與目前節點的意義](/files/6588d8fa0e2c0e6f9f3196cc9957ff2658e82329)

#### 回到範例

在節點圖示中，由 `A#1\fake{123 #1}` 所形成的 token list 包含本文開頭介紹的幾個「特殊 tokens」。此外，代表我們巨集的節點列表以一個「特殊的第一個節點」開始：我們將探討這些是什麼，以及它們有什麼作用。

巨集 token list（以及某些其他類型的 token list）中的第一個項目，儲存的不是 token 值，而是一個稱為巨集的 *參照計數* 的資料項，TeX 用它來追蹤巨集的使用情況。

![參照計數節點是 token list 中的第一個節點](/files/3b09bebb937d395f88fcfe413b8bbd783b5289c5)

第一個 token 是 `<參數文字>` 儲存在緊接於參照計數之後的節點中：你可以看到它是一個代表字母的 token `一個` ，其類別代碼為 11。從第 2 與第 3 部分的討論中，我們知道 character token 是使用

$$\text{token value}=256\times \text{category code} + \text{character code}$$

計算而得；對於一個字母 `一個` ，類別代碼為 11，則為

$$\text{token value}=256\times 11 + 65$$

因此得到 2881 的值，如節點中所示。

#### 在 \foo 中使用的「指令」\fake

在我們的巨集定義中 `\def\foo A#1\fake{123 #1}` 其中一個分隔符是一個 *未定義的* 指令 `\fake` ，它被儲存在 token list 中，作為 `<參數文字>` 部分的一部分。如你所見，在整個巨集 token list 中 `\fake` 是一個其值為 `19491`——一個由 TeX 使用第 3 部分所討論的公式計算出的整數值。當 TeX 嘗試執行 `\foo` 時，它會預期找到 `\fake` 這個 token 值，位於 `<參數文字>` 部分的結尾。TeX *不會* 嘗試執行 `\fake` 指令，因為它的角色僅僅是在 `<參數文字>` 「token 模板」中提供某種形式的「標點」。

![將指令 token 用作巨集分隔符](/files/8edfa4b8d494b4b52ba9398687a48226c8735d6e)

#### token list 中的特殊 tokens

**「結束比對」token**

在呼叫巨集時，TeX 的第一項工作是掃描使用者輸入的巨集，並比較使用者的 `<參數文字>` 部分中出現的 tokens 與模板中包含的 tokens `<參數文字>` ，也就是儲存在記憶體中的 token list（在巨集被定義時建立）。由於巨集的完整定義是由 `<parameter text><replacement text>` 所構成，並以一個長串連續的 tokens 列表儲存，所以 TeX 需要知道在那個 token list 中， `<參數文字>` *停止* 以及在哪裡 `<取代文字>` *開始*。為了達成這點，當 TeX 正在定義巨集（建立 token list）時，它會插入一個稱為 **結束比對** 的特殊終止 token，作為由 `<參數文字>`。 **結束比對** token 無法由使用者指令產生，只有 TeX 本身可以建立它，因此 TeX 能確定偵測到 `<參數文字>`.

![在 TeX token list 中顯示結束比對 token](/files/22c0f56bddaefccda2c22bf8ab9d80f26c6ed537)

在這裡，我們可以看到，緊接在 **結束比對** 之後的第一個 token 是一個代表數字 `1` 、類別代碼為 12 的 token。這是預期中的，因為 `<取代文字>` 對於我們的巨集 `\foo` 是 `123 #1`——也就是說，它以代表數字 `1` （類別代碼為 12）的 token 開始。

從第 2 與第 3 部分的討論中，我們知道 character token 是使用

$$\text{token value}=256\times \text{category code} + \text{character code}$$

計算而得；對於一個數字 `1` ，其類別代碼為 12，則為

$$\text{token value}=256\times 12 + 49$$

因此得到 3121 的 token 值，如節點中所示。

**「比對參數」tokens**

當 TeX 儲存巨集定義時，它會將任何參數 tokens（`#1`, `#2`… `#9`）中的 `<參數文字>` 轉換成一種稱為 **比對參數** token。這些 tokens 告訴 TeX 它需要開始在使用者的巨集呼叫中尋找 tokens，也就是巨集的引數。

![在 TeX token list 中顯示比對參數 token](/files/bdb7d84abe0e9a27e92c872e35e25fb6aeb14e4e)

### token list 中的特殊 tokens

#### 「輸出參數」tokens

當 TeX 處理完所有內容並準備實際執行（展開）巨集時， **輸出參數** tokens 會指示 TeX 在 `<取代文字>` 之內何處需要注入代表使用者在呼叫巨集時提供之引數的 tokens。實際上就是：「在此位置插入代表使用者第 n 個引數的 tokens，其中 n=1...9」。

在 `<取代文字>` 部分的已儲存巨集定義 token list 中，會有一個 **輸出參數** token 對應於每一個 `#1`, `#2`... `#9` 在原始定義中出現的參數。

![在 TeX token list 中顯示輸出參數 token](/files/725194cf59de7381cd4b79b95c43fcc694373f77)

如果我們查看對 `\foo` (`\def\foo A#1\fake{123 #1}`）的定義，我們會看到只有 1 個巨集參數（`#1`在 `<參數文字>` (`A#1\fake`），而且因此也只有 1 個巨集參數（`#1`）出現在 `<取代文字>` (`123 #1`）：這只會產生 1 個 **輸出參數** token 出現在代表 `<取代文字>`.

請注意代表 `\foo`的 `<取代文字>`:

* 緊接在 **輸出參數** token 之前的 token 代表一個空白字元（類別代碼 10、字元代碼 32），因為在 `123` 與巨集參數（`#1`）之間有一個空白，在 `\foo`;
* 該 **輸出參數** 的原始定義中，這是列表中的最後一個 token： **下一個節點** 具有一個特殊值「null」（意為「空」），用來終止列表：在 **輸出參數** 之後沒有更多節點，因為它是最後一個 token，表示 `<取代文字>` 以及巨集定義的結尾。

## 第 6 部分

在第 6 部分中，我們會使用一些詳細圖示來說明並探討巨集展開的確切意義，以及在將巨集引數送入巨集之前，TeX 對其進行 token 化所帶來的後果 `<取代文字>`.

[第 1 部分](/latex/zh-tw/geng-duo-zhu-ti/19-how-tex-macros-actually-work-part-1.md) [第 2 部分](/latex/zh-tw/geng-duo-zhu-ti/20-how-tex-macros-actually-work-part-2.md) [第 3 部分](/latex/zh-tw/geng-duo-zhu-ti/21-how-tex-macros-actually-work-part-3.md) [第 4 部分](/latex/zh-tw/geng-duo-zhu-ti/22-how-tex-macros-actually-work-part-4.md) [第 5 部分](/latex/zh-tw/geng-duo-zhu-ti/23-how-tex-macros-actually-work-part-5.md) [第 6 部分](/latex/zh-tw/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-tw/geng-duo-zhu-ti/23-how-tex-macros-actually-work-part-5.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.
