Циклическая ссылка в макросе LaTeX

Циклическая ссылка в макросе LaTeX

Пытаясь изучить макросы в LaTeX, я наткнулся наэто определение:

\x@protectмакрос с одним аргументом, представленным как " #1". \@typeset@protectтакже определяется как и, следовательно, выполняется \relaxпервая ветвь , которая ничего не делает. ( сравнивает значение двух макросов.) Таким образом, единственным результатом является то, что его аргумент, первый " " в определении , отбрасывается. Это оставляет команду \protect, которая является не-операцией, и себя самого. Это кажется циклическим определением. На самом деле, это не так. Это грязный трюк со стороны авторов LaTeX, пытающихся замести следы. Еще раз, крайне подозрительно, посмотрите на листинг . Между последним " " и точкой есть два пробела , тогда как после последней управляющей последовательности в других листингах есть только один! На самом деле, во всех листингах есть только один завершающий пробел. Предпоследний пробел в листинге является частью имени его последней управляющей последовательности, которая является " ", включая пробел!`\ifx\ifx\x@protect\\\\\\\\\\\\\\

Почему циклическая ссылка?

Почему он не ломается при обнаружении циклической ссылки?

решение1

Давайте начнем интерактивный сеанс с pdflatex test, где test.texнаходится

\documentclass{article}

\DeclareRobustCommand{\?}{js bibra}

\makeatletter

\show\?

Команда \showостановит выполнение, и мы сможем выполнить больше команд.

This is pdfTeX, Version 3.14159265-2.6-1.40.20 (TeX Live 2019) (preloaded format=pdflatex)
 restricted \write18 enabled.
entering extended mode
(./test.tex
LaTeX2e <2019-10-01> patch level 3
(/usr/local/texlive/2019/texmf-dist/tex/latex/base/article.cls
Document Class: article 2019/10/25 v1.4k Standard LaTeX document class
(/usr/local/texlive/2019/texmf-dist/tex/latex/base/size10.clo))
> \?=macro:
->\x@protect \?\protect \?  .
l.7 \show\?

? i\show\x@protect
> \x@protect=macro:
#1->\ifx \protect \@typeset@protect \else \@x@protect #1\fi .
<insert>   \show\x@protect

l.7 \show\?

? i\show\@x@protect
> \@x@protect=macro:
#1\fi #2#3->\fi \protect #1.
<insert>   \show\@x@protect

l.7 \show\?

Что происходит, когда \?обрабатывается? Есть два случая: если \protectне имеет того же значения, что и \@typeset@protect(который есть \relax), то следует ложная ветвь. Таким образом, входной поток будет иметь

\@x@protect\?\fi\protect\?

а расширение \@x@protectудалит последние два токена, оставив \protect\?\fi\fiв конечном итоге исчезнет).

Это происходит, например, в \protected@edefили \protected@write, когда \protectприсваивается иное значение, чем \@typeset@protect.

Если это так, то условие истинно, поэтому входной поток будет иметь, после пропуска ветви false,

\protect\?

Теперь \protectисчезает и мыказатьсябыть в том же месте, что и раньше. Но мы не там, потому что следующий токен \protect- этодругойиз \?этого был сделан ввод в тестовый документ.

Посмотрите внимательно на вывод первой \showкоманды. Получаем

->\x@protect \?\protect \?  .

Между ->и завершающей точкой TeX представляет заменяющий текст макроса. Правила для этого представления таковы, что за управляющими словами следует пробел, тогда как за управляющими символами — нет. Это объясняет пробел после \x@protectи , \protectа также отсутствие пробела после \?. Но завершающей точке предшествуетдвапробелы! Откуда они берутся?

Когда вы это делаете \DeclareRobustCommand{\?}{js bibra}, LaTeX выполняет несколько действий, главное из которых — что-то вроде

\expandafter\def\csname ? \endcsname{js bibra}

и затем использование этого макроса с очень нестандартным именем для определения «версии уровня пользователя» \?. Обратите внимание на пробел перед \endcsname, который оказывается в имени макроса.

Есть еще некоторые детали, но идея в том, чтобы облегчить написание вспомогательных файлов. В старых версиях LaTeX мы видели что-то вроде

\def\LaTeX{\protect\pLaTeX}
\def\pLaTeX{<the real definition>}

Когда был выпущен LaTeX2e, предыдущий код стал

\DeclareRobustCommand{\LaTeX}{<the real definition>}

эксплуатируя новый уровень абстракции. В старых версиях \LaTeX{}в заголовке раздела было бы написано

\protect\pLaTeX {}

во вспомогательных файлах. Теперь он выписывает

\LaTeX  {}

из-за завершающего пробела в имени и правиле. Двойной пробел будет проигнорирован при чтении вспомогательного файла.

\\Для управляющих символов, таких как или , это немного отличается \?, но общая идея та же.

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