Всегда ли TeX вставляет макрос \par?

Всегда ли TeX вставляет макрос \par?

Когда процессор ввода встречает два символа с кодом категории 5 подряд (другими словами, пустую строку), он вставляет макрос \par.

Когда \vbox{Abc.}заканчивается, TeX завершает текущий абзац, но не вставкой макроса \par. Похоже, что TeX вставляет \parпримитив вместо этого. Правильно ли я понимаю, что TeX делает в этом случае? А как насчет других мест, куда TeX вставляет \par? Когда это макрос \par, а когда примитив?

\catcode`@=11
\let\@@par\par
\def\par{\typeout{Macro!}\@@par}

Abc.

\vbox{Abc.\tracingall}

решение1

В программе TeX есть ровно 7 мест, где TeX выполняет внутренний конструктор абзацев, т.е. превращает горизонтальный список (если он находится в процессе построения) в абзац. Это происходитнетпутем вставки \parтокена во входной поток, но путем выполнения процедурыконец_графареализовано в модуле §1096 в программе TeX.

Эта процедура ничего не делает, если TeX не находится в горизонтальном режиме, и практически ничего, если он находится в горизонтальном режиме, но с пустым списком (пустые абзацы игнорируются TeX), и выполняет процедуруРазрыв строкив противном случае (и это делает всю магию, добавляя штрафы за прогулы и т. д.).

Семь мест:

  • в конце внутренних вертикальных структур, таких как закрывающая скобка, \vboxно также \noalignили \vcenterили ячейка выравнивания
  • когда примитивныйpar_endощущается (что изначально доступно на макроуровне как значение токена \par)
  • сразу после завершения процедуры вывода (OR) (таким образом, любой горизонтальный список, начатый в OR, не будет продолжаться материалом из гранок, а сформирует отдельный абзац)

Ни в одном из этих случаев не вставляется \parтокен (который может подлежать переопределению); вместо этогоконец_графапроцедура выполнена!

\parТокены вставляются только в горизонтальном режиме и встречаются примитивы, несовместимые с горизонтальным режимом (например \vskip, , , ... полный список в §1094 в коде TeX). И, конечно, в процессе токенизации, когда TeX заменяет два символа конца строки на (т. е. делая пустые строки эквивалентными ).\hrule\par\par

решение2

В соответствии сTeXbook, правило для окончания строк следующее

Если TeX видит символ конца строки (категория 5), он отбрасывает любую другую информацию, которая может остаться на текущей строке. Затем, если TeX находится в состоянииН(новая строка), символ конца строки преобразуется в токен управляющей последовательности\par (конец абзаца); если TeX находится в состоянииМ(середина строки), символ конца строки преобразуется в токен для символа 32 ( ) категории 10 (пробел); и если TeX находится в состоянииС(пропуская пробелы), символ конца строки просто опускается.

Здесь важно отметить, что TeX вставляет токен \par, а не \parпримитив. Это означает, что это \parдолжно быть определено при любых обстоятельствах. Кнут иллюстрирует этот момент, обсуждая команды, которые принудительно включают горизонтальный режим:

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

Теперь, то, что, кажется, нигде не упоминается, это то, что происходит в конце внутреннего вертикального режима. Очевидно, что приведенные выше правила не позволяют вставлять токен, \parпоскольку нет маркеров конца строки, с которыми нужно иметь дело. (Вы получаете вставленный, \parесли между последним материалом в \vboxи концом поля есть пустая строка.)

При чтении выходных данных трассировки нет упоминания о \parпримитиве в конце поля, но shipout показывает

....\penalty 10000
....\glue(\parfillskip) 0.0 plus 1.0fil

и, конечно, там явно построен абзац. Поэтому я пришел к выводу, что конец внутреннего вертикального режима неявно вставляет примитив \par, и таким образом вставляет обычный материал конца абзаца, а затем запускает конструктор абзаца.

решение3

Есть причина, по которой TeX помещает «первоначальное значение» \parв конец a \vbox: рассмотрим следующий глупый ввод

\vbox{\let\par\empty a}

Когда TeX находит }, он создает его резервную копию, завершает горизонтальный режим, вставляя «оригинал \par», а затем перечитывает , }который закрывает внутренний вертикальный режим.

Мы можем смоделировать, что произойдет, если TeX вставит текущее значение \parперед повторным чтением }by

\vbox{\let\par\empty a\vskip0pt}

потому что \vskipвставляет (текущее) \parи TeX перечитывает \vskip. Результат — бесконечный цикл!

(Найдено вДискуссия 1993 года по темеcomp.text.tex.)

Связанный контент