[texhax] Tracing a LaTeX macro
Doug McKenna
doug at mathemaesthetics.com
Tue Feb 1 02:34:32 CET 2011
Greetings.
I have been trying to wrap my head around how a piece of LaTeX works
under the hood, in particular the
\DeclareRobustCommand
macro when it declares
\DeclareRobustCommand\\{ ... }
soon after
\DeclareRobustCommand{\GenericError}[4]{ ... }
all in the source distribution file "ltpar.dtx". As the source notes
say, there will be a difference in how this macro works, depending on
whether the command name being defined is all letters or starts with a
non-letter character.
So my strategy to understand how the macro works was to edit a copy of
"latex.ltx", in which I placed a
\tracingcommands=3\tracingmacros=1
just before the invocation of the macro, and
\tracingcommands=0\tracingmacros=0
just after its invocation to turn tracing off. I then ran the new file
from the Unix terminal using the "tex" command (texlive 2008, installed
on my Mac, though I doubt that matters). I understand that "tex" is
running a pre-formatted interpreter, as the LaTeX code mentions in a
message right at the beginning after checking for CatCodes, but I don't
care abut getting to the end of the entire thing. I just wanted to see
the execution trace of how this particular macro operates when asked to
define \\. It all seems to work okay, for example, for earlier
invocations in the file, when declaring the various Generic... commands.
But when it comes to calling
DeclareRobustCommand\\{ ...
the parse goes to pieces and I keep getting lost as to what's
transpiring. TeX issues an error message about \number not finding an
integer to convert (because there's a '{' as the next token that causes
\number to be unhappy). This occurs while executing the \\@yargdef
macro, called from \@ifdefinable, called from @argdef. A cascade of
further errors involving illegal '#' characters on the input ensues.
Since one can only assume this error does not occur when building LaTeX,
I'm wondering what I'm missing, especially given that the macro seems to
manage fine with the earlier all-letter Generic... commands.
Any help would be much appreciated, especially as I've spent a whole lot
of time trying to figure this out, and am at my Witt's End. After
removing nearly all extraneous stuff from the input file, I can reproduce
the situation with just the following excerpt from the LaTeX code (I've
inserted commented blank lines for a touch of clarity):
\catcode`\{=1
\catcode`\}=2
\catcode`\#=6
\catcode`\^=7
\chardef\active=13
\catcode`\@=11
\countdef\count@=255
\let\bgroup={ \let\egroup=}%
%
\def\makeatletter{\catcode`\@11\relax}%
\makeatletter
\def\makeatother{\catcode`\@12\relax}%
\def\strip at prefix#1>{}%
\long\def \@gobble #1{}%
\long\def\@firstoftwo#1#2{#1}%
\long\def\@secondoftwo#1#2{#2}%
\def\@carcube#1#2#3#4\@nil{#1#2#3}%
%
\def\@ifundefined#1{%
\expandafter\ifx\csname#1\endcsname\relax
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi}%
%
\let\@typeset at protect\relax
%
\long\def\@ifdefinable #1#2{%
\edef\reserved at a{\expandafter\@gobble\string #1}%
\@ifundefined\reserved at a
{\edef\reserved at b{\expandafter\@carcube \reserved at a xxx\@nil}%
\ifx \reserved at b\@qend \@notdefinable\else
\ifx \reserved at a\@qrelax \@notdefinable\else
#2%
\fi
\fi}%
\@notdefinable}%
\let\@@ifdefinable\@ifdefinable
%
\def\x at protect#1{%
\ifx\protect\@typeset at protect\else
\@x at protect#1%
\fi
}%
\def\@x at protect#1\fi#2#3{%
\fi\protect#1%
}%
\long\def\@rc at ifdefinable#1#2{%
\let\@ifdefinable\@@ifdefinable
#2}%
%
\def\@star at or@long#1{%
\@ifstar
{\let\l at ngrel@x\relax#1}%
{\let\l at ngrel@x\long#1}}%
%
\long\def\@ifnextchar#1#2#3{%
\let\reserved at d=#1%
\def\reserved at a{#2}%
\def\reserved at b{#3}%
\futurelet\@let at token\@ifnch}%
\let\kernel at ifnextchar\@ifnextchar
\def\@ifnch{%
\ifx\@let at token\@sptoken
\let\reserved at c\@xifnch
\else
\ifx\@let at token\reserved at d
\let\reserved at c\reserved at a
\else
\let\reserved at c\reserved at b
\fi
\fi
\reserved at c}%
%
\def\@ifstar#1{\@ifnextchar *{\@firstoftwo{#1}}}%
%
\def\:{\let\@sptoken= } \: % this makes \@sptoken a space token
\def\:{\@xifnch} \expandafter\def\: {\futurelet\@let at token\@ifnch}%
%
\def\newcommand{\@star at or@long\new at command}%
\def\@newcommand#1[#2]{%
\kernel at ifnextchar [{\@xargdef#1[#2]}%
{\@argdef#1[#2]}}%
\def\new at command#1{%
\@testopt{\@newcommand#1}0}%
%
\long\def\@argdef#1[#2]#3{%
\@ifdefinable #1{\@yargdef#1\@ne{#2}{#3}}}
\long\def\@xargdef#1[#2][#3]#4{%
\@ifdefinable#1{%
\expandafter\def\expandafter#1\expandafter{%
\expandafter
\@protected at testopt
\expandafter
#1%
\csname\string#1\endcsname
{#3}}%
\expandafter\@yargdef
\csname\string#1\endcsname
\tw@
{#2}%
{#4}}}%
%
\long\def\@xargdef#1[#2][#3]#4{%
\@ifdefinable#1{%
\expandafter\def\expandafter#1\expandafter{%
\expandafter
\@protected at testopt
\expandafter
#1%
\csname\string#1\endcsname
{#3}}%
\expandafter\@yargdef
\csname\string#1\endcsname
\tw@
{#2}%
{#4}}}%
%
\long \def \@yargdef #1#2#3{%
\ifx#2\tw@
\def\reserved at b##11{[####1]}%
\else
\let\reserved at b\@gobble
\fi
\expandafter
\@yargd at f \expandafter{\number #3}#1% <-- Where things go bad!
}
\long \def \@yargd at f#1#2{%
\def \reserved at a ##1#1##2##{%
\expandafter\def\expandafter#2\reserved at b ##1#1%
}%
\l at ngrel@x \reserved at a 0##1##2##3##4##5##6##7##8##9###1%
}%
%
\long\def\@testopt#1#2{%
\kernel at ifnextchar[{#1}{#1[{#2}]}}%
%
\def\DeclareRobustCommand{\@star at or@long\declare at robustcommand}%
%
\def\declare at robustcommand#1{%
\ifx#1\@undefined\else\ifx#1\relax\else
\@latex at info{Redefining \string#1}%
\fi\fi
\edef\reserved at a{\string#1}%
\def\reserved at b{#1}%
\edef\reserved at b{\expandafter\strip at prefix\meaning\reserved at b}%
\edef#1{%
\ifx\reserved at a\reserved at b
\noexpand\x at protect
\noexpand#1%
\fi
\noexpand\protect
\expandafter\noexpand\csname
\expandafter\@gobble\string#1 \endcsname
}%
\let\@ifdefinable\@rc at ifdefinable
\expandafter\new at command\csname
\expandafter\@gobble\string#1 \endcsname
}%
%
\tracingcommands=3\tracingmacros=2%
\DeclareRobustCommand\\{%
\let \reserved at e \relax
\let \reserved at f \relax
\@ifstar{\let \reserved at e \vadjust \let \reserved at f \nobreak
\@xnewline}%
\@xnewline}%
\tracingcommands=0\tracingmacros=0%
Thanks for any guru guidance!
Doug McKenna
More information about the texhax
mailing list