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

# \expandafter hoạt động như thế nào: Một nghiên cứu chi tiết về các lệnh \expandafter liên tiếp

&#x20;[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)&#x20;

## Tình huống nghiên cứu: Hiểu \expandafter\expandafter\expandafter...

Các macro nâng cao, chẳng hạn như những macro có trong các gói LaTeX, thường sử dụng rộng rãi nhiều `\expandafter` lệnh liên tiếp để thực hiện việc “điều phối” token tinh vi. Với hầu hết chúng ta, những macro như vậy có thể khó hiểu hoặc khó viết. Trong phần này, chúng ta sẽ xem lại cơ chế nền tảng đằng sau việc TeX xử lý các `\expandafter` lệnh:

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

Để hỗ trợ lời giải thích, chúng ta sẽ thêm chỉ số dưới vào mỗi `\expandafter`—để chỉ rõ chúng ta đang nói đến cái nào:

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

Ngoài ra, chúng ta sẽ mở rộng ký hiệu cho các token được xử lý bởi mỗi `\expandafter` để dùng $$\mathrm{T^i\_1}$$ và $$\mathrm{T^i\_2}$$ đại diện cho các token $$\mathrm{T\_1}$$ và $$\mathrm{T\_2}$$ được đọc vào bởi `\expandafter` với chỉ số dưới `i`: `\expandafter`<sub>i</sub> $$\mathrm{T^i\_1T^i\_2}$$. Chúng ta cũng sẽ giả định rằng hai token $$\mathrm{T\_X}$$ và $$\mathrm{T\_Y}$$ theo sau `\expandafter<sub>3</sub>` để đầu vào của chúng ta trông như sau: `\expandafter<sub>1</sub>\expandafter<sub>2</sub>\expandafter<sub>3</sub>` $$\mathrm{T\_{X}T\_{Y}}$$.

Khi TeX bắt đầu xử lý đầu vào này, đối với `\expandafter<sub>1</sub>` nó sẽ thấy

* $$\mathrm{T^1\_1} =$$`\expandafter<sub>2</sub>` thứ được lưu lại để dùng sau *việc chèn lại* trở lại đầu vào
* $$\mathrm{T^1\_2} =$$`\expandafter<sub>3</sub>`, thứ được mở rộng

Nếu chúng ta quay lại phần thảo luận trước đó về [mã bên trong TeX](/latex/vi/bai-viet-chuyen-sau/20-how-does-expandafter-work-from-basic-principles-to-exploring-tex-s-source-code.md) mà thực thi `\expandafter`, thì chính với việc mở rộng `\expandafter<sub>3</sub>` mà ta thấy sự đệ quy diễn ra. Để xử lý `\expandafter<sub>1</sub>` TeX đã gọi hàm nội bộ của nó `expand()`, vì vậy để xử lý (mở rộng) `\expandafter<sub>3</sub>` TeX đang thực hiện một *lần thứ hai* lời gọi tới `expand()`—ngay bên trong `expand()` chính hàm đó.

Đối với `\expandafter<sub>3</sub>` ta có

* $$\mathrm{T^3\_1 = T\_X}$$, thứ được lưu lại để dùng sau *việc chèn lại* trở lại đầu vào
* $$\mathrm{T^3\_2 = T\_Y}$$, mà chúng ta sẽ giả định là có thể mở rộng

Hãy tiếp tục giả định rằng phần mở rộng của $$\mathrm{T\_Y}$$ cho ra chuỗi token sau: $$\mathrm{{T^1\_Y}{T^2\_Y}{T^3\_Y}}\cdots\mathrm{T^N\_Y}$$. Chúng ta giờ đã đi đến cuối quá trình mở rộng được bắt đầu bởi chuỗi lệnh `\expandafter<sub>1</sub>\expandafter<sub>2</sub>\expandafter<sub>3</sub>` $$\mathrm{T\_{X}T\_{Y}}$$ và TeX tiếp tục “gỡ ngược” quá trình đệ quy bắt đầu với `\expandafter<sub>1</sub>`.

Sau khi xử lý `\expandafter<sub>3</sub>` TeX có trong bộ nhớ một danh sách token chứa các token từ phần mở rộng của $$\mathrm{T\_Y\text{: }{T^1\_Y}{T^2\_Y}{T^3\_Y}}\cdots\mathrm{T^N\_Y}$$. TeX giờ bắt đầu chèn lại các token mà nó đã lưu trong khi xử lý `\expandafter` lệnh:

1. TeX bắt đầu bằng việc chèn lại token $$\mathrm{T\_X}$$ được lưu bởi `\expandafter<sub>3</sub>`. $$\mathrm{T\_X}$$ được chèn lại *ở trước* phần mở rộng của $$\mathrm{T\_Y}$$, điều này dẫn đến một chuỗi token: $$\mathrm{{{T\_X}T^1\_Y}{T^2\_Y}{T^3\_Y}}\cdots\mathrm{T^N\_Y}$$.
2. Tuy nhiên, chúng ta vẫn cần hoàn tất quá trình được bắt đầu bởi `\expandafter<sub>1</sub>` mà đã lưu token đại diện cho `\expandafter<sub>2</sub>`
3. Chuỗi token cuối cùng được TeX tập hợp, sẵn sàng để đọc ở giai đoạn tiếp theo trong quá trình xử lý của TeX là `\expandafter<sub>2 (token)</sub>` $$\mathrm{T\_{X}T^1\_{Y}T^2\_{Y}T^3\_{Y}\cdots T^N\_Y}$$
4. TeX giờ đã hoàn tất “vòng đầu tiên” của quá trình xử lý và chuyển sang đọc chuỗi các danh sách token mà nó đã tạo ra—chuỗi đó bắt đầu bằng `\expandafter<sub>2 (token)</sub>` mà TeX tiếp tục xử lý. Đối với `\expandafter<sub>2</sub>` ta có
   * $$\mathrm{T^2\_1} =\ \mathrm{T\_X}$$ thứ được lưu lại để dùng sau *việc chèn lại* trở lại đầu vào
   * $$\mathrm{T^2\_2} = \mathrm{T^1\_Y}$$ đây là token đầu tiên sinh ra từ việc mở rộng của $$\mathrm{T\_Y}$$; nếu có thể mở rộng, nó được mở rộng
5. Nếu chúng ta giả định token $$\mathrm{T^1\_Y}$$, token đầu tiên từ phần mở rộng của $$\mathrm{T\_Y}$$, mở rộng thành $$\mathrm{{T^A\_{Y1}}{T^B\_{Y1}}{T^C\_{Y1}}}$$ thì, sau khi TeX đã chèn lại $$\mathrm{T\_X}$$, chuỗi token thu được để TeX xử lý lại sẽ là: $$\mathrm{{T\_X}{T^A\_{Y1}}{T^B\_{Y1}}{T^C\_{Y1}}{T^2\_Y}{T^3\_Y}\cdots{T^N\_Y}}$$

   mà ta có thể diễn đạt lại là

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

Sơ đồ sau minh họa các danh sách token được tạo bởi mã TeX

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

![Hình minh họa TeX xử lý nhiều lệnh \expandafter](/files/a375a56762e683a9595267e21a2e8862e71d663b)

### Từ lý thuyết đến thực hành

Lấy một ví dụ, chúng ta sẽ định nghĩa các macro sau để đóng vai trò là $$\mathrm{T\_X}$$ và $$\mathrm{T\_Y}$$

* $$\mathrm{T\_X}=$$`\foo` trong đó chúng ta định nghĩa `\foo` là `\def\foo#1{\textbf{#1}}`
* $$\mathrm{T\_Y}=$$`\bar` trong đó trước tiên chúng ta định nghĩa `\def\abc{Hello}`, `\def\xyz{, World!}` và sau đó `\def\bar{\abc\xyz}`

Chúng ta sẽ dùng đoạn mã sau để minh họa phân tích trước đó của mình:

\expandafter\expandafter\expandafter\foo\bar

Từ phần thảo luận của chúng ta, kết quả của `\expandafter<sub>1</sub>\expandafter<sub>2</sub>\expandafter<sub>3</sub>` $$\mathrm{T\_X}\mathrm{T\_Y}$$ tạo ra một chuỗi token có dạng:

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

trong đó chuỗi chính xác phụ thuộc vào bản chất của token $$\mathrm{T\_Y}$$. Nếu chúng ta chèn các lệnh ví dụ của mình bằng $$\mathrm{T\_X}=$$`\foo` và $$\mathrm{T\_Y}=$$`\bar`, được định nghĩa là `\def\bar{\abc\xyz}`, ta thấy:

* token đầu tiên trong $$\mathrm{T\_Y}$$ là `\abc` và phần mở rộng của nó là một chuỗi các token ký tự: `Hello`
* các token còn lại trong $$\mathrm{T\_Y}$$ là token đơn lẻ đại diện cho `\xyz`.

Nếu đưa thông tin này vào phần “phân tích” của chúng ta, ta được

$$\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\*}$$

Lưu ý rằng các chỉ số dưới <sub>token</sub> và <sub>danh sách token (các ký tự)</sub> được dùng để nhấn mạnh (nhắc chúng ta) rằng TeX đang đọc *các giá trị số nguyên của token*, không phải *các ký tự văn bản*, do đó không cần hiển thị bất kỳ ký tự khoảng trắng hay dấu phân cách nào khác sau `\foo`: những dấu phân cách như vậy từ lâu đã được xử lý hoặc loại bỏ; ở đây chúng ta đang hoàn toàn ở thế giới nội tại của TeX gồm các danh sách token và các giá trị số nguyên của token.

Khi TeX xử lý chuỗi danh sách token do các `\expandafter` lệnh này tạo ra, nó sẽ dàn `**H**ello, World!`—chỉ `H` được dàn ở dạng đậm. Chúng ta có thể đạt cùng kết quả bằng cách viết mã TeX tương đương `\foo Hello\xyz`. Hãy lưu ý rằng định nghĩa của `\foo` đã dùng một tham số duy nhất; do đó, `\foo` hấp thụ token ký tự đơn lẻ `H` làm đối số cho nó, để lại các token ký tự còn lại (`ello`) không bị động đến.

**Lưu ý:**

* viết `\foo\bar` tạo ra kết quả rất khác: token cho `\bar` sẽ được dùng làm đối số cho `\foo` điều này dẫn đến việc dàn **`Hello, World`**—mọi thứ đều được dàn ở dạng đậm.
* viết `\expandafter\foo\bar` khiến `\bar` được mở rộng, điều này tạo ra hai token: $$\text{abc}*\text{token}\text{xyz}*\text{token}$$. Sau đó, sau khi $$\text{foo}*\text{token}$$ được chèn lại bởi `\expandafter` TeX xử lý chuỗi token $$\text{foo}*\text{token}\text{abc}*\text{token}\text{xyz}*\text{token}$$ mà sẽ dàn `**Hello**, World`—chỉ **`Hello`** được dàn ở dạng đậm. Ở đây, token đơn lẻ $$\text{abc}*\text{token}$$ được xử lý như đối số cho token macro $$\text{foo}*\text{token}$$, để lại token $$\text{xyz}\_\text{token}$$ không bị thay đổi và nội dung của nó được dàn bằng phông chữ hiện tại.

## Lưu ý về \expandafter và các macro có đối số

Khi sử dụng `\expandafter` để buộc mở rộng các macro, đáng để biết cách việc mở rộng macro hoạt động—đặc biệt với các macro nhận đối số. Trước khi TeX có thể thực thi một macro—tức là đọc và xử lý các token nằm trong định nghĩa của macro—TeX cần làm cho macro “sẵn sàng để chạy” bằng cách thực hiện quá trình mở rộng macro ban đầu. Nếu định nghĩa của một macro bao gồm việc dùng các tham số (`#1`, `#2`, ... `#9`) thì một phần của quá trình mở rộng macro đòi hỏi TeX quét đầu vào để tìm các token tạo thành đối số do người dùng cung cấp: những token đối số đó được hấp thụ (loại bỏ) khỏi đầu vào. Trong lúc mở rộng macro, TeX đọc và hấp thụ các token từ đầu vào để tạo ra các danh sách token nhỏ, mỗi danh sách cho một đối số; các danh sách token đó sau đó sẽ được chèn vào vị trí thích hợp trong thân macro—khi TeX thực thi nó. Bước cuối cùng của việc mở rộng macro là TeX định vị định nghĩa macro được lưu trong bộ nhớ và sắp xếp để vị trí đó trở thành nguồn mà từ đó TeX sẽ đọc bộ token đầu vào tiếp theo. Việc thực thi macro bắt đầu khi TeX bắt đầu đọc và xử lý những token đó, nạp vào các danh sách token đã tạo trước đó để lưu các đối số.

### Các token phân cách cũng được hấp thụ

Nếu định nghĩa macro ban đầu cũng dùng các token đóng vai trò phân cách, TeX cũng sẽ cần so sánh định nghĩa macro ban đầu với cách người dùng sử dụng (gọi) macro đó, để tìm và khớp các token phân cách. Khi đã khớp/xác định được, các token phân cách sau đó sẽ bị bỏ qua vì mục đích duy nhất của chúng là làm “dấu câu”, giúp TeX nhận ra và xác định các token thực sự sẽ tạo thành mỗi đối số.

&#x20;[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/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.
