Trying to understand the definition of \newcommand (complex handling of parameter tokens)
Your reasoning is correct except for what the #{
parameter does.
When TeX sees a #
in the <parameter text>
of a macro (as in \def\macro<parameter text>{<replacement text>}
), the following token can be either a digit in the range 1–9, or a {
. When the parameter is "the dreaded weird #{
parameter", then TeX behaves as if the delimiter of the previous argument was a {
(since you can't use a {
in the <parameter text>
).
In this definition (remember the {\bar}
is still in the input stream):
\def\reserved@a #12#2#{%
\expandafter\def\expandafter\foo\reserved@b #12%
}%
\l@ngrel@x \reserved@a 0#1#2#3#4#5#6#7#8#9#2{\bar }
when \reserved@a
expands, #1
will be, as you said, 0#1#
, and #2
will be everything up to the next {
, and not empty, so #3#4#5#6#7#8#9#2
, delimited by the {
in {\bar }
. This definition of \reserved@a
effectively throws away the remaining parameter tokens. So your "pretend[ing] that string before the {\bar}
isn't there" was actually correct. The rest of the code executes as you assumed.
A quote from The TeXbook, about the #{
parameter:
A special extension is allowed to these rules: If the very last character of the
<parameter text>
is#
, so that this#
is immediately followed by{
, TeX will behave as if the{
had been inserted at the right end of both the parameter text and the replacement text. For example, if you say '\def\a#1#{\hbox to #1}
', the subsequent text '\a3pt{x}
' will expand to '\hbox to 3pt{x}
', because the argument of\a
is delimited by a left brace.
I've already dealt with the problem in my book on LaTeX programming. My example is slightly different, but it's easier to copy. ;-) Suppose we have
\newcommand{\xyz}[2]{ab#1cd#2ef}
This becomes
\@star@or@long\new@command[2]{ab#1cd#2ef}
As there is no *
after \new@command
, this does \let\l@ngrel@x=\long
and \@star@or@long
disappears. Now \new@command
is expanded, yielding
\@testopt{\@newcommand\xyz}0[2]{ab#1cd#2ef}
This becomes
\kernel@ifnextchar[{\@newcommand\xyz}{\@newcommand\xyz[{0}]}[2]{ab#1cd#2ef}
The purpose is to add [0]
if the number of arguments is not given. Since there is a [
, we get
\@newcommand\xyz[2]{ab#1cd#2ef}
Now comes the lookup for a further optional argument, which I skip, and we obtain
\@argdef\xyz[2]{ab#1cd#2ef}
The token \xyz
is checked for definability; if it is not definable we get the error message, otherwise
\@yargdef\xyz\@ne{2}{ab#1cd#2ef}
and this is where the real fun starts:
\ifx\@ne\tw@
\def\reserved@b#11{[##1]}
\else
\let\reserved@b\@gobble
\fi
\expandafter\@yargd@f\expandafter{\number2}\xyz{ab#1cd#2ef}
This defines \reserved@b
to be \@gobble
and leads to
\@yargd@f{2}\xyz{ab#1cd#2ef}
Recall the definition of \@yarg@def
:
\long\def\@yargd@f#1#2{%
\def\reserved@a##1#1##2##{%
\expandafter\def\expandafter#2\reserved@b##1#1}%
\l@ngrel@x\reserved@a0##1##2##3##4##5##6##7##8##9###1%
}
The arguments are #1=2
and #2=\xyz
, so we get (double ##
are here reduced to a single #
)
\def\reserved@a#12#2#{\expandafter\def\expandafter\xyz\reserved@b#12}
\l@ngrel@x\reserved@a0#1#2#3#4#5#6#7#8#9##1{ab#1cd#2ef}
The first argument to \reserved@a
is delimited by 2
, the second argument by {
. This is a particular feature of TeX: the final argument can be delimited by the opening brace of the replacement text.
Thus the first argument is, in our case, 0#1#
. Since \l@ngrel@x
is \long
it triggers the expansion of \reserved@a
with the stated arguments:
\long\expandafter\def\expandafter\xyz\reserved@b0#1#2{ab#1cd#2ef}
Since \reserved@b
is \@gobble
, we end up with
\long\def\xyz{ab#1cd#2ef}