Referência circular na macro LaTeX

Referência circular na macro LaTeX

Ao tentar aprender macros em LaTeX, me depareiesta definição:

\x@protecté uma macro com um argumento, representado pelo " #1". \@typeset@protecttambém é definido como \relaxe, portanto, o primeiro ramo do \ifxé executado, o que não faz nada. ( \ifxcompara o significado de duas macros.) Portanto, o único resultado de \x@protecté que seu argumento, o primeiro " \\" na definição de \\, é descartado. Isso deixa o comando \protect, que não funciona, e \\ele próprio. Esta parece ser uma definição circular. Na verdade, não é. É um truque desagradável por parte dos autores do LaTeX tentando encobrir seus rastros. Dê uma segunda olhada extremamente suspeita na listagem de \\. Existem dois espaços entre o último " \\" e o ponto final, enquanto após a última sequência de controle em outras listagens, existe apenas um! Na verdade, há apenas um espaço à direita em todas as listagens. O penúltimo espaço na listagem de \\faz parte do nome de sua última sequência de controle, que é " \\", incluindo o espaço!`

Por que a referência circular?

Por que não falha ao encontrar uma referência circular?

Responder1

Vamos iniciar uma sessão interativa com pdflatex test, onde test.texestá

\documentclass{article}

\DeclareRobustCommand{\?}{js bibra}

\makeatletter

\show\?

O \showcomando interromperá a execução, então poderemos emitir mais comandos

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\?

O que acontece quando \?é processado? Existem dois casos: if \protectnão tem o mesmo significado que \@typeset@protect(que é \relax), então o ramo falso é seguido. Assim, o fluxo de entrada terá

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

e a expansão de \@x@protectremoverá os dois últimos tokens, saindo \protect\?\fi(e \fieventualmente desaparecerá).

Isso acontece, por exemplo, em \protected@edefou \protected@write, quando \protecté atribuído um significado diferente de \@typeset@protect.

Se tiver, a condicional é verdadeira, então o fluxo de entrada terá, após pular a ramificação falsa,

\protect\?

Agora \protectdesaparece e nósparecerestar no mesmo lugar de antes. Mas não estamos, porque o token a seguir \protectédiferentea partir \?disso foi inserido no documento de teste.

Observe atentamente a saída do primeiro \showcomando. Nós temos

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

Entre ->e o ponto final, TeX representa o texto de substituição da macro. As regras para esta representação são que as palavras de controle são seguidas por um espaço, enquanto os símbolos de controle não. Isso explica o espaço depois \x@protecte \protecttambém nenhum espaço depois \?. Mas o período final é precedido pordoisespaços! De onde eles vêm?

Quando você faz isso \DeclareRobustCommand{\?}{js bibra}, o LaTeX faz várias coisas, sendo a principal delas algo como

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

e então usar esta macro com um nome muito fora do padrão para definir a “versão de nível de usuário” do \?. Observe o espaço antes \endcsname, que termina no nome da macro.

Existem mais alguns detalhes, mas a ideia é facilitar a escrita de arquivos auxiliares. Nas versões mais antigas do LaTeX, vimos algo como

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

Quando o LaTeX2e foi lançado, o código anterior tornou-se

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

explorando um novo nível de abstração. Nas versões mais antigas, \LaTeX{}no título de uma seção teria escrito

\protect\pLaTeX {}

nos arquivos auxiliares. Agora ele escreve

\LaTeX  {}

por causa do espaço à direita no nome e na regra. O espaço duplo será ignorado quando o arquivo auxiliar for lido.

É um pouco diferente para símbolos de controle como \\ou \?, mas a ideia geral é a mesma.

informação relacionada