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'm using mdwtools and syntax package to write BNF grammar, I wonder is there a way to set the parindent so that each production line will be center algined instead of left aligned by default?

Minimal Example

\documentclass[10pt,letterpaper]{article}  
\usepackage{mdwtab}
\usepackage{syntax} 

\setlength{\grammarparsep}{0.25cm}   % vertical distance between production rules
\setlength{\grammarindent}{1cm}      % horizontal indent distance


\renewcommand{\syntleft}{}          % do not display '<' associated with variable, for example <A>
\renewcommand{\syntright}{}         % do not display '>' associated with variable, for example <A>

% Note: the empty line between production rules is not optional!

\begin{document}
    \begin{grammar}
        <A> $\rightarrow$ B | c | d

        <B> $\rightarrow$ B

        <C> $\rightarrow$ D 
    \end{grammar}
\end{document}

Update (\phantom solution)

\begin{grammar}\centering
        <S> $\ra$ abB 

        <A> $\ra$ aaBb

        <B> $\ra$ bbAa

        <A> $\ra$ $\lambda$
\end{grammar}
share|improve this question
    
Do you care about the alignment of the production lines compared to one another? For example, that <A>, <B> and <C> should be below one another. –  Werner Aug 21 '11 at 0:28
    
@Werner: Yes, I want to them to align with each other. Thank you. –  Chan Aug 21 '11 at 0:32
add comment

2 Answers

up vote 3 down vote accepted

You can use \centering right after \begin{grammar} to center each production in its own line:

\begin{grammar}\centering
    <A> $\rightarrow$ B | c | d

    <B> $\rightarrow$ B \phantom{| c | d}

    <C> $\rightarrow$ D \phantom{| c | d}
\end{grammar}

Another approach; the grammar environment is defined as a list, so you could define a similar environment, to manually specify the \leftmargin length. In the following example I defined a mygrammar environment with an optional argument allowing you to control the \leftmargin:

\documentclass[10pt,letterpaper]{article}  
\usepackage{mdwtab}
\usepackage{syntax} 
\usepackage{lipsum} % to geberate text for the example 

\setlength{\grammarparsep}{0.25cm}   % vertical distance between production rules
\setlength{\grammarindent}{1cm}      % horizontal indent distance


\renewcommand{\syntleft}{}          % do not display '<' associated with variable, for example <A>
\renewcommand{\syntright}{}         % do not display '>' associated with variable, for example <A>

% Note: the empty line between production rules is not optional!

\makeatletter
\newenvironment{mygrammar}[1][0pt]{%
\list{}{%
\labelwidth\grammarindent%
\leftmargin\dimexpr\grammarindent+#1\relax%
\advance\grammarindent\labelsep
\itemindent\z@%
\listparindent\z@%
\parsep\grammarparsep%
}%
\let\\\@normalcr
\syntaxShortcuts\relax\relax%
\def\alt{\\\llap{\textbar\quad}}%
\def\gr@setpar{%
\def\par{%
\parshape\@ne\@totalleftmargin\linewidth%
\@@par%
\catcode`\<12%
\everypar{%
\everypar{}%
\catcode`\<\active%
\gr@implitem%
}%
}%
}%
\gr@setpar%
\par%
\let\gr@leftsq\[%
\let\gr@rightsq\]%
\def\gr@endsyntdiag]{\end{syntdiag}\gr@setpar\par}%
\def\[{\@ifnextchar[{\begin{syntdiag}\@gobble}\gr@leftsq}%
\def\]{\@ifnextchar]\gr@endsyntdiag\gr@rightsq}%
}{%
\@newlistfalse%
\everypar{}%
\endlist%
}
\makeatother

\begin{document}

\begin{grammar}    

  <A> $\rightarrow$ B | c | d

   <B> $\rightarrow$ B

   <C> $\rightarrow$ D 
\end{grammar}

\begin{mygrammar}    

  <A> $\rightarrow$ B | c | d

   <B> $\rightarrow$ B

   <C> $\rightarrow$ D 
\end{mygrammar}

\begin{mygrammar}[3cm]    

  <A> $\rightarrow$ B | c | d

   <B> $\rightarrow$ B

   <C> $\rightarrow$ D 
\end{mygrammar}

\begin{mygrammar}[6cm]    

  <A> $\rightarrow$ B | c | d

   <B> $\rightarrow$ B

   <C> $\rightarrow$ D 
\end{mygrammar}

\end{document}

enter image description here

Here's another more automated approach: you simply provide the longest line as a mandatory argument for the newly defined Cgrammar environment, and you get the contents centered and with left alignment:

\documentclass[10pt,letterpaper]{article}  
\usepackage{mdwtab}
\usepackage{syntax} 
\usepackage{lipsum} % to geberate text for the example 

\setlength{\grammarparsep}{0.25cm}   % vertical distance between production rules
\setlength{\grammarindent}{1cm}      % horizontal indent distance


\renewcommand{\syntleft}{}          % do not display '<' associated with variable, for example <A>
\renewcommand{\syntright}{}         % do not display '>' associated with variable, for example <A>

% Note: the empty line between production rules is not optional!

\newlength\longest
\newlength\LeftMargin
\makeatletter
\newenvironment{Cgrammar}[1]{%
\list{}{%
\settowidth\longest{#1}
\setlength\LeftMargin{\dimexpr0.5\linewidth-0.5\longest}
\labelwidth\grammarindent%
\leftmargin\dimexpr\grammarindent+\LeftMargin\relax%
\advance\grammarindent\labelsep
\itemindent\z@%
\listparindent\z@%
\parsep\grammarparsep%
}%
\let\\\@normalcr
\syntaxShortcuts\relax\relax%
\def\alt{\\\llap{\textbar\quad}}%
\def\gr@setpar{%
\def\par{%
\parshape\@ne\@totalleftmargin\linewidth%
\@@par%
\catcode`\<12%
\everypar{%
\everypar{}%
\catcode`\<\active%
\gr@implitem%
}%
}%
}%
\gr@setpar%
\par%
\let\gr@leftsq\[%
\let\gr@rightsq\]%
\def\gr@endsyntdiag]{\end{syntdiag}\gr@setpar\par}%
\def\[{\@ifnextchar[{\begin{syntdiag}\@gobble}\gr@leftsq}%
\def\]{\@ifnextchar]\gr@endsyntdiag\gr@rightsq}%
}{%
\@newlistfalse%
\everypar{}%
\endlist%
}
\makeatother

\begin{document}

\begin{grammar}    

  <A> $\rightarrow$ B | c | d

   <B> $\rightarrow$ B

   <C> $\rightarrow$ D 
\end{grammar}

\lipsum[1]
\begin{Cgrammar}{A> $\rightarrow$ B | c | d}

  <A> $\rightarrow$ B | c | d

   <B> $\rightarrow$ B

   <C> $\rightarrow$ D 
\end{Cgrammar}

\lipsum[1]
\begin{Cgrammar}{<A> $\rightarrow$ B | c | d | e}

  <A> $\rightarrow$ B | c | d | e

   <B> $\rightarrow$ B

   <C> $\rightarrow$ D 
\end{Cgrammar}

\lipsum[1]
\begin{Cgrammar}{<A> $\ra$ aaBb}
        <S> $\ra$ abB 

        <A> $\ra$ aaBb

        <B> $\ra$ bbAa

        <A> $\ra$ $\lambda$
\end{Cgrammar}


\end{document}
share|improve this answer
    
Thanks a lot. However, the variables A, B, and C don't align vertically with each other. Is there a work around? –  Chan Aug 21 '11 at 0:33
    
@Chan: see my updated answer –  Gonzalo Medina Aug 21 '11 at 0:40
    
Very nice solution ;) Many thanks for your effort. I really appreciate it. –  Chan Aug 21 '11 at 0:42
    
@Chan: see my third edit for an automated solution which only requires you to pass the longest line as an argument. –  Gonzalo Medina Aug 21 '11 at 1:01
    
Melinda: Awesome. I bet I will learn many useful techniques from your solutions. Thank you Sir :) –  Chan Aug 21 '11 at 1:05
show 1 more comment

You can use \centering as @Gonzalo suggested, and suppliment this with ample use of \phantom{...} to acquire the desired alignment:

\begin{grammar}\centering
    <A> $\rightarrow$ B | c | d

    <B> $\rightarrow$ B \phantom{| c | d}

    <C> $\rightarrow$ D \phantom{| c | d}
\end{grammar}

enter image description here

\phantom{<stuff>} makes a box of width of <stuff>, but does not typeset anything.

For your other example, one could use a predefined length of the largest item on the right-hand side (RHS) of your production. Then, using this length, you place each RHS in a box:

\newlength{\widest}% Length of widest element
\settowidth{\widest}{aaBb}% Widest element is "aaBb"
\newcommand{\rhs}[1]{\makebox[\widest][l]{#1}}
...
\begin{grammar}\centering
  <S> $\rightarrow$ \rhs{abB}

  <A> $\rightarrow$ \rhs{aaBb}

  <B> $\rightarrow$ \rhs{bbAa}

  <A> $\rightarrow$ \rhs{$\lambda$}
\end{grammar}

Another centering method, this time using boxed to align BNF productions

The calc package also offers a \widthof{<stuff>} command that you could use and remove the declaration of a new length like I did. However, the above illustrates the concept.

share|improve this answer
    
Thanks a lot the fix. I wonder will it work with a grammar of the form. See my update. –  Chan Aug 21 '11 at 0:46
    
The graphic/image I've added shows that it does... –  Werner Aug 21 '11 at 0:48
    
In your example, there is always a letter for every production. In my case, there is a single \lambda and other productions are string of letters. So I'm not sure exactly where should I group my \phantom section? –  Chan Aug 21 '11 at 0:51
    
I the productions were just characters, liberal use of \phantom wherever you don't want something printed would work. However, introducing something like \lambda, which doesn't have a width that matches a regular character, requires a little more work. I've adapted my solution for such a case, placing the right-hand side elements in a box of fixed width, depending on the widest element you provide. –  Werner Aug 21 '11 at 1:17
    
Thanks a lot for an alternative solution ;)! –  Chan Aug 21 '11 at 3:52
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.