9

I would like to have a macro \ignorepars that removes all \pars following it. I wrote the following code:

\def\eat{}
\def\ignorepars{\futurelet\next\ignoreparsA} 
\def\ignoreparsA{\ifx\next\par\expandafter\ignorepars\eat\fi}

but it does not work (it causes a TeX capacity exceeded error). Suppose, for example, I have \ignorepars\par x. Then, according to me, the expansion of \ignorepars makes \next like \par and the token list becomes \ignoreparsA\par x; next after expanding \ignoreparsA it remains \expandafter\ignorepars\eat\par x; so, after another expansion the token list becomes \ignorepars x; which make \next have the value x and expands to \ignoreparsA x; this expands to nothing becase the \ifx predicate is false.

What is happening instead?

EDIT: \def\eat{} should have been \long\def\eat#1{} (it was a typing error)

  • 1
    \eat should take a paramater to actually eat something, i.e. \def\eat#1{}. – Henri Menke Nov 23 '15 at 21:11
  • and (if i understand) \eat should be \long – touhami Nov 23 '15 at 21:16
12

Let's do it slowly:

\ignorepars\par x

becomes

\futurelet\next\ignoreparsA\par x

Now \next is \let to \par and \ignoreparsA is expanded, so we have

\ifx\next\par\expandafter\ignorepars\eat\fi\par x

The conditional is true, so \ifx\next\par disappear, leaving

\expandafter\ignorepars\eat\fi\par x

Now \expandafter expands \eat, which has empty expansion, so we have

\ignorepars\fi\par x

OK, \ignorepars is expanded:

\futurelet\next\ignoreparsA\fi\par x

Now \next is \let to \fi and \ignoreparsA is expanded

\ifx\next\par\expandafter\ignorepars\eat\fi\fi\par x

The conditional is false, so we get

\fi\par x

Finally, the expansion of \fi is empty. So, as you see, no \par is swallowed. Indeed, the test file

\def\eat{}
\def\ignorepars{\futurelet\next\ignoreparsA}
\def\ignoreparsA{\ifx\next\par\expandafter\ignorepars\eat\fi}

x\ignorepars\par x

\bye

does not end up in TeX capacity exceeded, but prints two paragraphs.

If your definition of \eat is

\def\eat#1{}

then you'll indeed get into an infinite loop, because \eat will gobble \fi and present TeX with \ignorepars\par again and again.


You have better luck with

\long\def\eat#1{\ignorepars}
\def\ignorepars{\futurelet\next\ignoreparsA}
\def\ignoreparsA{\ifx\next\par\expandafter\eat\fi}

x\ignorepars\par x

\bye

The \expandafter gets rid of \fi, whereas \eat gobbles the \par token and supplies \ignorepars.

Test file

\long\def\eat#1{\ignorepars}
\def\ignorepars{\futurelet\next\ignoreparsA}
\def\ignoreparsA{\ifx\next\par\expandafter\eat\fi}

x\ignorepars\par x

y\ignorepars

y

z\ignorepars



z

\bye

enter image description here

  • Sorry, I forgot to copy the #1 in eat. (If it was right it would happen the TeX Capacity error). The problem was that I thought that \fi disappears after expanding the conditional. Thanks – User Nov 23 '15 at 21:33
  • 1
    @User I added a comment about the different definition; you should be able to see what's going wrong. – egreg Nov 23 '15 at 21:47
8

this has lots less finesse than egreg's suggestion, but sometimes brute force works.

\let\oldpar\par
\def\ignorepar{\let\par\ignorespaces}
\def\restorepar{\endgraf\let\par\oldpar}
\def\bye{\endgraf\end}

\ignorepar

abcdef ghijkl mnopqr stuv wxyz

abcdef ghijkl mnopqr stuv wxyz

abcdef ghijkl mnopqr stuv wxyz

abcdef ghijkl mnopqr stuv wxyz

\restorepar

abcdef ghijkl mnopqr stuv wxyz

abcdef ghijkl mnopqr stuv wxyz

\ignorepar

abcdef ghijkl mnopqr stuv wxyz

abcdef ghijkl mnopqr stuv wxyz

abcdef ghijkl mnopqr stuv wxyz

abcdef ghijkl mnopqr stuv wxyz

\restorepar

abcdef ghijkl mnopqr stuv wxyz

abcdef ghijkl mnopqr stuv wxyz

\bye
4

Spaces need special treatment to be ignored as they are character tokens but \par is a csname so you can more simply do \let\par\empty (which latex does for example in tabular) (obviously you need some hook such as end of group to restore the definition if \par is ignored in this manner.)

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.