
Intimamente relacionado:Como implementar \expandbefore, de forma semelhante a \expandafter?
Na questão relacionada, é feita referência ao "# Notation"
. Como funciona a sintaxe?
De uma resposta à outra pergunta:
\makeatletter
%
\newcommand\name{}%
\long\def\name#1#{\UD@innername{#1}}%
%
\newcommand\UD@innername[2]{%
\expandafter\UD@exchange\expandafter{\csname#2\endcsname}{#1}%
}%
%
\newcommand\UD@exchange[2]{#2#1}%
%
\makeatother
Como a sintaxe do parâmetro (sem número) realmente funciona? \def\test#1#{\csname teste#1\endcsname}? Quais são os bons casos de uso para usar esse padrão?
Responder1
A essência \name
é:
Com
\name⟨stuff without braces before the left-brace⟩{⟨stuff within braces⟩}
TeX deve buscar como primeiro argumento ⟨stuff without braces before the left-brace⟩
e como processo de segundo argumento ⟨stuff within braces⟩
:
The ⟨stuff within braces⟩
é considerado o nome de um token de sequência de controle que pode ser obtido agrupando ⟨stuff within braces⟩
e \csname..\endcsname
executando a \csname..\endcsname
expressão resultante.
Em vez disso, o token de sequência de controle estará por trás de .{⟨stuff within braces⟩}
⟨stuff without braces before the left-brace⟩
Quando macros com argumentos delimitados são executadas, (La)TeX reúne os tokens que formam os argumentos do fluxo de tokens e, por meio disso, no fluxo de tokens pesquisa os delimitadores de argumentos, pois os delimitadores de argumentos são tomados como marcadores para finalizar o processo de coletando tokens para o argumento em questão.
Quais delimitadores devem ser pesquisados devem ser indicados no⟨texto do parâmetro⟩da definição.
Você pode denotar que (La)TeX deve procurar como delimitador para o último argumento, por exemplo, a \relax
escrevendo \relax
como a última coisa do⟨texto do parâmetro⟩.
Você pode denotar que como delimitador para o último argumento (La)TeX deve procurar uma chave esquerda escrevendo #
como a última coisa do⟨texto do parâmetro⟩.
Em (quase ;-)) qualquer caso o⟨texto do parâmetro⟩de uma macrodefinição é seguida pela⟨texto de substituição⟩, aninhados entre colchetes.
Assim, em (quase ;-)) em qualquer caso, o⟨texto do parâmetro⟩de uma macrodefinição será seguida pela chave esquerda do par de chaves que circunda o⟨texto de substituição⟩.
Assim, quando o último token do⟨texto do parâmetro⟩é um #
, será seguido por um {
.
É por isso que essa coisa de denotar que (La)TeX deve procurar uma chave esquerda como delimitador ao reunir o último argumento para a macro, também é chamada de #{
-notação.
A diferença sutil entre a busca \relax
e a busca por uma chave de abertura é:
Quando (La)TeX como delimitador para um argumento de uma macro, por exemplo, pesquisa \relax
e encontra-o, ele não apenas para de coletar tokens para o argumento, mas também remove o delimitador/o \relax
-token.
Quando (La)TeX como delimitador para o último argumento de uma macro procura a chave esquerda e a encontra, ele para de coletar tokens para o último argumento e deixa esse delimitador/aquela chave no lugar e coloca a macro⟨texto de substituição⟩antes disso.
Citações do TeXbook do Prof. Donald Ervin Knuth, Capítulo 20: Definições (também chamadas de Macros) - Prof.professor emérito da arte da programação de computadores na Universidade de Stanford, é o inventor do TeX:
Agora que vimos vários exemplos, vamos dar uma olhada nas regras precisas que regem as macros TeX. As definições têm a forma geral
\def⟨sequência de controle⟩⟨texto do parâmetro⟩{⟨texto de substituição⟩}
onde o⟨texto do parâmetro⟩não contém colchetes e onde todas as ocorrências de{e }no⟨texto de substituição⟩estão devidamente aninhados. Além disso, o símbolo # tem um significado especial: no ⟨texto do parâmetro⟩, a primeira aparição de # deve ser seguida por 1, a próxima por 2 e assim por diante; até nove # são permitidos. No⟨texto de substituição⟩ cada # deve ser seguido por um dígito que apareceu depois de # no⟨texto do parâmetro⟩, ou então o # deve ser seguido por outro #. O último caso representa um único token # quando a macro é expandida; o primeiro caso representa a inserção do argumento correspondente.
[...]
Uma extensão especial é permitida para estas regras: Se o último caractere do⟨texto do parâmetro⟩é #, de modo que este # seja imediatamente seguido por {, o TeX se comportará como se o{foi inserido na extremidade direita do texto do parâmetro e do texto de substituição. Por exemplo, se você disser
'\def\a#1#{\hbox para #1}'
, o texto subsequente '\a3pt{x}' será expandido para '\hbox to 3pt{x}', porque o argumento de \a é delimitado por uma chave esquerda.
Em outras palavras:
Se você disser , o texto subsequente será processado da seguinte forma:\def\a#1#{\hbox to #1}
\a3pt{x}
Como argumento para a macro, \a
o TeX reunirá a partir do texto subsequente um argumento delimitado por uma chave esquerda: Ele reunirá a frase 3pt
.
A chave esquerda (e tudo o que está atrás dela) será deixada no lugar durante a substituição \a
e seu argumento pelo⟨texto de substituição⟩rende: \hbox to 3pt
para que tudo seja: \hbox to 3pt{x}
.
Resumindo: #{
-notation (observe a chave esquerda!) significa que o último parâmetro da macro em questão é delimitado por uma chave esquerda (do código de categoria 1 (begin group) ) que será deixado no lugar quando (La) O TeX coleta do token-stream o último argumento para aquela macro.
O fato de que neste caso especial o delimitador, ou seja, a chave esquerda, será deixado no lugar é digno de nota, pois esta é a única situação em que um delimitador de argumento não será removido do fluxo de token durante o processo de coleta de um argumento .
Ou seja, se o delimitador de argumento fosse, por exemplo, um \relax
-token como em
\def\mymacro#1\relax{The Argument#1 was delimited by relax. }
, o \relax
-token que serve como delimitador seria removido ao coletar o argumento do token-stream: With
\mymacro , which is nonsense,\relax...
como argumento para \mymacro
(La)TeX reuniria a sequência do token-stream , which is nonsense,
e então encontraria o token \relax
e pegaria esse \relax
-token como o delimitador do argumento e, portanto, (La)TeX pararia de coletar tokens para o argumento e isso removeria o delimitador. (Então começaria a reunir os outros argumentos de \mymacro
se de acordo com o⟨texto do parâmetro⟩de sua definição havia alguma. Mas não há nenhum.) Então ele entregaria o⟨texto de substituição⟩:
The Argument, which is nonsense, was delimited by relax.
Esse⟨texto de substituição⟩no fluxo de token seria seguido pelos três pontos e, portanto, agora o fluxo de token conteria:
The Argument, which is nonsense, was delimited by relax. ...
Mas se a definição for:
\def\mymacro#1#{The Argument#1 was delimited by a left-brace. }
e você diz
\mymacro , which is nonsense,{...
, você vai ter
The Argument, which is nonsense, was delimited by a left-brace. {...
porque ao contrário do caso anterior, onde o \relax
que delimita o argumento é removido, neste caso, a chave esquerda que delimita o argumento não será removida.
A frase
Se o último caractere do⟨texto do parâmetro⟩é #, de modo que este # seja imediatamente seguido por {, o TeX se comportará como se o{foi inserido na extremidade direita do texto do parâmetro e do texto de substituição.
significa:
Uma definição geralmente é de padrão
\def⟨sequência de controle⟩⟨texto do parâmetro⟩{⟨texto de substituição⟩}
Suponha que você deseja definir uma macro \macro
que processe dois argumentos, dos quais o primeiro argumento é indelimitado e do qual o segundo argumento é delimitado pela sequência \foo\bar
e que apenas "cospe" os argumentos.
Neste caso você cria uma expressão como:
\def\macro#1#2\foo\bar{argument 1: #1 argument 2: #2}
⟨sequência de controle⟩=\macro
⟨texto do parâmetro⟩=#1#2\foo\bar
⟨texto de substituição⟩=argument 1: #1 argument 2: #2
Quando você olha para a expressão, você vê quena extremidade direita do⟨texto do parâmetro⟩, haverá os tokens que formam o delimitador do último argumento, ou seja, os tokens \foo\bar
. Eles pertencem aos tokens que formam o⟨texto do parâmetro⟩. Logo atrás deles você pode ver a chave esquerda daquele par de chaves que circunda o⟨texto de substituição⟩.
Assim, neste caso, na extremidade direita do⟨texto do parâmetro⟩você encontra os tokens que delimitam o último argumento e encontra a chave esquerda do par de chaves que circunda o⟨texto de substituição⟩.
A sequência
\macro{A}B\foo\bar
rendimentos:
argument 1: A argument 2: B
Como você pode ver, os tokens delimitadores \foo\bar
foram removidos durante a coleta dos tokens que pertencem aos argumentos.
Se em vez disso você definir:
\def\macro#1#2\foo\bar{argument 1: #1 argument 2: #2\foo\bar}
⟨sequência de controle⟩=\macro
⟨texto do parâmetro⟩=#1#2\foo\bar
⟨texto de substituição⟩=argument 1: #1 argument 2: #2\foo\bar
,ou seja, se você inserir o delimitador \foo\bar
na extremidade direita do⟨texto de substituição⟩também, a sequência
\macro{A}B\foo\bar
rendimentos
argument 1: A argument 2: B\foo\bar
como se com a definição anterior o delimitador tivesse sido deixado no lugar.
E se você quiser definir tal coisa, mas o delimitador não for uma sequência, \foo\bar
mas uma chave esquerda?
A definição ainda deve ser de padrão
\def\macro#1#2⟨delimiter⟩{argument 1: #1 argument 2: #2⟨delimiter⟩}
mas por diversas razões você não pode {
considerar⟨delimitador⟩e escrever
\def\macro#1#2{{argument 1: #1 argument 2: #2{}
e por meio deste levo #1#2{
para o⟨texto do parâmetro⟩e argument 1: #1 argument 2: #2{
para o⟨texto de substituição⟩:
Em muitas situações, não é possível inserir facilmente colchetes únicos à esquerda sem obter erros devido ao desbalanceamento dos colchetes.
A situação seria ambígua porque (La)TeX teria que adivinhar se uma chave de abertura próxima/na extremidade direita do⟨texto do parâmetro⟩é um delimitador de argumento ou se pertence ao par de chaves que circunda o⟨texto de substituição⟩.
(La)TeX também teria que adivinhar se a chave direita deveria corresponder à chave esquerda no final do⟨texto de substituição⟩ou se deveria denotar o fim do⟨texto de substituição⟩.
Portanto, como solução sintática, #{
a notação foi inventada:
Com
\def\macro#1#2#{argument 1: #1 argument 2: #2}
⟨sequência de controle⟩= \macro
.
⟨texto do parâmetro⟩=#1#2#
⟨texto de substituição⟩=argument 1: #1 argument 2: #2
, o⟨texto do parâmetro⟩não termina com um token {
que delimitará o último argumento, mas termina com #
.
Isso #
é usado para denotar que (La)TeX deve procurar uma chave esquerda como delimitador de argumento durante o processo de expansão, \macro
reunindo os tokens do último argumento \macro
do fluxo de tokens. Isso #
também denota que a chave esquerda encontrada como delimitador deve ser deixada no lugar para que o⟨texto de substituição⟩de \macro
vai antes dele.
Em outras palavras:
Isso #
faz com que o (La)TeX se comporte como se fosse o último token que delimita o último argumento, uma chave esquerda foi encontrada no⟨texto do parâmetro⟩.
Também faz com que o (La)TeX se comporte como se o último token fornecido na definição⟨texto de substituição⟩era uma chave esquerda.
Para o seu comentário:
Hum. Eu não suponho que você poderia inventar alguma coisa? Um melhor palpite sobre o que está acontecendo? Deixe-me reformular, em seu outro exemplo, se você tiver caracteres do código cat 1 flutuando em tudo isso. É correto inferir que esse "comportamento primitivo" ocorre durante a fase de entrada da leitura do arquivo? (Desculpe, estou inventando a terminologia à medida que prossigo... estou falando do
process_input_buffer
manipulador de eventos.
O primeiro estágio do processamento no LaTeX é ler a entrada (do arquivo ou do console) e levá-la para um conjunto de instruções para colocarfichasno fluxo de token. (Tokens de caracteres/tokens de sequência de controle). Nas etapas subsequentes, os tokens no fluxo de tokens são processados. Em um desses estágios anteriores, os tokens expansíveis, por exemplo, macros, são expandidos. Ou seja, eles são substituídos por aqueles tokens que formam os textos de substituição de suas definições. Nesta fase ocorre a coleta de tokens para macro-argumentos. Assim, o comportamento não ocorre durante a leitura do arquivo, mas ocorre após a leitura e tokenização, na fase de expansão de tokens expansíveis e, assim, coleta de outrosfichascomo seus argumentos.
Tentei elaborar detalhadamente como o (La)TeX reúne e processa argumentos macro em minha resposta à perguntaComo o TeX procura argumentos delimitados?
Tentei elaborar detalhadamente sobre \expandafter
as maneiras de evitá-lo em minha resposta à perguntaComo posso saber o número de expansões ao anexar a uma macro csname?
Tentei elaborar detalhadamente a macro \name
em minha resposta à perguntaDefina uma sequência de controle depois que um espaço for importante