11

we know that

\stop

will cause LaTeX to stop parsing and output what it has processed up to this command.

But then I discovered another way to use it, as demonstrated in this minimum working example:

\documentclass{article}
  \def\demo#1-#2\stop{#2}
\begin{document}
  \def\sample{foo-bar}
  \expandafter\demo\sample\stop
  There's the Word 'bar' above this text and
  this made it into the output despite a stopping command.
\end{document}

How is \stop used here and why didn't it actually interrupt the LaTeX?

Joseph Wright
  • 259,911
  • 34
  • 706
  • 1,036
arney
  • 2,023

2 Answers2

12

The meaning of \stop is never actually read in the above. It is just used as a delimiter token. In this situation, absolutely anything will do:

\documentclass{article}
  \def\demo#1-#2\StopInTheNameOfTeX{#2}
\begin{document}
  \def\sample{foo-bar}
  \expandafter\demo\sample\StopInTheNameOfTeX
  There's the Word 'bar' above this text and
  this made it into the output despite a stopping command.
\end{document}

A simple \show\StopInTheNameOfTeX shows that this has no meaning, but in this context that meaningless is itself meaningless.

Andrew Stacey
  • 153,724
  • 43
  • 389
  • 751
10

You are defining a macro with delimited argument, something that the primitive commands \def, \gdef, \edef and \xdef can do, but \newcommand can't.

Let's see:

\def\demo#1-#2\stop{#2}

The parameter text consists of the following tokens

#1 • - • #2 • \stop

Here I use • just to separate the tokens and the spaces are for readability; in the context of the parameter text it's common to consider #1 as just one token.

This means that the first argument to \demo will be all that comes after \demo up to (and not including) the first - token at the same brace level; the second argument will be all after that - up to (and not including) \stop, again at the same brace level. So, if the call is

\demo 1{2-3}4-5\stop

TeX will set #1 <- 1{2-3}4 and #2 <- 5

The meaning of the delimiter tokens is never looked at when \demo is expanded: TeX just matches the pattern, taking the shortest match. For instance, with

\demo--\stop

we'll have an empty #1 and #2 will be changed into -.

You can even use an undefined token as delimiter:

\def\demo#1-#2\nobodydarestodefinethistoken{#2}

and TeX won't complain: the pattern is matched, parameters are substituted with the found arguments and the tokens used for the match will be discarded.


There is one exception: the left brace that starts the replacement text can be used also as a delimiter with a peculiar syntax: if you say

\def\demo#1-#2#{#2}

and then

\demo ABC-DEF{}

the second argument will be DEF and the left brace that must follow will not be discarded.

egreg
  • 1,121,712