[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