7

This question piggy-backs on the answer to Capture a macro's subscripts/superscripts by the macro by egreg.

I'm attempting to use the xparse package to create some macros and I'd rather not have to use different macros when I want to have sub and superscripts (or both at once!).

I'd like a macro like this:

\F
\F{m}
\F{m}_b
\F{m}^a
\F{m}_b^a
\F{m}^a_b

to produce output equivalent to this:

enter image description here

$F$
$F[m]$
$F_b[m]$
$F^a[m]$
$F_b^a[m]$
$F^a_b[m]$

Based on the abolve linked question, I can capture one or the other, but not both. I've made a few attempts, but there must be something very fundamental (or subtle) about now @ifnextchar works that is beyond me.

This code takes two optional arguments, rather than one, but the issue remains: The sub and superscripts always end up at the end of the line, not on the defined first character.

\documentclass{article}
\usepackage{xparse}
\makeatletter
\newcommand{\DFcmd}{\ensuremath{F}}

\NewDocumentCommand\DFhelp{ g g g g }
{
    \IfValueT{#3}{ \def\@DFcmdsub{\DFcmd^{#3}} }{ \def\@DFcmdsub{\DFcmd} }
    \IfValueT{#4}{ \def\@DFcmdsuper{\@DFcmdsub_{#4}} }{ \def\@DFcmdsuper{\@DFcmdsub} }
    \@DFcmdsuper
    \IfNoValueF{#1}{#1}{}
    \IfNoValueF{#2}{#2}{}   
}    

\NewDocumentCommand\DF{ o o }
{%
    \def\firstarg{}%
    \def\secondarg{}%
    \IfNoValueF{#1}{ \def\firstarg{[#1]} }{ \def\firstarg{} }%
    \IfNoValueF{#2}{ \def\secondarg{#2} }{ \def\secondarg{} }%
    \def\superopt{}%
    \def\subopt{}%
    \@ifnextchar^%
    {%
        \assign@superopt%
        \@ifnextchar_%
        {%
            \assign@subopt%
        }%
        {%
            \def\subopt{}%
        }%
    }%
    {%
        \@ifnextchar_%
        {%
            \assign@subopt%
            \@ifnextchar^%
            {%
                \assign@superopt%
            }%
            {%
                \def\superopt{}%
            }%
        }
        {%
            \def\subopt{}%
        }%
    }
    \DFhelp{\firstarg}{\secondarg}{\superopt}{\subopt}%
}    

\def\assign@superopt^#1{ \def\superopt{#1} }
\def\assign@subopt_#1{ \def\subopt{#1} }
\makeatother
3
  • I guess, there are multiple problems in your code: You use \If*ValueT or \If*ValueF but use both branches. Then you specify two optional arguments for \DF which are enclosed in [ and ], but you never use them. \@ifnextchar finds only \bgroup from the {m} argument. Furthermore, you use \assign@superopt right before \@ifnextchar although it expects a ^, this won’t work! Use the next \@ifnextchar inside the definition of \assign@*opt (after it has grabbed its argument). Jun 10, 2013 at 19:42
  • I can't see what gain there is over typing more naturally $F_a^b[m]$. Or, if you don't want to have an explicit "F", $\DF_a^b[m]$, after defining \DF to do what you desire.
    – egreg
    Jun 10, 2013 at 19:56
  • This is just a general thing. The idea is that notation (both of the operator and its arguments) isn't 100% set and I was asked if it would be possible to have this behavior in a macro. After spending some time on it, it became an "is it even possible" thing, well beyond the practicality. Now that I have a more clear picture, I'll try and clean the question up some to make it more clear.
    – renstar
    Jun 10, 2013 at 20:02

4 Answers 4

6

The following grabs multiple sub and superscripts.

The argument in braces (which apparently is optional) should probably better be in [ ].

Code

\documentclass{article}
\makeatletter
\def\F{%
  \let\f@sub\@empty
  \let\f@super\@empty
  \let\f@main\@empty
  \@ifnextchar\bgroup\f@catch@main\f@test
}
\def\f@catch@main#1{\def\f@main{#1}\f@test}
\def\f@test{%
  \@ifnextchar_\f@catch@sub{\@ifnextchar^\f@catch@super\f@finalize}%
}
\def\f@catch@sub_#1{\expandafter\def\expandafter\f@sub\expandafter{\f@sub#1}\f@test}
\def\f@catch@super^#1{\expandafter\def\expandafter\f@super\expandafter{\f@super#1}\f@test}
\def\f@finalize{%
      F
      \ifx\f@sub\@empty\else_{\f@sub}\fi
      \ifx\f@super\@empty\else^{\f@super}\fi
      \ifx\f@main\@empty\else[\f@main]\fi
}
\makeatother
\begin{document}
$ \F $ \par
$ \F{m} $ \par
$ \F{m}_b $ \par
$ \F{m}^a $ \par
$ \F{m}_b^a $ \par
$ \F{m}^a_b $ \par
$ \F{m}^a_b_a^b $ \par
\end{document}

Output

enter image description here

2
  • +1 (because you beat me by 28 seconds:-) and this implements what the OP asked for (making a {} delimited argument optional) but as I note in my answer this goes against LaTeX syntax either the argument should be mandatory or should be [] delimited. Jun 10, 2013 at 19:38
  • I ended up using something based on this answer to get the desired effect. I think the others would have worked as well, but something very similar to this did the trick. Thanks everyone!
    – renstar
    Jun 12, 2013 at 14:14
8

Since you only have one mandatory argument (and you are looking for ^ and _) I don't think xparse gains you a lot so i just use \@ifnextchar directly here. Also because you have m in a mandatory {} argument it should always be given so I changed \F to \F{} and added a test for the argument to be empty. (An alternative would be to make the argument optional but then it should be delimited by [] not {}.

enter image description here

\documentclass{article}

\makeatletter
\def\F#1{\def\F@{\ifx\relax#1\relax\else[#1]\fi}\def\F@@{F}\@ifnextchar^\@Fsp\@Fnsp}
\def\@Fsp^#1{\def\F@@{F^{#1}}\@ifnextchar_\@Fspsb{\F@@\F@}}
\def\@Fspsb_#1{\F@@_{#1}\F@}
\def\@Fnsp{\@ifnextchar_{\@Fsb}{\F@@\F@}}
\def\@Fsb_#1{\def\F@@{F_{#1}}\@ifnextchar^\@Fsbsp{\F@@\F@}}
\def\@Fsbsp^#1{\F@@^{#1}\F@}
\begin{document}



$\F{}$

$\F{m}$

$\F{m}_b$

$\F{m}^a$

$\F{m}_b^a$

$\F{m}^a_b$

\end{document}
4
  • I actually have no mandatory arguments, just a few optional ones. I tried to scrub things from my example that had nothing to do with (what I thought) was causing issues. xparse allows both [] and {} to be optional via 'o' and 'g' arguments.
    – renstar
    Jun 10, 2013 at 19:42
  • @renstar perhaps, but you shouldn't use optional {} arguments in latex2e:-) Jun 10, 2013 at 19:44
  • Fair enough, I can (and probably will) go with that, but then, why does xparse provide that as an option?
    – renstar
    Jun 10, 2013 at 19:53
  • @renstar maybe the rules will be different in latex3 (we haven't written the rules yet... Jun 10, 2013 at 19:56
2

The following seems to work reasonably well with (at least) the limitation that it requires a space after the macro in order to work.

enter image description here

\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn

\NewDocumentCommand{\F}{}{
    \peek_charcode:NTF \c_group_begin_token
        {\renstar_F:w}
        {$F$}
}

\cs_new:Npn \renstar_F:w #1#2~ {
    \ensuremath{F#2[#1]}~
}

\ExplSyntaxOff

\begin{document}

\F 

\F{m}

\F{m}_b

\F{m}^a

\F{m}_b^a

\F{m}^a_b

\end{document}
1

I'd go into a completely different direction. In your case there is no gain whatsoever in defining a complicated macro rather than typing more naturally

$F_{a}^{b}[m]$

In case this is only an example of a more complex situation, I would recommend you a key-value syntax, that avoids chasing for tokens and distinguishing among different situations. This is also more flexible.

Here's the example.

\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\DF}{O{}}
 {
  \group_begin:
  \keys_set:nn { renstar/DF } { #1 }
  \renstar_DF:
  \group_end:
 }
\keys_define:nn { renstar/DF }
 {
  arg .tl_set:N = \l_renstar_arg_tl,
  sub .tl_set:N = \l_renstar_sub_tl,
  sup .tl_set:N = \l_renstar_sup_tl,
  symbol .tl_set:N = \l_renstar_symbol_tl,
  symbol .initial:n = F,
 }
\cs_new:Npn \renstar_DF:
 {
  \l_renstar_symbol_tl
  \tl_if_empty:NF \l_renstar_sub_tl
   { \c_math_subscript_token { \l_renstar_sub_tl } }
  \tl_if_empty:NF \l_renstar_sup_tl
   { \c_math_superscript_token { \l_renstar_sup_tl } }
  \tl_if_empty:NF \l_renstar_arg_tl
   { [ \l_renstar_arg_tl ] }
 }
\ExplSyntaxOff

\begin{document}
$\DF$

$\DF[arg=m]$

$\DF[arg=m,sub=a]$

$\DF[sup=b,arg=m]$

$\DF[arg=m,sup=b,sub=a]$

$\DF[symbol=M,sup=x,arg=f]$
\end{document}

enter image description here

You must log in to answer this question.

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