> 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/vi/bai-viet-chuyen-sau/22-how-does-expandafter-work-the-meaning-of-expansion.md).

# \expandafter hoạt động như thế nào: Ý nghĩa của phép mở rộng

[Phần 1](/latex/vi/bai-viet-chuyen-sau/19-how-does-expandafter-work-an-introduction-to-tex-tokens.md) [Phần 2](/latex/vi/bai-viet-chuyen-sau/22-how-does-expandafter-work-the-meaning-of-expansion.md) [Phần 3](/latex/vi/bai-viet-chuyen-sau/21-how-does-expandafter-work-tex-uses-temporary-token-lists.md) [Phần 4](/latex/vi/bai-viet-chuyen-sau/20-how-does-expandafter-work-from-basic-principles-to-exploring-tex-s-source-code.md) [Phần 5](/latex/vi/bai-viet-chuyen-sau/17-how-does-expandafter-work-a-detailed-macro-case-study.md) [Phần 6](/latex/vi/bai-viet-chuyen-sau/18-how-does-expandafter-work-a-detailed-study-of-consecutive-expandafter-commands.md)

## Giới thiệu khái niệm “mở rộng” của TeX

Sau khi xem xét [các token của TeX và danh sách token](https://www.overleaf.com/learn/latex/Articles/\expandafter_TeX_tokens?preview=true), tiếp theo trong danh sách các chủ đề nền tảng cho `\expandafter` là khái niệm của TeX về *mở rộng*: quy trình cốt lõi của TeX `\expandafter` được thiết kế để làm việc với.

### Về thách thức khi giải thích sự mở rộng...

Đối với hầu hết chúng ta, khái niệm mở rộng của TeX và các lý do/cơ chế đằng sau nó có thể gây bối rối — chúng không dễ để *một cách đầy đủ* giải thích một cách đơn giản, ngắn gọn. Nhiều hoạt động/quá trình nội bộ của TeX liên hệ với nhau theo những cách khá phức tạp, điều này có thể tạo ra thách thức khi cố “mổ xẻ” một số khía cạnh trong hoạt động của TeX: tức là cố bàn về chúng tách rời khỏi toàn bộ chương trình. Mở rộng chắc chắn là một khái niệm thuộc loại đó vì nó là một *cơ bản* yếu tố trong hành vi của TeX, và được gắn sâu xuyên suốt các quá trình nội bộ của TeX. Tuy nhiên, bài viết này cố gắng xây dựng một lời giải thích về mở rộng, cung cấp một nền tảng để người đọc có thể phát triển thêm.

Để giải thích cơ chế mở rộng của TeX, chúng ta sẽ tiến từng bước, khảo sát một loạt chủ đề liên quan/có liên hệ, rồi ghép chúng lại để phát triển sự hiểu biết về yếu tố then chốt này trong hành vi của TeX. Về sau trong bài viết, và dành cho những độc giả ưa chi tiết và thích khám phá hơn, chúng ta sẽ nhìn vào bên trong chính TeX, tóm tắt mã nguồn then chốt điều khiển quá trình mở rộng.

### Những điểm chính về các token của TeX

Trong suốt phần thảo luận sau đây, cần nhớ rằng TeX có thể lấy mục đầu vào tiếp theo của nó từ hai nguồn:

1. **các tệp văn bản vật lý**: tạo ra *các token mới* bằng cách đọc/quét các ký tự và lệnh trong các tệp đó, hoặc
2. **danh sách token**: nhận đầu vào bằng cách đọc từ một danh sách các *được chuẩn bị sẵn*, các token được lưu trong bộ nhớ của TeX.

Ngoài ra, hãy nhớ rằng TeX dùng token như một cách thuận tiện để “đóng gói” gọn gàng thông tin về bất kỳ mục nào (ký tự hay lệnh) mà nó đã đọc vào.

Khi TeX đang tạo ra *các token mới* nó sẽ, *ngay tại thời điểm tạo token*, có quyền truy cập ngay lập tức vào thông tin về mục mà nó đang tính giá trị token của nó. Ví dụ, khi tạo ra các token lệnh mới, TeX trước tiên tính một giá trị gọi là `curcs` cho phép TeX tra cứu thông tin về lệnh mà nó sắp tạo token.

Tuy nhiên, nếu TeX đang đọc từ các danh sách token (chuỗi của *các token được lưu*) thì trước tiên nó sẽ cần “giải đóng gói” bất kỳ token nào trong danh sách đó trước khi có thể xác định mỗi token đại diện cho điều gì. Ví dụ, TeX có thể đang đọc các token được lưu như một phần của định nghĩa macro: những token đó đã được tạo ra từ văn bản đã được đọc vào từ lâu, chuyển thành token và cất đi. Loại token (ký tự hay lệnh) quyết định việc “giải đóng gói” của TeX thực sự có nghĩa là gì:

* cho *token lệnh* (giá trị token > 4095): tính `curcs` qua $$\text{curcs}=\text{token value}-4095$$ và dùng `curcs` để tra cứu thông tin về lệnh;
* cho *token ký tự* (giá trị token < 4095): tách token ký tự thành cặp thành phần của nó gồm (mã ký tự, mã loại).

### Ban đầu...

Để bắt đầu khám phá về mở rộng, chúng ta sẽ xem cách các engine TeX phân loại, hay xếp loại, tập hợp các lệnh mà chúng có thể xử lý. Tạm thời, hãy giả sử rằng “có thể mở rộng” chỉ đơn giản là một “thuộc tính” nào đó của một lệnh TeX, chưa được giải thích.

### Khái niệm về các lệnh “có thể mở rộng”

Tất cả các chương trình dàn trang dựa trên TeX (các “engine” TeX) đều hiểu hai “lớp” lệnh chính:

* các lệnh được tích hợp sẵn ngay trong chính engine thực thi: cái gọi là *các nguyên thủy*;
* các lệnh do người dùng định nghĩa: cái gọi là *macro*.

Các engine TeX cũng sử dụng “tính có thể mở rộng”, một kiểu “hành vi” của lệnh, như một cơ chế để phân loại tất cả các lệnh thành hai nhóm:

* các lệnh có thể mở rộng;
* các lệnh không thể mở rộng.

Vì vậy, ta có thể xem tập hợp tất cả các lệnh (primitive cộng macro) được phân loại như trong hình sau:

![Sơ đồ cho thấy cách phân loại tất cả các lệnh TeX](/files/7a25b0257275e477afbae555ba384ce6a5fb579d)

Mặc dù ta هنوز chưa biết mở rộng/có thể mở rộng thực sự có nghĩa là gì, nhưng có thể thấy rằng:

* tất cả macro đều được phân loại là các lệnh có thể mở rộng;
* một số lệnh nguyên thủy (tích hợp sẵn) cũng được phân loại là có thể mở rộng (đa số thì không).

**Lưu ý về các ký tự hoạt động**: Ngoài các primitive và macro, còn có một lớp thứ ba của mục “có thể mở rộng”: các ký tự hoạt động — bất kỳ ký tự nào được gán mã loại 13 cũng được xem là “có thể mở rộng” vì chúng được xử lý như những “macro thu nhỏ”.

#### TeX làm sao biết một lệnh có “có thể mở rộng” hay không?

Từ [thảo luận của chúng ta về các token của TeX](https://www.overleaf.com/learn/latex/Articles/\expandafter_TeX_tokens?preview=true) chúng ta biết rằng token không gì khác hơn là các số nguyên mà TeX tính toán và dùng để “đóng gói” thông tin về một mục đầu vào: một ký tự hoặc một lệnh. Chúng ta cũng đã lưu ý rằng, với bất kỳ giá trị token (số nguyên) nào, TeX có thể, nếu/khi cần, đảo ngược quá trình tạo token để “giải đóng gói” một token và làm lộ dữ liệu về lệnh hoặc ký tự mà nó đại diện.

Sử dụng dữ liệu được tạo ra khi TeX tạo một token mới, hoặc dữ liệu được trích ra từ một token hiện có — ví dụ, một token được lưu trong macro hay danh sách token khác — TeX có thể kiểm tra các bảng lưu trữ dữ liệu nội bộ của nó để tìm thông tin chi tiết về lệnh (hoặc ký tự) được token đó biểu diễn. Hình sau tóm tắt quá trình tạo một token lệnh (“đóng gói”) rồi, khi TeX cần một số thông tin, đảo ngược quá trình đó (“giải đóng gói” token) để lấy dữ liệu về lệnh được biểu diễn bởi một giá trị token cụ thể.

![Sơ đồ cho thấy cách TeX đóng gói/giải đóng gói các token](/files/77475b00b745f1f635f8c7def577eba7495295da)

### Mã lệnh

Một phần thông tin mà TeX lưu về mỗi lệnh (primitive hay macro) là thứ gọi là *mã lệnh*: một giá trị nguyên mà các engine TeX sử dụng (nội bộ) để phân loại các lệnh — những lệnh có hành vi/chức năng tương tự sẽ dùng chung một mã lệnh.

**Lưu ý**: Đối với một *không hoạt động*, ký tự *mã loại* mã lệnh của nó là

Dưới đây là một vài ví dụ về mã lệnh:

* `\hbox`, `\vbox`, `\vtop`, `\vcenter`, `\box` (và các lệnh khác) đều được phân loại là lệnh “tạo hộp” và dùng chung mã lệnh 20;
* `\def`, `\edef`, `\gdef`, `\xdef` đều là các lệnh “định nghĩa macro” và dùng chung mã lệnh 97;
* tất cả macro đều được phân loại với một trong các mã lệnh 111, 112, 113 hoặc 114: các mã lệnh khác nhau được xác định bởi việc dùng `\long` hoặc `\outer` khi định nghĩa macro:
* 111: mã lệnh cho một macro không dài, không outer (ví dụ, `\def\foo{...}`)
* 112: mã lệnh cho một macro dài, không outer (ví dụ, `\long\def\foo{...}`)
* 113: mã lệnh cho một macro không dài, outer (ví dụ, `\outer\def\foo{...}`)
* 114: mã lệnh cho một macro dài, outer (ví dụ, `\long\outer\def\foo{...}`)

TeX cũng dùng mã lệnh để xác định tập hợp con của các lệnh được phân loại là “có thể mở rộng”. Để làm vậy, TeX gán cho các lệnh có thể mở rộng các giá trị mã lệnh vượt quá ngưỡng 100 (giá trị được Knuth’s original TeX, e-TeX và pdfTeX dùng). Do đó:

* *không thể mở rộng* các lệnh (đa số) có mã lệnh <= 100
* *có thể mở rộng* các lệnh có mã lệnh > 100

Do đó, nếu TeX tra cứu chi tiết của một lệnh cụ thể và phát hiện mã lệnh > 100, TeX lập tức biết đó là lệnh có thể mở rộng. Tất cả macro và một số ít primitive (lệnh tích hợp sẵn) được gán một mã lệnh cho biết chúng có thể mở rộng: nhưng tại sao TeX lại phải bận tâm với việc phân loại “có thể mở rộng” này? Như bạn có thể đoán, điều đó đơn giản có nghĩa là những lệnh đó có phần “đặc biệt”; tức là, chúng có thể chịu tác động của quá trình *mở rộng*.

**Lưu ý (ký tự)**: Trừ khi một ký tự đã được định nghĩa là hoạt động (mã loại 13), tất cả các ký tự đều không thể mở rộng. Các ký tự hoạt động có thể được coi là “macro một ký tự”.

## Vâng, vâng nhưng mở rộng là gì???

Chúng ta đã lưu ý rằng các giá trị token lớn hơn 4095 được dùng để biểu diễn các lệnh; do đó, TeX có thể, nếu/khi cần, “giải đóng gói” token đó để truy cập thông tin về lệnh TeX được token ấy biểu diễn. TeX có thể tra cứu giá trị mã lệnh của lệnh đó để xác định xem nó có thuộc vào loại đặc biệt là có thể mở rộng hay không. Nhưng TeX làm gì với thông tin đó và “có thể mở rộng”, tức là sự mở rộng, *thực sự có nghĩa là*?

### Mở rộng: Một thuật ngữ chung cho một tập hợp các thao tác

Tại một số điểm trong quá trình xử lý của TeX, nó cần biết liệu một token có đại diện cho một lệnh có thể mở rộng hay không:

* **Không**: Nếu token lệnh đó *không* không thuộc loại có thể mở rộng, TeX sẽ đơn giản “chuyển tiếp” nó sang giai đoạn xử lý tiếp theo.
* **Có**: Nếu token lệnh đó *thì* thuộc loại có thể mở rộng, bạn có thể hiểu là TeX cần thực hiện một hành động dẫn đến việc “lọc bỏ” token cụ thể đó bằng cách thực hiện một quá trình mà TeX gọi là “mở rộng token đó”, hoặc thực hiện mở rộng.

Về bản chất, mở rộng bao gồm việc TeX *loại bỏ* token đó ra khỏi đầu vào của nó và *thay thế* thay thế nó

bằng các token phát sinh từ “quá trình mở rộng” đặc thù của lệnh đó hoặc của nhóm lệnh dùng chung cùng một mã lệnh. Cần luyện tập và kinh nghiệm để biết khi nào TeX đang, và không đang, thực hiện mở rộng token — trang 215 của The TeXbook liệt kê các tình huống mà token có thể mở rộng sẽ không được mở rộng. Thực tế là quá trình TeX thực hiện mở rộng rất phức tạp và tinh tế.

#### Những lệnh nào có thể mở rộng?

Nếu bạn xem một danh sách các lệnh nguyên thủy (tích hợp sẵn) mà các engine TeX phân loại là có thể mở rộng (ví dụ các trang 212–215 của The TeXbook), thì sẽ thấy rõ rằng trên thực tế, mở rộng là một thuật ngữ khá chung mà TeX dùng để mô tả hành vi của một nhóm lệnh khá đa dạng. Kết quả của việc mở rộng một lệnh (có thể mở rộng) cụ thể thì khác nhau, và ta có thể thấy điều đó bằng cách liệt kê một tập hợp các lệnh có thể mở rộng — được nhóm theo chức năng của chúng. Ý nghĩa chính xác của từng lệnh riêng lẻ không quan trọng ở đây; điều đáng quan tâm hơn cả là các hệ quả chung từ hành động của chúng — việc mở rộng của chúng thực sự *thực hiện hoặc đạt được*.

| **Lệnh**                                                                                                                                                                                                                                                                                                                                                                                                                                                                   | **Mô tả**                                                                                                                                                          | **Hành vi mở rộng**                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| <ul><li>tất cả macro</li></ul>                                                                                                                                                                                                                                                                                                                                                                                                                                             | Một chuỗi token lệnh/ký tự được lưu                                                                                                                                | <p>Trên thực tế, mở rộng macro có nghĩa là chèn một danh sách token để TeX đọc. Điều này bao gồm:</p><ul><li>tạo các danh sách token cho mọi đối số macro — quá trình đó bao gồm việc xác định/hấp thụ các token phân cách;</li><li>truy xuất một danh sách token được lưu (định nghĩa macro) và chuẩn bị chèn (vào định nghĩa macro) các token tham số được tạo ra ở bước đầu tiên.</li></ul><p>Về cơ bản, mở rộng macro <em>loại bỏ token macro</em> khỏi đầu vào và <em>thay thế nó</em> bằng các token chứa trong định nghĩa.</p> |
| <ul><li><code>\expandafter</code></li></ul>                                                                                                                                                                                                                                                                                                                                                                                                                                | Thay đổi thứ tự mở rộng                                                                                                                                            | Lọc/xáo trộn token                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| <ul><li><code>\noexpand</code></li></ul>                                                                                                                                                                                                                                                                                                                                                                                                                                   | Ngăn chặn mở rộng (vâng, ngạc nhiên là nó được phân loại là một lệnh có thể mở rộng)                                                                               | Trì hoãn mở rộng (kiểu như lọc token)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| <ul><li><code>\input</code>, <code>\endinput</code>, <code>\scantokens</code></li></ul>                                                                                                                                                                                                                                                                                                                                                                                    | Liên quan đến việc nạp một nguồn token mới qua các tệp nguồn — vâng, `\scantokens` thuộc mục này do việc nó dùng cái gọi là “tệp giả”                              | Đóng vai trò là nguồn token mới                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| <ul><li><code>\if</code>, <code>\ifcat</code>, <code>\ifnum</code>, <code>\ifdim</code>, <code>\ifodd</code>, <code>\ifvmode</code>, <code>\ifhmode</code>, <code>\ifmmode</code>, <code>\ifinner</code>, <code>\ifvoid</code>, <code>\ifhbox</code>, <code>\ifvbox</code>, <code>\ifx</code>, <code>\ifeof</code>, <code>\iftrue</code>, <code>\iffalse</code>, <code>\ifcase</code>, <code>\ifdefined</code>, <code>\ifcsname</code>, <code>\iffontchar</code></li></ul> | Bắt đầu một biểu thức điều kiện                                                                                                                                    | Bắt đầu “lọc” token: quyết định xử lý những token nào sau đây.                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| <ul><li><code>\fi</code>, <code>\or</code>, <code>\else</code></li></ul>                                                                                                                                                                                                                                                                                                                                                                                                   | Kết thúc một biểu thức điều kiện                                                                                                                                   | Dừng “lọc” token: quyết định xử lý những token nào                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| <ul><li><code>\csname</code>… <code>\endcsname</code></li></ul>                                                                                                                                                                                                                                                                                                                                                                                                            | Tạo/xây dựng một token lệnh                                                                                                                                        | Chuyển đổi một chuỗi token thành một token lệnh duy nhất                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| <ul><li><code>\number</code>, <code>\romannumeral</code>, <code>\string</code>, <code>\meaning</code>, <code>\fontname</code>, <code>\jobname</code>, <code>\eTeXrevision</code></li></ul>                                                                                                                                                                                                                                                                                 | Chuyển đổi một thứ gì đó thành một chuỗi token                                                                                                                     | Tạo ra một số token (đại diện cho một lượng hay giá trị nội bộ)                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| <ul><li><code>\the</code>, <code>\unexpanded</code>, <code>\detokenize</code></li></ul>                                                                                                                                                                                                                                                                                                                                                                                    | `\the` có nhiều cách dùng, bao gồm chèn token; `\detokenize` chuyển một danh sách token thành một danh sách các token ký tự; `\unexpanded` ngăn token được mở rộng | Chèn/tạo một số token hoặc điều khiển việc mở rộng                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| <ul><li><code>\topmark</code>, <code>\firstmark</code>, <code>\botmark</code>, <code>\splitfirstmark</code>, <code>\splitbotmark</code>, <code>\topmarks</code>, <code>\firstmarks</code>, <code>\botmarks</code>, <code>\splitfirstmarks</code>, <code>\splitbotmarks</code></li></ul>                                                                                                                                                                                    | Các lệnh để truy cập các danh sách token có công dụng chuyên biệt                                                                                                  | Truy cập một nguồn các token được lưu (danh sách token)                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |

Dựa trên danh sách ở trên, có thể rút ra được những “hành vi chung” nào từ tập hợp các lệnh này — để tinh chỉnh thêm sự hiểu biết của chúng ta về mở rộng? Gần đúng mà nói, kết quả của việc mở rộng một lệnh rơi vào vài hoạt động then chốt:

* tạo token
* chèn token
* lọc token
* thay đổi/điều khiển việc mở rộng của token tiếp theo

### Và cuối cùng: ý nghĩa của mở rộng?

Ta có thể xem việc mở rộng một token lệnh (bao gồm cả ký tự hoạt động) là việc TeX **loại bỏ** token lệnh đó ra khỏi đầu vào và **thay thế** thay thế token đó bằng các token khác phát sinh từ hành vi mở rộng của nó: tạo/chèn token, lọc token hoặc thay đổi/điều khiển việc mở rộng của token tiếp theo. Khi một token đã được mở rộng, TeX sẽ tiếp tục đọc/xử lý mọi token có thể phát sinh từ quá trình mở rộng. Chính xác khi nào hoặc ở đâu TeX sẽ thực hiện mở rộng là một câu hỏi rất khác: do những sắc thái và độ phức tạp của quá trình xử lý TeX, đây là điều mà chúng ta không thể hy vọng giải quyết đầy đủ trong bài này, nhưng chúng ta có thể cung cấp một cái nhìn tổng quan về hành vi xử lý đầu vào chính của TeX.

## Mở rộng và cấu trúc của TeX

Có lẽ, cách tốt nhất để thấy TeX phân biệt giữa các lệnh có thể mở rộng và không thể mở rộng là xem mã nguồn của TeX.

Bên trong, TeX là một phần mềm cực kỳ phức tạp; do đó, việc cố gắng mô tả đầy đủ vô số hành vi tinh vi vốn có trong hoạt động của TeX là không thực tế. Như đã nói, chính xác khi nào hoặc ở đâu TeX thực sự sẽ thực hiện mở rộng khi nó đọc các token là “khá phức tạp”; vì vậy, phần thảo luận sau đây giả định TeX đang ở trạng thái cần diễn ra quá trình mở rộng. Những tình huống mà TeX sẽ đọc/tạo token nhưng không thực hiện mở rộng bao gồm việc tạo/lưu token cho `\def` macro-định nghĩa hoặc lưu token trong một `\toks` thanh ghi.

Sơ đồ sau đây đưa ra một cái nhìn tổng quan đơn giản hóa về các phần cốt lõi trong cấu trúc của TeX liên quan đến việc nhập và xử lý token: mục tiêu là làm nổi bật cách các token có thể mở rộng và không thể mở rộng được “lọc” trong quá trình xử lý đầu vào của TeX. Ngôn ngữ lập trình C được dùng để mô tả các hàm then chốt khác nhau, nhưng hy vọng rằng cấu trúc cơ bản vẫn sẽ rõ ràng ngay cả khi bạn không quen với ngôn ngữ C.

![](/files/7f33005416a2d4c674c9c43f60361bdc658b8a60)

### Giải thích sơ đồ cấu trúc TeX

Khái quát, việc xử lý của TeX được điều khiển bởi một hàm gọi là `maincontrol()` mà trong mã nguồn TeX, Knuth gọi là “chief executive” và mô tả như sau:

> “Bây giờ ta đến `maincontrol` routine, vốn chứa công tắc chính làm cho mọi bộ phận khác nhau của TeX thực hiện công việc của chúng, theo đúng thứ tự… đây là đỉnh điểm lớn của chương trình… Giờ đây ta đang ở trung tâm của mạng nhện, hệ thần kinh trung ương chạm đến phần lớn các bộ phận khác và gắn kết chúng lại.”

Mô tả sau đây được đơn giản hóa đôi chút nhưng cho ta một “cảm nhận” về cấu trúc nền tảng của phần mềm dựa trên TeX: cách các lệnh có thể mở rộng và không thể mở rộng được xác định (“chặn lại”) và lọc bỏ trong quá trình xử lý đầu vào của TeX.

Về bản chất, trong giai đoạn xử lý đầu vào sớm nhất của TeX, nó dùng giá trị mã lệnh của lệnh hiện tại (token) để phát hiện các lệnh có thể mở rộng (macro, primitive có thể mở rộng và ký tự hoạt động); nếu phát hiện một lệnh như vậy, các lệnh đó sẽ bị “chặn lại” và được “tiền xử lý” — bằng cách mở rộng. Thông qua quá trình lọc (mở rộng) này, TeX loại bỏ các lệnh có thể mở rộng khỏi đầu vào và thay thế chúng bằng các token phát sinh từ hành vi mở rộng tương ứng của chúng. Khi quá trình mở rộng hoàn tất, TeX sẽ đọc mọi token được tạo ra từ việc mở rộng đó. Chỉ những mục không thể mở rộng mới được chuyển tiếp sang giai đoạn xử lý tiếp theo của TeX: “big switch” nơi TeX sẽ thực thi tất cả các lệnh nguyên thủy không thể mở rộng và dàn chữ các ký tự.

### Hiểu maincontrol()

Tính năng `maincontrol()` hàm chứa một [câu lệnh switch](https://en.wikipedia.org/wiki/Switch_statement)khổng lồ — Knuth gọi nó là “big switch” — mà TeX dùng để thực thi tất cả *không thể mở rộng* các lệnh nguyên thủy: những lệnh có mã lệnh <=100.

Để thực thi một lệnh (hoặc ký tự) cụ thể, câu lệnh “big switch” này sử dụng sự kết hợp giữa chế độ hiện tại của TeX:

* chế độ dọc nội bộ/ngoài, hoặc
* chế độ ngang hạn chế/đoạn văn, hoặc
* chế độ toán học hiển thị/toán học

*cộng với* giá trị của mã lệnh cho mỗi primitive hoặc ký tự — mã lệnh của một *không hoạt động* ký tự là *mã loại* giá trị của nó. Ghi lại rằng, cả 6 chế độ của TeX đều được gán một giá trị nguyên có thể dùng bởi TeX để lưu và khôi phục chế độ hiện tại khi nó chuyển đổi giữa việc dàn trang các cấu trúc khác nhau — toán học, đoạn văn, hộp, v.v. Sau đây là các số nguyên được gán cho các chế độ khác nhau của TeX:

|                               |                                                 |                    |
| ----------------------------- | ----------------------------------------------- | ------------------ |
| **Chế độ**                    | **Ý nghĩa**                                     | **Giá trị chế độ** |
| Dọc ngoài                     | Giữa các đoạn văn (dựng trang)                  | 1                  |
| Dọc trong                     | Ngay bên trong một `\vbox{...}`                 | -1                 |
| Ngang                         | Khi dàn trang/xây dựng các đoạn văn             | 102                |
| Ngang hạn chế                 | Ngay bên trong một `\hbox{...}`                 | -102               |
| Toán học hiển thị             | Dàn trang *hiển thị* các phương trình/công thức | 203                |
| Toán học nội dòng (công thức) | Dàn trang *nội dòng* các phương trình/công thức | -203               |

Lưu ý việc dùng các giá trị âm cho phần bù của các chế độ khác nhau, chẳng hạn giữa dọc trong và dọc ngoài. Khi xử lý các lệnh trong `maincontrol()`, TeX dùng giá trị tuyệt đối của chế độ hiện tại — tức là bỏ qua dấu âm. Vì vậy, chẳng hạn, nếu TeX đang ở một trong hai chế độ ngang và cần xử lý một ký tự có mã loại 11, nó sẽ dùng tổng $$102 + 11 = 113$$ trong “big switch” của mình để rẽ sang mã xử lý những ký tự đó trong một trong hai chế độ ngang (xây dựng đoạn văn hoặc bên trong một `\hbox`).

#### Lấy token tiếp theo

Tính năng `maincontrol()` hàm gọi hàm `getxtoken()` để lấy token đầu vào tiếp theo; tiếp đó, `getxtoken()` gọi hàm nhập ở mức thấp nhất `getnext()`. Sau khi `getnext()` đã hoàn thành công việc của nó, và đặt giá trị của các *biến toàn cục*, `getxtoken()` kiểm tra xem mục vừa đọc vào có phải là một macro hay một primitive có thể mở rộng hay không.

Một vài ghi chú về `getnext()` và `getxtoken()`:

* **`getnext()`**: đây là hàm nhập cốt lõi của TeX. Nó đọc và xử lý các ký tự đầu vào từ một tệp vật lý hoặc đọc các token từ một danh sách token. Lưu ý rằng `getnext()` không thực sự tính giá trị token nhưng nó có đặt một số *toàn cục* biến (ví dụ, mã lệnh và `curcs`mã loại) được dùng về sau trong quá trình xử lý.
* **`getxtoken()`**: “get expanded token” dùng `getnext()` để đọc mục đầu vào tiếp theo. Sau đó nó kiểm tra mã lệnh của mục vừa đọc để xem mục đó có phải là một lệnh có thể mở rộng hay không: nếu có, nó sẽ được mở rộng hoặc macro sẽ được gọi. Với các mục không thể mở rộng, `getxtoken()` tính giá trị token và những chi tiết này được chuyển sang giai đoạn xử lý tiếp theo: “big switch” nơi các primitive không thể mở rộng được thực thi và các ký tự được dàn chữ.

Về cơ bản, chính thông qua `getxtoken()` mà tất cả các mục có thể mở rộng đều được “lọc ra” trước khi chúng được xử lý trong `maincontrol()`: điều này khiến “big switch” của TeX chỉ xử lý các lệnh nguyên thủy không thể mở rộng.

Một lần nữa, chúng ta nhấn mạnh rằng sơ đồ trên chỉ là một sự đơn giản hóa vì các khu vực khác trong quá trình xử lý của TeX cũng sẽ khiến token được mở rộng; chẳng hạn:

* khi TeX đang tìm (quét) các giá trị số, nó sẽ kích hoạt việc mở rộng trong quá trình tìm số nguyên (bằng cách gọi `getxtoken()`) ;
* lệnh nguyên thủy `\romannumeral` gây ra việc mở rộng — xem bài viết [Mở rộng bằng `\romannumeral`](https://www.texdev.net/2011/07/05/expansion-using-romannumeral/) để thấy cách dùng tinh tế của điều đó;
* Tính năng `\edef` (“expanded definition”) lệnh định nghĩa macro buộc mở rộng hoàn toàn;
* TeX sẽ mở rộng token tại một số điểm khi xử lý phần tiền đề của một `\halign` hoặc `\valign` (cả hai lệnh đều liên quan đến các thuật toán dàn bảng của TeX).

[Phần 1](/latex/vi/bai-viet-chuyen-sau/19-how-does-expandafter-work-an-introduction-to-tex-tokens.md) [Phần 2](/latex/vi/bai-viet-chuyen-sau/22-how-does-expandafter-work-the-meaning-of-expansion.md) [Phần 3](/latex/vi/bai-viet-chuyen-sau/21-how-does-expandafter-work-tex-uses-temporary-token-lists.md) [Phần 4](/latex/vi/bai-viet-chuyen-sau/20-how-does-expandafter-work-from-basic-principles-to-exploring-tex-s-source-code.md) [Phần 5](/latex/vi/bai-viet-chuyen-sau/17-how-does-expandafter-work-a-detailed-macro-case-study.md) [Phần 6](/latex/vi/bai-viet-chuyen-sau/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/vi/bai-viet-chuyen-sau/22-how-does-expandafter-work-the-meaning-of-expansion.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.
