> 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/21-how-tex-macros-actually-work-part-3.md).

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

[第 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)

## 該停一停了！

在進入這個故事的下一部分之前，我們需要先做個回顧：提醒自己目前進展到哪裡，並整理思緒，確保所有關鍵概念都已就位。提醒一下，我們的範例是基於這個假設：TeX 已經讀入了一行包含 `Hello World \jobname` 的文字，而且 TeX 正在排版它以建立一個段落。

### 最終目標

我們的目標是更好（更深入）地理解 TeX 巨集的本質以及它們如何運作。然而，要達到這一點，我們首先需要理解 TeX 如何讀取輸入檔，以及如何處理其中的字元。以下是目前為止涵蓋主題的摘要。

* TeX 會讀取（掃描）你輸入中的每個字元，而且對於每個字元，TeX 都有兩項資訊：
* **字元碼**：用來識別該字元的整數，例如，當它儲存在 .tex 輸入檔中時；
* **類別碼**：TeX 內部的另一個整數，用來為從輸入讀入的每個字元指定意義。
* 一旦 TeX 讀入某個字元，每個字元的類別碼就會 *永久地* 透過建立一個字元記號，與該個別字元產生關聯：
* TeX 使用一個簡單的公式，將字元碼及其對應的類別碼「包裝」成一個稱為字元記號的整數。
* 你可以改變 TeX 已經 *尚未讀入* 的任何字元的意義；方法是為你想改變其行為的字元指定不同的類別碼——也就是修改 TeX 對該字元的處理方式。
* 重新定義（重新對應）類別碼是透過 TeX 的原始指令 `\catcode` 來完成的。
* 當 TeX 看到類別碼 0 時，它會切換到一種特殊的掃描模式，開始尋找一個命令：要不是一個（可能）多字母的 *控制詞* ，就是一個單字元的 *控制符號*.

到目前為止，我們把 TeX 的輸入掃描過程看作是它辨識個別字元，並使用每個字元的類別碼來判斷下一步要做什麼。有些字元只是供排版的普通文字項目（例如類別碼 11），但我們也看過空白字元（類別碼 10）與跳脫字元（類別碼 0）。還有其他類別碼，為了簡潔起見，我們尚未討論——例如類別碼 1（「開群組」，例如， `{`），類別碼 2（「結群組」，例如， `}`）以及其他。每個類別碼在 TeX 的輸入掃描，以及隨後由 TeX 內部的軟體程序／演算法所進行的處理中，都扮演各自的角色。

### 記號：快速回顧

「記號」這個概念對 TeX 的運作方式至關重要：你會在各種與 TeX 相關的書籍、文章和線上社群中看到「記號」被提及或引用，因此值得稍微回顧一下這個主題——你可以在先前發表的一篇文章中找到更多細節 [什麼是「TeX 記號」？](/latex/zh-tw/shen-ru-wen-zhang/53-what-is-a-tex-token.md)

我們已經看到，TeX 會把輸入字元轉換成記號，方法是將字元碼與類別碼合併成一個單一的複合整數。TeX 對命令也做類似的事：它使用命令名稱計算出一個稱為 *命令記號* 的整數（我們會更詳細地探討這點）。作為一個指南，你可以把記號看作是 TeX 將它從輸入讀入的項目「包裝」起來的方法，讓這些項目準備好被送往 TeX 處理的下一階段。把所有項目（字元或命令）整齊地包裝成單一的數值表示，會讓它們在後續處理鏈中更容易被處理。例如，當 TeX 想把你的某些輸入儲存起來以便稍後使用，例如一個巨集定義時，TeX 只需要把你的巨集定義——不論多複雜——儲存成一系列整數，其中每個整數都是一個記號，代表構成（包含於）你的巨集定義中的某個字元或命令。

## 那麼，下一步是什麼？

在第 2 部分的最後一節，我們看到一個跳脫字元（類別碼 0）如何將 TeX 切換到一種特殊的處理模式，讓它去尋找命令名稱。在我們的範例中，TeX 偵測到了字元字串 `jobname` ，而我們在第 2 部分結束時，TeX 正準備對那串字元（命令名稱）「做些什麼」。在這一部分，我們將詳細看看 TeX 接下來會做什麼。

一旦 TeX 已經辨識出你輸入檔中的某一串字元代表某個命令的名稱（此處， `jobname`）TeX 可能需要執行那個命令，這取決於它當下正在做什麼。我們說「可能需要」，是因為有時 TeX 不會立刻嘗試執行命令：例如，在它定義巨集時（TeX 正在建立記號清單）——這些主題我們稍後會討論。不過，我們會繼續沿用我們的範例：TeX 正在排版一個段落，而且 *將會*在這種情況下，需要執行 `\jobname`.

### 從一串字元到執行命令：怎麼做？

首先，讓我們回顧第 2 部分中的圖 5b，在那裡 TeX 已經辨識出輸入中的某一串字元構成了某個命令的名稱： `jobname`。圖 5b 顯示 TeX 必須「檢查內部表格……」。那到底 *實際上是什麼意思*?

![TeX 尋找命令名稱](/files/9cf0bcee34b5cc9d6c7ff039607fb63341bca508)

還有另一種更詳細的描述，說明 TeX 如何「檢查內部表格」，以便從一串字元（例如， `jobname`）過渡到精確判斷那個命令是什麼，以及它代表什麼，可以在先前的一篇文章中找到 [什麼是「TeX 記號」？](/latex/zh-tw/shen-ru-wen-zhang/53-what-is-a-tex-token.md) 在這裡，我們會在避免過度重複的前提下，總結關鍵概念。

先從一個類比開始。假設你正在讀一本書，遇到一個不熟悉的字：你會怎麼做？今天，多半是「拿 Google 搜尋」，但我們先假設你偏好較傳統的方法：你會拿起一本列出單字並提供其意義的字典。TeX 也有類似的機制：一個內部的「字典」，列出目前 TeX 已知的所有命令，以及那些命令的「意義」。這裡所說的「意義」，是指它屬於哪一類命令：它做什麼，以及 TeX 執行該命令時可能需要的任何其他資訊。也要注意，「命令」這個術語包含使用者／TeX 程式設計者撰寫的任何 TeX/LaTeX 巨集，以及 [數百個內建的原始命令](/latex/zh-tw/geng-duo-zhu-ti/46-tex-primitives-listed-by-tex-engine.md).

延續我們的字典類比。當我們作為人類讀者，需要查找某個字的意義時，我們會使用字典提供的字母順序列表來搜尋該字——但當然，TeX 的運作方式並不完全如此。回到我們原先的 `jobname` 範例，TeX 如何在它的「字典」中找到 `jobname`的「意義」——而那個「意義」究竟為 TeX 提供了什麼？

TeX 並不是提供一份內部的、所有 TeX 已知命令的「字母順序列表」，而是做了稍微不同的事情。TeX 會把命令名稱中包含的整個字元序列轉換成一個單一整數，該整數將用來識別（代表）那個命令。TeX 在內部維護著一個很大的「字典」，其中儲存了所有已知命令所對應的 *整數* ，這些整數是根據命令名稱計算出來的——請注意，那個字典並不是以字母序列形式儲存實際的命令名稱本身（稱為 *字串*）。TeX 對所有內建命令（原始命令）都使用這個字典 *以及* 它也會用這個字典來儲存使用者建立的任何巨集（命令）的細節：你的巨集名稱會被轉換成一個整數，而那個整數會在 TeX 的字典中被「登記」。

每當 TeX 偵測到你輸入中使用了一個命令，而且需要知道那個命令的某些資訊時，它就會把命令名稱中的那串字元轉換成一個「等效」的整數，然後用那個整數在它的「大字典」中查找該命令。在座的程式設計師可能會想知道，TeX 使用一種 [雜湊函式](https://en.wikipedia.org/wiki/Hash_function) 來完成這個轉換。

![雜湊函式示意圖](/files/c372feaf8ed6d68f83c5e3a578223e6b300c73e6)

### 圖 6：從字元到命令意義

下圖顯示了一個命令在 TeX 將字元字串轉換成一個等效整數的過程，而這個整數稱為 **curcs**，並且 TeX 會用這個整數在它的「大字典」中查找該命令的意義。這次查找的結果是兩項資訊：兩個整數，稱為 **curcmd** 以及 **curchr**，TeX 可利用它們來確切判斷命令做什麼，以及之後如何執行它。

![TeX 將一串字元轉換成等效整數，以查找命令的意義](/files/c3236a191d298755576af696c4019f6cea36c2a7)

在內部，TeX 維護一個稱為 **curcs** (**cur**rent **c**ontrol **s**equence) which is used to store the integer value of the command that TeX is currently working on—i.e., **curcs** 儲存由命令名稱計算出的整數值。事情還不完全是這樣，因為還有另一個細節：如果 TeX 剛剛讀入／處理的是一個字元，而不是一個命令，它會將 **curcs** 設為 0，以記住最近讀入的是字元，而不是命令。

### 命令對 TeX 的意義

如果我們看看 [TeX 引擎提供的內建命令集合](/latex/zh-tw/geng-duo-zhu-ti/46-tex-primitives-listed-by-tex-engine.md) ，我們可以看到其中有些命令彼此密切相關：它們執行類似的任務；例如，所有 TeX 引擎都使用 4 個原始命令來定義（建立）巨集： `\def`, `\gdef`, `\edef`, `\xdef`。這 4 個命令都用來定義巨集，但當然，每一個的做法都略有不同。如果從程式設計的角度來看：這裡有 4 個巨集定義命令，大致上做的是同一件事，但我們需要在它們之間做選擇，以適應它們各自不同的行為。

為了處理這件事，TeX 會為每個命令指定兩個值，而這兩個值就是 TeX 所理解的命令「意義」（它的角色／它做什麼）——這兩個值存在於 TeX 內部，是軟體深處的一部分，也是使用者無法存取的「內部機制」。每個 TeX 命令，不論是內建原始命令，或是使用者定義的命令，都會被指定兩個值，這兩個值在 TeX 看來會定義／分類它的行為——也就是它對 TeX 來說是什麼意思。當 TeX 使用它的「大字典」查找某個命令時，它會找到這兩個關鍵資訊：

* **命令碼**：一種「一般分類」，表示這是一種什麼樣的命令——例如「巨集定義」命令（其中之一是 `\def`, `\gdef`, `\edef`, `\xdef`）；「製盒」命令（其中之一是 `\hbox`, `\vbox` 或 `\vcenter`）等等，TeX 引擎支援的數百個命令皆然。巨集（使用者定義的命令）也會被指定命令碼。
* **命令修飾碼**：這是附屬資訊，向 TeX 提供某個命令的特定資訊。巨集（使用者定義的命令）也會被指定命令修飾碼——不過，對巨集而言，命令修飾碼所扮演的角色與原始命令略有不同（對巨集來說，命令修飾碼會指出巨集定義儲存在記憶體中的位置）。

合起來看，命令碼與命令修飾碼可以唯一識別每個命令。以下是 Knuth 最初的 TeX 軟體中，巨集定義命令所使用的命令碼與命令修飾碼——請注意，其他 TeX 引擎可能使用不同的數值，但它們遵循完全相同的原則：

|         |                                                  |                                                    |
| ------- | ------------------------------------------------ | -------------------------------------------------- |
| **命令**  | <p><strong>命令</strong><br><strong>碼</strong></p> | <p><strong>命令</strong><br><strong>修飾碼</strong></p> |
| `\def`  | 97                                               | 0                                                  |
| `\gdef` | 97                                               | 1                                                  |
| `\edef` | 97                                               | 2                                                  |
| `\xdef` | 97                                               | 3                                                  |

### 回顧：釐清所有這些變數／值

到這裡為止，我們已經充滿了關於值、變數、命令值以及各種細節的大量資訊——很快就會讓人感到混亂，所以讓我們整理一下目前所知道的內容。當 TeX 從你的輸入中讀到某些東西時，它不是字元就是命令。每當 TeX 從輸入讀到某些東西時，它都需要儲存剛剛讀入（掃描）的項目之資訊：

* 對於 **字元**：它需要記錄字元碼與類別碼。它還需要建立並儲存 TeX 使用這些值計算出的記號值。
* 對於 **命令**：TeX 需要知道它從命令名稱計算出的數值等價物， **curcs**。它也可能需要儲存透過在 TeX 的「字典」中查找該命令而取得的「意義」：也就是命令碼與命令修飾碼。此外，TeX 也需要計算一個代表該命令的記號值。

沒錯，這很令人混淆：有很多變數和記號概念四處浮動，所以讓我們試著把它理清楚。

在內部，TeX 使用四個全域變數來儲存 TeX 最近讀入（或目前正在「處理」）的項目資訊——我們不會詳細討論這些變數，但知道它們的存在，有助於提供更多背景，以理解真正發生了什麼：

* **curcmd**： （目前命令）一個整數變數。它用來儲存 *目前命令* 的值 *或* 它儲存著當前 *類別碼* 的字元；
* **curchr**： （目前字元）一個整數變數，但它儲存的內容取決於 TeX 剛剛從輸入中讀到的是什麼：
* **字元**：如果最近讀入的項目是字元， **curchr** 會儲存目前 *字元碼*.
* **命令**：如果最近讀入的項目是命令， **curchr** 會儲存 *命令修飾碼*：TeX 用來支援／釐清 **curcmd**的附加資訊——因為正如上面所見，有些命令共享相同的 **curcmd**
* **curcs**： （目前控制序列）一個整數變數，用來儲存由命令名稱中的字元字串計算出來的值。 **curcs** = 0，若最近讀入的項目是單一字元，而不是控制序列（命令名稱）的名稱；
* **curtok**： （目前記號）一個整數變數，保存目前記號的值——它可能是命令記號，也可能是字元記號。

以下是上述資訊以表格呈現：

|                    |                                                                                                                                                    |                                                                                |
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ |
| **TeX 內部使用的全域變數：** | **當 TeX 掃描字元時：**                                                                                                                                   | **當 TeX 掃描命令時：**                                                               |
| **curcmd**         | 儲存目前字元的類別碼                                                                                                                                         | 儲存 *命令碼*——用來識別目前命令的「類型」                                                        |
| **curchr**         | 儲存目前字元的字元碼                                                                                                                                         | 儲存附加資料（稱為 *命令修飾碼*），提供有關目前命令的額外資訊                                               |
| **curcs**          | 0                                                                                                                                                  | 一個非零的正整數，透過雜湊函式，根據命令名稱中的字元字串計算而得。它用來存取 TeX 的「字典」，以查找目前命令的意義——也就是取得它的命令碼與命令修飾碼。 |
| **curtok**         | 對於 8 位元 TeX 引擎， *字元記號* 是使用以下公式計算的： $$\text{curtok}=256\times \text{curcmd} + \text{curchr}$$ 其中 $$\text{curcmd}$$ 是字元的類別碼，而 $$\text{curchr}$$ 是字元碼 | 對於 8 位元 TeX 引擎， *命令記號* 是使用以下公式計算的： $$\text{curtok}=4095 + \text{curcs}$$       |

### 關於目前記號的補充說明

對於字元，能得到的最大記號值，是使用最大的類別碼（15）以及最大的字元碼所獲得；對 8 位元 TeX 引擎而言，最大的字元碼是 255。理論上（對 8 位元 TeX 引擎而言），最大的字元記號值 $$\text{curtok}\_{\text{max}}$$，是：

$$\text{curtok}\_{\text{max}}= 256\times 15 + 255 = 4095$$

我們說「理論上」，是因為類別碼 15 用來表示「無效字元」，而這會導致 TeX 產生錯誤：無效字元永遠無法通過 TeX 的輸入掃描過程，因此它永遠不會成為字元記號。

對命令而言，目前記號（$$\text{curtok}$$）是由 $$\text{curtok}=4095 + \text{curcs}$$ 計算而得，但對命令來說 $$\text{curcs}$$ 是 *永遠* 非零，因此 TeX 可以很容易判定一個記號代表什麼：

* 如果 $$\text{curtok} > 4095$$ 那就是命令記號；
* 如果 $$\text{curtok} < 4095$$ 它就是字元記號。

實際上，TeX 使用記號——一個簡單的整數值——來「包裝」它需要知道的所有關於從輸入讀入之項目的資訊。

## 第 4 部分

在第 4 部分中，我們將探索一系列範例巨集，以說明巨集的 `<parameter text>` 區段所扮演的角色與用途；它作為一個「記號樣板」，可以透過使用分隔符記號來構成。

[第 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/21-how-tex-macros-actually-work-part-3.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.
