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

# Danh sách token TeX là gì

## Vậy, chính xác thì một "danh sách token TeX" là gì?

Trong một [bài viết trước](/latex/vi/bai-viet-chuyen-sau/53-what-is-a-tex-token.md)—cũng là một phần của [chuỗi bài về các khía cạnh kỹ thuật TeX cấp thấp](/latex/vi/bai-viet-chuyen-sau/01-a-new-series-of-articles-tex-tokens-and-related-concepts-but-why-and-how.md)—chúng ta đã khám phá các quá trình mà qua đó TeX quét `.tex` tệp của bạn để tạo ra các token mới: chúng ta đã xem xét bản chất cơ bản của một token TeX và cách TeX tạo ra chúng (xem [“TeX token” là gì?](/latex/vi/bai-viet-chuyen-sau/53-what-is-a-tex-token.md)).

Trong bài viết tiếp theo này, chúng ta sẽ xem xét *danh sách token*s: chúng là gì và các bộ máy TeX tạo/sử dụng chúng như thế nào. Hiểu được danh sách token có thể khó vì chúng được lưu rất sâu bên trong nội bộ TeX: những chi tiết đó được giấu khỏi người dùng—mặc dù, ngày nay, điều này không phải lúc nào cũng đúng nếu bạn làm lập trình nâng cao hơn với LuaTeX. Nhưng trước hết, bạn có thể bắt đầu nghĩ về danh sách token như là cách TeX lưu trữ một chuỗi các giá trị nguyên, trong đó mỗi số nguyên là một token được suy ra từ một ký tự hoặc lệnh mà TeX đã đọc từ tệp đầu vào của bạn.

Danh sách token đóng vai trò then chốt trong hoạt động nội bộ của TeX, thường theo những cách khá bất ngờ, chẳng hạn như hoạt động nội bộ của các lệnh như `\uppercase` và `\lowercase`. Một cách sử dụng đặc biệt quan trọng của danh sách token là lưu trữ và thực thi macro, một chủ đề mà chúng ta sẽ xem xét chi tiết trong một bài viết tương lai của chuỗi này.

### TeX nhận đầu vào từ tệp và danh sách token

Các bộ máy TeX có ba nguồn đầu vào—hai nguồn mà có thể bạn đã biết:

* các tệp văn bản vật lý được lưu trên đĩa;
* văn bản mà người dùng gõ vào terminal (dòng lệnh);

nhưng nó còn có một cách thứ ba để đọc/nhận đầu vào: danh sách token!

Về thực chất, danh sách token là một cơ sở lưu trữ dữ liệu nội bộ mà TeX dùng như một phần trong hoạt động của nó. Vì danh sách token của TeX đóng vai trò như một “cơ sở lưu trữ” cho các token đã được tạo trước đó, nên việc TeX có thể tái sử dụng chúng như một nguồn đầu vào khác là điều hợp lý. Khi cần lấy đầu vào tiếp theo từ một danh sách token cụ thể nào đó (hoặc TeX được yêu cầu làm vậy), TeX sẽ tạm ngừng đọc đầu vào từ một tệp vật lý (tức là tạo *các token mới*) và chuyển sang lấy đầu vào của nó từ *các token hiện có*: vị trí trong bộ nhớ nơi danh sách token được lưu. Rõ ràng, với một danh sách token thì quá trình quét + tạo token đã diễn ra rồi, nên TeX chỉ cần xem từng token trong danh sách và quyết định phải làm gì với từng token.

Ví dụ nhanh, lệnh cấp thấp (nguyên thủy TeX) `\toks` cho phép bạn tạo một danh sách token mà TeX lưu trong bộ nhớ để dùng lại sau này:

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

Để truy xuất các token đó (tức là bảo TeX coi chúng như nguồn đầu vào tiếp theo của nó) bạn sẽ đưa ra một lệnh như

```latex
\the\toks100
```

Điều này sẽ khiến TeX chuyển từ việc tạo token mới từ tệp đầu vào của bạn sang lấy token tiếp theo từ nơi các token đó (được tạo bởi `\toks`) được lưu—trong một cái gọi là *thanh ghi token* chỉ là một vị trí bộ nhớ nội bộ mà TeX biết đến (ở đây là thanh ghi 100).

Ngoài ra, danh sách token cũng có thể được tạo nội bộ, tức thời, bởi một số lệnh TeX. Một ví dụ là lệnh `\jobname` lệnh này tạo ra một chuỗi các token ký tự—một token cho mỗi ký tự trong tên của tệp chính mà TeX đang xử lý. Một ví dụ khác là `\string` lệnh; chẳng hạn

```latex
\string\mymacro
```

tạo ra một chuỗi các token ký tự cho từng chữ cái trong tên `\mymacro`—bao gồm cả `\` ký tự ban đầu. Chúng ta sẽ xem kỹ hơn một số “lệnh tạo token” ở cuối bài viết này.

## Danh sách token: Giải thích bằng phép so sánh

Trừ khi bạn có nền tảng lập trình và/hoặc biết chút về khoa học máy tính, “danh sách token” có thể là một khái niệm hơi mờ nhạt và, có lẽ, hơi khó hiểu. Tuy nhiên, nếu bạn muốn trở nên thành thạo trong việc viết macro TeX/LaTeX thì việc hiểu tốt các chủ đề như token TeX, danh sách token và mã phân loại (`\catcode`) sẽ cực kỳ hữu ích.

Trong phần này, chúng ta sẽ dùng một phép so sánh để giải thích/minh họa các ý tưởng/nguyên lý cốt lõi của một danh sách token TeX: cách TeX lưu token trong bộ nhớ. Đáng để dành thời gian đọc kỹ phần này vì danh sách token là một *cơ bản* khía cạnh của TeX và đáng để hiểu chi tiết hơn một chút.

### Danh sách token: Một phép so sánh (thí nghiệm tư duy)

Chúng ta sẽ thực hiện một “thí nghiệm tư duy” để làm nền tảng cho việc hiểu các danh sách token TeX. Hãy tưởng tượng rằng bạn có quyền truy cập vào một bộ lớn các vật chứa, chẳng hạn hàng trăm cái hộp thiếc—chúng ta không thể dùng thuật ngữ “box” để mô tả các vật chứa trong thí nghiệm tư duy của mình vì, dĩ nhiên, “box” có một ý nghĩa rất cụ thể trong TeX, không liên quan gì đến cuộc thảo luận ở đây. Vì vậy ta sẽ gọi các vật chứa của mình là “Hộp thiếc”, trong đó mỗi Hộp thiếc:

* có một số định danh duy nhất được in bên ngoài;
* được chia (ở bên trong) thành hai ngăn.

Hai ngăn đó được thiết kế như sau:

* ngăn bên trái chứa món đồ bạn muốn bỏ vào Hộp thiếc;
* ngăn bên phải được thiết kế để chứa một mảnh giấy mà trên đó bạn có thể viết một con số duy nhất: con số định danh cho một Hộp thiếc khác.

![kiểm tra](/files/3d38ffd217e6893e5377148e4020856a6dad6290)

Giả sử bạn có một bộ gồm, chẳng hạn, 5 món đồ và bạn muốn lưu bộ đồ vật đó trong các Hộp thiếc ấy; nhưng tiếc là mỗi Hộp thiếc chỉ chứa được 1 món đồ thuộc loại bạn muốn lưu.

Để đơn giản, hãy giả sử chúng ta muốn lưu 5 hình tròn màu:

![{{{alt}}}](/files/7c7afaea84624ef42572a80681266ee5d7c863b2)

Hơn nữa, khi bạn quay lại để lấy những món đồ đó từ hệ thống lưu trữ (các Hộp thiếc) thì các món đồ đó *phải* phải được lấy/tìm theo một thứ tự nhất định—theo đúng thứ tự chúng đã được lưu: chuỗi đó phải được giữ nguyên. Làm sao đạt được điều này?

Chúng ta có thể tận dụng thực tế rằng mỗi Hộp thiếc:

* có một số định danh duy nhất được gắn bên ngoài;
* có 2 ngăn—trong đó chỉ 1 ngăn ta sẽ dùng để chứa món đồ, ngăn còn lại chứa một mảnh giấy với số của một Hộp thiếc khác được viết lên đó.

Ta sẽ giả định mọi Hộp thiếc đều rỗng—nhưng không có gì ngăn bạn mở bất kỳ Hộp thiếc nào để kiểm tra xem nó có rỗng không; nếu không, hãy thử cái tiếp theo cho đến khi bạn tìm thấy một Hộp thiếc rỗng.

Ta có thể làm như sau. Đặt món đồ đầu tiên của chúng ta (hình tròn xanh lá đậm) vào một trong các Hộp thiếc (ví dụ, Hộp thiếc 124) và ghi lại số của Hộp thiếc đầu tiên này—không quan trọng Hộp thiếc đầu tiên đó mang số gì, điều quan trọng là ta ghi nó ở đâu đó và lưu lại để dùng sau.

![{{{alt}}}](/files/195fe32e23ecab541daaa1b73baa25917ada6b5f)

Tìm một Hộp thiếc thứ hai—bất kỳ số Hộp thiếc nào (ví dụ, Hộp thiếc 432)—và ghi lại số của nó. Viết số của Hộp thiếc thứ hai đó (432) lên một mảnh giấy và đặt ghi chú đó *vào trong Hộp thiếc đầu tiên* (Hộp thiếc 124). Chúng ta đặt món đồ thứ hai (hình tròn xanh lá nhạt) vào Hộp thiếc thứ hai. Như vậy, hiện giờ chúng ta có tình huống sau:

* một ghi chú viết tay—không nằm trong Hộp thiếc—nói rằng Hộp thiếc đầu tiên là số 124 (nó chứa món đồ đầu tiên của chúng ta);
* bên trong Hộp thiếc 124, ta đã thêm một ghi chú khác nói rằng món đồ tiếp theo nằm trong Hộp thiếc 432.

Về bản chất, chúng ta đã *liên kết* hai Hộp thiếc đầu tiên của mình: ta biết bắt đầu từ đâu (Hộp thiếc 124) và rằng một ghi chú trong Hộp thiếc 124 cho biết Hộp thiếc nào chứa món đồ tiếp theo (Hộp thiếc 432).

![{{{alt}}}](/files/35fd8236620db6d541b860cf91d2afbb87b30b56)

Sau đó ta tìm một Hộp thiếc thứ ba, viết số của nó (ví dụ, Hộp thiếc 543) lên một mảnh giấy và đặt nó vào *Hộp thiếc* thứ hai (số 432). Sau đó ta đặt món đồ thứ ba (hình tròn đỏ) vào Hộp thiếc thứ ba.

Bây giờ ta đã liên kết ba Hộp thiếc theo chuỗi: điểm bắt đầu của chúng ta, Hộp thiếc 124 (hình tròn xanh lá đậm) → Hộp thiếc 432 (hình tròn xanh lá nhạt)→ Hộp thiếc 543 (hình tròn đỏ) →…

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

Lặp lại quá trình này cho hai món đồ cuối cùng (hình tròn xanh dương nhạt và xanh dương đậm) bằng Hộp thiếc 213 (hình tròn xanh dương nhạt) và Hộp thiếc 102 (hình tròn xanh dương đậm).

![{{{alt}}}](/files/89a6745c9152fd3d6a78ae9812e790ef6220bc4e)

Giờ thì tất cả 5 Hộp thiếc đã được liên kết với nhau (sử dụng mã định danh số của từng Hộp thiếc) và ta có thể lấy lại tất cả các món đồ đã lưu—đúng thứ tự—chỉ bằng cách đi qua từng Hộp thiếc lần lượt, lấy món đồ của mình ra và xem ghi chú cho biết Hộp thiếc nào chứa món đồ tiếp theo.

### Còn món đồ cuối cùng trong danh sách của chúng ta (Hộp thiếc 102) thì sao?

Tại sao ta nên quan tâm đặc biệt đến món này? Cho đến giờ, ta đã lưu từng món đồ trong một Hộp thiếc, cùng với một ghi chú nói Hộp thiếc nào chứa món đồ tiếp theo: vậy với món cuối cùng trong danh sách, ghi chú đó nên nói gì—vì không có Hộp thiếc tiếp theo.

Khi ta chạm đến món cuối cùng (Hộp thiếc) thì phải thật rõ ràng rằng Hộp thiếc này (chứa món cuối cùng) là món cuối cùng trong danh sách của ta—ta không cần tìm một Hộp thiếc khác, vì không có cái nào cả. Một cách để làm điều đó là đặt một số Hộp thiếc “đặc biệt” vào trong Hộp thiếc cuối cùng của chúng ta (102). Ta có thể dùng bất kỳ số nào ta muốn, miễn là chọn một số duy nhất không phải là số của một Hộp thiếc thực—ví dụ “Hộp thiếc -1”, “Hộp thiếc 0”: không quan trọng, miễn là ta biết rằng “Hộp thiếc -1” hoặc “Hộp thiếc 0” v.v. ngay lập tức báo cho ta dừng lại: ta không cần tìm thêm Hộp thiếc nào nữa vì đây là cái cuối cùng và vì thế không còn món đồ nào khác để lấy.

### Từ “món đồ” và “Hộp thiếc” đến token và TeX

Giờ chúng ta cần chuyển từ phép so sánh sang một mô tả gần hơn với thực tế của TeX. Trước hết, thay vì lưu các hình tròn với màu khác nhau trong các Hộp thiếc tưởng tượng của mình, cần hiểu rằng ta có thể xem các Hộp thiếc đó như đang lưu các token TeX: các số nguyên đơn giản. Đó là phần dễ hơn khi chuyển phép so sánh của chúng ta sang lĩnh vực phần mềm (TeX). Nhưng tương đương phần mềm của các Hộp thiếc được đánh số có “ngăn” vật lý của chúng ta có thể là gì?

Ta không muốn đi quá sâu vào các khái niệm lập trình, nhưng bạn có thể hình dung các “Hộp thiếc” của chúng ta đại diện cho vài byte bộ nhớ máy tính đã được “đóng gói” thành một đơn vị lưu trữ tiện lợi. Mã định danh số cho mỗi Hộp thiếc trong phép so sánh có thể được xem như vị trí bên trong bộ nhớ máy tính nơi từng gói bộ nhớ nhỏ ấy nằm. Bên trong chính TeX, những gói lưu trữ nhỏ đó được gọi là “memory words”—một thuật ngữ phản ánh thời điểm/kỷ nguyên mà TeX được tạo ra (những năm 1970). Những “memory words” này là khối xây dựng cơ bản được dùng trong TeX nhưng ở đây chúng ta không cần tìm hiểu thêm chi tiết—ai muốn biết thêm có thể xem bài viết trên [blog cá nhân của tác giả](http://www.readytext.co.uk/?p=3537).

Trong thuật ngữ lập trình máy tính, điều chúng ta đang thảo luận được gọi là một [*danh sách liên kết*](https://en.wikipedia.org/wiki/Linked_list): một danh sách token TeX là một danh sách liên kết được tạo từ các thùng lưu trữ của TeX gọi là *memory words* trong đó mỗi memory word có thể dùng để lưu:

* a *giá trị*: giá trị của token (một số nguyên);
* a *liên kết*: địa chỉ bộ nhớ của memory word tiếp theo chứa token tiếp theo trong danh sách của chúng ta.

## TeX dùng danh sách token ở đâu?

Khắp nơi! Điều này đúng vì một định nghĩa macro TeX/LaTeX (ví dụ, một lệnh LaTeX) được lưu dưới dạng một hình thức danh sách token (hơi chuyên biệt)—chuyên biệt ở chỗ nó chứa các token mà bạn không thấy trong các danh sách token “chuẩn” (liên quan đến việc khớp các tham số macro, v.v.). Đừng lo về điều này vì chúng ta sẽ đề cập các chi tiết đó trong một bài viết tương lai.

### Một macro ví dụ

Có thể xem một macro gồm ba phần:

```
\def\<tên macro><văn bản tham số>{<văn bản thay thế>}
```

Lưu ý rằng thay vì `\def` bạn có thể đã dùng `\edef`, `\gdef` hoặc `\xdef`.

**Ghi chú cho người dùng LaTeX**: Ở đây chúng ta đang định nghĩa macro bằng các lệnh TeX thô, cấp thấp (gọi là *các nguyên thủy*). Người dùng LaTeX sẽ quen hơn với việc tạo macro thông qua `\newcommand` của LaTeX (bản thân nó cũng là một macro).

Khi bạn yêu cầu TeX tạo (định nghĩa) một macro, nó sẽ tạo ra một token đại diện cho `<macro name>` và một *danh sách token* đại diện cho phần `<parameter text>` và `<replacement text>`kết hợp `<macro name>` . TeX sẽ lưu cẩn thận mọi thứ để token đại diện cho`<parameter text>` và `<replacement text>`).

Ví dụ, nếu chúng ta định nghĩa `\mymacro` như sau:

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

Ta có thể thấy các phần cấu thành của nó là:

* `<macro name>` = `mymacro`
* `<parameter text>` = `abc #1 defz`
* `<replacement text>` = `I typed "#1"!`

Ví dụ, bạn có thể gọi `\mymacro` như sau:

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

kết quả là `I typed "THIS TEXT"!` được dàn chữ— `abc` và `defz` đang *không* được dàn chữ. `abc` và `defz` là các chuỗi token ký tự được dùng để *phân định* tham số macro `#1` và được hấp thụ rồi bỏ đi khi lời gọi macro của bạn được TeX xử lý thành công.

Khi bạn đã định nghĩa `\mymacro`, mẫu token có trong phần được lưu sẽ hoạt động như một “mẫu” mà TeX có thể dùng để xác định:

* token nào trong đầu vào của bạn là các token phân định;
* token nào trong đầu vào của bạn thực sự tạo thành tham số (các tham số) của macro của bạn (ở đây, những gì bạn dùng cho `#1` trong lời gọi `\mymacro`).

Bạn phải gọi `\mymacro` bằng một `<parameter text>` chứa các dấu phân định giống hệt như những dấu dùng để định nghĩa nó—điều này bao gồm cả việc dùng các dấu phân định dạng ký tự với mã phân loại giống hệt. Nếu các dấu phân định trong `<parameter text>` dùng để gọi `\mymacro` khác với những dấu đã dùng để định nghĩa nó (mẫu “template” được lưu trong bộ nhớ), thì TeX có thể khá bối rối—khi nó cố xử lý `\mymacro` nó sẽ không thể khớp với “template” mà nó đã lưu trong bộ nhớ.

Khi TeX thấy rằng bạn đang gọi một macro, nó sẽ quét văn bản đầu vào của bạn để tạo các token mới và thử, token theo token, khớp chúng với mẫu danh sách token `<parameter text>` được lưu như một phần của định nghĩa macro của bạn. Nếu các dấu phân định dùng trong văn bản đầu vào của bạn tạo ra một chuỗi token không khớp với những token được lưu trong “template” thì TeX thường sẽ báo lỗi.

TeX rất khắt khe—hãy nhớ rằng token ký tự là sự kết hợp của mã ký tự và mã phân loại: nếu bạn thay đổi mã phân loại của một ký tự thì bạn sẽ nhận được một giá trị token khác từ ký tự đó.

Giả sử ta đã thay đổi mã phân loại của `z` thành, chẳng hạn, 12—thông thường nó là 11—và thử gọi macro của mình như sau:

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

Lần này nó sẽ không hoạt động vì mã phân loại của `z` đã bị thay đổi. Bạn sẽ thấy một lỗi như sau:

```latex
Runaway argument?
THIS TEXT defz
! Paragraph ended before \mymacro was complete.
<to be read again>
\par
l.22
```

Khi TeX đọc và quét `z` trong `defz` nó không thể nhận ra nó là phần kết thúc của `\mymacro`của `<parameter text>` được dùng trong tệp đầu vào của bạn. Cho đến trước khi nhìn thấy `z` sai đó, TeX đã khớp đúng 3 ký tự đầu tiên `def` nhưng `z` (với mã phân loại 12) làm TeX bị vấp trong quá trình quét. Giả sử `z` có mã phân loại 11 khi chúng ta *định nghĩa* `\mymacro`: điều đó sẽ tạo ra một giá trị token 256×11 + 122 = 2938 được lưu như một phần của định nghĩa `\mymacro`(tức là lưu như một phần của “template”). Tuy nhiên, với mã phân loại 12, `z` sẽ giờ tạo ra giá trị token 256×12 + 122 = 3194. Vì giá trị token (cho `z`) đọc từ đầu vào của bạn (giá trị 3194) không khớp với token `z`được chứa trong mẫu danh sách token đã lưu (giá trị 2938), TeX sẽ tiếp tục quét đầu vào của bạn. TeX sẽ tiếp tục quét văn bản theo sau macro của bạn ( `<parameter text>` more text her&#x65;*...) để tìm các token bổ sung—cố gắng khớp mẫu đã lưu với các token nó tìm thấy trong đầu vào của bạn. Nó có lẽ sẽ không tìm thấy mẫu token đúng và lỗi sẽ phát sinh khi TeX “quét quá đà” đầu vào của bạn và đọc nhầm thêm văn bản để tạo ra các token bổ sung—những token bổ sung đó lẽ ra không nên được đọc ở thời điểm này và gần như chắc chắn sẽ tạo ra lỗi.* Chúng ta sẽ đi sâu hơn về điều này trong một bài viết tương lai.

Các cách dùng khác của danh sách token

## Các lệnh khác dùng để tạo/lưu danh sách token bao gồm:

\toks\<n>={...}

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

Mỗi lệnh trong số này tạo ra một danh sách token từ các ký tự và lệnh nằm trong dấu ngoặc nhọn ‘{...}’ và danh sách token đó được dự định để tái sử dụng trong những hoàn cảnh nhất định. Ví dụ, `\everypar={...}` tạo và lưu một tập hợp token (một danh sách token) mà TeX chèn vào đầu vào ngay trước khi nó bắt đầu một đoạn văn mới.

## Các cách dùng ẩn của danh sách token: ví dụ

Trong phần cuối này, chúng ta sẽ xem một số ví dụ thực tế về việc danh sách token được dùng theo những cách mà bạn có thể không ngờ tới.

### Ví dụ 1: \uppercase{...} và \lowercase{....}—các danh sách token tạm thời

Ngoài các lệnh tường minh để tạo danh sách token, có những trường hợp TeX tạo ra một danh sách token nội bộ ẩn và tạm thời để thực hiện một số xử lý đặc biệt. Hãy nhớ rằng khi TeX đọc/xử lý các ký tự/lệnh đầu vào của bạn, chúng được biến thành token: khối xây dựng cơ bản mà các bộ máy TeX làm việc cùng.

Một ví dụ hay là các lệnh `\uppercase{...}` hoặc `\lowercase{...}` vì cách hoạt động của chúng, khi mới gặp lần đầu, có thể khá khó hiểu. Một khi bạn hiểu chúng đang làm gì—ở sâu bên trong TeX và vô hình với người dùng—thì cách hoạt động của chúng sẽ dễ nắm bắt hơn nhiều.

Giả sử bạn có một chuỗi chữ cái đơn giản mà bạn muốn chuyển thành chữ hoa—ví dụ abcde và đổi nó thành ABCDE. Vâng, điều đó khá đơn giản với `\uppercase` lệnh:

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

sẽ khiến TeX xuất ra `ABCDE`. Bây giờ giả sử ta muốn lưu chuỗi chữ cái đơn giản này để dùng sau—tức là ta không muốn xuất chúng ngay lập tức, vì vậy ta sẽ dùng cơ chế *nội bộ* duy nhất của TeX—not cơ chế bên ngoài (tệp)—để lưu dữ liệu: dùng một danh sách token. Ta có thể làm điều đó bằng cách tạo một macro hoặc dùng một lệnh danh sách token tường minh:

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

Rồi, đến một lúc nào đó, bạn có thể muốn tái sử dụng chuỗi chữ cái của mình nhưng, lần này, ở dạng chữ hoa; vì thế bạn thử

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

và

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

Nhưng tiếc là cả hai cách này đều không hoạt động. Tại sao vậy?

### Những danh sách token bí mật!

Để hiểu các lệnh `\uppercase{...}` `\lowercase{...}` thực sự hoạt động như thế nào, tôi đã phải nhìn vào bên trong các cơ chế nội tại của TeX, nên phần giải thích sau đây được rút ra từ việc đó.

Khi TeX phát hiện `\uppercase{<material>}` hoặc `\lowercase{<material>}` trong đầu vào của bạn, việc đầu tiên TeX làm là tạo một danh sách token nội bộ (tạm thời) từ `<material>` được đặt trong ‘{’ và ‘}’ sau khi `\uppercase{...}` hoặc `\lowercase{...}` các lệnh—danh sách token tạm thời đó là nội bộ đối với TeX.

Một điểm then chốt, và là trung tâm để hiểu cách `\uppercase{<material>}` và `\lowercase{<material>}` thực sự hoạt động, là bất kỳ lệnh hay macro nào nằm trong `<material>` đều không *mở rộng*: tất cả những gì TeX làm là tạo token từ các ký tự và lệnh đặt giữa `{...}`. Trong quá trình của `\uppercase{<material>}` hoặc `\lowercase{<material>}` không có gì nằm giữa các dấu ngoặc nhọn được thực thi: nó chỉ đơn giản được biến thành token.

Sau `<material>` bên trong `{...}` đã được chuyển thành một danh sách token (tạm thời), TeX sẽ xem lại từng token trong danh sách đó và kiểm tra xem nó có phải là một *ký tự* token ký tự hay một *lệnh* token lệnh `\uppercase` hoặc `\lowercase` (dựa trên giá trị số của token). Nếu TeX phát hiện một token ký tự, nó sẽ chỉnh sửa token đó để thay đổi chữ hoa/thường của ký tự (tùy theo việc

đang được xử lý). TeX đơn giản bỏ qua mọi token lệnh và không “nhìn vào” bất kỳ token lệnh nào để xem chúng đại diện cho gì hoặc chứa gì (ví dụ, một macro chứa các ký tự)—chúng chỉ bị bỏ qua: chỉ các token ký tự mới thực sự được xử lý/bị ảnh hưởng bởi các thao tác đổi chữ hoa/thường. `\uppercase{abcde}` TeX sẽ tạo một danh sách token từ `abcde` chứa không gì ngoài các token ký tự: tất cả chúng được điều chỉnh để tạo thành một chuỗi token đã biến đổi đại diện cho A, B, C, D và E. Những token đã biến đổi đó được đưa trở lại bộ xử lý đầu vào của TeX, và kết quả là `ABCDE` được dàn chữ. Tuy nhiên, nếu ta đã lưu các ký tự của mình *bên trong một macro*—ví dụ `\def\mychars{abcde}`—và thử chuyển chúng sang chữ hoa như thế này:

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

thì nó sẽ thất bại và abcde sẽ được dàn chữ—not ABCDE như bạn có thể mong đợi. Nếu sau đó ta thử lưu các ký tự của mình trong một danh sách token như `\toks0={abcde}` và làm `\uppercase{\the\toks0}` thì một lần nữa, `\uppercase` sẽ thất bại vì danh sách token sẽ hoàn toàn gồm những token không bị ảnh hưởng bởi `\uppercase`.

Lấy ví dụ macro của chúng ta, `\mychars`, sau khi TeX phát hiện `\uppercase` trong đầu vào, TeX tra cứu ý nghĩa của `\uppercase` và thực thi nó, tạo ra một danh sách token tạm thời từ `{\mychars}`. Rõ ràng, danh sách token tạm thời đó chỉ chứa một token không phải là token ký tự mà là token đại diện cho lệnh macro của chúng ta `\mychars`: vì thế, đối với mục đích thực thi `\uppercase`, token đó bị bỏ qua—`\mychars` không đại diện cho một token ký tự. Tuy nhiên, như đã lưu ý ở trên, một khi `\uppercase` đã làm xong công việc của nó, danh sách token tạm thời (được tạo bởi hành động của `\uppercase`) được đưa trở lại cơ chế xử lý đầu vào (quét) đầy đủ của TeX. Khi TeX đọc lại danh sách token đó, nó phát hiện một token đại diện cho macro `\mychars` mà TeX thực thi (mở rộng) và tạo ra một chuỗi ký tự để dàn chữ abcde—vẫn ở dạng chữ thường vì chúng đã được “đóng gói” bên trong một macro và do đó vô hình đối với các thao tác của `\uppercase`.

Một khi TeX đã xem xét lại danh sách token tạm thời được tạo cho `\uppercase{...}` hoặc `\lowercase{...}`, và đã xử lý bất kỳ token ký tự nào, nó sẽ chuyển sang dùng danh sách token tạm thời đó làm nguồn đầu vào của mình: dàn chữ các ký tự (các token ký tự đã được xử lý) và thực thi các lệnh cùng macro.

### Làm sao khắc phục điều này?

Bởi vì `\uppercase{...}` hoặc `\lowercase{...}` chỉ tác động lên các token ký tự, ta cần một cách để “buộc bung ra” các ký tự đang được đóng gói trong macro `\mychars` của chúng ta (hoặc nằm trong một `\toks` thanh ghi) trước khi `\uppercase{...}` hoặc `\lowercase{...}` tác động lên nó. Bằng “bung ra” ở đây, điều ta thực sự muốn nói là quá trình TeX *mở rộng*:

* thay thế một lệnh TeX/LaTeX bằng *chuỗi* token *mà từ đó lệnh đó* (*ví dụ, một macro*) *được cấu thành,* hoặc
* tạo ra chuỗi token mà một lệnh được thiết kế để *tạo ra*. Một ví dụ về lệnh tạo token là `\jobname`, lệnh này tạo ra một chuỗi token ký tự biểu diễn tên của tệp TeX chính đang được xử lý.

#### Ma thuật cấp thấp hơn: scantoks(..., ...)

Ở đây ta thực sự đang đào vào một số góc tối hơn trong nội bộ TeX nên bạn có thể bỏ qua phần này trừ khi bạn thích các chi tiết…

Sau khi TeX phát hiện `\uppercase` hoặc `\lowercase` trong luồng đầu vào, nó thực thi một hàm nội bộ gọi là `scantoks(..., ...)` nhiệm vụ của nó là tạo danh sách token bằng các mục giữa dấu ‘{’ mở và dấu ‘}’ đóng—như đã nói, danh sách token đó sau đó được xem xét để phát hiện (rồi điều chỉnh) mọi token ký tự nhằm thay đổi chữ hoa/thường theo yêu cầu. Lưu ý cẩn thận rằng chúng ta đang nói đến `scantoks(..., ...)` như là hàm nội bộ được tích hợp trong mã nguồn của các bộ máy TeX—ở đây, nó không được nhắc đến như là tên của một control sequence.

Trong quá trình làm việc của nó, `scantoks(..., ...)` có thể được chỉ định nên mở rộng hay không mở rộng danh sách token mà nó đang xây dựng và đối với `\uppercase` và (`\lowercase`) nó không mở rộng các token: nó chỉ tạo ra chúng và đặt chúng vào một danh sách token.

Một trong những việc đầu tiên mà `scantoks(..., ...)` phải làm là kiểm tra xem có dấu ‘{’ mở (hoặc bất kỳ ký tự nào có `\catcode` 1) hay không, vì nó phải đảm bảo người dùng đã không mắc lỗi cú pháp và quên dấu ‘{’ mở (hoặc bất kỳ ký tự nào có mã phân loại 1)—bởi vì một ký tự có mã phân loại 1 là bắt buộc để đánh dấu sự bắt đầu của một danh sách các mục sẽ được token hóa.

Và đây là chiêu mẹo: nhiệm vụ tìm dấu ‘{’ mở kích hoạt `scantoks(..., ...)` chạy quá trình mở rộng của TeX, điều đó có nghĩa là các ví dụ sau sẽ hoạt động:

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

Lấy ví dụ `\obb`, một macro, nó được nhận ra là một *lệnh có thể mở rộng* và được TeX mở rộng đúng cách (thông qua `scantoks(..., ...)` hàm) trong quá trình tìm dấu ngoặc nhọn mở (bất kỳ ký tự nào có mã phân loại 1). Điều này có nghĩa là ta có thể dùng “`\expandafter` chiêu mẹo” để đạt được mục tiêu “bung ra” các ký tự của mình khỏi giới hạn của macro—tức là mở rộng nó. Lưu ý rằng `\expandafter` cũng thuộc loại là một *lệnh có thể mở rộng*, vì vậy TeX thực thi nó ở đây và để nó làm việc của mình như một phần của quá trình tìm dấu ‘{’ mở (hoặc bất kỳ ký tự nào có mã phân loại 1).

Vậy, nếu bạn định nghĩa:

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

Và làm như sau:

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

trong cả hai trường hợp, bạn sẽ thấy ABCDE được dàn chữ vì `\expandafter` gây ra việc “bung ra” (mở rộng) của `\mychars` và `\the\toks0`—cả hai đều dẫn đến `\uppercase` việc nhìn thấy một luồng token ký tự, mà chúng có thể xử lý để đổi chữ hoa/thường.

### Ví dụ 2: \string—thêm các danh sách token tạm thời

Về mặt nội bộ, TeX phân loại `\string` là một trong các lệnh “convert” của nó: thực hiện thao tác “chuyển sang văn bản”. The `\string` lệnh này được thiết kế để chuyển một token thành một phiên bản văn bản có thể đọc được bởi con người—tức là, sắp chữ chuỗi ký tự có thể đọc được bởi con người mà token đó ban đầu được tạo ra từ đó.

Ví dụ `\string\hello` tạo ra một danh sách token tạm thời chứa các ký tự \\, h, e, l, l, o — vâng, ngay cả cả dấu ‘\’ ban đầu. Khi danh sách token đó đã được tạo ra, TeX sẽ đọc lại nó và văn bản của lệnh “`\hello`” sẽ được sắp chữ—vâng, bao gồm cả ‘\’ nếu bạn chọn đúng phông chữ…

Bạn có thể tự hỏi bằng cách nào/tại sao TeX có thể sắp chữ ký tự thoát khi nó thường được dùng để kích hoạt bộ quét của TeX tạo ra một token lệnh: tại sao ở đây nó không làm vậy? Câu trả lời liên quan đến mã loại: thông thường, một ký tự ‘\’ có catcode 0 (ký tự thoát) nhưng khi `\string` nó tạo ra danh sách token nội bộ của mình, nó làm điều gì đó hơi khác. Khi nó tạo một danh sách token ký tự, nó gán mã loại 12 cho mọi ký tự ngoại trừ ký tự khoảng trắng, ký tự này được gán catcode 10—hãy nhớ rằng token ký tự được tính từ 256 x catcode + giá trị ASCII. Vì vậy, khi TeX đọc lại (nhập) danh sách token tạm thời đó mà `\string` được tạo ra từ `\hello`, TeX *không thấy một ký tự thoát* bởi vì token cho ‘\’ được tính với catcode 12 chứ không phải 0: TeX chỉ coi ‘\’ như một ký tự bình thường và sắp chữ nó.

Nói một cách chặt chẽ, có lẽ chúng ta nên lưu ý rằng TeX thực ra không tạo token cho các ký tự thoát khi nó phát hiện chúng trong đầu vào. Một khi nó đã nhận ra một ký tự với mã loại 0, ký tự đó chỉ được dùng để “kích hoạt” việc tạo một token dãy điều khiển: khi nó đã kích hoạt TeX làm điều đó thì ký tự thoát đã hoàn thành nhiệm vụ của mình và không còn được xét đến nữa.

### Ghi chú kỹ thuật

Một lệnh có tên `\showtokens{...}` (được giới thiệu bởi bộ máy e-TeX) có thể hiển thị các danh sách token (trong tệp log). Theo sổ tay e-TeX:

> Lệnh `\showtokens{<token list>}` hiển thị danh sách token, và cho phép hiển thị những giá trị không thể được hiển thị bởi `\show` hoặc `\showthe`, ví dụ:
>
> ```latex
> \showtokens\expandafter{\jobname}
> ```

## Kết luận

Trong mục 291 của mã nguồn TeX (xem trang 122 của [TeX: Chương trình](https://www.amazon.co.uk/Computers-Typesetting-TeX-Program-TEX/dp/0201134373)) Knuth mô tả một danh sách token như sau:

> “Một danh sách token là một danh sách liên kết đơn gồm các nút một từ trong bộ nhớ mem, trong đó mỗi từ chứa một token và một liên kết. Các định nghĩa macro, định nghĩa routine xuất, các dấu, `\write` văn bản, và một vài thứ khác được TeX ghi nhớ dưới dạng các danh sách token, thường được đặt trước bởi một nút có số đếm tham chiếu trong trường “token\_ref\_count” của nó.”

Khi đọc lần đầu, điều này có lẽ không dễ hiểu, nhưng hy vọng giờ đây nó đã trở nên dễ hiểu hơn một chút.


---

# 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/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.
