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
.
The 'classical' approach is to use \expandafter
\documentclass{article}
\begin{document}
\def\x#1#2#3#4{%
\def\arga{#2}%
\def\argb{#3}%
\def\argc{#4}%
\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter#1%
\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter
{\expandafter\expandafter\expandafter\arga\expandafter\expandafter\expandafter}%
\expandafter\expandafter\expandafter{\expandafter\argb\expandafter}\expandafter
{\argc}}
\def\y#1#2#3{\detokenize{#1#2#3}}
\x\y{arg1}{arg2}{arg3}
\end{document}
where we need so many of them to expand arg3
then arg2
and finally arg1
. (This is what is effectively wrapped up in expl3
's \exp_args:Nooo
).
The rule of the number of \expandafter
s we need is 2n – 1, where n is how many tokens we want to expand. So for one token somewhere ahead, we need just one \expandafter
in each place to be 'skipped', to expand two tokens (second one then the first one) we need three \expandafter
s, for three tokens (as in the current case) we need seven \expandafter
s, and so one. This is easiest to see if you write/print out a short second and cross off the commands as TeX would read them: you'll find everything works out.
With e-TeX available, we can use an \edef
and \unexpanded
:
\documentclass{article}
\begin{document}
\def\x#1#2#3#4{%
\def\arga{#2}%
\def\argb{#3}%
\def\argc{#4}%
\begingroup
\edef\x{%
\endgroup
\noexpand#1
{\unexpanded\expandafter{\arga}}%
{\unexpanded\expandafter{\argb}}%
{\unexpanded\expandafter{\argc}}%
}%
\x
}
\def\y#1#2#3{\detokenize{#1#2#3}}
\x\y{arg1}{arg2}{arg3}
\end{document}
(You can do the same without e-TeX using a series of toks, but that gets a bit confusing so I'd not normally do it.)
The question says no expl3
, but for contrast the approach using a minimium of the functions it provides would read
\documentclass{article}
\usepackage{expl3}
\begin{document}
\ExplSyntaxOn
\def\x#1#2#3#4{
\def\arga{#2}
\def\argb{#3}
\def\argc{#4}
\exp_args:Nooo#1\arga\argb\argc
}
\ExplSyntaxOff
\def\y#1#2#3{\detokenize{#1#2#3}}
\x\y{arg1}{arg2}{arg3}
\end{document}
which is I hope a lot more readable. (I'd probably want to use \exp_args:NVVV
as we are using 'value stored in a variable', but that function is not pre-defined so I've avoided it here.)
Best Answer
The
\expandafter
command tries to expand one level the token immediately following the next one.With your code, the tried token is
{
, which is not expandable.Reaching the last token in the argument is impossible with
\expandafter
, because you don't know how many of them there are.Some tricks are possible, though. The easiest one is to force complete expansion of the argument:
On the other hand, the
\ext
can better go in the definition:A different trick with
xparse
andexpl3
, so it's easy to also accommodate the optional argument to\includegraphics
.See also Choosing whether to include PDF or PNG in PDFLaTeX for different strategies.