> 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/22-how-tex-macros-actually-work-part-4.md).

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

[Частина 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)

## Вступ і огляд

У частинах 1–3 ми глибоко занурилися в деякі низькорівневі деталі, готуючись до розуміння того, як працюють макроси TeX. У цій статті ми «спливемо на поверхню», щоб розглянути деякі базові практичні принципи макросів TeX, готуючись до ще одного глибокого занурення в частинах 5 і 6. Упродовж цієї статті ми показуватимемо приклади макросів, визначених за допомогою примітивної команди TeX `\def`: ми не будемо використовувати, можливо, більш звичну команду LaTeX `\newcommand`. Для цього є дуже вагома причина: наша мета — зрозуміти фундаментальні принципи, що лежать в основі поведінки макросів TeX, але для цього нам потрібно використовувати основні команди *вбудовані в* програмне забезпечення TeX. Команди LaTeX, як-от `\newcommand`, самі є макросами: командами зі специфічною запрограмованою поведінкою, які зрештою побудовані зі шарів примітивних команд TeX нижчого рівня. Щоб краще зрозуміти фундаментальну поведінку TeX, ми маємо використовувати примітиви TeX, а не макроси LaTeX.

### Куди ми прямуємо?

По суті, ми працюємо над поясненням макросів як спеціалізованої форми списку токенів: коли ви наказуєте TeX визначити макрос, він створює послідовність токенів (список токенів) і зберігає їх у своїй пам’яті, пов’язавши з іменем, яке ви визначаєте. У частинах 5 і 6 ми розглянемо списки токенів макросів дещо докладніше, але якщо вам захочеться перейти з цієї статті до читання довідкової інформації, ви знайдете її в [Що таке список токенів TeX?](/latex/uk/dokladni-statti/54-what-is-a-tex-token-list.md)

Списки токенів для макросів і їхні параметри містять кілька додаткових нюансів, які ми розглянемо докладно — і використаємо чимало прикладів. Щоб краще зрозуміти поведінку(и) обробки макросів TeX, справді є один ключовий фактор, який слід пам’ятати: TeX думає про символи лише на найранішому етапі обробки введення; відтоді й далі це суцільно токени! У цій та наступних статтях серії ми дослідимо роль, яку токени відіграють у макросах TeX.

## Чотири частини макроса

### Нагадування: параметри макроса і аргументи макроса

Перш ніж почати, варто нагадати собі про різницю між *параметрами* макроса та *аргументи*його

```
\def\foo#1#2{This is #1, this is #2}
```

Конструкції (токени) `#1`, `#2` (до `#9`) називаються *параметрами*параметрами макроса: сприймайте їх як «заповнювачі» для фактичних даних, які ви використовуватимете, коли викликаєте макрос:

```
\foo{alpha}{beta}
```

Тут, `alpha` та `beta` є *аргументи* аргументами, використаними в цьому виклику \foo: аргументи макроса — це фактичні значення, підставлені в заповнювачі параметрів (`#1`, `#2`... `#9`) , використані під час визначення макроса.

### Визначення макроса: має 4 елементи

Почнемо з того, що, можливо, виглядає як дещо формальне визначення макроса, але воно дає корисну основу для подальших обговорень.

Будь-яке визначення макроса складається з 4 частин:

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

де:

* `<TeX macro primitive>`: один із `\def`, `\edef`, `\gdef` або `\xdef`;
* `<macro name>`: ім’я, надане вашій макрокоманді, наприклад `\foo`;
* `<parameter text>`: це може бути відсутнім, але якщо воно є, то це послідовність *токени* які стоять перед `<replacement text>` макроса. `<parameter text>` може містити параметри макроса (`#1`, `#2`... `#9`) та інші типи токенів. По суті, і, як ми побачимо докладно, `<parameter text>` надає своєрідний *шаблон токенів* який TeX використовує, щоб з’ясувати, які токени користувач хоче використати як аргументи макроса: коли ви викликаєте макрос, TeX передає *аргументу* токени у ваш `<replacement text>` (що також є списком токенів);
* `{<replacement text>}`: це фактичне тіло вашого макроса: це послідовність токенів, у яку *аргументи* «вводяться» під час обробки макроса (розгортання). Аргументи подаються в позиції, позначені параметрами макроса, використаними в початковому визначенні.

**ПРИМІТКА**: Упродовж обговорення ми припускаємо, що `<macro name>` за ним ітиме символ пробілу з кодом категорії 10, який слугуватиме роздільником для завершення `<macro name>`. Ми *не* показали цей символ пробілу явно в нашому тексті/обговоренні, але припускаємо, що він є. Строго кажучи, слід було б подати це приблизно так:

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

Однак ми опустимо явне включення символу `<space>` і неявно припускатимемо його наявність.

#### Примітки щодо {}

Ми показали використання двох фігурних дужок: `{` та `}` які обрамляють (обмежують) фактичне тіло `<replacement text>`вашого макроса. Однак використання `{` та `}` — це лише прийнята домовленість, тому що насправді TeX очікує, що текст вашого макроса `<replacement text>` починатиметься символом із кодом категорії 1 («Початок групи») і завершуватиметься символом із кодом категорії 2 («Кінець групи»). За домовленістю, це `{` та `}` символи відповідно. Однак, якщо хочете, ви можете призначити будь-яку пару символів для цього. Наприклад

```
\catcode`\(=1
\catcode`\)=2
```

Тепер ви можете визначати й використовувати макроси так:

```
\def\foo #1(Hello, #1)
\foo(World!)
```

І ви все ще можете використовувати `{` та `}` тому що ми не змінювали їхні коди категорій — кілька символів можуть і мають той самий код категорії, тож ви можете й далі визначати макроси звичайним способом:

```
\def\foo #1{Hello, #1}
\foo{World!}
```

### і {}

Найважливішими для нашого обговорення компонентами визначення макроса є `<parameter text>` та `{<replacement text>}`. Коли ви визначаєте макрос, `<parameter text>` фактично є суворим шаблоном токенів, який визначає, як слід використовувати макрос. Як зазначено, `<parameter text>` може бути порожнім, наприклад `\def\foo{Some text}` де між нашою назвою команди (`\foo`) і відкривною дужкою нічого немає `{` яка тут позначає початок `<replacement text>`.

**Примітка**: Деякі читачі можуть знати про механізм «hashquote» TeX (`#{`) але ми тут цього не торкатимемося.

### і роздільники макроса

Ця конкретна стаття не задумана як вичерпний огляд написання макросів, але варто коротко освіжити пам’ять, з прикладами, показавши, що `<parameter text>` може ставати складним, тому що TeX дозволяє `<parameter text>` містити:

* **параметри макроса**: (`#1`, `#2`,... `#9`) які слугують «заповнювачами» для значень, які користувач надасть під час запуску макроса — *аргументи*;
* **токени-роздільники**: довільні токени, розміщені між токенами параметрів і навколо них, які використовуються для визначення межі між параметрами макроса. Можна думати про ці роздільники як про своєрідну «пунктуацію», що робить `<parameter text>` «шаблоном токенів», якого вам потрібно дотримуватися, коли ви використовуєте макрос. Токени-роздільники не набираються у верстку.

То що ж це насправді означає — давайте подивимося на кілька прикладів. `<parameter text>` знаходиться між назвою макроса та лівою фігурною дужкою `{` визначення макроса.

#### Роздільники: приклад 1

Припустімо, ми визначаємо базовий макрос `\foo` так:

```
\def\foo ABC{hello, there}
```

* `<parameter text>` = `ABC`
* Токенів параметрів немає (`#1`, `#2`,... `#9`)
* Роздільниками є *три символьні токени* `ABC` але в цьому прикладі вони дещо зайві й наведені лише як приклад.

Три символьні токени `ABC` розглядаються як роздільники: не те, що слід набирати у верстку, а «пунктуація», яка, як очікується, має бути присутньою, коли макрос викликається — коли ви використовуєте макрос `\foo` ви повинні надати ті самі роздільники, які були присутні під час його визначення.

Якщо ви введете `\foo ABC` у своєму тексті, це набере у верстку `hello, there`— символьні токени `ABC` не набираються у верстку, але TeX дуже ретельно перевірив, чи були вони присутні у вашому виклику `\foo`. TeX шукає ці роздільники («пунктуацію») і видаляє (поглинає) їх, як ви можете бачити на такому зображенні екрана Overleaf: `ABC` не набирається у верстку:

![Overleaf запускає макрос TeX](/files/4e73ae39c0e1beab5c431d7912f2c3a42a8d7d26)

Якщо ви спробуєте використати `\foo` без `ABC` роздільників, TeX поскаржиться `Використання \foo не відповідає його визначенню.`:

![Показ помилки TeX в Overleaf](/files/5d49b33a59bcd45fa1838326a6fa44fe0e606cac)

У наведеному вище прикладі, після виявлення `\foo` TeX очікує побачити три символьні токени `ABC` але цього не відбувається: він бачить символьний токен `w` і одразу виявляє, що щось не так.

#### Роздільники: приклад 2

Цікавим і, можливо, несподіваним фактом є те, що роздільниками можуть бути довільні токени команд — зокрема команди, які *ще навіть не були визначені*. Наприклад, ми могли б визначити `\foo` так:

```
\def\foo A\bob B\anne{Hello \TeX{}}
```

* `<parameter text>` = `A\bob B\anne`
* Токенів параметрів немає (`#1`, `#2`,... `#9`)
* Роздільниками є токени `A\bob B\anne` але знову ж таки, у цьому прикладі вони зайві й наведені лише для обговорення. Зверніть увагу, що `\bob` та `\anne` є вигаданими командами, які *не були визначені*— і не обов’язково мають бути визначені.

Коли ви викликаєте макрос, TeX перевіряє (сканує) `<parameter text>` що присутнє *у вашому виклику макроса* і порівнює це токен за токеном із версією «шаблону токенів», *збереженою в пам’яті*— тією, що була створена під час визначення макроса. TeX сканує *використані у вашому виклику макроса* і просто перетворює будь-які команди, які там знаходить, на їхнє числове значення токена: він не намагається виконати ці команди, тож не має значення, що `\bob` та `\anne` ніколи не були визначені. TeX просто використовує шаблон токенів, збережений у пам’яті, як орієнтир, що дає йому змогу з’ясувати, які токени в `<parameter text>` вашого виклику макроса є фактичними аргументами, які слід передати в `<replacement text>`.

Як ви можете бачити з наведеного нижче фрагмента екрана Overleaf, жоден із символьних токенів (`Скопійований` та `B`) у `A\bob B\anne` не набрався у верстку, і наші невизначені команди `\bob` та `\anne` не спричинили жодних проблем. Усі ці токени були *поглинуті* TeX під час зіставлення вашого використання `\foo` з визначенням (шаблоном токенів) `\foo` (списку токенів), збереженим у пам’яті.

![Overleaf запускає макрос TeX](/files/48f3f65901deae5b4bd7f0b1afb0c2e7536269e5)

#### Роздільники: приклад 3

Ви можете перемежовувати різні роздільники (символьні токени, токени команд) з параметрами макроса, як у цьому прикладі:

```
\def\foo A\bob#1B\anne#2\jane#3bye!{Hello from \TeX{} to \#1=#1, \#2=#2 and \#3=#3}
```

* `<parameter text>` = `A\bob#1B\anne#2\jane#3bye!`
* Є 3 токени параметрів макроса: `#1`, `#2`, `#3`
* Цього разу параметри (`#1`, `#2`, `#3`) розмежовані комбінацією токенів:

  `A\bob#1B\anne#2\jane#3bye!`

Тут ви, по суті, надали TeX шаблон, який він дуже ретельно спробує зіставити і який очікуватиме, коли ви викликаєте `\foo`: він пройде через ваш виклик макроса, *токен за токеном*, і очікуватиме зіставлення (знаходження):

* двох токенів `Скопійований` та `\bob` до того, як `#1`
* двох токенів `B` та `\anne` до того, як `#2`
* токена `\jane` перед параметром `#3` та *чотири символьні токени* `b`, `y`,`e` та `!` після `#3`.

**Пам’ятайте**: TeX мислить токенами, тож `bye!` є *чотири символьні токени*.

Є два способи використати цей макрос — ми могли б помістити будь-які багатотокенові аргументи у фігурні дужки, щоб утворити групу:

```
\foo A\bob{This}B\anne{That}\jane{Other}bye!
```

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

```
\foo A\bob ThisB\anne That\jane Otherbye!
```

і TeX може виділити аргументи, щоб отримати той самий результат, що й при використанні груп `{...}`:

![Overleaf запускає макрос TeX із використанням роздільників](/files/dd8eb6f7a47469f4077221ddda23d135fc3a6f87)

Зверніть увагу, як TeX зміг точно виявити, які токени відповідали параметрам `#1` та `#3`:

![Overleaf запускає макрос TeX із використанням роздільників](/files/78eb9bfe0fc8107c86aca7c7b7a1945671d9d667)

#### Роздільники: приклад 4 (усе про токени, а не символи!)

Ось короткий приклад, який демонструє, що під час роботи з макросами важливо пам’ятати: ми справді перебуваємо у світі *токени* та **не** *символи*…

Визначимо такий короткий макрос, де A і B — символи, що діють як роздільники, і обидва мають код категорії 11. Це працює без проблем:

```
\documentclass{article}
\begin{document}
\def\foo A#1B{Hello, #1}
\foo AGrahamB
\end{document}
```

і набирає у верстку `Hello, Graham`.

Однак, якщо змінити код категорії A або B на щось інше, ніж 11, виклик макроса завершиться невдачею. Припустімо, ми змінюємо код категорії B на 12, використовуючи ``\catcode`B=12`` і намагаємося знову викликати макрос, як і раніше:

```
\documentclass{article}
\begin{document}
\def\foo A#1B{Hello, #1}
\foo AGrahamB % Це працює
\catcode`\B=12\relax
\foo AGrahamB
\end{document}
```

Він завершується помилкою, яка дещо збиває з пантелику:

```
Параметр забіг за межі?
GrahamB \end {document}
! Файл закінчився під час сканування використання \foo.
<inserted text>
                \par
<*> main.tex

Я підозрюю, що ви забули `}', через що я
прочитав далі, ніж ви хотіли, щоб я зупинився.
Я спробую відновитися; але якщо помилка серйозна,
вам краще зараз ввести `E' або `X' і виправити файл.

! Аварійна зупинка.
<*> main.tex

*** (завдання перервано, не знайдено допустимого \end)
```

![Overleaf показує помилку макроса TeX](/files/8359bfe18f58de6c7f662b6f510cbd6a183f6cd9)

На жаль, стандартна порада TeX щодо ``Я підозрюю, що ви забули `}'`` є **є**хибною, це не спричинено відсутньою фігурною дужкою (`}`).

#### Що сталося?

TeX намагається зіставити `\foo` макрокоманду *виклик* з `\foo` макрокоманду *визначенням* яке він зберіг у пам’яті. Коли ви викликаєте макрос, якому потрібен один або кілька аргументів, TeX має перевірити (просканувати) ваше використання макроса, щоб з’ясувати *аргументи* які ви подаєте цьому макросу. Тут TeX очікує, що аргумент буде затиснутий між A (код категорії 11) і B (код категорії 11). Пам’ятайте: TeX мислить у *токени*, **не** *символи*.

Значення токенів для A і B, $$\mathrm{T\_A}$$ та $$\mathrm{T\_B}$$ відповідно, є:

$$\mathrm{T\_A = 256 \times 11 + 65 = 2881}$$ $$\mathrm{T\_B = 256 \times 11 + 66 =2882}$$

Однак, коли TeX продовжує пошук, він бачить B *але* тепер він має код категорії 12, і це дає інше значення токена:

$$\mathrm{T'\_B= 256 \times 12 + 66 =3138}$$

У `\foo` У визначенні макроса значення токена для B (використаного як роздільник) було 2882, але тепер TeX бачить значення токена 3138: він думає, що це просто ще один токен, призначений для використання в *аргументу* поданому до `\foo`. З погляду TeX, кінцевий токен аргументу ще не знайдено, тож він переходить до пошуку ще одного токена B з кодом категорії 11. Саме тоді і чому макрос зазнає збою: у спробі знайти аргумент TeX «перестрибує» далі і починає читати токени, які ви не мали наміру включати до складу аргументу для `\foo` виклику макроса. Що станеться далі, залежить від токенів, які TeX виявить після B — вони спричинять різні `Параметр забіг за межі?` помилки.

У нашому прикладі TeX «перестрибує» далі й споживає потік токенів `\end {document}` і швидко доходить до кінця файла, звідси повідомлення про помилку:

```
! Файл закінчився під час сканування використання \foo
```

## Частина 5

Як ми бачили вище, `<parameter text>` розділ нашого визначення макроса може варіюватися від дуже простого до складної суміші параметрів макроса, перемежованих символьними токенами та токенами команд, що діють як роздільники. TeX здатен обробляти різні комбінації токенів, присутні в `<parameter text>` щоб видобути аргументи, подані макросу, і виявити, коли ми намагаємося використати макрос неправильно. Як він це робить — тема наступної статті в серії.

[Частина 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/22-how-tex-macros-actually-work-part-4.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.
