> 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/shen-ru-wen-zhang/18-how-does-expandafter-work-a-detailed-study-of-consecutive-expandafter-commands.md).

# \expandafter 如何運作：連續 \expandafter 指令的詳細研究

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

## 案例研究：理解 \\\expandafter\\\expandafter\\\expandafter...

進階巨集，例如 LaTeX 套件中的那些，常常大量使用連續的多個 `\\expandafter` 命令來執行複雜的記號「操弄」。對大多數人而言，這類巨集可能很難理解，或令人望而生畏。在本節中，我們將回顧 TeX 處理連續的 `\\expandafter` 命令：

```
\\expandafter\\expandafter\\expandafter...
```

為了協助說明，我們會在每個 `\\expandafter`後加上下標——以指出我們所指的是哪一個：

```
        \\expandafter1\\expandafter2\\expandafter3...
```

此外，我們會擴充每個 `\\expandafter` 所處理的記號之表示法，改為使用 $$\mathrm{T^i\_1}$$ 以及 $$\mathrm{T^i\_2}$$ 用來表示記號 $$\mathrm{T\_1}$$ 以及 $$\mathrm{T\_2}$$ 被 `\\expandafter` 帶有下標 `i`: `\\expandafter`<sub>i</sub> $$\mathrm{T^i\_1T^i\_2}$$。我們也將假設有兩個記號 $$\mathrm{T\_X}$$ 以及 $$\mathrm{T\_Y}$$ 接在 `\\expandafter<sub>3</sub>` 因此我們的輸入看起來像這樣： `\\expandafter<sub>1</sub>\\expandafter<sub>2</sub>\\expandafter<sub>3</sub>` $$\mathrm{T\_{X}T\_{Y}}$$.

當 TeX 開始處理這個輸入時，對於 `\\expandafter<sub>1</sub>` 它會看到

* $$\mathrm{T^1\_1} =$$`\\expandafter<sub>2</sub>` 它會被保存以供稍後 *重新插入* 回到輸入中
* $$\mathrm{T^1\_2} =$$`\\expandafter<sub>3</sub>`，而它會被展開

如果我們回頭看先前對於 [TeX 內部程式碼](/latex/zh-tw/shen-ru-wen-zhang/20-how-does-expandafter-work-from-basic-principles-to-exploring-tex-s-source-code.md) 用來實作 `\\expandafter`，正是在展開 `\\expandafter<sub>3</sub>` 時，我們會看到遞迴在發生。要處理 `\\expandafter<sub>1</sub>` TeX 已經呼叫了其內部函式 `expand()`，因此要處理（展開） `\\expandafter<sub>3</sub>` TeX 正在進行一次 *第二次* 呼叫 `expand()`——從 `expand()` 函式本身內部。

對於 `\\expandafter<sub>3</sub>` 我們有

* $$\mathrm{T^3\_1 = T\_X}$$，它會被保存以供稍後 *重新插入* 回到輸入中
* $$\mathrm{T^3\_2 = T\_Y}$$，我們假設它可展開

我們再進一步假設， $$\mathrm{T\_Y}$$ 的展開會產生以下記號序列： $$\mathrm{{T^1\_Y}{T^2\_Y}{T^3\_Y}}\cdots\mathrm{T^N\_Y}$$。我們現在已到達由命令序列開始的展開程序結尾 `\\expandafter<sub>1</sub>\\expandafter<sub>2</sub>\\expandafter<sub>3</sub>` $$\mathrm{T\_{X}T\_{Y}}$$ ，而 TeX 接著會「回溯展開」由……開始的遞迴程序 `\\expandafter<sub>1</sub>`.

在處理 `\\expandafter<sub>3</sub>` 之後，TeX 在記憶體中有一個記號清單，內含 $$\mathrm{T\_Y\text{: }{T^1\_Y}{T^2\_Y}{T^3\_Y}}\cdots\mathrm{T^N\_Y}$$的展開所產生的記號。TeX 現在開始重新插入它在處理 `\\expandafter` 命令：

1. TeX 先重新插入記號 $$\mathrm{T\_X}$$ 由……保存的 `\\expandafter<sub>3</sub>`. $$\mathrm{T\_X}$$ 被重新插入 *在前面* 於……的展開 $$\mathrm{T\_Y}$$，這會產生一個記號序列： $$\mathrm{{{T\_X}T^1\_Y}{T^2\_Y}{T^3\_Y}}\cdots\mathrm{T^N\_Y}$$.
2. 不過，我們仍然需要完成由 `\\expandafter<sub>1</sub>` 所保存代表 `\\expandafter<sub>2</sub>`
3. TeX 組裝完成、可供下一階段處理讀入的最終記號序列是 `\\expandafter<sub>2 (token)</sub>` $$\mathrm{T\_{X}T^1\_{Y}T^2\_{Y}T^3\_{Y}\cdots T^N\_Y}$$
4. TeX 現在已完成處理的「第一輪」，並切換為讀取它所產生的記號清單序列——該序列以 `\\expandafter<sub>2 (token)</sub>` 開頭，TeX 接著會處理。對於 `\\expandafter<sub>2</sub>` 我們有
   * $$\mathrm{T^2\_1} =\ \mathrm{T\_X}$$ 它會被保存以供稍後 *重新插入* 回到輸入中
   * $$\mathrm{T^2\_2} = \mathrm{T^1\_Y}$$ 它是由……展開所產生的第一個記號 $$\mathrm{T\_Y}$$；如果可展開，則會將其展開
5. 如果我們假設記號 $$\mathrm{T^1\_Y}$$，即由……展開所產生的第一個記號 $$\mathrm{T\_Y}$$，會展開為 $$\mathrm{{T^A\_{Y1}}{T^B\_{Y1}}{T^C\_{Y1}}}$$ 那麼，在 TeX 重新插入 $$\mathrm{T\_X}$$之後，重新由 TeX 處理的記號序列將會是： $$\mathrm{{T\_X}{T^A\_{Y1}}{T^B\_{Y1}}{T^C\_{Y1}}{T^2\_Y}{T^3\_Y}\cdots{T^N\_Y}}$$

   我們可以將其重新表述為

   $$\mathrm{T\_X}\text{\<expansion of the first token in }\mathrm{T\_Y}\text{>\<remaining tokens in }\mathrm{T\_Y}\text{>}$$

下圖說明由 TeX 程式碼建立的記號清單

```
    \\expandafter1\\expandafter2\\expandafter3TXTY
```

![顯示 TeX 處理多個 \\\expandafter 命令的圖片](/files/25d487636d8f090020a6526ddeb712d1abf54a55)

### 理論應用於實作

作為範例，我們將定義以下巨集來充當 $$\mathrm{T\_X}$$ 以及 $$\mathrm{T\_Y}$$

* $$\mathrm{T\_X}=$$`\foo` 其中我們將定義 `\foo` 為 `\\def\\foo#1{\\textbf{#1}}`
* $$\mathrm{T\_Y}=$$`\\bar` 其中我們先定義 `\\def\\abc{Hello}`, `\\def\\xyz{, World!}` ，然後 `\\def\\bar{\\abc\\xyz}`

我們將使用以下程式碼片段來示範先前的分析：

\\\expandafter\\\expandafter\\\expandafter\\\foo\\\bar

根據我們的討論， `\\expandafter<sub>1</sub>\\expandafter<sub>2</sub>\\expandafter<sub>3</sub>` $$\mathrm{T\_X}\mathrm{T\_Y}$$ 的結果會產生如下形式的記號序列：

$$\mathrm{T\_X}\text{\<expansion of the first token in }\mathrm{T\_Y}\text{>\<remaining tokens in }\mathrm{T\_Y}\text{>}$$

其中實際的序列取決於記號 $$\mathrm{T\_Y}$$的性質。如果我們使用 $$\mathrm{T\_X}=$$`\foo` 以及 $$\mathrm{T\_Y}=$$`\\bar`來插入我們的範例命令，其定義為 `\\def\\bar{\\abc\\xyz}`，我們會看到：

* 在……中的第一個記號 $$\mathrm{T\_Y}$$ 是 `\\abc` 而其展開是一串字元記號： `Hello`
* 在……中的其餘記號 $$\mathrm{T\_Y}$$ 是代表……的單一記號 `\\xyz`.

如果我們將這些資訊代入我們的「分析」，就會得到

$$\begin{align\*} &\mathrm{T\_X}\text{\<expansion of the first token in }\mathrm{T\_Y}\text{>\<remaining tokens in }\mathrm{T\_Y}\text{>}\ &=\text{foo}*{\text{token}}\text{\<expansion of \abc>}*\text{token list (characters)}\text{xyx}*\text{token}\ &=\text{foo}*\text{token}\text{Hello}*\text{token list (characters)}\text{xyx}*\text{token}\\\[10pt] \end{align\*}$$

請注意，下標 <sub>記號</sub> 以及 <sub>記號清單（字元）</sub> 是用來強調（提醒我們）TeX 讀取的是 *整數記號值*，而不是 *文字字元*，因此在 `\foo`：這類分隔符早已被處理或丟棄；此處我們已完全置身於 TeX 的內部世界——記號清單與整數記號值。

當 TeX 處理由我們的 `\\expandafter` 命令產生的記號清單序列時，它會排版出 `**H**ello, World!`——只有 `H` 會以粗體排版。我們也可以透過撰寫等效的 TeX 程式碼來達到相同結果 `\\foo Hello\\xyz`。請注意， `\foo` 的定義使用了單一參數；因此， `\foo` 會吸收單一的 `H` 作為其引數的字元記號，並將其餘字元記號（`ello`）保持不變。

**注意：**

* 撰寫 `\\foo\\bar` 會產生非常不同的輸出： `\\bar` 的記號會被用作……的引數 `\foo` ，其結果會排版出 **`Hello, World`**——所有內容都會以粗體排版。
* 撰寫 `\\expandafter\\foo\\bar` 會使 `\\bar` 被展開，並產生兩個記號： $$\text{abc}*\text{token}\text{xyz}*\text{token}$$。接著，在 $$\text{foo}*\text{token}$$ 被 `\\expandafter` TeX 處理該記號序列 $$\text{foo}*\text{token}\text{abc}*\text{token}\text{xyz}*\text{token}$$ 會以粗體排版。在這裡，單一記號 `**Hello**, World`——只有 **`Hello`** 會以粗體排版。在這裡，單一記號 $$\text{abc}*\text{token}$$ 會被當作巨集記號的引數來處理 $$\text{foo}*\text{token}$$，而保留記號 $$\text{xyz}\_\text{token}$$ 不變，並以目前字型排版其內容。

## 關於 \\\expandafter 與帶引數巨集的說明

當使用 `\\expandafter` 若要強制展開巨集，值得了解巨集展開的運作方式——尤其是會接受引數的巨集。在 TeX 能執行一個巨集之前——也就是讀取並處理巨集定義內所含的記號——TeX 需要先執行初始的巨集展開程序，讓巨集「準備執行」。如果某個巨集的定義包含參數的使用（`#1`, `#2`, ... `#9`），巨集展開程序的一部分就要求 TeX 掃描輸入，尋找由使用者提供的引數所構成的記號：那些引數記號會從輸入中被吸收（移除）。在巨集展開期間，TeX 會從輸入讀取並吸收記號，建立迷你記號清單，每個引數對應一個清單；當 TeX 執行巨集時，這些記號清單隨後會插入到巨集本體中的適當位置。巨集展開的最後一步，是讓 TeX 找到儲存在記憶體中的巨集定義，並安排讓那個位置成為 TeX 讀取下一組輸入記號的來源。當 TeX 開始讀取並處理那些記號，並將先前建立用來儲存引數的記號清單送入時，巨集執行便開始。

### 分隔符記號也會被吸收

如果原始巨集定義也使用了充當分隔符的記號，TeX 還必須將原始巨集定義與使用者對該巨集的使用（呼叫）進行比對，尋找並配對分隔符記號。一旦配對／找到之後，分隔符記號便會隨後被忽略，因為它們唯一的用途是充當「標點」，幫助 TeX 挑出並辨識出用來構成各個引數的實際記號。

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