summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/formal-grammar/formal-grammar.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'macros/latex/contrib/formal-grammar/formal-grammar.dtx')
-rw-r--r--macros/latex/contrib/formal-grammar/formal-grammar.dtx384
1 files changed, 384 insertions, 0 deletions
diff --git a/macros/latex/contrib/formal-grammar/formal-grammar.dtx b/macros/latex/contrib/formal-grammar/formal-grammar.dtx
new file mode 100644
index 0000000000..92bf02e871
--- /dev/null
+++ b/macros/latex/contrib/formal-grammar/formal-grammar.dtx
@@ -0,0 +1,384 @@
+% \iffalse meta-comment
+% Copyright (C) 2021 by Martin Vassor
+% This file may be distributed and/or modified under the
+% conditions of the LaTeX Project Public License, either
+% version 1.3 of this license or (at your option) any later
+% version. The latest version of this license is in:
+%
+% http://www.latex-project.org/lppl.txt
+%
+% and version 1.3 or later is part of all distributions of
+% LaTeX version 2005/12/01 or later.
+%
+% \fi
+
+
+
+% \iffalse
+%<package>\NeedsTeXFormat{LaTeX2e}
+%<package>\ProvidesPackage{formal-grammar}[2021/11/10 v1.0 A package to typeset formal grammars]
+%<package>\RequirePackage{xparse}
+%<package>\RequirePackage{float}
+%<package>\RequirePackage{xcolor}
+%<package>\RequirePackage{colortbl}
+%<package>\RequirePackage{array}
+%<package>\definecolor{LightCyan}{rgb}{0.8,1,1}
+%<*driver>
+\documentclass{ltxdoc}
+\usepackage{formal-grammar}
+\EnableCrossrefs
+\CodelineIndex
+\RecordChanges
+\begin{document}
+ \DocInput{formal-grammar.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+% \CheckSum{83}
+%
+% \CharacterTable
+% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
+% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
+% Digits \0\1\2\3\4\5\6\7\8\9
+% Exclamation \! Double quote \" Hash (number) \#
+% Dollar \$ Percent \% Ampersand \&
+% Acute accent \' Left paren \( Right paren \)
+% Asterisk \* Plus \+ Comma \,
+% Minus \- Point \. Solidus \/
+% Colon \: Semicolon \; Less than \<
+% Equals \= Greater than \> Question mark \?
+% Commercial at \@ Left bracket \[ Backslash \\
+% Right bracket \] Circumflex \^ Underscore \_
+% Grave accent \` Left brace \{ Vertical bar \|
+% Right brace \} Tilde \~}
+%
+%
+% \changes{v1.0}{2021/11/21}{Initial version for publication}
+%
+% \GetFileInfo{formal-grammar.sty}
+%
+% \title{The \textsf{formal-grammar} package\thanks{This document
+% corresponds to \textsf{formal-grammar}~\fileversion,
+% dated \filedate.}}
+% \author{Martin Vassor\\ \texttt{bromind+ctan@gresille.org}}
+%
+% \maketitle
+%
+%\iffalse
+%% \begin{abstract}
+%% The \textsf{formal-grammar} package provides commands to typeset formal grammars.
+%% \end{abstract}
+%\fi
+% \tableofcontents
+%
+% \section{Introduction}
+%
+% This package provides a new environment (|grammar|) and associated commands to
+% typeset BNF grammars. It allows to easily write formal grammars, for instance
+% the syntax of the \(\lambda\) calculus is given in Grammar~\ref{gr:lambda}.
+%
+%\begin{grammar}[\(\lambda\) calculus syntax][][gr:lambda]
+% \firstcase{T}{\nonterm{V}}{Variable}
+% \highlight
+% \otherform{(\nonterm{T}\ \nonterm{T})}{Application}
+% \highlight
+% \otherform{\lambda \nonterm{V}\cdot\nonterm{T}}{Abstraction}
+% \downplay
+% \firstcase{V}{x, y, \dots}{Variables}
+%\end{grammar}
+%
+% \section{Usage}
+% \subsection{Basic usage}
+%
+% \paragraph{Creating a grammar.}
+% We first start creating a grammar using the |grammar| environment.
+%
+% \DescribeEnv{grammar}
+% This is the main environment to write your grammar. |grammar| accepts 3
+% optional arguments: the first one is a possible caption; the second is a
+% positionning option; and the third is a label.
+%
+% If none of the optional arguments is provided, the grammar is inlined (i.e.
+% not in a float environment. If the first argument is set (the optional
+% caption), the grammar is typeset in a float, captionned with the provided
+% caption.
+% The second optional argument is a positionning option (one of \texttt{t},
+% \texttt{b}, \texttt{p}, \texttt{h}, etc.). The default is \texttt{p}.
+% The last argument is a label, used to reference the grammar elsewhere in the
+% document.
+%
+% The grammar can then be populated using two basic constructs: |firstcase| and
+% |otherform|.
+%
+% \DescribeMacro{\firstcase}
+% The |firstcase| command creates a new non-terminal of the grammar. It takes 3 mandatory
+% arguments: the letter(s) of the non-terminal, the definition, and an
+% explanation.
+% \DescribeMacro{\otherform}
+% On the other hand, |otherform| create an alternative for the preceding
+% non-terminal, on a new line. It takes two arguments: the definition of the
+% alternative, and an explanation. For instance, the following grammar typesets
+% as the grammar in Grammar~\ref{gr:simple_grammar}.
+% \begin{verbatim}
+% \begin{grammar}[A simple grammar][t][gr:simple_grammar]
+% \firstcase{A}{()}{Parenthesis}
+% \otherform{\{\}}{Curly brackets}
+% \end{grammar}
+% \end{verbatim}
+% \begin{grammar}[A simple grammar][t][gr:simple_grammar]
+% \firstcase{A}{()}{Parenthesis}
+% \otherform{\{\}}{Curly brackets}
+% \end{grammar}
+%
+% \paragraph{Referencing non-terminals}
+%
+% \DescribeMacro{\nonterm}
+% This allows you to typeset a symbol as a non-terminal. In the current version,
+% the default typesetting is to wrap in a \verb+\mathcal+ command. This allow
+% to reference those non-terminals, both in grammar rules and elsewhere in the
+% document. Notice that, since the typesetting is just a wrapper over
+% \verb+\mathcal+, it should be used in a math environment. For instance, the
+% only non-terminal of Grammar~\ref{gr:simple_grammar} is \(\nonterm{A}\)
+% (\verb+\(\nonterm{A}\)+).
+%
+%
+% \subsection{Advanced capabilities}
+% In this subsection, we will explain the more advanced capabilities of the
+% package. These would allow to typeset more complex grammars such as the one
+% displayed in Grammar~\ref{gr:advanced_grammar}.
+%
+% \begin{grammar}[A more advanced grammar][t][gr:advanced_grammar]
+% \firstcase{B}{(\nonterm{B})\gralt \{\nonterm{B}\}}{Nested parenthesis or brackets}
+% \firstcasesubtil{\(\nonterm{C}_1\)}{\nonterm{B}}{Example of subtil non-terminal}
+% \highlight
+% \firstcase{D}{\nonterm{B}}{An interesting line}
+% \downplay
+% \otherform{\nonterm{D}}{An uninteresting line}
+% \otherform{\lochighlight{\nonterm{D} + \nonterm{D}}
+% \gralt \nonterm{A}}{Important item}
+% \end{grammar}
+%
+% \paragraph{Variants on the same line.}
+% \DescribeMacro{\gralt}
+% When variants are short and simple, it is possible to display multiple of them
+% on the same line using |\gralt|. For instance, the first line of
+% Grammar~\ref{gr:advanced_grammar} is typeset with the following command:
+% \begin{verbatim}
+% \firstcase{B}{(\nonterm{B})\gralt \{\nonterm{B}\}}{Nested parenthesis or brackets}
+% \end{verbatim}
+% \paragraph{Subtle typesetting of non-terminals}
+% Since nonterminal are, by default, typeset using \verb+\mathcal+, it can lead
+% to the usual issues of \verb+\mathcal+ (typically, for lowercases). Therefore, we provide \emph{subtle}
+% variants of |\firstcase| and |\nonterm|, in which the non-terminal symbol is
+% not typeset (i.e. as the user, you have to typeset it manually).
+%
+% \DescribeMacro{\nontermsubtil}
+% This is equivalent to |\nonterm|, but where typesetting is left to the user.
+% In the current implementation does nothing. However users are encouraged to
+% use it for future modifications of the package. For instance, it is possible
+% to typeset a non-terminal with a number index as follow
+% \(\nontermsubtil{\nonterm{C}_1}\) with the following command:
+% \verb+\(\nontermsubtil{\nonterm{C}_1}\)+
+%
+% \DescribeMacro{\firstcasesubtil}
+% The subtil variant of |\firstcase|. Works similarly, except that the
+% non-terminal (i.e. the first argument) is not embedded in a \verb+\mathcal+
+% macro. For instance, the \(\nontermsubtil{\nonterm{C}_1}\) in
+% Grammar~\ref{gr:advanced_grammar} is typeset with the following command:
+% \begin{verbatim}
+% \firstcasesubtil{\(\nonterm{C}_1\)}{\nonterm{B}}{Example of subtil non-terminal}
+% \end{verbatim}
+%
+% \paragraph{Highlighting and downplaying variants}
+% Three commands are provided to highlight or downplay some part of a grammar.
+% |\highlight| highlights a whole line, |\loghighlight| highlights a part of a
+% line, while |\downplay| downplays a line.
+%
+% \DescribeMacro{\downplay}
+% \DescribeMacro{\highlight}
+% The two commands |\highlight| and |\downplay| work similarly: when used before
+% a |\firstcase|, |\firstcasesubtil|, or |\otherform|, the next line is
+% highlighted in blue, or printed in light grey. For instance, in
+% Grammar~\ref{gr:advanced_grammar}, the rule for non-terminal \(\nonterm{D}\)
+% is typeset with:
+% \begin{verbatim}
+% \highlight
+% \firstcase{D}{\nonterm{B}}{An interesting line}
+% \downplay
+% \otherform{\nonterm{D}}{An uninteresting line}
+% \end{verbatim}
+%
+% \DescribeMacro{\lochighlight}
+% For more local highlighting, it is possible to use |\lochighlight|, which
+% prints some part of a rule in red. The last line of
+% Grammar~\ref{gr:advanced_grammar}, which contains such local highlight, is
+% typeset with the following command:
+% \begin{verbatim}
+% \otherform{\lochighlight{\nonterm{D} + \nonterm{D}}
+% \gralt \nonterm{A}}{Important item}
+% \end{verbatim}
+%
+% \StopEventually{\PrintIndex}
+%
+% \section{Implementation}
+%
+% \begin{environment}{floatgrammar}
+% This is a new float that contains floating grammars. This is needed so that
+% they are labeled with 'Grammar'.
+% \begin{macrocode}
+\newfloat{floatgrammar}{t b h p}{.gram}
+\floatname{floatgrammar}{Grammar}
+% \end{macrocode}
+% \end{environment}
+%
+%\iffalse
+%% Taken from https://tex.stackexchange.com/a/26364/107341
+%\fi
+%
+% \begin{macro}{\@rowstyle}
+% The default \verb+rowstyle+ is empty.
+% \begin{macrocode}
+\newcommand*{\@rowstyle}{}
+% \end{macrocode}
+% \end{macro}
+%
+
+% \begin{macro}{\rowstyle}
+% An internal command used to set the style of a row. In addition, we add column
+% types to reset the style (\verb:=:) and to keep the style from one column to
+% the other (\verb:+:).
+% \begin{macrocode}
+\newcommand*{\rowstyle}[1]{% sets the style of the next row
+ \gdef\@rowstyle{#1}%
+ \@rowstyle\ignorespaces%
+}
+% \end{macrocode}
+% \begin{macrocode}
+\newcolumntype{=}{% resets the row style
+ >{\gdef\@rowstyle{}}%
+}
+
+\newcolumntype{+}{% adds the current row style to the next column
+ >{\@rowstyle}%
+}
+% \end{macrocode}
+% \end{macro}
+%\iffalse
+%% End of stackexchange
+%\fi
+%
+% \begin{environment}{grammar}
+% This is the implementation of the |grammar| environment. The main difficulty
+% is to check whether optional arguments are provided. If the first is provided,
+% we embed the grammar into a \verb+floatgrammar+; then if the second argument
+% is provided, we use it as the position, (otherwise, we use \verb+p+). Finally,
+% if the third argument is provided, we use it as a label.
+% \begin{macrocode}
+\ExplSyntaxOn
+%% 1st argument: caption (makes it float)
+%% 2nd argument: positionning option (`p` by default)
+%% 3rd argument: label
+ \NewDocumentEnvironment{grammar} {o o o}
+ {
+ \IfNoValueTF{#1} {
+ }{
+ \IfNoValueTF{#2}{
+ \begin{floatgrammar}[p]
+ } {
+ \begin{floatgrammar}[#2]
+ }
+ \centering
+ }
+
+ \begin{tabular}{=l +r +l +l}
+ }{
+ \end{tabular}
+
+ \IfNoValueTF{#1} {
+ \linebreak
+ } {
+ \caption{#1}
+ \IfNoValueTF{#3}{
+ } {
+ \label{#3}
+ }
+ \end{floatgrammar}
+ }
+ }
+\ExplSyntaxOff
+% \end{macrocode}
+% \end{environment}
+
+% \begin{macro}{\firstcase}
+% The |\firstcase| is typeset as a new line in the array, which first cell is
+% the symbol of the non-terminal, the second cell is just \(::=\), the third
+% cell is the rule (it is directly printed, without any modification), and the
+% last cell is the description of the rule, in greyish color.
+% \begin{macrocode}
+\newcommand{\firstcase}[3]{\(\mathcal{#1}\) & \(::=\) & \(#2\) & {\itshape \color{gray!90!black} #3}\\}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\firstcasesubtil}
+% The |\firstcasesubtil| is implemented similarly to |\firstcase|, except that
+% the first argument is not surrounded by \verb+\mathcal+.
+% \begin{macrocode}
+\newcommand{\firstcasesubtil}[3]{#1 & \(::=\) & \(#2\) & {\itshape \color{gray!90!black} #3}\\}
+% \end{macrocode}
+% \end{macro}
+
+% \begin{macro}{\otherform}
+% Adds a line with an empty first cell, and which second cell is just a pipe.
+% The third and fourth cells are similar to |\firstcase|.
+% \begin{macrocode}
+\newcommand{\otherform}[2]{& \(|\) & \(#1\) & {\itshape \color{gray!90!black} #2}\\}
+% \end{macrocode}
+% \end{macro}
+
+% \begin{macro}{\nonterm}
+% Typesets in \verb+\mathcal+.
+% \begin{macrocode}
+\newcommand{\nonterm}[1]{\mathcal{#1}}
+% \end{macrocode}
+% \end{macro}
+
+% \begin{macro}{\nontermsubtil}
+% Does nothing right now.
+% \begin{macrocode}
+\newcommand{\nontermsubtil}[1]{#1}
+% \end{macrocode}
+% \end{macro}
+
+% \begin{macro}{\gralt}
+% |\gralt| is simply a pipe surrounded by large spaces.
+% \begin{macrocode}
+\newcommand{\gralt}[0]{\quad |\quad }
+% \end{macrocode}
+% \end{macro}
+
+
+% \begin{macro}{\highlight}
+% We simply set the row color to LightCyan.
+% \begin{macrocode}
+\newcommand{\highlight}[0]{\rowcolor{LightCyan}}
+% \end{macrocode}
+% \end{macro}
+
+% \begin{macro}{\lochighlight}
+% We simply surround the argument with red.
+% \begin{macrocode}
+\newcommand{\lochighlight}[1]{{\color{red} #1}}
+% \end{macrocode}
+% \end{macro}
+
+% \begin{macro}{\downplay}
+% We simply apply a style that write in light grey for the row.
+% \begin{macrocode}
+\newcommand{\downplay}[0]{\rowstyle{\color{white!80!black}}}
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \Finale
+\endinput