Ao tentar aprender macros em LaTeX, me depareiesta definição:
\x@protect
é uma macro com um argumento, representado pelo "#1
".\@typeset@protect
também é definido como\relax
e, portanto, o primeiro ramo do\ifx
é executado, o que não faz nada. (\ifx
compara 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.tex
está
\documentclass{article}
\DeclareRobustCommand{\?}{js bibra}
\makeatletter
\show\?
O \show
comando 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 \protect
nã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@protect
removerá os dois últimos tokens, saindo \protect\?\fi
(e \fi
eventualmente desaparecerá).
Isso acontece, por exemplo, em \protected@edef
ou \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 \protect
desaparece 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 \show
comando. 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@protect
e \protect
també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.