> For the complete documentation index, see [llms.txt](https://ayakaleaf-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://ayakaleaf-pro.ayaka.space/latex/uk/inshi-temi/24-how-tex-macros-actually-work-part-6.md).

# Як насправді працюють макроси TeX: частина 6

[Частина 1](/latex/uk/inshi-temi/19-how-tex-macros-actually-work-part-1.md) [Частина 2](/latex/uk/inshi-temi/20-how-tex-macros-actually-work-part-2.md) [Частина 3](/latex/uk/inshi-temi/21-how-tex-macros-actually-work-part-3.md) [Частина 4](/latex/uk/inshi-temi/22-how-tex-macros-actually-work-part-4.md) [Частина 5](/latex/uk/inshi-temi/23-how-tex-macros-actually-work-part-5.md) [Частина 6](/latex/uk/inshi-temi/24-how-tex-macros-actually-work-part-6.md)

## Вступ і огляд: Історія на цей момент

У попередніх 5 частинах цієї серії ми побачили:

* як TeX читає символи у вхідному файлі та використовує коди категорій, щоб розпізнавати різні «класи» символів і згодом перетворювати їх на символьні токени та токени команд;
* що макрос, по суті, складається з чотирьох частин:

```
<TeX macro primitive><macro name><parameter text>{<replacement text>}
```

де:

* `<TeX macro primitive>` = один із `\def`, `\edef`, `\gdef` або `\xdef`;
* `<macro name>`=ім'я вашого макроса, наприклад `\foo`;
* `<parameter text>` може бути «null» (відсутнім) або це може бути рядок токенів-розділювачів і токенів параметрів макроса;
* `<replacement text>` є фактичною тілом вашого макроса: розділом, який «виконується» (розгортається), коли ви викликаєте макрос.
* як `<parameter text>` розділ може містити широкий спектр токенів, а TeX використовує цей розділ як «шаблон токенів», щоб зіставити виклик макроса з його початковим визначенням і з'ясувати аргументи, використані з макросом, — і як TeX очікує, що ваше використання макроса відповідатиме його початковому визначенню;
* що всередині TeX визначення макроса зберігається як безперервна послідовність токенів, що представляють `<parameter text>` та `<replacement text>` розділи.

Коли ви використовуєте команду макроса, TeX спершу перевіряє, чи приймає вона якісь параметри. Якщо так, TeX тоді має визначити фактичні *аргументи* що використовуються у вашому виклику макроса. TeX має перевірити ваш виклик макроса за збереженим у пам’яті визначенням «шаблону токенів». Зокрема, TeX використовує своє внутрішнє (збережене) визначення `<parameter text>` розділу макроса як шаблон, через який він може вибрати *токени* які є фактичними аргументами, а які *токени* лише слугують розділювачами.

## Суть розгортання макроса

Тепер ми, нарешті, готові перейти до найважливішої теми: як TeX обробляє аргументи макроса і фактично виконує макрос: процес, який TeX називає *розгортанням макроса*.

### Але спершу короткий приклад: щось дивне?

Щоб «створити контекст» для пояснення механізму, за яким TeX обробляє макроси та їхні аргументи, ми скористаємося коротким прикладом, який покаже питання, що нам потрібно врахувати.

#### Аргументи спочатку перетворюються на токени

Наведений нижче приклад ґрунтується на прикладі, розглянутому на сторінках 114–115 [The Advanced TeXbook](https://www.amazon.co.uk/Advanced-Texbook-David-Salomon/dp/0387945563) написаної Девідом Саломоном. Його вибрано, бо він дуже вдало стисло втілює ключові ідеї в надзвичайно короткому макросі TeX.

Під час звичайної роботи TeX/LaTeX, `$` знак має код категорії 3 («зсув у математику»), який вмикає/вимикає TeX у режим вбудованої математичної формули (`$...$`) або режиму відображуваної математичної формули (`$$...$$`) — звісно, LaTeX використовує `\(..\)` та `\[..\]` для тих самих цілей.

Припустімо, ми хочемо макрос, який змінює код категорії `$` знака, скажімо, на 11, щоб ми могли набирати його як звичайний символ. Ми можемо використати примітивну команду TeX `\catcode` і нашою першою спробою такого макроса, `\docat`, може бути

```
\def\docat #1{\catcode`\$=11 #1}
```

Однак, коли ми намагаємося використати його ось так

```
\begin{document}
\def\docat #1{\catcode`\$=11 #1}
I paid \docat{$90} for that book.
\end{document}
```

ми очікуємо, що TeX набере `I paid $90 for that book.` але це завершується помилкою:

```
! Missing $ inserted.
<inserted text>
                $
<читати ще раз>
                   \par
l.7
```

Із повідомлення про помилку здається, що `$` знак, використаний в аргументі нашого макроса, досі змушує TeX набирати математику; очевидно, TeX *не* змінив код категорії `$` знака, використаного в аргументі нашого макроса (`$90`). Питання в тому, *чому* чому TeX не змінив код категорії `$` на 11 і не набрав його як звичайний символ? Коротка відповідь така: TeX спочатку перетворює аргументи макроса на токени **до того, як** перед тим, як подати їх у список токенів `<replacement text>`— але ми розглянемо базові механізми набагато детальніше.

Потрібно пам’ятати, що наше уявлення про TeX, який використовує текст/символи, стосується лише вмісту файла, який TeX читає: щойно TeX зчитав будь-які символи, ми опиняємося у світі *токени*. Виклики макросів TeX працюють із *токени*, а не з фактичним *записаним/текстовим поданням* команд TeX/LaTeX — це стане ясніше, коли ми розберемо приклад.

Спочатку ми могли б подумати, що наше використання `\docat` макроса в `I paid \docat{$90} for that book.` те саме, що й безпосередньо записати еквівалентний код TeX (або LaTeX), наприклад наведений нижче, який *не* працює:

```
\begin{document}
I paid \catcode`\$=11 $90 for that book.
\end{document}
```

![Деякий код TeX, що виконується в Overleaf](/files/5d242678f378278418e64a9d0f3a2e96e3b986dd)

Однак, як ми бачили вище, спосіб, у який TeX обробляє аргументи макроса, дає результат (`! Missing $ inserted.`), який суттєво відрізняється від простого записування коду TeX: зараз ми дослідимо *чому* це.

### Макроси й аргументи як списки токенів

Щоб повністю зрозуміти поведінку `\docat` макроса та його аргументу (`$90`), і чому він не працює, нам знову потрібно уявити визначення `\docat` макроса та будь-які аргументи, що використовуються (коли \docat викликається), як *списки токенів*, а не як послідовність символів.

Коли TeX сканує ваш вхідний текст, він розпізнав би `\docat` як команду макроса; після цього він перевіряє, чи приймає вона якісь параметри — як саме TeX це робить, пояснюється в наступному розділі для читачів, яким цікаві дрібніші деталі.

#### Для тих, хто любить деталі...

Після виклику макроса TeX перевіряє, чи є перший токен (у збереженому списку токенів визначення макроса) **токен завершення збігу** токену: якщо так, TeX може бути певен, що макрос не приймає жодних параметрів.

**Приклад**

Наведені нижче діаграми списку вузлів порівнюють списки токенів для двох макросів:

* `\def\foo A#1B{#1}`: тут є `<parameter text>` значення `A#1B`, отже **токен завершення збігу** токен є **не** першим токеном, тож TeX перейде до пошуку параметрів;
* `\def\foo{X}`: тут немає `<parameter text>` розділу, отже **токен завершення збігу** токен є першим у списку токенів, і TeX знає, що не слід шукати жодних параметрів.

![Як TeX перевіряє, чи приймає макрос параметри](/files/4a4512f015d6e5cbab1e947191189fb82d5f782c)

## До «великого фіналу»: розгортання

Нагадаємо собі питання: чому наступний макрос не спрацював; тобто чому TeX не змінює код категорії жодного `$` знака, використаного в аргументі `\docat` макроса, наприклад `\docat{$90}`?

```
\begin{document}
\def\docat #1{\catcode`\$=11 #1}
I paid \docat{$90} for that book.
\end{document}
```

Як пояснено вище, коли TeX сканує ваш вхід і розпізнає команду макроса — у момент, коли TeX збирається її виконати — TeX спершу перевіряє, чи має цей макрос якісь параметри. Якщо так, TeX потрібно буде далі сканувати вхідний файл, щоб визначити фактичні *аргументи* які користувач надав для цього конкретного виклику макроса: TeX має зробити це **до того, як** перед тим, як він зможе викликати власне код макроса. Очевидно, TeX потрібно визначити дані, які користувач хоче передати макросу.

Щоб ідентифікувати аргументи, наявні у вхідних даних (у виклику макроса користувача), TeX керуватиметься внутрішньо збереженим визначенням цього макроса: а саме, `<parameter text>` розділом збереженого визначення макроса (списку токенів), який забезпечує своєрідний «шаблон токенів». Використовуючи цей «шаблон токенів», TeX має визначити, які *токени* у виклику макроса користувача є лише *роздільники* (по суті «розділовими знаками») і які *токени* є частиною *аргументу*. Саме коли TeX натрапляє на **токен параметра збігу** у збереженому визначенні макроса `<parameter text>` розділі («шаблоні токенів»), він знає, що треба починати формувати *список токенів* для цього конкретного аргументу.

Щойно TeX розпізнає потребу ідентифікувати аргумент користувача, він сканує вхід, щоб згенерувати токени, і дуже уважно перевіряє їх токен за токеном, зіставляючи із збереженим визначенням макроса. TeX продовжує збирати токени для аргументу, доки не виявить токен, який насправді є розділювачем, або доки не виявить **токен завершення збігу** токен: у будь-якому разі TeX тоді знає, що настав час припинити пошук токенів, які є частиною цього аргументу.

### Чому макрос \docat не спрацював

Як зазначалося, *до того, як* Щоб TeX міг справді викликати макрос, він має ідентифікувати та підготувати всі аргументи, які будуть використані з цим макросом. Однак, щоб ідентифікувати аргумент(и), готові до подавання в макрос, TeX має згенерувати кожен аргумент як *список токенів*: і це причина `\docat`невдачі

У нашому прикладі ми надали `\docat` для нього аргумент `$90` але цей аргумент спочатку *перетворюється на список токенів* під час сканування TeX виклику макроса — аргумент перетворюється на токени *до того, як* до того, як макрос справді буде викликано. Тут для аргументу `$90`TeX згенерує три символьні токени: по одному токену для кожного з `$`, `9` та `0`.

Наведена нижче ілюстрація показує список токенів, згенерований для аргументу `$90`, перед тим як його буде подано в тіло `\docat` макроса:

![Список токенів TeX, згенерований для аргументу макроса](/files/0dc2c3a1c9652aba75d0670abb29189cb8843a61)

На наведеній вище ілюстрації ми чітко бачимо, що список токенів аргументу містить `$` як символьний токен, заснований на коді категорії 3.

Як ми бачили в частинах 1–3, символьні токени створюються з використанням значень кодів категорій *що діють у момент зчитування символу*— тобто в момент, коли створюється список токенів аргументу (перетворюється на токени). У момент, коли аргументи токенізуються, макрос `\docat` ще не було виконано, тож зміна коду категорії, яку ми вставили у виклик макроса (``\catcode`\$=11``) *не* ) не впливає на коди категорій, які використовуються для створення токенів аргументу.

Щойно TeX згенерує список токенів, що представляє аргумент `$90`, ці три символьні токени подаються у власне макрос `<replacement text>`. Однак це призводить до `$` того, що *символьним токеном* створеного з кодом категорії 3: «math on», і ми бачили, що щойно символьний токен сформовано, пов’язаний код категорії є незмінним.  `$` є *не* переданий у макрос *не як символ*, а як *символьним токеном* основаного на `$` тому, що має код категорії 3.

### Виконання \docat: розгортання макроса

TeX називає процес «виконання» макроса *розгортанням макроса*; цей термін, на думку автора, трохи заплутаний, але це загальноприйнята термінологія, тож ми й надалі його використовуватимемо.

#### Справжній зміст розгортання макроса

Після того, як TeX виявляє `\docat` команду у введенні користувача, він сканує аргументи та генерує список токенів для свого аргументу(`$90`). Щоб виконати (розгорнути) макрос, TeX відводить погляд від вхідного файла користувача і починає читати токени, що містяться `\docat`’s `<replacement text>` у списку токенів, збереженому в пам’яті TeX.

Коли TeX обробляє `\docat`визначення, він тоді побачить і виконає послідовність токенів, спочатку використаних для визначення макроса (`**catcode**`, ``**`**``, `**\$**`, `**=**`, `**1**`, `**1**`, `**#1**`).

Наведена нижче ілюстрація показує процес розгортання `\docat` макроса: TeX перестає отримувати токени з вхідного файла і починає читати токени з `<replacement text>` розділу `\docat` визначення макроса, збереженого в пам’яті. TeX продовжує виконувати ці підготовлені токени, доки не побачить **токен вихідного параметра** токен, який наказує TeX прочитати («впровадити») і «виконати» токени аргументу в цьому місці. У нашому прикладі це три символьні токени, що представляють `$90` і це призводить до помилки, тому що попередньо підготовлений символьний токен для `$` має код категорії 3. Оскільки ми маємо справу із символьними токенами, а не з символами, `$` не зазнає впливу попередньої зміни коду категорії, спричиненої токенами в ``\catcode`\$=11``.

![Показ процесу розгортання макроса \docat](/files/d46c1f7af5e784a1fcaaf9d47c07bd455ffc6b95)

Після того, як TeX обробив токени, що представляють ``\catcode`\$=11``, зміна коду категорії для `$` тепер набуде чинності. Потім TeX натрапляє на «спеціальний токен» під назвою **токен вихідного параметра** який наказує TeX **вставляють** список токенів аргументу. Однак цей список токенів — це три символьні *токени*, перший з яких є токеном для `$` із присвоєним йому кодом категорії 3 («math on»): попередня зміна коду категорії всередині макроса не може вплинути на цей символьний токен, тож TeX трактує цей токен як сигнал почати математичну обробку, що й спричиняє збій макроса.

### Чи можна виправити макрос \docat?

Із наведеного вище зрозуміло, що будь-які символи, які з’являються в аргументах макроса, токенізуються з використанням кодів категорій, що діють у момент токенізації, — а в нашому прикладі це *завжди* до того, як `<replacement text>` цього `\docat` макрос фактично буде виконано. Отже, як ми можемо забезпечити зміну кодів категорій аргументів макроса?

Один зі способів — змінити `\docat` так, щоб він став макросом без параметрів, який лише змінює код категорії — у нього немає жодних аргументів для токенізації. Потім ми використовуємо другий макрос, `\getarg`, який приймає один параметр, і забезпечуємо, щоб його аргумент токенізувався, коли відповідний код категорії для `$` є активним.

```
\begin{document}
\def\docat{\catcode`\$=11 \getarg} % No parameters, calls a second macro \getarg
\def\getarg#1{#1} %1 parameter whose argument will be tokenized
Тепер ви можете запускати це так, і воно працюватиме:

I paid \docat{$90} for that book.
\end{document}
```

Коли ми використовуємо нашу нову версію `\docat` (ось так `\docat{$90}`) *здається* так, ніби `$90` і досі використовується як аргумент для `\docat` макроса. Однак, як обговорювалося вище, коли TeX виявляє `\docat` у вхідних даних, він перевіряє, чи має він якісь аргументи: тепер не має, тож TeX переходить до його виконання (розгортання). Розгортання `\docat` є послідовністю токенів `**catcode**`, ``**`**``, `**\$**`, `**=**`, `**1**`, `**1**`, `**пробіл**`, `**getarg**` і це відбувається *до того, як* коли TeX починає читати (токенізувати) наступні символи, що містяться у вхідному файлі, — тобто групу `{$90}`. Пам’ятайте, що коли TeX розгортає макрос, він отримує свій наступний вхід, читаючи токени, що містяться у списку токенів визначення цього макроса; тобто з його `<replacement text>` розділу, збереженого в пам’яті.

TeX обробить і виконає розгортання `\docat` і виявить *токен* **`getarg`**, розпізнаючи його як токен, що представляє команду, яка приймає параметри. На цьому етапі TeX скануватиме вхідний файл у пошуках **`getarg`**&#x430;ргументу `{$90}`. Як завжди, вони токенізуються, але оскільки TeX вже прочитав і обробив розгортання `\docat`, символи `$90` токенізуються, коли код категорії `$` було змінено на 11. Визначення (`<replacement text>`) для `\getarg` просто `#1` що означає набрати наданий аргумент, і саме це відбувається, у результаті чого з’являється `$` згенерований токен символу з кодом категорії 11, який безпечно набирався.

## Підсумкові зауваження: історія у вузлах

Послідовність подій, що виникає внаслідок переписування `\docat` з використанням макроса `\getarg` міститься в наведеній нижче анотованій діаграмі списку вузлів, яка показує процес розгортання макроса `\docat`. Читачі, які хочуть уважно вивчити цю діаграму, можуть завантажити зображення як [PDF](https://assets.ctfassets.net/nrgyaltdicpt/7MOBdavza4WxAEQGISEEht/cabe5097d9063a6415bc553cd38237e6/newdocatexpansion.pdf) або [SVG](https://images.ctfassets.net/nrgyaltdicpt/2FIqqVRXjakdAzTpZsV0m9/10ccc1353741d42d3df18f1692d8aa84/newdocatexpansion--plain.svg) файл для офлайн-використання.

![Показ процесу розгортання зміненого макроса \docat і макроса \getarg](/files/4160e798a46993a9113f473480e6adf1187b0a24)

[Частина 1](/latex/uk/inshi-temi/19-how-tex-macros-actually-work-part-1.md) [Частина 2](/latex/uk/inshi-temi/20-how-tex-macros-actually-work-part-2.md) [Частина 3](/latex/uk/inshi-temi/21-how-tex-macros-actually-work-part-3.md) [Частина 4](/latex/uk/inshi-temi/22-how-tex-macros-actually-work-part-4.md) [Частина 5](/latex/uk/inshi-temi/23-how-tex-macros-actually-work-part-5.md) [Частина 6](/latex/uk/inshi-temi/24-how-tex-macros-actually-work-part-6.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://ayakaleaf-pro.ayaka.space/latex/uk/inshi-temi/24-how-tex-macros-actually-work-part-6.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.
