7

The command \@ifnextchar cannot be used in a \section and the like. It fails with a "TeX capacity exceeded" message. This is pretty clearly related to the recycling of the section name for the table of contents and/or page marks, as shown by the following minimal pair:

\documentclass{article}

\begin{document}
\makeatletter
\section[Safe command]{This: \@ifnextchar /{A}{B} works fine}

\section{This: \@ifnextchar /{A}{B} triggers an error}
The end. 
\end{document}

I believe I have ruled out superficial name clashes, so I'm putting my hopes on robustness. Is there a robust version I can try out, or some other way around this limitation?

Notes

  1. I've seen some discussion of the expl3 equivalent (e.g., here, but they don't discuss robustness.

  2. I'm actually using a self-constructed variant of \@ifnextchar that does not skip over whitespace, so ultimately I'm looking for a solution with the same property.

  3. This is all related to a bug report on gb4e, called to my attention by Alan Munn.

Edit:

Since apparently my minimal example was too minimal, here's the actual use case (still simplified):

In gb4e, ^ and _ are made into \active characters so that they can be used outside math mode. In order to switch in and out of math mode correctly, they need to check if the next command is also a sub- or super-script command, hence the call to \@ifnextchar (or really to a modified version, but that's irrelevant here).

\documentclass{article}
  \makeatletter
  \catcode`\_=\active
  \catcode`\^=\active
  \def_#1{\@ifnextchar^{\automath@two_{#1}}{\ensuremath{\sb{#1}}}}
  \def^#1{\@ifnextchar_{\automath@two^{#1}}{\ensuremath{\sp{#1}}}}
  % handle consecutive sub- and super- scripts:
  \def\automath@two#1#2#3#4{\ensuremath{#1{#2}\relax #3{#4}}}

\begin{document}
    \section{This A_B fails}
\end{document}
6
  • 2
    Using \@ifnextchar outside a macro definition doesn't make much sense. Can you show a real example?
    – egreg
    Commented Jun 13, 2014 at 19:55
  • Try using \usepackage{etoolbox} \makeatletter \robustify\@ifnextchar \makeatother...
    – Werner
    Commented Jun 13, 2014 at 19:56
  • @egreg, the actual use is indeed in another macro: It is part of gb4e.sty, and it's used to detect when a subscript is immediately followed by a superscript or vice versa. If there's a solution specific to use via a macro, that's all that's needed here.
    – alexis
    Commented Jun 13, 2014 at 20:05
  • 1
    @alexis What macro? That one should be the object of the example.
    – egreg
    Commented Jun 13, 2014 at 20:08
  • Ok, added a simplified version of the actual use case. Sorry the example was too minimal!
    – alexis
    Commented Jun 13, 2014 at 22:25

2 Answers 2

6

You should use \protected\def; this requires e-TeX extensions that, however, have been active in LaTeX for several years.

\documentclass{article}
\makeatletter
{ % Temporarily change catcodes
  \catcode`\_=\active
  \catcode`\^=\active

  \global\def\automath{%
    \catcode`\_=\active
    \catcode`\^=\active
    \protected\def_##1{\gb@ifnextchar^{\automath@two\sb{##1}}{\ensuremath{\sb{##1}}}}%
    \protected\def^##1{\gb@ifnextchar_{\automath@two\sp{##1}}{\ensuremath{\sp{##1}}}}}
}
\def\automath@two#1#2#3#4{\ensuremath{#1{#2}#3{#4}}}
% Restore default catcodes for ^, _
\def\noautomath{\catcode`\_=8 \catcode`\^=7 }

% The original \@ifnextchar discards spaces when looking for the next
% ``character''. This variant accepts any token.
\long\def\gb@ifnextchar#1#2#3{%
  \let\reserved@d=#1%
  \def\reserved@a{#2}%
  \def\reserved@b{#3}%
  \futurelet\@let@token\@gbifnch}
\def\@gbifnch{%
    \ifx\@let@token\reserved@d
      \let\reserved@c\reserved@a
    \else
      \let\reserved@c\reserved@b
    \fi
  \reserved@c}
\makeatother
\begin{document}
\automath
\section{A subscript_{s}^{t}}
\section{A subscript^{t}_{s}}
\section{A subscript_{s} ^{t}}
\section{A subscript^{t} _{s}}
\end{document}

enter image description here

You probably have to add a check for the presence of e-TeX extensions at the beginning of the package.

I got the definition of \gb@ifnextchar from Alan Munn in chat.

4
  • Brilliant, thanks! That does it indeed. I could never get my head around all the protection rackets going on in LaTeX...
    – alexis
    Commented Jun 13, 2014 at 22:30
  • Please stop me if this qualifies as "ask a new question" material, but would you say that \providecommand\protected{\relax} is a good enough fall-back for non-e-TeX systems? Or ought I to include an explicit check for e-TeX?
    – alexis
    Commented Jun 13, 2014 at 22:39
  • @alexis Yes, it is good. Of course the usage of _ and ^ in section titles would break as it did with the previous code. I'd add the check for e-TeX nonetheless, at least to warn users that they should upgrade their TeX distribution, which would be several years old.
    – egreg
    Commented Jun 13, 2014 at 22:43
  • Yes, that's the idea, thanks. Users with old engines won't be able to use ^ and _ in section titles, but if I don't add a check, they won't be able to use them at all.
    – alexis
    Commented Jun 14, 2014 at 8:44
5

The standard instructions for using a fragile command (such as one defined using \@ifnextchar) in a moving argument (such as the main argument of \section) is to prefix it with \protect.

2
  • Thanks! \protect didn't work, but \protected did (as suggested by @egreg to Alan Munn in another channel...)
    – alexis
    Commented Jun 13, 2014 at 22:28
  • @alexis it would work if used in the right place:-) You didn't provide an example (Alan provided one in chat) \protected\def_{...} can be \def_{\protect\gb@underscore} \def\gb@underscore{...} Commented Jun 13, 2014 at 22:45

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .