> 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/18-how-overleaf-created-the-tex-primitive-reference-data.md).

# Как Overleaf создал справочные данные по примитивам TeX

В этой статье описываются методы и техники, использованные для создания двух перекрёстных таблиц ссылок на примитивные команды TeX:

* [Примитивы TeX, перечисленные по движкам TeX](/latex/ru/drugie-temy/46-tex-primitives-listed-by-tex-engine.md) и;
* [Примитивы TeX, перечисленные по движкам CJK TeX](/latex/ru/drugie-temy/45-tex-primitives-listed-by-cjk-tex-engine.md).

Эта информация предоставляется для читателей, интересующихся более тонкими деталями, но не является обязательной для использования самой перекрёстной таблицы ссылок. Чтобы удовлетворить потребности разных читателей, мы предлагаем очень краткую сводку, а также более подробное объяснение для тех, кто хочет глубже разобраться в вопросе.

## Краткая сводка/обзор

Для создания перекрёстной таблицы ссылок Overleaf обработал исходный код 9 движков TeX, чтобы извлечь список примитивов, поддерживаемых каждым из них: этот процесс дал 9 текстовых файлов (по 1 файлу на каждый движок TeX). Затем эти 9 наборов примитивов были объединены, чтобы создать «главный список», который, по сути, представлял собой объединение отдельных наборов примитивов: в итоге получилось около 1000 уникальных примитивов, распределённых по различным движкам. Для каждого движка его собственный список примитивов был сопоставлен с главным файлом (набором всех команд), чтобы определить, какие из этих \~1000 команд он поддерживает: результаты этих сравнений сведены в следующих двух таблицах:

* [Данные перекрёстной ссылки на примитивы TeX](/latex/ru/drugie-temy/46-tex-primitives-listed-by-tex-engine.md)
* [Данные перекрёстной ссылки на примитивы TeX (для движков CJK)](/latex/ru/drugie-temy/45-tex-primitives-listed-by-cjk-tex-engine.md)

## «Сборка программного обеспечения» 101: что это значит?

На протяжении остальной части этой статьи мы будем ссылаться на понятие «сборки движков TeX», которое может быть незнакомо, если вы не программист или не программируете на компилируемых языках, таких как C или C++. Для наших целей сборка ПО — то есть движков TeX — это процесс создания исполняемой программы TeX из её составных частей — файлов исходного кода, написанных на языке программирования, используемом для разработки программы.

## Полная версия: хотите подробностей? Читайте дальше...

Каждый движок для вёрстки на базе TeX поддерживает «диалект» языка TeX: определённый набор примитивных команд, которые управляют средствами вёрстки каждого движка и служат строительными блоками для создания/определения макросов — пользовательских последовательностей команд. Каждый макрос, будь то написанный для LaTeX, plain TeX или любого другого пакета макросов, в конечном счёте состоит из примитивных команд — хотя вам, возможно, придётся довольно глубоко «копать» через слои дополнительных макросов, прежде чем вы доберётесь до «коренной породы» примитивов TeX. Набор из 9 движков TeX, проанализированных для получения справочных данных по примитивным командам, конечно, имеет множество общих команд, но у каждого движка TeX также есть собственные примитивные команды, добавленные его разработчиками, чтобы обеспечить поддержку особенностей, специфичных для этой «версии» TeX.

Примитивные команды движка TeX встроены в исполняемое ПО TeX: примитивы — это не макросы, созданные пользователями, а фундаментальные, неделимые/атомарные инструкции, используемые для управления поведением каждого движка при вёрстке. Следовательно, наиболее надёжный способ создать авторитетный список примитивных команд, поддерживаемых любым движком TeX, — это изучить фактический исходный код, из которого собираются (компилируются) исполняемые программы TeX, и извлечь список примитивов, определённых в исходном коде. Звучит так, будто это должно быть легко, верно? Однако из-за 40-летней истории развития TeX изучение/просмотр файлов исходного кода движков TeX (за исключением LuaTeX) не особенно тривиально. Причина этих сложностей заключается в инструментах, языке программирования (Pascal) и методологии (литературное программирование), которые Кнут использовал для написания оригинального исходного кода TeX — от которого, в конечном счёте, происходят все остальные движки.

Мы отмечаем исключение для LuaTeX, поскольку его код ядра движка был переписан на C, чтобы убрать использование Pascal и других устаревших сложностей, описанных ниже (Web2C); следовательно, хотя исходный код LuaTeX весьма объёмен, способ его «упаковки» и распространения гораздо более понятен по сравнению с другими движками TeX. Поэтому, исходя из рабочего процесса/процессов, используемых для их сборки из исходного кода, удобно разделить движки TeX на две категории:

1. LuaTeX: собственный (более современный) процесс сборки
2. Все остальные движки: устаревший процесс сборки (Web2C)

## Контекст устаревшего кода: почему сборка (большинства) движков TeX сложна

Как мы рассмотрим ниже, Кнут выпустил свой оригинальный исходный код TeX как единый монолитный файл под названием `tex.web` который раз в 7 лет Кнут продолжает обновлять, исправляя оставшиеся ошибки — новые функции никогда не добавляются, это исключительно работа по исправлению ошибок.

Расширение исходного кода TeX (`.web`) вряд ли покажется знакомым, и вы можете задаться вопросом, на каком языке Кнут писал TeX? Ответ — Pascal, но расширение `.web` нуждается в небольшом пояснении. Кнут разработал методологию программирования, которую он назвал [литературным программированием](https://en.wikipedia.org/wiki/Literate_programming) в которой исходный код программы и документация объединяются и выпускаются как единый составной файл (код плюс документация) с расширением `.web`: этот тип файла называется WEB-файлом. Ниже мы немного подробнее объясним, что такое WEB-файлы.

### Создание новых движков TeX: требования Кнута

Хотя Кнут давно сделал свой исходный код TeX (`tex.web`) свободно доступным для всех, он, как имеет на это полное право, выдвинул важное условие: его исходный код (`tex.web`) не должен напрямую редактироваться/изменяться и распространяться под названием программы «TeX». В исходном коде он пишет:

```
% Эта программа защищена авторским правом (C) 1982 D. E. Knuth; все права защищены.
% Копирование этого файла разрешено только если (1) вы — D. E. Knuth, или если
% (2) вы не вносите в свою копию абсолютно никаких изменений. (Система WEB предусматривает
% внесение изменений через вспомогательный файл; основной файл должен оставаться неизменным.)
```

а также:

```
Если эта программа изменена, получившуюся систему не следует называть
`\TeX'; официальное имя `\TeX' само по себе зарезервировано
для программных систем, которые полностью совместимы друг с другом.
Специальный тестовый набор под названием ``\.{TRIP} test'' доступен для
помощи в определении того, заслуживает ли конкретная реализация того, чтобы называться
`\TeX' [ср.~отчёт Стэнфордского компьютерного факультета CS1027,
ноябрь 1984 г.].
```

По сути: не вносите изменения путём редактирования и распространения модифицированных версий основного исходного кода TeX и продолжайте называть его `tex.web`. Если вы всё же хотите вносить изменения, например добавить новые примитивы и т. п., то вы должны делать это, внося «изменения через вспомогательный файл», и дать своей программе — «производной от TeX» — имя, отличающее её от «TeX», которое в наборном виде ($$\mathrm\TeX$$) является товарным знаком Американского математического общества.

### Наследие устаревшего кода

Хотя были попытки полностью переписать TeX с использованием современных языков и методологий программирования — например, двух инициатив на Java [New Typesetting System](https://en.wikipedia.org/wiki/New_Typesetting_System) и [εχTEX](http://www.extex.org/) и других, таких как [одна на Clojure](https://www.infoq.com/news/2015/01/implementing-tex-in-clojure), ни одна не оказалась полностью успешной. История проектов и инициатив, направленных на дальнейшее развитие TeX, — интересная тема, и читатели, возможно, захотят [посетить UK TeX FAQ](https://texfaq.org/FAQ-enginedev) для получения дополнительной информации.

Те не-LuaTeX-инициативы, которые также оказались успешными, такие как e-TeX, pdfTeX, XeTeX и другие движки, были построены *непосредственно поверх* оригинального кода Кнута: они брали его исходный код и «вносили изменения», чтобы получить новый движок с дополнительными возможностями — такими как добавление новых примитивов, генерация PDF-вывода, поддержка ввода текста UTF-8 и так далее. Хотя этот путь привёл к заметным успехам, он также означает, что эти производные движки наследуют устаревший код и методы разработки, созданные Кнутом 40 лет назад.

Ключевой вывод здесь заключается в том, что, за исключением LuaTeX, большинство движков TeX, происходящих от оригинального исходного кода Кнута, создаются путём взятия одного монолитного файла (обычно `tex.web`) и внесения изменений, которые порождают ещё один единый монолитный файл, содержащий исходный код ядра этого нового движка. Продвинутые читатели могут захотеть перейти к поясняющим [заметкам о pdfTeX и XeTeX](#aside-xetex-and-pdftex).

### Некоторая дополнительная история/предыстория TeX

Момент рождения TeX был [записан в дневнике Кнута как 30 марта 1977 года](/latex/ru/podrobnye-stati/55-what-s-in-a-name-a-guide-to-the-many-flavours-of-tex.md#the-genesis-of-tex-a-brief-history), то есть более 40 лет назад. Внутренне TeX — это чрезвычайно сложная программа, исходный код которой Кнут приложил огромные усилия, чтобы [задокументировать с исключительной подробностью](https://www.amazon.co.uk/Computers-Typesetting-TeX-Program-TEX/dp/0201134373). Для этого Кнут разработал стиль программирования, который он назвал [литературным программированием](https://en.wikipedia.org/wiki/Literate_programming) в котором исходный код программы и документация объединяются и выпускаются как составной файл с расширением `.web` (называемый WEB-файлом). Кнут выбрал Pascal в качестве языка программирования для написания своего программного обеспечения TeX и, неудивительно, использовал язык вёрстки TeX для написания финальной документации. Следовательно, основной исходный код TeX Кнута опубликован как единый монолитный файл под названием `tex.web`: смесь исходного кода на Pascal и кода вёрстки TeX для документации.

Если программа написана с использованием стиля/методологии литературного программирования Кнута (как TeX, MetaFont, BibTeX и другие), то для извлечения документации или исходного кода необходимо предварительно обработать WEB-файл. Чтобы получить доступ к документации программы, вы обрабатываете WEB-файл (например, `tex.web`) с помощью утилиты под названием [WEAVE](http://tug.org/texinfohtml/web2c.html#weave-invocation) которая создаёт документацию как `.tex` файл, который можно набрать. Чтобы извлечь исходный код на Pascal, используется другая утилита под названием [TANGLE](http://tug.org/texinfohtml/web2c.html#tangle-invocation) которая выводит файл с расширением `.p` содержащий исходный код Pascal.

На момент написания (начало 2019 года) последняя версия TeX Кнута — 3.14159265, датированная январём 2014 года. Ещё раз отметим, что исходный код TeX Кнута содержится всего в одном файле примерно на 25 000 строк кода TeX/Pascal!

### От Pascal к C

За 40+ лет, прошедших с момента рождения TeX, Pascal вышел из моды, и сегодня мало кто, если вообще кто-либо, рассматривает возможность сборки TeX из его оригинального исходного кода на Pascal. Чтобы обойти использование Кнутом Pascal, был разработан рабочий процесс под названием [Web2C](http://tug.org/texinfohtml/web2c.html) в рамках которого исходный код TeX на Pascal механически (то есть с помощью программного обеспечения) преобразуется в эквивалент на C, который затем используется для компиляции TeX и сборки исполняемой программы. Это работает хорошо, но единственный недостаток заключается в том, что механически сгенерированный исходный код на C не предназначен для беглого просмотра человеком: он *чрезвычайно* многословен и почти непроницаем, поскольку предназначен для компиляторов, а не для людей — вот снимок экрана, показывающий небольшой фрагмент кода на C, сгенерированного из исходника TeX на Pascal:

![](/files/3c9d2f8617d76fa842fa019664b6bcf28cb745a2)

### Ещё один кнутизм: WEB-файлы изменений

Как отмечалось выше, чтобы развивать оригинальный исходный код Кнута, вы «вносите изменения» или, словами Кнута, делаете «изменения через вспомогательный файл»: но что это на самом деле означает? Здесь на сцену выходит *механизм файлов изменений*.

### Файлы изменений: механизм создания новых движков TeX

Разработчики, желающие каким-либо образом расширить TeX Кнута, то есть развивать его оригинальную работу, обычно хотят создать совершенно новую «версию» TeX или предоставить *расширение* которое можно добавить к любому движку TeX. Примеры расширений включают [SyncTeX](https://github.com/jlaurens/synctex) и [EncTeX](https://ctan.org/pkg/enctex?lang=en)— SyncTeX, например, — очень полезное расширение, которое теперь включено во все движки TeX. Потребность в EncTeX во многом была вытеснена развитием движков TeX, понимающих Unicode, — но отметим, что EncTeX встроен в pdfTeX.

Независимо от того, стремятся ли разработчики создать новую «версию» TeX (то есть производную от оригинального TeX Кнута) или создать расширение, они начинают с оригинального исходного кода Кнута и вносят необходимые изменения для создания нового движка TeX (или подключаемого расширения). Однако, как отмечалось выше, любой, кто хочет изменить поведение TeX, должен делать это с помощью «изменений через вспомогательный файл», поскольку эти изменения/модификации нельзя вносить путём *непосредственного* редактирования оригинального исходного кода Кнута: разработчики обязаны использовать так называемый WEB *механизм файлов изменений*. Код для модификации TeX Кнута пишется на WEB-«языке» и сохраняется в один или несколько файлов кода (называемых *change-файлами*), которые затем *объединяются* с оригинальным, не изменённым основным исходным кодом Кнута. Этот процесс объединения создаёт новый составной WEB-файл, который теперь содержит *основной* исходный код нового/изменённого ПО на базе TeX. *Change-файлы* часто имеют расширение `.ch` но на практике они могут иметь любое расширение, выбранное разработчиками.

#### Как использовать/применять change-файлы?

Сегодня самый простой способ применить change-файлы и изменить «основной» WEB-файл — использовать утилиту под названием [TIE](https://ctan.org/pkg/tie). Например, предположим, что вы хотите изменить TeX Кнута, добавив, скажем, пару новых примитивов, или хотите изменить поведение существующего (стандартного) примитива TeX. Вы написали бы свой код (на Pascal!) с использованием системы литературного программирования WEB и сохранили бы его в файл, скажем, `myprim.ch`. Следующий шаг — объединить ваш код (в `myprim.ch`) с основным исходным файлом Кнута `tex.web` и получить новый составной WEB-файл, представляющий то, что мы назовём `mytex.web`. Для этого достаточно запустить программу TIE вот так:

```
tie -m mytex.web tex.web myprim.ch
```

Предполагая, что объединение прошло успешно, это приведёт к появлению нового WEB-файла `mytex.web`, при этом основной исходный файл Кнута `tex.web` остаётся полностью без изменений, как и требуется.

Теперь предположим, что кому-то ещё понравились ваши изменения и он хочет модифицировать вашу работу, чтобы добавить свои изменения поверх или в дополнение к тому, что сделали вы. Вместо распространения вашей модифицированной версии TeX (`mytex.web`) вы решаете публиковать/делиться только файлом изменений, `myprim.ch`. Любой, кто захочет развивать вашу работу, теперь может создать и поделиться своим файлом изменений, скажем, под названием `moreprim.ch` который каким-то образом расширяет ваш код. Теперь любой другой, кто хочет воспользоваться обоими файлами изменений, может сгенерировать новый составной WEB-файл, объединив *оба* файла изменений с оригиналом Кнута, чтобы получить ещё одну программу TeX, скажем, `newmytex.web`:

```
tie -m newmytex.web tex.web myprim.ch moreprim.ch
```

### Реальные системы TeX: несколько файлов изменений

Приведённое выше описание TIE на самом деле очень близко к тому, как на практике собираются многие движки TeX: они начинают с `tex.web` и добавляют последовательность файлов изменений, чтобы сгенерировать WEB-исходный файл для этого движка. Для каждого движка TeX требуется свой особый набор файлов изменений, которые нужно применять/обрабатывать (объединять) в строгом порядке: если перепутать порядок, процесс объединения завершится неудачей, потому что каждый файл изменений в последовательности опирается на изменения, внесённые файлами изменений, стоящими ранее в цепочке.

Вот пример запуска TIE с применением нескольких файлов изменений к оригинальному `tex.web` чтобы сгенерировать `ktex.web`— составной WEB-файл с модификациями TeX Кнута, делающими его готовым (подходящим) для преобразования в C через процесс Web2C. Также обратите внимание на следующее:

* `tex.ch` — очень большой change-файл, который, среди прочего, модифицирует TeX для использования Kpathsea;
* расширение SyncTeX добавляется через несколько change-файлов.

```
tie -m ktex.web tex.web tex.ch enctex.ch synctex-def.ch0 synctex-mem.ch0 synctex-mem.ch2 synctex-rec.ch0 synctex-rec.ch1 synctex-rec.ch2 tex-binpool.ch
Это TIE, версия CWEB 2.4.
Авторское право (c) 1989,1992 THD/ITI. Все права защищены.
(tex.web)
(tex.ch)
(enctex.ch)
(synctex-def.ch0)
(synctex-mem.ch0)
(synctex-mem.ch2)
(synctex-rec.ch0)
(synctex-rec.ch1)
(synctex-rec.ch2)
(tex-binpool.ch)
....500....1000....1500....2000....2500....3000....3500....4000....4500
....5000....5500....6000....6500....7000....7500....8000....8500....9000
....9500....10000....10500....11000....11500....12000....12500....13000
....13500....14000....14500....15000....15500....16000....16500....17000
....17500....18000....18500....19000....19500....20000....20500....21000
....21500....22000....22500....23000....23500....24000....24500....
(Ошибок не обнаружено.)
```

#### В сторону: XeTeX и pdfTeX

Для полноты картины следует отметить, что процесс сборки pdfTeX и XeTeX на самом деле не начинается с оригинального файла Кнута `tex.web`; вместо этого он начинается с файлов под названием `pdftex.web` и `xetex.web` соответственно: вероятно, потому, что изменения настолько обширны, что разумнее распространять/публиковать WEB-файлы, уже содержащие очень существенные модификации оригинального кода Кнута.

### Пример: e-upTeX

Японское сообщество TeX разработало ряд движков TeX, предназначенных для решения сложностей вёрстки японского текста:

* **pTeX**: движок TeX Кнута, расширенный для поддержки вёрстки на японском языке;
* **e-pTeX**: комбинация e-TeX и pTeX (плюс несколько примитивов, введённых pdfTeX);
* **upTeX**: Unicode-ориентированная версия pTeX плюс расширения для лучшей обработки CJK (китайского, японского и корейского);
* **e-upTeX**: комбинация (объединение) e-TeX и upTeX.

#### Создание составного исходного файла для e-upTeX

Чтобы создать составной WEB-исходный файл для e-upTeX (с SyncTeX), вы начинаете с оригинального файла Кнута `tex.web` но нужно применить **26** отдельные change-файлы в следующем порядке, чтобы получить единый составной файл, из которого можно извлечь список примитивных команд:

```
etex.ch, tex.ch0, tex.ch, tex.ech, etex.ch0,
ptex-base.ch, uptex-m.ch, euptex.ch0, eptex.ech,
etex.ch1, euptex.ch1, synctex-def.ch0, synctex-ep-mem.ch0,
synctex-mem.ch0, synctex-e-mem.ch0, synctex-ep-mem.ch1,
synctex-p-rec.ch0, synctex-rec.ch0, synctex-rec.ch1,
synctex-e-rec.ch0, synctex-p-rec.ch1, fam256.ch,
pdfstrcmp-eup-pre.ch, pdfutils.ch, pdfstrcmp-eup-post.ch,
tex-binpool.ch
```

#### Применение change-файлов: какие файлы и в каком порядке?

Как уже отмечалось, критически важно применять/обрабатывать change-файлы в строгом порядке — но как узнать, какие файлы нужны и в каком порядке их обрабатывать? К счастью, эта важнейшая информация записана в файлах, входящих в дистрибутив TeX Live, а изучение исходного кода TeX Live позволило выявить правила, которые определяют требования к сборке для каждого движка TeX. Следуя этим правилам, Overleaf смог восстановить составной WEB-исходный файл для каждого движка TeX и извлечь список примитивов для последующей обработки данных.

## И наконец: как извлечь список примитивов?

После того как составной WEB-файл создан, задача извлечения списка примитивов с помощью регулярных выражений тривиальна, поскольку все примитивные команды определяются («регистрируются») с использованием одной функции Pascal под названием `primitive(...)`. Вот несколько реальных примеров из исходного кода Кнута: `tex.web` исходный код:

```
primitive("lineskip",assign_glue,glue_base+line_skip_code)
primitive("baselineskip",assign_glue,glue_base+baseline_skip_code)
primitive("parskip",assign_glue,glue_base+par_skip_code)
primitive("abovedisplayskip",assign_glue,glue_base+above_display_skip_code)
primitive("belowdisplayskip",assign_glue,glue_base+below_display_skip_code)
primitive("abovedisplayshortskip",assign_glue,glue_base+above_display_short_skip_code)
...
...
```

Как видите, `primitive(...)` эту функцию очень удобно обрабатывать текстом с регулярными выражениями: имя регистрируемого примитива находится в кавычках (`"..."`) вместе с дополнительными данными, которые классифицируют поведение каждого примитива (мы не будем рассматривать это подробно). После извлечения списка примитивов для каждого движка эти данные были обработаны несколькими скриптами Lua для создания HTML с табличными результатами.

### Возвращаясь к LuaTeX

Мы отметили, что LuaTeX не использует точно такой же процесс сборки, как остальные 8 движков TeX. Кратко рассмотрев процесс Web2C, преобразование Pascal в C и механизм файлов изменений, мы теперь можем объяснить, чем LuaTeX отличается: разработчики LuaTeX решили отказаться от громоздкого процесса преобразования Pascal в C — как отмечено в [Справочном руководстве LuaTeX](http://www.pragma-ade.com/general/manuals/luatex):

> ...структура компиляции — это web2c, и мы продолжаем её использовать, но без шага преобразования Pascal в C.

Код ядра LuaTeX был переписан на C, что означает, что процесс его сборки несколько более стандартен и, безусловно, гораздо удобнее. Одним из полезных следствий является то, что примитивы, поддерживаемые LuaTeX, аккуратно выделены в отдельный исходный файл на C, что значительно упростило задачу доступа к ним/их перечисления.

Строго говоря, следует также отметить, что некоторые файлы исходного кода LuaTeX используют вариант методологии литературного программирования Кнута, называемый [CWEB](https://en.wikipedia.org/wiki/CWEB), основанный на C, а не на Pascal.

### Не только WEB-файлы: требуется и другой исходный код

После генерации составного WEB-исходного файла для любого движка TeX (кроме LuaTeX) исходный код на Pascal должен быть извлечён и преобразован в код на C, но это не всё решение. Помимо C-кода, сгенерированного из WEB-исходника (Pascal⮕C), большинство движков TeX также полагаются на ряд дополнительных вспомогательных файлов исходного кода (библиотек), которые обычно пишутся на C — таких как [Kpathsea](https://www.tug.org/kpathsea/). Вспомогательные исходные файлы (библиотеки) реализуют функциональность, которую не нужно или невозможно писать на WEB (Pascal). Всё, что написано на WEB-«языке» для TeX, должно использовать язык Pascal, который затем извлекается и преобразуется в машинно-сгенерированный C: если вам не нужно делать это, почему бы не написать это сразу на C или C++.


---

# 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/18-how-overleaf-created-the-tex-primitive-reference-data.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.
