> 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/54-what-is-a-tex-token-list.md).

# 什麼是 TeX token list

## 那麼，究竟什麼是「TeX token list」？

在一個 [上一篇文章](/latex/zh-tw/shen-ru-wen-zhang/53-what-is-a-tex-token.md)——也是本 [低階 TeX 技術系列的一部分](/latex/zh-tw/shen-ru-wen-zhang/01-a-new-series-of-articles-tex-tokens-and-related-concepts-but-why-and-how.md)——我們探討了 TeX 掃描您的 `.tex` 檔案以產生新 token 的過程：我們檢視了 TeX token 的基本性質，以及 TeX 如何建立它們（請參閱 [什麼是「TeX token」？](/latex/zh-tw/shen-ru-wen-zhang/53-what-is-a-tex-token.md)).

在這篇後續文章中，我們將探討 *token list*：它們是什麼，以及 TeX 引擎如何建立／使用它們。由於 token list 儲存在 TeX 內部深處，理解它們可能相當困難：這些細節對使用者是隱藏的——不過，如今若您使用 LuaTeX 進行較進階的程式設計，情況不一定總是如此。但目前，您可以開始把 token list 想成 TeX 儲存一連串整數值的方法，其中每個整數都是從 TeX 讀入檔案中的字元或指令衍生而來的 token。

Token list 在 TeX 的內部運作中扮演關鍵角色，常以一些令人意外的方式出現，例如下列指令的內部運作： `\uppercase` 和 `\lowercase`。Token list 有一項特別重要的用途，就是儲存及執行巨集；我們將在本系列未來的文章中詳細探討這個主題。

### TeX 從檔案與 token list 取得輸入

TeX 引擎有三種輸入來源——其中兩種您可能已經知道：

* 儲存在磁碟上的實體文字檔；
* 使用者在終端機（命令列）輸入的文字；

但它還有第三種讀取／取得輸入的方式：token list！

實際上，token list 是 TeX 在運作過程中使用的內部資料儲存機制。由於 TeX 的 token list 是先前建立之 token 的「儲存設施」，TeX 能將其重新用作另一個輸入來源也是合理的。當需要從某個特定 token list 取得下一個輸入（或 TeX 被指示這樣做）時，TeX 會暫停從實體檔案讀取輸入（亦即建立 *新 token*），並改為從 *既有 token*取得輸入：亦即儲存 token list 的記憶體位置。顯然地，對於 token list 而言，掃描與產生 token 的程序已經完成，因此 TeX 只需查看串列中的每個 token，並決定如何處理。

舉個簡單例子，低階的（TeX primitive） `\toks` 指令可讓您建立一個 token 串列，供 TeX 儲存在記憶體中以供日後重複使用：

```latex
\toks100={Hello}
```

若要取回這些 token（亦即告訴 TeX 將它們視為下一個輸入來源），您可使用如下指令

```latex
\the\toks100
```

這會使 TeX 從根據輸入檔建立新 token，切換成從這些 token（由 `\toks`）所建立的 token 儲存位置取得下一個輸入——位於所謂的 *token 暫存器* ，這只是 TeX 已知的一個內部記憶體位置（此處為暫存器 100）。

此外，許多 TeX 指令都能在執行時於內部產生 token list。範例之一是指令 `\jobname` ，它會產生一連串字元 token——TeX 正在處理的主檔案名稱中，每個字元各有一個 token。另一個例子是 `\string` 指令；例如

```latex
\string\mymacro
```

會針對名稱中的每個字母產生一連串字元 token `\mymacro`——包括開頭的 `\\` 字元。我們會在本文結尾更仔細檢視一些「產生 token 的指令」。

## Token list：以類比方式說明

除非您有程式設計背景及／或一些電腦科學知識，否則「token list」可能是有些模糊的概念，或許也有點令人困惑。不過，若您希望熟練撰寫 TeX／LaTeX 巨集，良好理解 TeX token、token list 與類別碼（`\catcode`）等主題將非常有用。

本節將用一個類比來解釋／說明 TeX token list 的核心概念／原理：TeX 如何在記憶體中儲存 token。值得花時間讀完，因為 token list 是 TeX 的 *基本* 面向，值得更深入地理解。

### Token list：一個類比（思想實驗）

我們將透過一個「思想實驗」來建立理解 TeX token list 的基礎。想像您能使用一大批容器，例如數百個鐵罐——我們不能使用「box」一詞來描述這個思想實驗中的容器，因為當然地，「box」在 TeX 中有非常特定的意義，與此處討論完全無關。因此，我們稱這些容器為「鐵罐」（Tin），每個鐵罐：

* 外部印有唯一的識別編號；
* （內部）分成兩個隔間。

這兩個隔間的設計如下：

* 左側隔間放置您要存入鐵罐的物品；
* 右側隔間設計為放置一張紙，您可以在上面寫一個數字：另一個鐵罐的識別編號。

![測試](/files/a32dcd7372189726ec72d445dd1c608820e0df42)

假設您有一組例如 5 個物品，並希望將這組物品存放在這些鐵罐中；但遺憾的是，每個鐵罐只能容納您要儲存類型中的 1 個物品。

為求簡化，假設我們要儲存 5 個彩色圓形：

![{{{alt}}}](/files/b289326b780c720b17936308b1d1b2c99f0042a5)

此外，當您回來從儲存系統（鐵罐）取回這些物品時，這些物品 *必須* 必須以特定順序取回／找到——也就是它們儲存時的順序：必須保留該序列。該如何做到？

我們可以利用每個鐵罐具有以下特性的事實：

* 外部附有唯一的識別編號；
* 有 2 個隔間——其中只有 1 個用於容納物品，另一個放著寫有另一個鐵罐編號的紙張。

我們假設每個鐵罐都是空的——但沒有任何事能阻止您打開任何一個特定鐵罐，檢查它是否為空；如果不是，就試下一個，直到找到空鐵罐為止。

我們可以這樣做：將第一個物品（深綠色圓形）放進其中一個鐵罐（例如鐵罐 124），並記下這個第一個鐵罐的編號——第一個鐵罐的編號是什麼並不重要，重要的是我們將其寫在某處並保留以供日後使用。

![{{{alt}}}](/files/77abbc78770527b9921c5c2155f1d5e8c8c942b7)

找一個第二個鐵罐——任何編號皆可（例如鐵罐 432）——並記下其編號。將第二個鐵罐的編號（432）寫在紙上，並將那張紙條放 *進第一個鐵罐* （鐵罐 124）。我們把第二個物品（淺綠色圓形）放入第二個鐵罐。因此，目前情況如下：

* 一張未存放在鐵罐中的紙條，寫著第一個鐵罐是 124 號（它裝有我們的第一個物品）；
* 在鐵罐 124 內，我們放入另一張紙條，說明下一個物品可在鐵罐 432 找到。

本質上，我們已經 *連結* 了前兩個鐵罐：我們知道從哪裡開始（鐵罐 124），而鐵罐 124 內的紙條會告訴我們哪個鐵罐裝著下一個物品（鐵罐 432）。

![{{{alt}}}](/files/8f24239df0b216c2f04a4649f79cec19fbdd54aa)

接著，我們找第三個鐵罐，將其編號（例如鐵罐 543）寫在紙上，並將紙放入 *第二個* 鐵罐（編號 432）。接著將第三個物品（紅色圓形）放進第三個鐵罐。

現在我們已依序連結三個鐵罐：起點鐵罐 124（深綠色圓形）→ 鐵罐 432（淺綠色圓形）→ 鐵罐 543（紅色圓形）→…

![{{{alt}}}](/files/914e448a0d1551def5127badeb4b8b95c102f83c)

針對最後兩個物品（淺藍與深藍圓形）重複此程序，使用鐵罐 213（淺藍圓形）與鐵罐 102（深藍圓形）。

![{{{alt}}}](/files/0d388dbdf02edd132694f63daf451c869818a43f)

現在我們已連結全部 5 個鐵罐（使用每個鐵罐的數字識別碼），只要依序造訪每個鐵罐、取出物品並查看告訴我們下一個物品所在鐵罐的紙條，就能以正確順序取回所有儲存的物品。

### 那麼串列中最後一個物品（鐵罐 102）呢？

為什麼我們要特別關注它？到目前為止，我們將每個物品放在鐵罐中，並附上一張紙條說明下一個物品在哪個鐵罐：但對於串列中的最後一個物品，那張紙條該寫什麼——因為不存在下一個鐵罐。

當我們到達最後一個物品（鐵罐）時，必須明顯知道這個鐵罐（裝著最後一個物品）是串列中的最後一項——我們不需要尋找另一個鐵罐，因為沒有另一個。一種做法是在最後一個鐵罐（102）中放入一個「特殊」的鐵罐編號。我們可使用任何數字，只要選擇一個不是真實鐵罐編號的唯一數字——例如「鐵罐 -1」、「鐵罐 0」：只要我們知道「鐵罐 -1」或「鐵罐 0」等會立刻告訴我們停止尋找即可：不需再找任何鐵罐，因為這是最後一個，也就沒有更多物品可取回。

### 從「物品」與「鐵罐」到 token 與 TeX

現在我們需要從類比轉向更接近 TeX 實際情況的描述。首先，與其在想像中的鐵罐儲存不同顏色的圓形，顯然我們可以把那些鐵罐想成儲存 TeX token：簡單的整數。這是將類比轉移到軟體（TeX）領域中較容易的部分。但帶有「隔間」的實體編號鐵罐，在軟體中的對應物可能是什麼？

我們不想過度深入程式設計概念，但您可將「鐵罐」想成代表幾個位元組的電腦記憶體，已被「封裝」成便利的儲存單位。我們類比中每個鐵罐使用數字識別碼，可視為每個小型記憶體封裝所處的電腦記憶體位置。在 TeX 本身中，這些小型儲存封裝稱為「memory words」——此術語反映了 TeX 建立的時代（1970 年代）。這些「memory words」是 TeX 內部使用的基本建構單元，但我們不需要在此進一步探討——希望瞭解更多細節的人可參閱一篇刊登於 [作者個人部落格](http://www.readytext.co.uk/?p=3537).

以電腦程式設計的術語來說，我們一直討論的是稱為 [*linked list*](https://en.wikipedia.org/wiki/Linked_list)的結構：TeX token list 是由稱為 *memory words* 的 TeX 儲存容器所建構的連結串列，其中每個 memory word 可用來儲存：

* a *值*：token 的值（一個整數）；
* a *連結*：記憶體中下一個 memory word 的位置，該 word 包含串列中的下一個 token。

## TeX 在哪裡使用 token list？

到處都是！這是因為 TeX／LaTeX 巨集定義（例如 LaTeX 指令）是以（一種略為特化的）token list 形式儲存——特化之處在於它包含一般 token list 看不到的 token（與比對巨集參數等相關）。不必擔心，未來文章會處理這些細節。

### 巨集範例

巨集可視為由三個部分組成：

```
\def\<macro name><parameter text>{<replacement text>}
```

請注意，除了 `\def` 之外，您也可以使用 `\edef`, `\gdef` 或 `\xdef`.

**給 LaTeX 使用者的注意事項**：此處我們使用原始、低階的 TeX 指令來定義巨集（稱為 *原始命令*）。LaTeX 使用者應更熟悉透過 LaTeX 的 `\newcommand` （其本身也是一個巨集）來建立巨集。

當您要求 TeX 建立（定義）一個巨集時，它會建立一個代表 `<巨集名稱>` 和一個 *token list* 的 token，其代表組合後的 `<參數文字>` 和 `<取代文字>`。TeX 會仔細儲存一切，使代表 `<巨集名稱>` 的 token 連結至代表其定義的 token list（`<參數文字>` 和 `<取代文字>`).

例如，如果我們定義 `\mymacro` 如下：

```latex
\def\mymacro abc #1 defz{I typed "#1"!}
```

我們可看到其組成部分為：

* `<巨集名稱>` = `mymacro`
* `<參數文字>` = `abc #1 defz`
* `<取代文字>` = `我輸入了「#1」！`

例如，您可呼叫 `\mymacro` 如下：

```latex
\mymacro abc THIS TEXT defz
```

其結果是 `我輸入了「THIS TEXT」！` 被排版出來—— `abc` 和 `defz` 已 *不* 被排版。 `abc` 和 `defz` 是用來 *界定* 巨集參數 `#1` 的字元 token 序列，且當 TeX 成功處理您的巨集呼叫時會被吸收並捨棄。

當您定義 `\mymacro`時，儲存內容中的 token 模式會作為一個「範本」，供 TeX 判斷：

* 輸入中的哪些 token 是分隔符 token；
* 輸入中的哪些 token 實際構成巨集的參數（此處即您用於 `#1` ，在您呼叫 `\mymacro`).

時）。您必須呼叫 `\mymacro` 取代，改成一個 `<參數文字>` ，且其所含分隔符必須與定義時使用的分隔符完全相同——包括使用具有相同類別碼的字元分隔符。若用於呼叫 `<參數文字>` 的 `\mymacro` 與定義它時使用的分隔符（儲存在記憶體中的「範本」）不同，TeX 可能會相當困惑——當它嘗試處理 `\mymacro` 時，便無法比對記憶體中儲存的「範本」。

當 TeX 看到您正在呼叫巨集時，它會掃描輸入文字以建立新 token，並嘗試逐一將其與 token list `<參數文字>` 範本比對；該範本儲存為巨集定義的一部分。若輸入文字中使用的分隔符產生一系列與「範本」中儲存者不相符的 token，TeX 通常會報錯。

TeX 非常嚴格——請記得字元 token 是字元碼與類別碼的組合：若您變更字元的類別碼，就會從該字元得到不同的 token 值。

假設我們將 `z` 的類別碼改為例如 12——通常是 11——並像這樣嘗試呼叫巨集：

```latex
\catcode`z=12
\mymacro abc THIS TEXT defz more text here...
```

這次將不會成功，因為 `z` 的類別碼已變更。您會看到如下錯誤：

```latex
失控的引數？
THIS TEXT defz
！段落在 \mymacro 完成前結束。
<再次讀取>
\par
第 22 行
```

當 TeX 讀取並掃描 `z` 中插入一個 `defz` 時，它無法辨識其構成 `\mymacro`的 `<參數文字>` 在輸入檔所使用的結尾。在看到那個錯誤的 `z` 之前，TeX 已正確比對前 3 個字元 `def` ，但是 `z` （類別碼為 12）會干擾 TeX 的掃描。假設 `z` 在我們 *定義* `\mymacro`時的類別碼為 11：這會使 token 值 256×11 + 122 = 2938 被儲存為 `\mymacro`定義的一部分（亦即儲存為「範本」的一部分）。不過，類別碼為 12 時， `z` 現在會產生 token 值 256×12 + 122 = 3194。因為從輸入讀入的 token 值（對於 `z`，值為 3194）不符合儲存的 `z`-token 所含的 `<參數文字>` token list 範本（值為 2938），TeX 會繼續掃描您的輸入。TeX 將繼續掃描巨集之後的文字（*此處有更多文字* …），尋找額外的 token——嘗試使儲存的範本與輸入中找到的 token 相符。它大概找不到正確的 token 模式，當 TeX「越過」輸入並錯誤讀取額外文字以建立額外 token 時便會出錯——那些額外 token 不應在此時讀取，且幾乎必定會產生錯誤。

我們會在未來文章中更詳細說明。

## Token list 的其他用途

其他用來建立／儲存 token list 的指令包括：

```latex
\toks<n>={...}
\everypar={...}
\everymath={...}
\everydisplay={...}
\everyhbox={...}
\everyvbox={...}
\output={...}
\everyjob={...}
\everycr={...}
\errhelp={...}
```

這些指令各自會根據大括號「{...}」內的字元與指令建立一個 token list，而該 token 串列會在某些情況下重複使用。例如， `\everypar={...}` 會建立並儲存一組 token（一個 token list），TeX 會在開始新段落之前立刻將其插入輸入中。

## Token list 的隱藏用途：範例

在最後一節，我們將看看一些實用範例，瞭解 token list 如何以您可能意想不到的方式使用。

### 範例 1：\uppercase{...} 與 \lowercase{....}——暫時 token list

除了明確產生 token list 的指令外，在某些情況中，TeX 會產生隱藏的暫時內部 token list 來進行特殊處理。請記得，當 TeX 讀取／處理輸入的字元／指令時，它們會轉換成 token：這是 TeX 引擎處理的基本建構單元。

一個很好的例子是指令 `\uppercase{...}` 或 `\lowercase{...}` ，因為初次接觸時，其運作方式可能相當令人困惑。一旦理解它們在 TeX 更深層、使用者看不見之處所做的事情，其運作就更容易理解。

假設您有一連串簡單的字母想轉為大寫——例如 abcde 轉成 ABCDE。使用 TeX 的 `\uppercase` 命令：

```latex
\uppercase{abcde}
```

會使 TeX 輸出 `ABCDE`。現在假設我們想將這串簡單字母儲存起來供日後使用——亦即不想立刻輸出它們，因此我們將使用 TeX 唯一的 *內部* 機制——不是外部（檔案）機制——來儲存資料：使用 token list。我們可透過建立巨集或使用明確的 token list 指令來做到：

```latex
\toks100={abcde}
\def\mychars{abcde}
```

接著，在某個時候，您可能決定想重複使用這串字母，但這次要轉為大寫；於是嘗試

```latex
\uppercase{\the\toks100}
```

和

```latex
\uppercase{\mychars}
```

但遺憾的是，兩者都無法運作。為什麼？

### 祕密 token list！

為了理解指令 `\uppercase{...}` `\lowercase{...}` 實際如何運作，我需要窺探 TeX 的內部機制，因此以下說明源自這項研究。

當 TeX 偵測到任一 `\uppercase{<material>}` 或 `\lowercase{<material>}` 出現在輸入中時，TeX 首先會從 `<material>` 建立一個（暫時的）內部 token list；它位於隨後的「{」與「}」之間 `\uppercase{...}` 或 `\lowercase{...}` 指令後方——該暫時 token list 屬於 TeX 內部。

一項關鍵要點，也是理解 `\uppercase{<material>}` 和 `\lowercase{<material>}` 實際運作方式的核心，是包含在 `<material>` 中的任何指令或巨集都不會 *展開*執行：TeX 所做的只是從置於 `{...}`之間的字元與指令產生 token。在執行 `\uppercase{<material>}` 或 `\lowercase{<material>}` 期間，大括號內的內容不會被執行：它只會被轉換成 token。

在 `<material>` 在 `{...}` 被轉換成（暫時）token list 後，TeX 會再次檢視該串列中的每個 token，並測試其是否為 *字元* 字元 *指令* token 或 `\uppercase` 或 `\lowercase` token（使用 token 的數值）。若 TeX 偵測到字元 token，便會修改該 token 以調整字元的大小寫（視乎正在處理

）。TeX 會完全忽略任何指令 token，也不會「深入查看」任何指令 token 以瞭解它們代表或包含什麼（例如包含字元的巨集）——它們會直接略過：只有字元 token 實際會受到大小寫轉換操作的處理／影響。 `\uppercase{abcde}` TeX 將從 `abcde` 建立一個只含字元 token 的 token list：它們全都會被調整，建立一連串代表 A、B、C、D 與 E 的修改 token。這些修改後的 token 會送回 TeX 的輸入處理器，結果是 `ABCDE` 被排版出來。然而，如果我們將字元儲存 *在巨集內*——例如 `\def\mychars{abcde}`——並嘗試像這樣將其轉為大寫：

```latex
\uppercase{\mychars}
```

那麼它將失敗，並且 abcde 會被排版——而非您可能預期的 ABCDE。若接著嘗試將字元儲存在像這樣的 token list 中 `\toks0={abcde}` 並執行 `\uppercase{\the\toks0}` 那麼，再一次， `\uppercase` 會失敗，因為 token list 將完全由不受 `\uppercase`.

影響的 token 構成。以巨集範例 `\mychars`為例，在 TeX 偵測到 `\uppercase` 出現在輸入中後，TeX 會查找 `\uppercase` 的意義並執行它，從 `{\mychars}`建立暫時 token list。顯然地，該暫時 token list 只有一個 token；它不是字元 token，而是代表巨集指令 `\mychars`的 token：因此，為執行 `\uppercase`之目的，該 token 會被忽略——`\mychars` 並不代表字元 token。然而，如上所述，一旦 `\uppercase` 完成工作，由 `\uppercase`的動作所建立的暫時 token list 會送回 TeX 完整的輸入處理（掃描）機制。當 TeX 重新讀取該 token list 時，它偵測到一個代表我們 `\mychars` 巨集的 token，TeX 便執行（展開）它，並產生一連串字元來排版 abcde——仍為小寫，因為它們被「包裝」在巨集內，因而對 `\uppercase`.

的動作不可見。 `\uppercase{...}` 或 `\lowercase{...}`一旦 TeX 重新檢查為

### 建立的暫時 token list，並處理所有字元 token，便會切換成使用該暫時 token list 作為輸入來源：排版字元（已處理的字元 token），並執行指令與巨集。

因為 `\uppercase{...}` 或 `\lowercase{...}` 由於只會作用於字元 token，我們需要一種方法，在 `\mychars` （或包含在 `\toks` 暫存器中）的字元受到 `\uppercase{...}` 或 `\lowercase{...}` 作用之前，「強制解包」巨集中的字元。所謂「解包」，實際上是指 TeX 的 *展開*:

* 以 *token* 序列取代一個 TeX／LaTeX 指令 *的程序，該指令* (*例如一個巨集*) *由其構成，* 或
* 產生一個指令設計用來 *生成*的 token 序列。會產生 token 的指令之一是 `\jobname`，它會產生一連串代表正處理之主 TeX 檔案名稱的字元 token。

#### 較低階的魔法：scantoks(..., ...)

此處我們確實正在探究 TeX 內部運作較幽暗的角落，除非您喜歡細節，否則可略過這一節……

在 TeX 偵測到 `\uppercase` 或 `\lowercase` 位於輸入串流後，它會執行一個名為 `scantoks(..., ...)` 的內部函式，其工作是根據開頭「{」與結尾「}」之間的項目產生 token list——如前所述，隨後會檢查該 token list，以偵測（然後調整）任何字元 token，從而按需要改變字元大小寫。請特別注意，我們將 `scantoks(..., ...)` 視為內建於 TeX 引擎原始碼的內部函式——此處並不是指控制序列的名稱。

作為其工作的一部分， `scantoks(..., ...)` 可被指示是否展開正在建構的 token list；而對於 `\uppercase` 與（`\lowercase`），它不會展開 token：只是建立它們並將其置入 token list。

其中一個首先要做的事情是， `scantoks(..., ...)` 必須檢查是否有開頭的「{」（或任何 `\catcode` 類別碼為 1 的字元），因為它必須確保使用者沒有犯語法錯誤而忘記開頭的「{」（或任何類別碼為 1 的字元）——因為需要類別碼為 1 的字元來界定要轉換為 token 的項目串列之開始。

而訣竅在這裡：尋找開頭「{」的工作會觸發 `scantoks(..., ...)` 執行 TeX 的展開程序，這表示以下範例將可運作：

```latex
\let\ob={
\uppercase\ob abcde}
\def\obb{\ob}
\uppercase\obb xyz}
```

以 `\obb`這個巨集為例，它會被辨識為一個 *可展開命令* ，並由 TeX（透過 `scantoks(..., ...)` 函式）在搜尋開頭大括號（任何類別碼為 1 的字元）時適當地展開。這表示我們可以使用「`\expandafter` 訣竅」來達成從巨集限制中「解包」字元的目標——亦即展開它。請注意， `\expandafter` 也屬於 *可展開命令*的類別，因此 TeX 會在這裡執行它，讓它在尋找開頭「{」（或任何類別碼為 1 的字元）的過程中完成工作。

因此，若您定義：

```latex
\toks0={abcde}
\def\mychars{abcde}
```

並執行：

```latex
\uppercase\expandafter{\mychars}
\uppercase\expandafter{\the\toks0}
```

在兩種情況下，您現在都會看到 ABCDE 被排版，因為 `\expandafter` 會使 `\mychars` 和 `\the\toks0`「解包」（展開）——兩者都會使 `\uppercase` 看到一個字元 token 串流，讓它們能處理以改變大小寫。

### 範例 2：\string——更多暫時 token list

在內部，TeX 將 `\string` 歸類為其所謂的「convert」指令之一：執行「轉換為文字」操作。 `\string` 這個指令的設計目的是將一個 token 轉換為人類可讀的文字版本——也就是把產生該 token 時原本用來建立它的可讀字元字串排版出來。

例如 `\string\hello` 會建立一個暫時的 token 清單，其中包含字元 \\, h, e, l, l, o——沒錯，甚至包含開頭的『\』。一旦建立了這個 token 清單，TeX 接著會重新讀取它，而指令「`\hello`」就會被排版出來——沒錯，如果你選擇正確的字型，甚至連『\』也會一起排版……

你或許會想，TeX 平常是用逃脫字元來觸發掃描器建立命令 token，為什麼它在這裡卻能把逃脫字元排版出來呢？答案與類別碼有關：通常，『\』字元的 catcode 是 0（逃脫字元），但當 `\string` 它產生內部 token 清單時，做法有些不同。當它建立一個字元 token 清單時，除了空白字元會被指定為 catcode 10 之外，所有字元都會被指定為類別碼 12——別忘了，字元 token 是由 256 × catcode + ASCII 值計算出來的。因此，當 TeX 重新讀入（輸入）那個暫時 token 清單時， `\string` 該清單是由 `\hello`所產生的，TeX *看不到逃脫字元* 因為『\』的 token 是用 catcode 12 而不是 0 計算出來的：TeX 只會把『\』當作一般字元並將其排版。

嚴格來說，我們或許應該指出，TeX 在輸入中偵測到逃脫字元時，實際上並不會為它產生一個 token。一旦它辨識出類別碼為 0 的字元，那個字元就只是用來「觸發」產生控制序列 token：一旦它已經觸發 TeX 這麼做，逃脫字元的工作就完成了，之後便不再被考慮。

### 技術說明

有一個名為 `\showtokens{...}` （由 e-TeX 引擎引入）可以顯示 token 清單（在記錄檔中）。摘自 e-TeX 手冊：

> 命令 `\showtokens{<token list>}` 會顯示 token 清單，並允許顯示那些無法由 `\show` 或 `\showthe`顯示的項目，例如：
>
> ```latex
> \showtokens\expandafter{\jobname}
> ```

## 總結

在 TeX 原始碼的第 291 節中（見 [《TeX：程式》](https://www.amazon.co.uk/Computers-Typesetting-TeX-Program-TEX/dp/0201134373)第 122 頁），Knuth 如下描述 token 清單：

> 「token 清單是 mem 中由單字節點構成的單向鏈結串列，其中每個字都包含一個 token 和一個連結。巨集定義、輸出例行程序定義、標記， `\write` 文字，以及其他少數幾項內容，TeX 會以 token 清單的形式記住，通常在前面先放一個節點，其 “token\_ref\_count” 欄位中有一個參照計數。」

初次讀到這段話時，也許不太容易理解，但希望現在會稍微比較有道理一些。


---

# 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/54-what-is-a-tex-token-list.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.
