> 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/ru/drugie-temy/23-how-tex-macros-actually-work-part-5.md).

# Как на самом деле работают макросы TeX: часть 5

[Часть 1](/latex/ru/drugie-temy/19-how-tex-macros-actually-work-part-1.md) [Часть 2](/latex/ru/drugie-temy/20-how-tex-macros-actually-work-part-2.md) [Часть 3](/latex/ru/drugie-temy/21-how-tex-macros-actually-work-part-3.md) [Часть 4](/latex/ru/drugie-temy/22-how-tex-macros-actually-work-part-4.md) [Часть 5](/latex/ru/drugie-temy/23-how-tex-macros-actually-work-part-5.md) [Часть 6](/latex/ru/drugie-temy/24-how-tex-macros-actually-work-part-6.md)

## Введение и обзор

В части 4 мы рассмотрели некоторые базовые свойства макросов TeX в подготовке к следующим двум статьям, где мы подробно изучим лежащие в основе механизмы макросов TeX: специализированные списки токенов. В этих двух заключительных статьях мы используем диаграммы, называемые списками узлов, которые были подготовлены на основе данных, сгенерированных с помощью специально модифицированной версии оригинального программного обеспечения TeX Кнута — эти модификации были предназначены для доступа к внутренним структурам данных TeX, которые обычно недоступны пользователю. «Подключившись» к внутренним процедурам обработки и выполнения макросов TeX, удалось вывести графические данные, которые позволяют более подробно и точно обсудить поведение TeX при обработке макросов. Overleaf надеется, что эти диаграммы помогут читателям лучше понять, как на самом деле работают макросы TeX.

### Возможное дополнительное ознакомление с фоном

Overleaf уже опубликовал две статьи, связанные с токенами, которые дают дополнительную справочную информацию о токенах TeX и списках токенов TeX. Пожалуйста, уделите время, чтобы ознакомиться с ними, если вам нужно заполнить пробелы в понимании и извлечь максимум пользы из частей 5 и 6 этой серии.

* [Что такое «токен TeX»?](/latex/ru/podrobnye-stati/53-what-is-a-tex-token.md)
* [Что такое список токенов TeX?](/latex/ru/podrobnye-stati/54-what-is-a-tex-token-list.md)

## Макросы как списки токенов

Когда TeX обнаруживает команду создания макроса (`\def`, `\edef`, `\gdef` или `\xdef`) в потоке ввода, он запускает процесс, который преобразует обе части `<текст параметров><текст замены>` определения нашего макроса в один длинный список токенов — но очень особого типа списка токенов.

Списки токенов для макросов немного отличаются от других списков токенов, используемых в TeX, потому что они содержат «специальные» значения токенов, которые могут создавать/генерировать только внутренние процессы самого TeX: такие специальные токены нельзя напрямую создать никакими командами, которые можно включить в ваш файл .tex. TeX создает и использует эти «специальные» значения токенов, чтобы помочь в обработке вызова вашего макроса, как мы рассмотрим и объясним ниже.

### Кратко о том, как хранятся списки токенов: узлы

Чтобы хранить список токенов (целочисленных значений), TeX использует структуру данных, называемую [связанным списком](https://en.wikipedia.org/wiki/Linked_list), который, в случае TeX, состоит из набора так называемых *узлов*. Узел можно представить как небольшой фрагмент памяти компьютера, который можно использовать для хранения набора элементов данных. Чтобы хранить макрос, эти узлы связываются друг с другом в цепочку, где каждый узел (звено в цепочке) может хранить несколько единиц информации — включая значение токена и адрес памяти следующего узла в списке. Для получения дополнительной информации вы можете прочитать статью [Что такое список токенов TeX](/latex/ru/podrobnye-stati/54-what-is-a-tex-token-list.md) но следующая диаграмма суммирует ключевые особенности макроса, хранящегося как список токенов:

![Диаграмма списка токенов макроса TeX, хранящегося как связанный список узлов](/files/d2594f74089f26c503d8cfca8eecd1359eda7247)

### Напоминание: 4 части определения макроса

Как обсуждалось в части 4, структуру любого макроса можно записать так:

```
<примитив макроса TeX><имя макроса><текст параметров>{<текст замены>}
```

где:

* `<примитив макроса TeX>` = один из `\def`, `\edef`, `\gdef` или `\xdef`;
* `<имя макроса>`=имя вашего макроса, например `\foo`;
* `<текст параметров>` может быть «пустым» (отсутствовать) или может быть строкой из токенов-разделителей и токенов параметров макроса;
* `<текст замены>` — это фактическое тело вашего макроса: часть, которая «выполняется» при вызове макроса.

**ПРИМЕЧАНИЕ**: (Как также отмечалось в части 4) на протяжении обсуждения мы предполагаем, что `<имя макроса>` будет сопровождаться пробельным символом с кодом категории 10, который будет служить разделителем, завершающим `<имя макроса>`. Мы *не* явно показали этот пробельный символ в нашем тексте/обсуждении, но предполагаем, что он там есть. Строго говоря, следовало бы представить это примерно так:

```
<примитив макроса TeX><имя макроса><пробел><текст параметров>{<текст замены>}
```

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

**ПРИМЕЧАНИЕ**: Символы `{` и `}` *не* становятся частью списка токенов макроса: их назначение — лишь сообщать сканеру ввода TeX (который создает токены), где `<текст замены>` начинается и заканчивается.

Когда TeX определяет макрос, разделы `<текст параметров><текст замены>` преобразуются в один длинный непрерывный список токенов — общее количество токенов в этом списке зависит от сложности макроса. Как мы уже видели, текст параметров имеет особую задачу: он служит «шаблоном токенов» или «чертежом», который TeX использует, чтобы выделить токены, образующие аргументы (значения), используемые с самим макросом: то есть токены, которые нужно подать на вход `<текст замены>`.

Чтобы закрепить эти идеи, возьмем пример макроса, но сделаем его коротким, чтобы последующие диаграммы не были слишком перегружены:

```
\def\foo A#1\fake{123 #1}
```

Для нашего макроса, `\foo`

* `<текст параметров>` = `A#1\fake`
* `<текст замены>` = `123 #1`

Хотя этот пример — простой макрос, он содержит все элементы, которые нам нужно рассмотреть.

Как отмечалось, TeX преобразует `<текст параметров><текст замены>` в один длинный список токенов, который вы можете увидеть на диаграмме ниже. В нашем примере токены, образованные из `A#1\fake{123 #1}` были преобразованы в последовательную последовательность токенов, хранящихся в списке токенов (в виде связного списка узлов).

## Иллюстрация, показывающая реальный список токенов макроса

Следующая диаграмма, показывающая, как макрос `\def\foo A#1\fake{123 #1}` хранится, использует реальные данные изнутри движка TeX. Она была создана с помощью [модифицированной версии TeX Кнута](/latex/ru/podrobnye-stati/01-a-new-series-of-articles-tex-tokens-and-related-concepts-but-why-and-how.md#how-can-you-study-tex-tokens3f) которая была дополнительно изменена кодом, перехватывающим вызовы макросов, исследующим внутренние данные TeX и экспортирующим их в формат для обработки с помощью программы для работы с графикой с открытым исходным кодом под названием [Graphviz](https://www.graphviz.org/).

Вы можете скачать следующую иллюстрацию как [PDF-файл](https://assets.ctfassets.net/nrgyaltdicpt/N6gT757eXCxRV3FtdPPga/7ce120dc05ed05962bb911ff1124734b/annotatednodelist-plain.pdf) (675 КБ) или [SVG-файл](https://images.ctfassets.net/nrgyaltdicpt/4PkmtHDhO8KF892ZDWuLHP/2c9c8385c6948fd122b228c5c780a3a6/annotatednodelist-plain.svg) (1,8 МБ).

![Диаграмма аннотированного списка токенов TeX](/files/3ee6b307fdeaa9a124fc90fa166c4bf3afad49a6)

#### Понимание узлов

На диаграмме выше вы увидите, что каждый узел содержит два элемента данных, называемые **следующий узел** и **текущий узел**. Это всего лишь целые значения, представляющие адреса памяти внутри TeX — места, где хранятся другие узлы. Значения **следующий узел** и **текущий узел** не имеют значения; они просто хранят расположения (адреса памяти), позволяющие связывать узлы в список.

![Значение «следующего узла» и «текущего узла»](/files/ea80d924e6b2a84d2015007d5e123471fabf535c)

#### Вернемся к примеру

На диаграмме узлов список токенов, образованный из `A#1\fake{123 #1}` содержит несколько «специальных токенов», введенных в начале этой статьи. Кроме того, список узлов, представляющий наш макрос, начинается со «специального первого узла»: мы рассмотрим, что это такое и что они делают.

Самый первый элемент в списке токенов макроса (а также в некоторых других типах списков токенов) хранит не значение токена, а элемент данных, называемый *счетчиком ссылок* который TeX использует для отслеживания использования макроса.

![Узел счетчика ссылок — первый в списке токенов](/files/c1f75efd27515a1f10282033f217a6b59443f53d)

Первый токен `<текст параметров>` хранится в узле, который следует сразу после счетчика ссылок: как видите, это токен, представляющий букву `Скопированный` с кодом категории 11. Из обсуждений в частях 2 и 3 мы знаем, что символный токен вычисляется с помощью

$$\text{token value}=256\times \text{category code} + \text{character code}$$

что для буквы `Скопированный` с кодом категории 11 равно

$$\text{token value}=256\times 11 + 65$$

что дает значение 2881, как показано в узле.

#### «Команда» \fake, используемая в \foo

Внутри нашего определения макроса `\def\foo A#1\fake{123 #1}` одним из разделителей является *неопределенная* команда `\fake` которая хранится в списке токенов как часть `<текст параметров>` текста параметров. Как видите, в общем списке токенов макроса `\fake` есть токен, значение которого равно `19491`— целому значению, вычисленному TeX по формуле, обсуждавшейся в части 3. Когда TeX пытается выполнить `\foo` он будет ожидать найти `\fake` значение токена в конце `<текст параметров>` текста параметров. TeX *не будет* пытаться выполнять `\fake` команду, потому что ее роль состоит лишь в том, чтобы служить своего рода «пунктуацией» внутри `<текст параметров>` «шаблона токенов».

![Использование токена команды в качестве разделителя макроса](/files/93eb15b4e2d1d66c10e76a3a56cecb6eee736f4c)

#### Специальные токены в списке токенов

**Токен «конца сопоставления»**

При вызове макроса первой задачей TeX является просканировать макрос, введенный пользователем, и сравнить токены, присутствующие в пользовательском `<текст параметров>` тексте параметров, с токенами, содержащимися в шаблоне `<текст параметров>` хранящемся в памяти (созданном в момент определения макроса). Поскольку полное определение макроса, построенное из `<текст параметров><текст замены>` хранится как один длинный непрерывный список токенов, TeX нужно знать, где в этом списке токенов `<текст параметров>` *останавливается* и где `<текст замены>` *начинается*. Чтобы добиться этого, когда TeX определяет макрос (строит список токенов), он вставляет специальный завершающий токен, называемый **концом сопоставления** в качестве самого последнего токена в наборе токенов, сгенерированных из `<текст параметров>`. **концом сопоставления** этот токен не может быть создан командами пользователя, его может создать только сам TeX, поэтому TeX наверняка обнаружит конец `<текст параметров>`.

![Показ токена конца сопоставления в списке токенов TeX](/files/2a1fa7b01f6cea4d69b0fc9a46d288d69dfd18ec)

Здесь мы видим, что первый токен, следующий после **концом сопоставления** — это токен, представляющий цифру `1` с кодом категории 12. Этого и следовало ожидать, потому что `<текст замены>` для нашего макроса `\foo` это `123 #1`— то есть она начинается с токена, представляющего цифру `1` (с кодом категории 12).

Из обсуждений в частях 2 и 3 мы знаем, что символный токен вычисляется с помощью

$$\text{token value}=256\times \text{category code} + \text{character code}$$

что для цифры `1` с кодом категории 12 равно

$$\text{token value}=256\times 12 + 49$$

что дает значение токена 3121, как показано в узле.

**токены «параметра сопоставления»**

Когда TeX хранит определение макроса, он преобразует любые токены параметров (`#1`, `#2`… `#9`) `<текст параметров>` в один, называемый **параметр сопоставления** токен. Эти токены сообщают TeX, что ему нужно начать искать токены в вызове макроса пользователем, которые являются аргументами макроса.

![Показ токена параметра сопоставления в списке токенов TeX](/files/ef57a75e0ac355333dd44077e87b7b257dfe7530)

### Специальные токены в списке токенов

#### токены «выходного параметра»

Когда TeX обработал все и готов фактически выполнить (раскрыть) макрос, **выходной параметр** токены указывают TeX места внутри `<текст замены>` где ему нужно подставить токены, представляющие аргументы, переданные пользователем при вызове макроса. По сути: «В этом месте вставить токены, представляющие аргумент пользователя n, где n=1...9».

Внутри `<текст замены>` раздела хранимого списка токенов определения макроса будет **выходной параметр** токен, соответствующий каждому `#1`, `#2`... `#9` присутствующему в исходном определении.

![Показ токена выходного параметра в списке токенов TeX](/files/626f015ebdd75d6d2bfac1c62dae61af5cd0ba81)

Если мы посмотрим на наше определение `\foo` (`\def\foo A#1\fake{123 #1}`) мы видим, что существует только 1 параметр макроса (`#1`) в `<текст параметров>` (`A#1\fake`) и, соответственно, только 1 параметр макроса (`#1`) появляется в `<текст замены>` (`123 #1`): в результате имеется лишь 1 **выходной параметр** токен, присутствующий в списке токенов, представляющем `<текст замены>`.

Обратите внимание на следующее в списке узлов, представляющем `\foo`’s `<текст замены>`:

* токен непосредственно перед **выходной параметр** токен представляет пробельный символ (код категории 10, код символа 32), потому что между `123` и параметром макроса (`#1`) в исходном определении `\foo`;
* этом **выходной параметр** является последним токеном в списке: **следующий узел** имеет специальное значение «null» (то есть «пусто»), которое используется для завершения списка: после **выходной параметр** поскольку это последний токен, указывающий на конец `<текст замены>` и, следовательно, конец определения макроса.

## Часть 6

В части 6 мы используем подробные графические материалы, чтобы объяснить и исследовать точный смысл раскрытия макросов и последствия токенизации аргументов макроса в TeX до их передачи в `<текст замены>`.

[Часть 1](/latex/ru/drugie-temy/19-how-tex-macros-actually-work-part-1.md) [Часть 2](/latex/ru/drugie-temy/20-how-tex-macros-actually-work-part-2.md) [Часть 3](/latex/ru/drugie-temy/21-how-tex-macros-actually-work-part-3.md) [Часть 4](/latex/ru/drugie-temy/22-how-tex-macros-actually-work-part-4.md) [Часть 5](/latex/ru/drugie-temy/23-how-tex-macros-actually-work-part-5.md) [Часть 6](/latex/ru/drugie-temy/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/ru/drugie-temy/23-how-tex-macros-actually-work-part-5.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.
