Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

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}
share|improve this question
2  
Using \@ifnextchar outside a macro definition doesn't make much sense. Can you show a real example? –  egreg Jun 13 at 19:55
    
Try using \usepackage{etoolbox} \makeatletter \robustify\@ifnextchar \makeatother... –  Werner Jun 13 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 Jun 13 at 20:05
    
@Werner, I'll give it a try asap, thanks. –  alexis Jun 13 at 20:05
1  
@alexis What macro? That one should be the object of the example. –  egreg Jun 13 at 20:08

2 Answers 2

up vote 5 down vote accepted

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.

share|improve this answer
    
Brilliant, thanks! That does it indeed. I could never get my head around all the protection rackets going on in LaTeX... –  alexis Jun 13 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 Jun 13 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 Jun 13 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 Jun 14 at 8:44

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.

share|improve this answer
    
Thanks! \protect didn't work, but \protected did (as suggested by @egreg to Alan Munn in another channel...) –  alexis Jun 13 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{...} –  David Carlisle Jun 13 at 22:45

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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