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
.
I'd use the xparse
package to do this, as everything is then 'pre-packaged':
\documentclass{article}
\usepackage{color,xparse}
\NewDocumentCommand\MyTextColor{m+g}{%
\IfNoValueTF{#2}
{\color{#1}}
{\textcolor{#1}{#2}}%
}
\begin{document}
\MyTextColor{green}{stuff}
\MyTextColor{red} Some text
\end{document}
The same can of course be done using \@ifnextchar
\documentclass{article}
\usepackage{color}
\makeatletter
\newcommand*\MyTextColor[1]{%
\@ifnextchar\bgroup
{\textcolor{#1}}
{\color{#1}}%
}
\makeatother
\begin{document}
\MyTextColor{green}{stuff}
\MyTextColor{red} Some text
\end{document}
The key point is that you need to look for {
using \bgroup
rather than trying to use it directly (as it is the begin-group character).
To explain how the \@ifnextchar
part deals with the need for either 1 or 2 arguments, what happens in my second approach is that
\newcommand*\MyTextColor[1]{%
defines a macro which absorbs one argument. So:
\MyTextColor{red}{stuff}
absorbs red
as #1
and leaves {stuff}
in the input stream, while
\MyTextColor{red} other stuff
also absorbs red
as #1
and leaves other stuff
in the input stream. We now apply \@ifnextchar
, which 'peeks' at the next token without absorbing it. The test reads
\@ifnextchar\bgroup
{\textcolor{#1}}
{\color{#1}}%
and so depending on the result, either \textcolor{red}
or \color{red}
is inserted into the input stream. Thus we end up with either
\textcolor{red}{stuff}
or
\color{red} other stuff
which means that \textcolor
will get the required two arguments, while \color
only gets one. The key is that {red}
is reinserted into the input after either \textcolor
or \color
.
Although it is not directly related to the question, a few notes on the xparse
approach may be useful. When using the xparse
package, arguments are described by letter, with m
representing a mandatory argument and g
representing an optional argument in braces (i.e. an optional TeX group). A +
before the letter allows that argument to accept paragraph tokens, so in my definition the first argument cannot (it's supposed to be the name of a colour), while the second one can (it is arbitrary text).
The g
argument returns a special token (\NoValue
) if the optional argument was not present at all. If a default value was wanted, I'd have used G{<default>}
. The same approach applies to standard LaTeX optional arguments, which are represented as o
or O
, depending on whether a default value is required. I have tested for \NoValue
with the test \IfNoValueTF
; \IfNoValueT
and \IfNoValueT
are also available.
Best Answer
Based on details from How to iterate over a comma separated list?, you can define your versions of
\page
and\pages
in the following way:\page
passes its argument on to making a\def
inition called\@page
.\pages
iterates over the CSV list, passing every item to\@page
for execution.