Use column-separator & (ampersand) inside \newenvironment

I'd like to define a grammar environment which basically wraps a tabular environment. Inside the grammar environment I'd like to use an environment called production to insert rows. Example:

\documentclass[a4paper,10pt]{article}

\newenvironment{production}[1]
{\noindent\ignorespaces#1 ::= &}
{\\}

\newenvironment{grammar}
{\begin{tabular}{p{3cm}l}}
{\end{tabular}}

\begin{document}
\begin{grammar}
\begin{production}{XmlStartTag}
...
\end{production}
\begin{production}{XmlEndTag}
...
\end{production}
\end{grammar}

\end{document}


The goal of this code is to put the name of the non-terminal that is being defined in the left column and the actual production into the right column of the tabular.

Unfortunately this fails due to the & and \\ within the production environment. I guess it has something to do with macro expansion. I guess I have to escape the & and \\ with something that is only expanded after the macro was used?

Thanks!

-

The problem is that the \begin{...} and \end{...} pair commands automatically create a "group" so that, in effect, the & and \\ are "out of scope" for the tabular, while inside the "production" environment they just show up at a place where the compiler is not expecting them.

A second problem with your definitions is that, even if they would work, they would be adding an extra \\ at the end of the tabular, adding an unwanted space at the end. Perhaps some more appropriate definitions would be

\documentclass[a4paper,10pt]{article}

\newcommand{\production}[1]{#1 ::= &}
\newenvironment{grammar}{\tabular{p{3cm}l}}{\endtabular}

\begin{document}
\begin{grammar}
\production{XmlStartTag} ... \\
\production{XmlOtherTag} ... \\
\production{XmlEndTag} ...
\end{grammar}
\end{document}


Note no \\ at the end of the last production. Also in the definition of the grammar you don't need to repeat the work of \begin/\end, and you can instead directly use \tabular and \endtabular.

-
Thanks for the clarification and the newline hint! It works as Ulrike Fischer and you propose (using a command). However, I still wonder if there would be an easy way to make it work with an environment. Using an environment I would have more ways to change the formatting of the entire production as one unit. –  desperate Sep 16 '10 at 7:24
No, not an easy way. At least not if you continue to use a tabular around. Can't you do without the tabular and use inside the production environment \parbox, \makebox, minipage, lrbox etc? You could also look at the eqparbox-package. –  Ulrike Fischer Sep 16 '10 at 8:16
Thanks for the pointers! –  desperate Sep 20 '10 at 15:33

I found a trick when trying to solve this question. You can use the environ package to do the following:

\usepackage{environ}
\NewEnviron{production}[1]{%
\expandafter\gdef\expandafter\gtemp\expandafter{%
\expandafter\noindent\expandafter\ignorespaces
\expandafter#1\expandafter\separator\expandafter&\BODY\\
}%
\aftergroup\gtemp
}
\newcommand{\separator}{ ::= }


\BODY is the content of your environment, and the \expandafters ensure that you expand \BODY before defining \gtemp (a global temporary variable... yuck!). Then, \aftergroup ensures that we are doing \gtemp outside the group. See the answer to the question I mention above.

Two questions for more experienced TeXers: can I use \unexpanded to do this better? Is there a good way of executing a lot of stuff \aftergroup: I hate having to define \gtemp globally.

-