[texhax] Composing two commands one inside another
Les Saper
saper at math.duke.edu
Thu Aug 12 17:36:11 CEST 2004
Dear Rudolfo,
The reference for the discussion that follows is Chapter 20 of
the TeXbook by Donald Knuth, which is well worth studying
carefully.
You asked why in Plain TeX the code
\edef\a#1,#2{#1}
\edef\b#1{#1,dog}
\edef\c#1,#2{\b{\a#1,#2}}
\c{cat,mouse}
\bye
did not give the desired result, namely: cat,dog. If you run
this code you get the response:
Runaway argument?
{cat,mouse}
! Forbidden control sequence found while scanning use of \c.
<inserted text>
\par
<to be read again>
\bye
l.5 \bye
This is actually a good clue to the problem. It says that the
usage of \c did not match its definition. In your case, you have
defined \c to have two arguments, separated by a comma. However
an argument in TeX always has properly nested braces, so in your
usage the text {cat,mouse} is being absorbed into the first
argument and while TeX was searching after that for a comma it
found \bye!
This suggests trying
\edef\a#1,#2{#1}
\edef\b#1{#1,dog}
\edef\c#1,#2{\b{\a#1,#2}}
\c cat,{mouse}
\bye
The space after \c serves to separate the control sequence from
the argument but will otherwise be ignored. The braces around
mouse are needed since otherwise only the "m" will be taken as
the second argument. After the correct argument is determined,
TeX will strip off the braces. (Braces are not needed around cat
since the first argument is delimited by the comma.)
Unfortunately the result of this code is: cat2,dog. What is
going on? You have chosen to use \edef, expanded definition.
This means that even before the macro \c gets used, the macros
present in its replacement text will get expanded. In
particular, the text \a#1,#2 will be expanded. The first
argument to \a will be the text #1 (since it is delimited by the
comma) and the second argument to \a will be the character #.
That means there will be an extraneous 2 left over which appears
in the final output.
"How does TeX determine where an argument stops, you ask". The
answer (which has been used many times in the above discussion)
is in the double dangerous bend paragraph at the bottom of p.
203 in the TeXbook.
Another problem with the above code is that you wanted the form
of the input to be \c{cat,mouse}, instead of using the odd
looking \c cat,{mouse}. This means that \c should defined to
only have one argument, namely the full string cat,mouse and the
parsing of the two words separated by a comma could be left to
another macro. But this seems to imply that you can't use \edef
for \c.
At this point there are many solutions, depending on what you
need. Here is one:
\def\a#1,#2,{#1}
\def\b#1{#1,dog}
\def\c#1{\b{\a#1,}}
\c{cat,mouse}
\bye
The argument to \c will be cat,mouse (with the braces stripped as
noted above). To avoid have just m taken as the second argument
to \a, I have inserted another comma in the definition of \c
after \a#1 and I have have modified \a to look for two arguments,
each delimited by a comma.
I hope this helps.
- Les
-----------------------------------------------------------
Leslie Saper e-mail: saper at math.duke.edu
Department of Mathematics phone: 919-660-2843
Duke University Fax: 919-660-2821
Box 90320
Durham, NC 27708-0320
USA
More information about the texhax
mailing list