4

I have the following code which doesn't work:

\documentclass[12pt]{article}

\tracingcommands=2
\tracingmacros=2
\tracingall

\makeatletter

\let\sep\relax

\def\put@stack@#1#2{\edef#2{#1\sep#2}}

\def\put@queue@#1#2{\edef#2{#2\sep#1}}

\def\get@#1#2{\expandafter\get@@#2\endget@@#1#2}

\def\get@@#1\sep#2\endget@@#3#4{\edef#3{#1}\edef#4{#2}}

\def\empty@stack{\sep}

\newtoks\piecetoks

\def\leftrightbr{
    \let\o@left\left
    \let\o@right\right
    \let\piece@nd\relax
    \let\pieces@stack\empty@stack
    \let\delims@stack\empty@stack
    \let\on@end@line\empty@stack
    \let\on@begin@line\empty@stack
    \def\left##1{
        \piece@nd
        \let\piece@nd\endgroup
        \def\on@first@right{
            \put@stack@{\the\toks0}{\pieces@stack}
        }
        \put@stack@{##1}{\delims@stack}
        \let\repl\relax
        \let\vphantomer####1{}
        \put@stack@{\the\piecetoks}{\pieces@stack}
        \put@stack@{\right.}{\on@end@line}
        \put@stack@{\left.}{\on@begin@line}
        \piecetoks=\begingroup
    }
    \def\right##1{
        \endgroup
        \on@first@right
        \let\on@first@right\relax
        \get@\@dummy\on@end@line
        \get@\@dummy\on@begin@line
        \get@\@lpart\pieces@stack
        \get@\@ldelim\delims@stack
        \ifx\@lpart\empty
            \repl
        \else
            \edef\repl{\o@left\@ldelim\@lpart\vphantomer{\the\piecetoks}\repl\the\piecetoks\vphantomer{\@lpart}\o@right##1}
        \fi
    }
    \def\mathbr{
        \piece@end
        \put@stack@{\piece}{\pieces@stack}
        \let\vphantomer\vphantom
        \edef\repl{\on@end@line \\ \on@begin@line}
        \def\piece\begingroup
    }
}

\begin{document}

\begin{equation}
    \leftrightbr
    \left(a\right)
\end{equation}

\end{document}

So what's the catch?

EDIT: The error is

! Undefined control sequence.
<argument> \@dummy 

l.85     \left(
               a\right)

Looking into log gets us to conclusion that the problem is caused by call to \get@\@dummy\on@end@line. This seems to be strange since direct call to \get@ on \empty@stack results in no error.

EDIT: The code can be narrowed down:

\documentclass[12pt]{article}

\tracingcommands=2
\tracingmacros=2
\tracingall

\newtoks\piecetoks

\def\leftrightbr{
    \def\left##1{
        \piecetoks=\begingroup
    }
    \def\right##1{
        \endgroup
    }
}

\begin{document}

\begin{equation}
    \leftrightbr
    \left(a\right)
\end{equation}

\end{document}

This is shorter, isn't it? :-) It gives the other error, and the other question arises: how can we achieve behavior in which TeX captures tokens between two macros' calls?

24
  • Welcome to TeX.SX! I get Undefined control sequence \@some with the second code. It would be beneficial if you explained what the macros are supposed to do.
    – egreg
    Sep 21, 2013 at 19:59
  • 1
    After fixing the typos \@some to \some both files run without errors. Sep 21, 2013 at 20:08
  • 1
    Sorry, my mistake. I have much more code and while trying to make MWE i obviously mistyped. Sep 21, 2013 at 20:11
  • Maybe it's not so much code after all. I'll edit the question in a couple of minutes. Sep 21, 2013 at 20:22
  • 1
    @AndrewZabavnikov With a delimited macro argument. Your \left expects a \right, so you can gather all tokens between them. But, if you plan to use this with amsmath alignments, I can see many other problems.
    – egreg
    Sep 21, 2013 at 22:10

2 Answers 2

7

You can't assign tokens to a token register with

\piecetoks=\begingroup...\endgroup`

Nor you can start the assignment with a macro and end it with another one, because

<toks register>={...}

needs an explicit brace at the end and no expansion takes place during the evaluation of the <balanced text> to be stored.

In the TeXbook, page 276, you find what a <variable assignment> is; one of the alternatives is

<token variable> <equals> <general text>

and some lines above you see

<general text> → <filler> { <balanced text> <right brace>

In the syntax rules, { means an implicit or explicit character token of category code 1, while <right brace> means an explicit character token of category code 2.

7

Delimited arguments need to look for a fixed token, but you don't need to look ahead for \\-or-\right you can look ahead for \right and then look in the tokens you collected to see if there was a \\.

so

\documentclass{article}


\makeatletter
\newtoks\tA
\newtoks\tB

\def\left#1\right{%
  \zz#1\\\right}

\def\zz#1\\#2\right#3{%
\ifx\relax#2\relax
  \tA{\left#1\right#3}%
  \typeout{^^J^^Jno \space\string\\:^^J\the\tA^^J}%
  \expandafter\remove@to@nnil
\else
  \tA{\left#1\right.\\}%
  \expandafter\zzb
 \fi
 #2\right#3\@nnil}

\def\zzb#1\\\right#2\@nnil{%
  \tB{\left.#1\right#2}%
  \typeout{^^J^^Jhas \string\\:^^J\the\tA\space \the\tB^^J}}
\makeatother

\begin{document}

\left( a b\right)

\left( a \\ b\right)

\end{document}

produces

no  \\:
\left ( a b\right )



has \\:
\left ( a \right .\\ \left . b\right )

However I would never use this in production. redefining \left and \right to take macro arguments changes their scanning rules and will introduce all kinds of incompatibilities. Even if you avoid that by using new names rather than redefining the primitives, using \right.\\ \left. at the line break does not ensure that the paired delimiters are the same size so can not produce an acceptable result.

It is better really just to use \bigl( in one cell and \bigr) in a later cell.

4
  • I thought that \vphantom will ensure that corresponding delimiters wil have the same size. Was i wrong? Sep 22, 2013 at 9:19
  • Another question - are there rules on how to select sizes for delimiters? Sep 22, 2013 at 9:20
  • @AndrewZabavnikov not really, just whatever looks best, it's a subjective judgement. In particular depending on the context sometimes you always want different sizes for nested pairs so the outer ones in ((a+b)+(c+d)) are bigger, and sometimes you don't. Sep 22, 2013 at 12:33
  • @AndrewZabavnikov I mainly answered your argument scanning question, as indicated in comments on the question it was hard to guess what the original code was doing. If you grab everything and measure then it's possible to use vphantom to ensure equal size stretching, yes. Sep 22, 2013 at 12:36

You must log in to answer this question.

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