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.

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
share|improve this question
    
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). –  Qrrbrbirlbel Jun 10 '13 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 '13 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 '13 at 20:02

4 Answers 4

up vote 6 down vote accepted

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

share|improve this answer
    
+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. –  David Carlisle Jun 10 '13 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 '13 at 14:14

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}
share|improve this answer
    
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 '13 at 19:42
    
@renstar perhaps, but you shouldn't use optional {} arguments in latex2e:-) –  David Carlisle Jun 10 '13 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 '13 at 19:53
    
@renstar maybe the rules will be different in latex3 (we haven't written the rules yet... –  David Carlisle Jun 10 '13 at 19:56

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}
share|improve this answer

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

share|improve this answer

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.