10

Consider the following macro definition, and subsequent invocation:

\def\foo #1 #2 \bar{stuff with #1 and #2 goes here}
\foo arg1 arg2 \bar

The \bar simply acts as the terminator for \foo. This all works just as expected, #1 gets "arg1" and #2 gets "arg2." But now consider this:

\def\foo #1 #2\bar{stuff with #1 and #2 goes here}
\foo arg1 arg2 \bar

Here I have removed the space before \bar in the macro definition, but I have left it remaining in the macro invocation. Since TeX is usually pretty strict I would expect the macro invocation to no longer trigger. The call of \foo<SPACE>arg1<SPACE>arg2\bar naturally does not technically match the template \foo<SPACE>#1<SPACE>#2<SPACE>\bar, but TeX doesn't seem to care.

What exactly are the rules being applied here? What if I put two spaces before the \bar, would the first definition them put arg2<SPACE> into #2, and would the second definition then fail? I'm about to go try that out now, and obviously the workings of this one rule could be deduced by experimentation, but it would be nice to see some sort of detailed explanation of how TeX matches macro calls to invocations, if such a thing exists.

Just reaching out for thoughts and potential guidance.

  • I added a macro name to your \definitions, without which they are wrong. – Ryan Reich Aug 30 '13 at 21:53
  • 1
    Yes, it matches, #2 is simply arg2␣ with the space. Try \def\foo #1 #2\bar{…} and use it as \foo arg1 arg2 \bar. (By the way, the space between \foo and #1 doesn’t count at all.) – Qrrbrbirlbel Aug 30 '13 at 21:54
8

You want to distinguish "TeX is strict about parameter text" and "TeX cares about spaces in parameter text". The latter is true but misleading: TeX cares about everything in parameter text, of which space is one insidious example (except after a control sequence). If you put a space into the macro parameters, then that space will be sought whenever the macro is expanded. On the other hand, if you do not put a space into the parameters, and a space is nonetheless found when expanding, it is just interpreted as one of the arguments if that fits with the entire parameter specification.

So in your example,

\def\foo #1 #2\bar{...}
\foo arg1 arg2 \bar

TeX looks for #2 after seeing its first space (the one after arg1) and takes it to be everything up until \bar, including the space you thought it cared about. It doesn't, because that space never came up in the definition of \foo so is just some tokens for this purpose.

6

With your first definition

\def\foo⍽#1⍽#2⍽\bar{stuff⍽with⍽#1⍽and⍽#2⍽goes⍽here}

the <parameter text> is (with • for separating tokens and <space> meaning a space token)

#1<space>#2<space>\bar

and the call

\foo⍽arg1⍽arg2⍽\bar

results in #1<-arg1 and #2<-arg2. The two <space> tokens are removed together with \bar because of how TeX macro expansion works. There is no space token at the start of the <parameter text> because spaces are ignored after control sequences. The resulting token list after the expansion of \foo will be

stuff<space>with<space>arg1<space>and<space>arg2<space>goes<space>here

The call

\foo⍽arg1⍽arg2⍽⍽\bar

would give exactly the same result, because consecutive spaces are normalized to a single space token during tokenization.

With the second definition, that is,

\def⍽#1⍽#2\bar{stuff⍽with⍽#1⍽and⍽#2⍽goes here}

the <parameter text> is (again with • for separating tokens)

#1<space>#2\bar

and the call

\foo⍽arg1⍽arg2⍽\bar

will result in #1<-arg1 and #2<-arg2<space> (with a trailing space in the second argument), and the resulting token list will be

stuff<space>with<space>arg1<space>and<space>arg2<space><space>goes<space>here

Note that in this case two space tokens will be there, because tokenization has already taken place.

2

The definition of

\def\foo #1 #2\bar{stuff with ``#1'' and ``#2'' goes here}

still matches

\foo arg1 arg2 \bar

#2 simply is replaced by arg2␣ (notice the horizontal space between arg2 and in the output below).

The replacement for #1 is everything until the next space, but #2 is simply everything until the next \bar whatever that might be.

For the first definition of \foo

\def\foo #1 #2 \bar{stuff with ``#1'' and ``#2'' goes here}

and the use of

\foo arg1 arg2 arg3? \bar 

similar applies: #1 is everything up to the next space (but excluding it); #2 will be everything up to the next token sequence ␣\bar and not “everything up to the next space and then hopefully a \bar will follow”.

Code

\def\foo #1 #2 \bar{stuff with ``#1'' and ``#2'' goes here}
\foo arg1 arg2 \bar \par \foo arg1 arg2 arg3? \bar \par\bigskip

\def\foo #1 #2\bar{stuff with ``#1'' and ``#2'' goes here}
\foo arg1 arg2 \bar \par \foo arg1 arg2 arg3? \bar

\bye

Output

enter image description here

1

I assume that you have defined \foo

 \def \foo #1 #2 \bar{stuff with #1 and #2 goes here}.

Spaces are a difficult subject in TeX. One rule is that spaces following a control word (that is a control sequence of all letters), are ignored. Another rule is that two or more consecutive spaces are (most of the times) seen as one space. For clarity let's redefine \foo by

 \def \foo #1*#2**\bar{stuff with #1 and #2 goes here}

To use \foo, it must be followed by a string with "*" to end the first argument and "*\bar" to end the second argument. So when TeX reads

 \foo arg1*arg2**\bar

the first argument to \foo will be "arg1" (without quotes), the second argument is "arg2*". If we would define

 \def \goo #1*#2\bar{stuff with #1 and #2 goes here}

the second argument is ended by \bar. So when TeX reads

 \goo arg1*arg2**\bar

the first argument to \goo will be "arg1", the second argument is "arg2**". Note that when an argument begins with "{" and ends with "}", these brackets are removed. So when TeX reads

 \goo {arg1}*{arg}2**\bar

the first argument to \goo will be "arg1", the second argument is "{arg}2**". Another example: when TeX reads

 \goo {arg1*}{arg}2**\bar

the first argument to \goo will be "{arg1*}{arg}2", the second argument is "*".

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.