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.

I have looked through answers on this forum that did bring me closer to the solution of the problem stated above, but both the approach via \xdef and via \g@addto@macro give errors or wrong results.

What I want to do is to define a macro with an optional argument that is parsed in a loop: the input \gttest[Mg=x,Fe=y,Ca=z] is supposed to create a chemical formula of the form Mg_x Fe_y Ca_(1-x-y); spaces and parens are given here for clarity only and don't appear in the actual output. Here is the code (part of a .sty file):

\RequirePackage{xspace}
\RequirePackage{xstring}
\RequirePackage{ifthen}
\RequirePackage{fp-eval}
\RequirePackage{twoopt}
% preliminaries for the components
\newcommand{\@sublow}{\vphantom{A}}
\newcommand{\@chem}[2]{%
\ifthenelse{\equal{#2}{1}}{#1}{%
\ensuremath{\mathrm{#1}\@sublow_{#2}}}}
\newcommand{\@GCresb}{}
\newcommand{\@GCresc}{}
\newcommand{\@GCtmpa}{}
\newcommand{\@GCtmpb}{}
\newcommand{\@GCtmpc}{}
\newcommand{\@GCtmpd}{}
\newcounter{isscmp}
\newcounter{jsscmp}
\newcounter{lsscmp}
\newcounter{nsscmp}
% the actual macro
\newcommand{\gttest}[1][]{%
\StrCount{#1}{=}[\nsscmp]%
\setcounter{lsscmp}{\nsscmp}%
\setcounter{isscmp}{0}%
\setcounter{nsscmp}{1}%
\renewcommand{\@GCtmpa}{}%
\renewcommand{\@GCresc}{}%
\whiledo{\value{nsscmp}<\value{lsscmp}\OR\value{nsscmp}=\value{lsscmp}}{%
\ifthenelse{\value{nsscmp}<\value{lsscmp}}{%
\StrPosition[\thensscmp]{#1}{,}[\jsscmp]%
\StrMid{#1}{\value{isscmp}+1}{\numexpr\jsscmp-1}[\@GCtmpb]}{%
\StrGobbleLeft{#1}{\value{isscmp}}[\@GCtmpb]}%
\StrBefore{\@GCtmpb}{=}[\@GCtmpc]%
\StrBehind{\@GCtmpb}{=}[\@GCtmpd]%
\ifthenelse{\value{nsscmp}<\value{lsscmp}}{%
% all but last comp.: use given subscript and accumulate
\xdef\@GCresc{\@GCresc-\@GCtmpd}%
\renewcommand{\@GCresb}{\@chem{\@GCtmpc}{\@GCtmpd}}}{%
% last comp.: apply closure condition \sum x_i=1
\renewcommand{\@GCresb}{\@chem{\@GCtmpc}{1\@GCresc}}}%
\xdef\@GCtmpa{\@GCtmpa\@GCresb}% <-- causes Incomplete iffalse
%\g@addto@macro\@GCtmpa{\@GCresb}% <-- produces wrong result
\setcounter{isscmp}{\jsscmp}%
\stepcounter{nsscmp}}%
\@GCtmpa}

In this form, the code throws an error:

! Incomplete \iffalse; all text was ignored after line 5.

\fi

<*> mytest

If I comment the xdef line signaled with the <-- and uncomment the following line with the g@addto... instead, it runs smoothly but the result is Ca_(1-x-y) Ca_(1-x-y) Ca_(1-x-y)

So - why doesn't this work? I have no idea where an incomplete if clause would be in the first variant nor how the last appendage gets to be repeated three times in the second variant, although the argument is correctly parsed.

share|improve this question
1  
Could you please convert your code snippet into a full-fledge minimal working example (MWE)? Also, why add z when it's converted to 1-x-y? –  Werner Oct 7 '12 at 2:21
    
Welcome to TeX.SE. –  Peter Grill Oct 7 '12 at 2:41
    
I think you are going to be much better off using a dedicated keyval parsing routine to do this. However, I'm not 100% clear on the interface. Presumably, you know the general formula, which must contain calcium. Is the element list fixed? –  Joseph Wright Oct 7 '12 at 8:56
    
Werner, I just tried to paste the code from my larger test file into a separate mwe file, but it turns out that this changes the error in the case of xdef line. As for adding the z subscript: this just signals that the subscript is not a number (this macro is actually a subset of a macro that is also meant to handle numbers). –  TomR Oct 7 '12 at 13:09
    
Joseph, I have indeed considered using keyval, but if I understand the docs correctly, that would require a set of predefined keys, in other words, I couldn't give the command arbitrary arguments. So, no, the element list is not really fixed. The goal is to be able to give any number of elements >2 as an argument (in practice that would be 2-4 in most cases). The last entry must fulfill the closure condition that the sum of the indices should be 1, as you will have noticed. –  TomR Oct 7 '12 at 13:17

1 Answer 1

enter image description here

I think the coding's a lot more complicated than it need be, which makes it harder to keep track of the expansion. I think the tests can be a lot simpler, something like:

\documentclass{article}

\makeatletter

\newcommand{\@chem}[2]{%
\def\xtest{#1}%
\def\xtest{1}%
\mathrm{#1}%
\ifx\xtest\ytest\else\@sublow_{#2}\fi}

\newcommand{\@sublow}{\vphantom{A}}

\newcommand\gttest[1][]{\ensuremath{%
\gdef\chem@last{1}%
\@for\tmp:=#1\@empty\do{%
\expandafter\x@chem\tmp\relax
}}}

\def\last@test#1\@empty#2#3\@nil{#2}

\def\x@chem#1=#2\relax{%
\expandafter\ifx\expandafter!\last@test#2!\@empty?\@nil
\@chem{#1}\chem@last
\else
\g@addto@macro\chem@last{-#2}%
\@chem{#1}{#2}%
\fi}
\begin{document}


\gttest[Mg=x,Fe=y,Ca=z]
\end{document}
share|improve this answer
    
This is obviously a Grand Master at work and far beyond my humble LaTeX skills. It looks to me as if it worked for some more general tasks, so I have to try if I can integrate it into my planned package. Ultimately, my goal is to have a command that can handle also handle numerical subscripts (I have left that part out in my problem report) and will assemble a more complex sum formula (for a garnet solid solution in this case). Anyway, thanks so far. –  TomR Oct 7 '12 at 14:16
    
Finally being able to return to this, I do have two questions about this: shouldn't the first two lines of the \@chem command be \def\xtest{#2}% \def\ytest{1}% because otherwise we wouldn't compare the subscripts and print a subscript 1. The other question is how to make the content of \chem@last into something that can be evaluated with \FPeval if the expression composed while running through that loop contains only operators and real numbers. –  TomR Oct 13 '12 at 1:56

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.