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'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!

share|improve this question
add comment

4 Answers

up vote 8 down vote accepted

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.

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

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.

share|improve this answer
add comment

It has nothing to do with macro expansion but with grouping: Cells in a tabular build a group. You are starting an environment in one group and close it in the next. Use better a command \production.

share|improve this answer
    
Thanks for the clarification! –  desperate Sep 16 '10 at 7:22
add comment

I suppose having separate prod1 and prodn production commands would allow \\ to be automatically inserted: make prodn prepend \\.

share|improve this answer
add comment

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.