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 some complicated expressions with loads of nested commands which are difficult to work with. To solve this I wrote a parser using pgfparser which creates the expressions for me. I can then copy the output back in to LaTeX and it outputs what I need.

I was wondering if I could automate this. I can store the text (a sequence of commands) in a variable but then I can't find a way to run the commands in the variable

The parser itself is not of much interest but as a mwe this is a simplified version of what I have:

\documentclass{standalone}
\usepackage[T1]{fontenc}
\usepackage{pgf}
\usepgfmodule{parser}

\pgfparserdef{mweparser}{initial}{\meaning [}{\textbackslash overline\{}
\pgfparserdef{mweparser}{initial}{\meaning ]}{\}}
\pgfparserdef{mweparser}{initial}{\meaning A}{A}
\pgfparserdef{mweparser}{initial}{subscript character _}{\_\{\pgfparserswitch{subscript}}
\pgfparserdef{mweparser}{subscript}{\meaning +}{\textbackslash hat\{\pgfparserswitch{edgename}}
\pgfparserdef{mweparser}{subscript}{\meaning -}{\textbackslash check\{\pgfparserswitch{edgename}}
\pgfparserdef{mweparser}{edgename}{\meaning a}{a\}\pgfparserswitch{subscript}}
\pgfparserdef{mweparser}{edgename}{\meaning b}{b\}\pgfparserswitch{subscript}}
\pgfparserdef{mweparser}{subscript}{subscript character _}{\}\pgfparserswitch{initial}}
\pgfparserdef{mweparser}{all}{the character ;}{\pgfparserswitch{final}}

\begin{document}
    \pgfparserparse{mweparser}[A_+a-b-a_[A_+a+b-a_]];%
\end{document}

This will output:

\overline{A_{\hat{a}\check{b}\check{a}}\overline{A_{\hat{a}\hat{b}\check{a}}}}

Which is what I would like to run (in math mode). I can store this text in a variable but can't see how I can run it.

I am new to this stuff so I apologise if I have done anything wrong.

share|improve this question
    
Welcome to TeX.SX! Please make your code compilable (if possible), or at least complete it with \documentclass{...}, the required \usepackage's, \begin{document}, and \end{document}. That may seem tedious to you, but think of the extra work it represents for TeX.SX users willing to give you a hand. Help them help you: remove that one hurdle between you and a solution to your problem. –  Jubobs Mar 25 at 17:55
    
Sorry it seems to compile fine to me. I realise my example is quite long. I could create a shorter version. Thanks for replying so fast and for the help. –  DQuick Mar 25 at 18:03
1  
Sorry about my last edit (I misinterpreted some of your text as code). Yes, you should reduce your code to the bare minimum (but it should still be compilable) for explaining your problem; you stand a greater chance of getting a good answer quickly if you do that. –  Jubobs Mar 25 at 18:08
    
Thanks, I've tried to minimise the parser as much as possible, still presenting the problem I have. Do you have any ideas for other tags I should add? I don't really know how to refer to the problem I have. –  DQuick Mar 25 at 18:33
add comment

1 Answer 1

up vote 5 down vote accepted

I don't really know how the PGF parser works, but what you get with your code is a string which is not what you want: \textbackslash is not a backslash but a command to print one.

Here's an implementation with l3regex, the regular expression parser of LaTeX3; the wanted result has been added for checking against what the macros do.

\documentclass[border=3,varwidth]{standalone}
\usepackage[T1]{fontenc}
\usepackage{xparse,l3regex}

\ExplSyntaxOn
\NewDocumentCommand{\term}{m}
 {
  \dquick_term:n { #1 }
 }

\tl_new:N \l__dquick_input_tl

\cs_new_protected:Npn \dquick_term:n #1
 {
  \tl_set:Nn \l__dquick_input_tl { #1 }
  %% subscripts (works so long you don't have nested subscripts)
  \regex_replace_all:nnN { \_(.*?)\_ } { \cD\_\cB\{\1\cE\} } \l__dquick_input_tl
  %% [ becomes \overline\bgroup (nesting is allowed)
  \regex_replace_all:nnN { \[ } { \c{overline}\c{bgroup} } \l__dquick_input_tl
  %% ] becomes \egroup
  \regex_replace_all:nnN { \] } { \c{egroup} } \l__dquick_input_tl
  %% +<char> becomes \hat{<char>}
  \regex_replace_all:nnN { \+(.) } { \c{hat}\cB\{\1\cE\} } \l__dquick_input_tl
  %% -<char> becomes \check{<char>}
  \regex_replace_all:nnN { \-(.) } { \c{check}\cB\{\1\cE\} } \l__dquick_input_tl
  $\tl_use:N \l__dquick_input_tl$
 }
\ExplSyntaxOff

\begin{document}
\term{[G_+a-b-c_[H_+a+a-c_]]}

$\overline{G_{\hat{a}\check{b}\check{c}}\overline{H_{\hat{a}\hat{a}\check{c}}}}$
\end{document}

enter image description here


A slightly different version that allows specifying delimiter characters (they must be different) for nested macro, here shown with \overline.

\documentclass[border=3,varwidth]{standalone}
\usepackage[T1]{fontenc}
\usepackage{xparse,l3regex}

\ExplSyntaxOn
\NewDocumentCommand{\term}{m}
 {
  \dquick_term:n { #1 }
 }

\tl_new:N \l__dquick_input_tl

\cs_new_protected:Npn \dquick_term:n #1
 {
  \tl_set:Nn \l__dquick_input_tl { #1 }
  %% subscripts (works so long you don't have nested subscripts)
  \regex_replace_all:nnN { \_(.*?)\_ } { \cD\_\cB\{\1\cE\} } \l__dquick_input_tl
  %% brackets can be nested, this requires a slower routine
  \dquick_replace_nested:nnn { \[ } { \] } { overline }
  %% +<char> becomes \hat{<char>}
  \regex_replace_all:nnN { \+(.) } { \c{hat}\cB\{\1\cE\} } \l__dquick_input_tl
  %% -<char> becomes \check{<char>}
  \regex_replace_all:nnN { \-(.) } { \c{check}\cB\{\1\cE\} } \l__dquick_input_tl
  \tl_use:N \l__dquick_input_tl
 }

\cs_new_protected:Npn \dquick_replace_nested:nnn #1 #2 #3
 {% #1 is the left delimiter
  % #2 is the right delimiter
  % #3 is the macro name for replacement
  \regex_match:nVT { #1 ( [^#1#2]*? ) #2 } \l__dquick_input_tl
   {
    \regex_replace_all:nnN { #1 ( [^#1#2]*? ) #2 } { \c{#3}\cB\{\1\cE\} } \l__dquick_input_tl
    \dquick_replace_nested:nnn { #1 } { #2 } { #3 }
   }
 }
\cs_generate_variant:Nn \regex_match:nnT { nV }

\ExplSyntaxOff

\begin{document}
$\term{[G_+a-b-c_[H_+a+a-c_]]}$

$\overline{G_{\hat{a}\check{b}\check{c}}\overline{H_{\hat{a}\hat{a}\check{c}}}}$
\end{document}
share|improve this answer
1  
Incredible answer. I'll have to make sure I understand what is going on and that I can apply it to my more complicated example but it looks perfect. Thanks for putting in the time and effort. –  DQuick Mar 25 at 19:06
    
I have one issue still which can be seen by replacing overline in your example with test defined as \newcommand{\test}[1]{l #1 r} then \term{[a]} becomes lra instead of lar. –  DQuick Mar 25 at 23:33
    
@DQuick I used the fact that the argument of \overline can be delimited by \bgroup and \egroup. Nested things like those can be tricky with regular expressions. Can you be more precise about your need? –  egreg Mar 25 at 23:41
    
I have a few commands defined like \newcommand{\box}[2]=\left[ #1 \right]^{ #2 }. I wish to use these instead of overline above. My plan was to replace [ with \c{box}\c{bgroup} and ](.) with \c{egroup}\cB\{\1\cE\}. But I guess as you said this is not what bgroup and cgroup do. –  DQuick Mar 26 at 0:11
    
@DQuick No, you can't use \bgroup and \egroup for delimiting macro arguments. If those commands are not nested there should be no problem in doing like for _. Oh, and don't redefine \box! –  egreg Mar 26 at 0:14
show 5 more comments

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.