我正在使用mdwtools
和syntax
包来编写 BNF 语法,我想知道是否有办法设置parindent
以便每条生产线都默认居中而不是左对齐?
最小示例
\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}
更新(\phantom
解决方案)
\begin{grammar}\centering
<S> $\ra$ abB
<A> $\ra$ aaBb
<B> $\ra$ bbAa
<A> $\ra$ $\lambda$
\end{grammar}
答案1
您可以使用\centering
right after\begin{grammar}
将每个产品置于其自己的行的中心:
\begin{grammar}\centering
<A> $\rightarrow$ B | c | d
<B> $\rightarrow$ B \phantom{| c | d}
<C> $\rightarrow$ D \phantom{| c | d}
\end{grammar}
另一种方法;grammar
环境被定义为一个列表,因此您可以定义一个类似的环境,以手动指定长度\leftmargin
。在下面的例子中,我定义了一个mygrammar
带有可选参数的环境,允许您控制\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}
这是另一种更自动化的方法:您只需提供最长的行作为新定义环境的强制参数Cgrammar
,即可获得居中和左对齐的内容:
\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}
答案2
您可以\centering
按照@Gonzalo 的建议使用,并充分使用\phantom{...}
以获得所需的对齐:
\begin{grammar}\centering
<A> $\rightarrow$ B | c | d
<B> $\rightarrow$ B \phantom{| c | d}
<C> $\rightarrow$ D \phantom{| c | d}
\end{grammar}
\phantom{<stuff>}
制作一个宽度为 的框<stuff>
,但不排版任何内容。
对于您的另一个示例,可以使用产品右侧 (RHS) 上最大项目的预定义长度。然后,使用此长度,将每个 RHS 放入一个盒子中:
\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}
这calc
包裹还提供了一个\widthof{<stuff>}
命令,您可以使用它并删除新长度的声明,就像我做的那样。但是,上面说明了这个概念。