mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-05-20 18:52:39 +02:00
2876 lines
87 KiB
TeX
2876 lines
87 KiB
TeX
% \begin{meta-comment}
|
|
%
|
|
% $Id$
|
|
%
|
|
% Syntax typesetting package for LaTeX 2e
|
|
%
|
|
% (c) 1996 Mark Wooding
|
|
%
|
|
%----- Revision history -----------------------------------------------------
|
|
%
|
|
% $Log$
|
|
% Revision 1.1 1998-09-21 10:19:01 michael
|
|
% Initial implementation
|
|
%
|
|
% Revision 1.9 1996/11/28 00:19:10 mdw
|
|
% Added abbreviations for syntax diagram constructions. These have been
|
|
% getting on my nerves for too long now...
|
|
%
|
|
% Revision 1.8 1996/11/19 21:02:15 mdw
|
|
% Entered into RCS
|
|
%
|
|
%
|
|
% \end{meta-comment}
|
|
%
|
|
% \begin{meta-comment} <general public licence>
|
|
%%
|
|
%% syntax package -- typesetting syntax descriptions
|
|
%% Copyright (c) 1996 Mark Wooding
|
|
%%
|
|
%% This program is free software; you can redistribute it and/or modify
|
|
%% it under the terms of the GNU General Public License as published by
|
|
%% the Free Software Foundation; either version 2 of the License, or
|
|
%% (at your option) any later version.
|
|
%%
|
|
%% This program is distributed in the hope that it will be useful,
|
|
%% but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
%% GNU General Public License for more details.
|
|
%%
|
|
%% You should have received a copy of the GNU General Public License
|
|
%% along with this program; if not, write to the Free Software
|
|
%% Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
%%
|
|
% \end{meta-comment}
|
|
%
|
|
% \begin{meta-comment} <Package preamble>
|
|
%<+package>\NeedsTeXFormat{LaTeX2e}
|
|
%<+package>\ProvidesPackage{syntax}
|
|
%<+package> [1996/05/17 1.9 Syntax typesetting (MDW)]
|
|
% \end{meta-comment}
|
|
%
|
|
% \CheckSum{1465}
|
|
%% \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 \~}
|
|
%%
|
|
%
|
|
% \begin{meta-comment} <driver>
|
|
%
|
|
%<*driver>
|
|
%
|
|
% This hacking will remember the old default underscore character. Even if
|
|
% T1 fonts are being used, it will get the grotty version. Why is it that
|
|
% all of the encoding handling ends up looking like this?
|
|
%
|
|
\expandafter\let\expandafter\oldus\csname?\string\textunderscore\endcsname
|
|
%
|
|
\input{mdwtools}
|
|
\describespackage{syntax}
|
|
\DeclareRobustCommand\syn{\package{syntax}}
|
|
\mdwdoc
|
|
%</driver>
|
|
%
|
|
% \end{meta-comment}
|
|
%
|
|
% \section{User guide}
|
|
%
|
|
% \subsection{Introduction}
|
|
%
|
|
% The \syn\ package provides a number of commands and environments which
|
|
% extend \LaTeX\ and allow you to typeset good expositions of syntax.
|
|
%
|
|
% The package provides several different types of features: probably not all
|
|
% of these will be required by every document which needs the package:
|
|
% \begin{itemize}
|
|
% \item A system of abbreviated forms for typesetting syntactic items.
|
|
% \item An environment for typesetting BNF-type grammars
|
|
% \item A collection of environments for building syntax diagrams.
|
|
% \end{itemize}
|
|
%
|
|
% The package also includes some other features which, while not necessarily
|
|
% syntax-related, will probably come in handy for similar types of document:
|
|
% \begin{itemize}
|
|
% \item An abbreviated notation for verbatim text, similar to the
|
|
% \package{shortvrb} package.
|
|
% \item A slightly different underscore character, which works as expected
|
|
% in text and maths modes.
|
|
% \end{itemize}
|
|
%
|
|
% \subsection{The abbreviated verbatim notation}
|
|
%
|
|
% In documents describing programming languages and libraries, it can become
|
|
% tedious to type "\verb|...|" every time. Like Frank Mittelbach's
|
|
% \package{shortvrb} package, \syn\ provides a way of setting up single-^^A
|
|
% character abbreviations. The only real difference between the two is that
|
|
% the declarations provided by \syn\ obey \LaTeX's normal scoping rules.
|
|
%
|
|
% \DescribeMacro\shortverb
|
|
% You can set up a character as a `verbatim shorthand' character using the
|
|
% |\shortverb| command. This takes a single argument, which should be a
|
|
% single-character control sequence containing the character you want to use.
|
|
% So, for example, the command
|
|
% \begin{listing}
|
|
%\shortverb{\|}
|
|
% \end{listing}
|
|
% would set up the `"|"' character to act as a verbatim delimiter. While a
|
|
% |\shortverb| declaration is in force, any text surrounded by (in this case)
|
|
% vertical bar characters will be typeset as if using the normal |\verb|
|
|
% command.
|
|
%
|
|
% \DescribeEnv{shortverb}
|
|
% Since \LaTeX\ allows any declaration to be used as an environment, you can
|
|
% use a \env{shortverb} environment to delimit the text over which your
|
|
% character is active:
|
|
% \begin{listing}
|
|
%Some text...
|
|
%\begin{shortverb}{\|}
|
|
%...
|
|
%\end{shortverb}
|
|
% \end{listing}
|
|
%
|
|
% \DescribeMacro\unverb
|
|
% If you want to disable a |\shortverb| character without ending the scope
|
|
% of other declarations, you can use the |\unverb| command, passing it
|
|
% a character as a control sequence, in the same way as above.
|
|
%
|
|
% The default \TeX/\LaTeX\ underscore character is rather too short for
|
|
% use in identifiers. For example:
|
|
%
|
|
% \begingroup \let\_=\oldus
|
|
% \begin{demo}{Old-style underscores}
|
|
%Typing long underscore-filled
|
|
%names, like big\_function\_name,
|
|
%is normally tedious. The normal
|
|
%positioning of the underscore
|
|
%is wrong, too.
|
|
% \end{demo}
|
|
% \endgroup
|
|
%
|
|
% The \syn\ package redefines the |\_| command to draw a more attractive
|
|
% underscore character. It also allows you to use the |_|~character
|
|
% directly to produce an underscore outside of maths mode: |_|~behaves
|
|
% as a subscript character as usual inside maths mode.
|
|
%
|
|
% \begin{demo}{New \syn\ underscores}
|
|
%You can use underscore-filled
|
|
%names, like big_function_name,
|
|
%simply and naturally. Of
|
|
%course, subscripts still work
|
|
%normally in maths mode, e.g.,
|
|
%$x_i$.
|
|
% \end{demo}
|
|
%
|
|
% \subsection{Typesetting syntactic items}
|
|
% \begin{synshorts}
|
|
%
|
|
% The \syn\ package provides some simple commands for typesetting syntactic
|
|
% items.
|
|
%
|
|
% \DescribeMacro\synt
|
|
% Typing "\\synt{"<text>"}" typesets <text> as a \lq non-terminal',
|
|
% in italics and surrounded by angle brackets. If you use "\\synt" a lot,
|
|
% you can use the incantation
|
|
% \begin{listing}
|
|
%\def\<#1>{\synt{#1}}
|
|
% \end{listing}
|
|
% to allow you to type "\\<"<text>">" as an alternative to
|
|
% "\\synt{"<text>"}".
|
|
%
|
|
% \DescribeMacro\lit
|
|
% You can also display literal text, which the reader should type directly,
|
|
% using the "\\lit" command.
|
|
%
|
|
% \begin{demo}{Use of \cmd\lit}
|
|
%Type \lit{ls} to display a
|
|
%list of files.
|
|
% \end{demo}
|
|
%
|
|
% Note that the literal text appears in quotes. To suppress the quotes,
|
|
% use the `*' variant.
|
|
%
|
|
% The "\\lit" command produces slightly better output than "\\verb" for
|
|
% running text, since the spaces are somewhat narrower. However, "\\verb"
|
|
% allows you to type arbitrary characters, which are treated literally,
|
|
% whereas you must use commands such as "\\{" to use special characters
|
|
% within the argument to "\\lit". Of course, you can use "\\lit" anywhere
|
|
% in the document: "\\verb" mustn't be used inside a command argument.
|
|
% \end{synshorts}
|
|
%
|
|
% \subsection{Abbreviated forms for syntactic items}
|
|
%
|
|
% It would be very tedious to require the use of commands like |\synt|
|
|
% when building syntax descriptions like BNF grammars. It would also make
|
|
% your \LaTeX\ source hard to read. Therefore, \syn\ provides some
|
|
% abbreviated forms which make typesetting syntax quicker and easier.
|
|
%
|
|
% Since the abbreviated forms use several characters which you may want to
|
|
% use in normal text, they aren't enabled by default. They only work
|
|
% with special commands and environments provided by the \syn\ package.
|
|
%
|
|
% The abbreviated forms are shown in the table below:
|
|
%
|
|
% \begin{tab}[\synshorts]{ll} \hline
|
|
% \bf Input & \bf Output \\ \hline
|
|
% "<some text>" & <some text> \\
|
|
% "`some text'" & `some text' \\
|
|
% "\"some text\"" & "some text" \\ \hline
|
|
% \end{tab}
|
|
%
|
|
% Within one of these abbreviated forms, text is treated more-or-less
|
|
% verbatim:
|
|
% \begin{itemize}
|
|
%
|
|
% \item Any |$|, |%|, |^|, |&|, |{|, |}|, |~| or |#| characters are treated
|
|
% literally: their normal special meanings are ignored.
|
|
%
|
|
% \item Other special characters, with the exception of |\|, are also treated
|
|
% literally: this includes any characters made special by |\shortverb|.
|
|
%
|
|
% \end{itemize}
|
|
%
|
|
% However, the |\| character retains its meaning. Since the brace
|
|
% characters are not recognised, most commands can't be used within
|
|
% abbreviated forms. However, you can use special commands to type some
|
|
% of the remaining special characters:
|
|
%
|
|
% \begin{tab}[\synshorts]{ll} \hline
|
|
% \bf Command & \bf Result \\ \hline
|
|
% "\\\\" & A `\\' character \\
|
|
% "\\>" & A `>' character \\
|
|
% "\\'" & A `\'' character \\
|
|
% "\\\"" & A `"' character \\
|
|
% "\\\ " & A `\ ' character (not a space) \\ \hline
|
|
% \end{tab}
|
|
%
|
|
% Note that |\\|, |\>|, |\"| and \verb*|\ | are only useful in a |\tt| font,
|
|
% i.e., inside |`...'| and |"..."| forms, since the characters don't exist
|
|
% in normal fonts. The |\>|, |\"| and |\'| commands are only provided so
|
|
% you can use these characters within |<...>|, |"..."| and |`...'| forms
|
|
% respectively: in the other forms, there is no need to use the special
|
|
% command.
|
|
%
|
|
% In addition, when the above abbreviations are enabled, the character "|"
|
|
% is set to typeset a \syntax{|} symbol, which is conventionally used to
|
|
% separate alternatives in syntax descriptions.
|
|
%
|
|
% \DescribeMacro\syntax
|
|
% Normally, these abbreviated forms are enabled only within special
|
|
% environments, such as \env{grammar} and \env{syntdiag}. To use them
|
|
% in running text, use the |\syntax| command. The abbreviations are made
|
|
% active within the argument of the |\syntax| command.\footnote{^^A
|
|
% The argument of the \cmd\syntax\ command may contain commands such
|
|
% as \cmd\verb, which are normally not allowed within arguments.
|
|
% } Note that you cannot use the |\syntax| command within the argument
|
|
% of another command.
|
|
%
|
|
% \DescribeMacro\synshorts
|
|
% \DescribeEnv{synshorts}
|
|
% You can also enable the syntax shortcuts using the |\synshorts| declaration
|
|
% or the \env{synshorts} environment. This enables the syntax shortcuts
|
|
% until the scope of the declaration ends.
|
|
%
|
|
% \DescribeMacro\synshortsoff
|
|
% If syntax shortcuts are enabled, you can disable them using the
|
|
% |\synshortsoff| declaration.
|
|
%
|
|
% \subsection{The \env{grammar} environment}
|
|
%
|
|
% \DescribeEnv{grammar}
|
|
% For typesetting formal grammars, for example, of programming languages,
|
|
% the \syn\ package provides a \env{grammar} environment. Within this
|
|
% environment, the abbreviated forms described above are enabled.
|
|
%
|
|
% Within the environment, separate production rules should be separated by
|
|
% blank lines. You can use the normal |\\| command to perform line-breaking
|
|
% of a production rule. Note that a production rule must begin with a
|
|
% nonterminal name enclosed in angle brackets (|<| \dots |>|), followed by
|
|
% whitespace, then some kind of production operator (usually `::=') and then
|
|
% some more whitespace. You can control how this text is actually typeset,
|
|
% however.
|
|
%
|
|
% \DescribeMacro{\[[}
|
|
% \DescribeMacro{\]]}
|
|
% You can use syntax diagrams (see below) instead of a straight piece of BNF
|
|
% by enclosing it in a |\[[| \dots |\]]| pair. Note that you can't mix
|
|
% syntax diagrams and BNF in a production rule, and you will get something
|
|
% which looks very strange if you try.
|
|
%
|
|
% \DescribeMacro\alt
|
|
% In addition, a command |\alt| is provided for splitting long production
|
|
% rules over several lines: the |\alt| command starts a new line and places
|
|
% a \syntax{|} character slightly in the left margin. This is useful when
|
|
% a symbol has many alternative productions.
|
|
%
|
|
% \begin{demo}[w]{The \env{grammar} environment}
|
|
%\begin{grammar}
|
|
%<statement> ::= <ident> `=' <expr>
|
|
% \alt `for' <ident> `=' <expr> `to' <expr> `do' <statement>
|
|
% \alt `{' <stat-list> `}'
|
|
% \alt <empty>
|
|
%
|
|
%<stat-list> ::= <statement> `;' <stat-list> | <statement>
|
|
%\end{grammar}
|
|
% \end{demo}
|
|
%
|
|
% You can modify the appearance of grammars using three length parameters:
|
|
%
|
|
% \begin{description} \def\makelabel{\hskip\labelsep\cmd}
|
|
%
|
|
% \item [\grammarparsep] is the amount of space inserted between production
|
|
% rules. It is a rubber length whose default value is 8\,pt, with
|
|
% 1\,pt of stretch and shrink.
|
|
%
|
|
% \item [\grammarindent] is the amount by which the right hand side of a
|
|
% production rule is indented from the left margin. It is a rigid
|
|
% length. Its default value is 2\,em.
|
|
%
|
|
% \end{description}
|
|
%
|
|
% \DescribeMacro\grammarlabel
|
|
% You can also control how the `label' is typeset by redefining the
|
|
% |\grammarlabel| command. The command is given two arguments: the name of
|
|
% the nonterminal (which was enclosed in angle brackets), and the `production
|
|
% operator'. The command is expected to produce the label. By default, it
|
|
% typesets the nonterminal name using |\synt| and the operator at opposite
|
|
% ends of the label, separated by an |\hfill|.
|
|
%
|
|
% \subsection{Syntax diagrams}
|
|
%
|
|
% A full formal BNF grammar can be somewhat overwhelming for less technical
|
|
% readers. Documents aimed at such readers tend to display grammatical
|
|
% structures as \emph{syntax diagrams}.
|
|
%
|
|
% \DescribeEnv{syntdiag}
|
|
% A syntax diagram is always enclosed in a \env{syntdiag} environment. You
|
|
% should think of the environment as enclosing a new sort of \LaTeX\ mode:
|
|
% trying to type normal text into a syntax diagram will result in very ugly
|
|
% output. \LaTeX\ ignores spaces and return characters while in syntax
|
|
% diagram mode.
|
|
%
|
|
% The syntax of the environment is very simple:
|
|
%
|
|
% \begin{grammar}
|
|
% <synt-diag-env> ::= \[[
|
|
% "\\begin{syntdiag}"
|
|
% \begin{stack} \\ "[" <decls> "]" \end{stack}
|
|
% <text>
|
|
% "\\end{syntdiag}"
|
|
% \]]
|
|
% \end{grammar}
|
|
%
|
|
% The \<decls> contain any declarations you want to insert, to control
|
|
% the environment. The parameters to tweak are described below.
|
|
%
|
|
% Within a syntax diagram, you can include syntactic items using the
|
|
% abbreviated forms described elsewhere. The output from these forms is
|
|
% modified slightly in syntax diagram mode so that the diagram looks
|
|
% right.
|
|
%
|
|
% I probably ought to point out now that the syntax diagram typesetting
|
|
% commands produce beautiful-looking diagrams with all the rules and curves
|
|
% accurately positioned. Some device drivers don't position these objects
|
|
% correctly in their output. I've had particular trouble with |dvips|. I'll
|
|
% say it again: it's not my fault!
|
|
%
|
|
% \DescribeEnv{syntdiag*}
|
|
% The \env{syntdiag} environment only works in paragraph mode, and it acts
|
|
% rather like a paragraph, splitting over several lines when appropriate.
|
|
% If you just want to typeset a snippet of a syntax diagram, you can
|
|
% use the starred environment \env{syntdiag$*$}.
|
|
%
|
|
% \begin{grammar}
|
|
% <synt-diag-star-env> ::= \[[
|
|
% "\\begin{syntdiag*}"
|
|
% \begin{stack} \\ "[" <decls> "]" \end{stack}
|
|
% \begin{stack} \\ "[" <width> "]" \end{stack}
|
|
% <text>
|
|
% "\\end{syntdiag*}"
|
|
% \]]
|
|
% \end{grammar}
|
|
%
|
|
% When typesetting little demos like this, it's not normal to fully adorn
|
|
% the syntax diagram with the full double arrows
|
|
% (`\begin{syntdiag*}[\left{>>-}\right{-><}]\tok{$\cdots$}\end{syntdiag*}').
|
|
% The two declarations \syntax{"\\left{"<arrow>"}" and "\\right{"<arrow>"}"}
|
|
% allow you to choose the arrows on each side of the syntax diagram snippet.
|
|
% The possible values of \<arrow> are shown in the table-ette below:
|
|
%
|
|
% ^^A Time to remember what I learned about tables while writing mdwtab.
|
|
% ^^A Just for the embarassment factor, here's the number of attempts I
|
|
% ^^A took to get the table below to look right: __6. Hmm... not as bad
|
|
% ^^A as I expected. Most of them were fine-tuning things.
|
|
%
|
|
% \medskip ^^A Leave a vertical gap
|
|
% \hbox to\columnwidth{\hfil\vbox{\tabskip=0pt ^^A Centre it horizontally
|
|
% \sdsize \csname sd@setsize\endcsname ^^A Position syntdiag arrows
|
|
% \halign to .5\columnwidth{ ^^A Set the table width
|
|
% &\ttfamily\ignorespaces#\unskip\hfil\tabskip=0pt ^^A Typeset the name
|
|
% &\quad\csname sd@arr@#\endcsname\hfil ^^A Typeset the arrow
|
|
% &\setbox0=\hbox{#}\tabskip=0pt plus 1fil\cr ^^A Stretch between columns
|
|
% >>-&>>-& &>-&>-& &->&->\cr
|
|
% -><&-><& &...&...& &-&-\cr
|
|
% }}\hfil} ^^A Close the boxing
|
|
% \medskip ^^A And leave another gap
|
|
%
|
|
% These declarations should be used only in the optional argument to the
|
|
% \env{syntdiag$*$} command. The second optional argument to the
|
|
% environment, if specified, fixes the width of the syntax diagram snippet;
|
|
% if you omit this argument, the diagram is made just wide enough to
|
|
% fit everything in.
|
|
%
|
|
% \begin{figure}
|
|
% \begin{demo}[w]{Example of \env{syntdiag$*$}}
|
|
%\newcommand{\bs}[2]{%
|
|
% \begin{minipage}{1.6in}%
|
|
% \begin{syntdiag*}[\left{#1}\right{#2}][1.6in]%
|
|
%}
|
|
%\newcommand{\es}{\end{syntdiag*}\end{minipage}}
|
|
%
|
|
%\begin{center}
|
|
%\begin{tabular}{cl} \\ \hline
|
|
%\bf Construction & \bf Meaning \\ \hline
|
|
%\bs {>>-} {...} \es & Start of syntax diagram \\
|
|
%\bs {...} {-><} \es & End of syntax diagram \\
|
|
%\bs {>-} {...} \es & Continued on next line \\
|
|
%\bs {...} {->} \es & Continued from previous line \\ \hline
|
|
%\bs {...} {...}
|
|
% \begin{stack} <option-a> \\ <option-b> \\ <option-c> \end{stack}
|
|
%\es & Alternatives: choose any one \\
|
|
%\bs {...} {...}
|
|
% \begin{rep} <repeat-me> \\ <separator> \end{rep}
|
|
%\es & One or more items, with separators \\ \hline
|
|
%\end{tabular}
|
|
%\end{center}
|
|
% \end{demo}
|
|
% \end{figure}
|
|
%
|
|
% \DescribeMacro\tok
|
|
% You can also include text using the |\tok| command. The argument of this
|
|
% command is typeset in \LaTeX's LR~mode and inserted into the diagram.
|
|
% Syntax abbreviations are allowed within the argument, so you can, for
|
|
% example, include textual descriptions like
|
|
% \begin{listing}
|
|
%\tok{any <char> except `"'}
|
|
% \end{listing}
|
|
%
|
|
% \DescribeEnv{stack}
|
|
% Within a syntax diagram, a choice between several different items is
|
|
% shown by stacking the alternatives vertically. In \LaTeX, this is done
|
|
% by enclosing the items in a \env{stack} environment. Each individual item
|
|
% is separated by |\\| commands, as in the \env{array} and \env{tabular}
|
|
% environments. Each row may contain any syntax diagram material, including
|
|
% |\tok| commands and other \env{stack} environments.
|
|
%
|
|
% Note if you end a \env{stack} environment with a |\\| command, a blank
|
|
% row is added to the bottom of the stack, indicating that none of the items
|
|
% need be specified.
|
|
%
|
|
% The commands |\(| and |\)| are abbreviations for `|\begin{stack}|' and
|
|
% `|\end{stack}|' respectively. Also, |\[| is `|\begin{stack}\\|' and
|
|
% |\]| is `|\end{stack}|' -- these two are useful for stacks in which the
|
|
% first item is blank (i.e., none of the options need be taken).
|
|
%
|
|
% \DescribeEnv{rep}
|
|
% Text which can be repeated is enclosed in a \env{rep} environment: the
|
|
% text is displayed with a backwards pointing arrow drawn over it, showing
|
|
% that it may be repeated. Optionally, you can specify text to be
|
|
% displayed in the arrow, separating it from the main text with a |\\|
|
|
% command.
|
|
%
|
|
% Note that items on the backwards arrow of a \env{rep} construction should
|
|
% be displayed \emph{backwards}. You must put the individual items in
|
|
% reverse order when building this part of your diagrams. \syn\ will
|
|
% correctly reverse the arrows on \env{rep} structures, but apart from
|
|
% this, you must cope on your own. You are recommended to keep these parts
|
|
% of your diagrams as simple as possible to avoid confusing readers.
|
|
%
|
|
% The commands |\<| and |\>| are abbreviations for `|\begin{rep}|' and
|
|
% `|\end{rep}|' respectively.
|
|
%
|
|
% \begin{demo}[w]{A syntax diagram}
|
|
%\begin{syntdiag}
|
|
%<ident> `('
|
|
% \begin{rep} \begin{stack} \\
|
|
% <type> \begin{stack} \\ <ident> \end{stack}
|
|
% \end{stack} \\ `,' \end{rep}
|
|
%\begin{stack} \\ `...' \end{stack} `)'
|
|
%\end{syntdiag}
|
|
% \end{demo}
|
|
%
|
|
% \subsubsection{Line breaking in syntax diagrams}
|
|
%
|
|
% Syntax diagrams are automatically broken over lines and across pages.
|
|
% Lines are only broken between items on the outermost level of the diagram:
|
|
% i.e., not within \env{stack} or \env{rep} environments.
|
|
%
|
|
% You can force a line break at a particular place by using the |\\| command
|
|
% as usual. This supports all the usual \LaTeX\ features: a `|*|' variant
|
|
% which prohibits page breaking, and an optional argument specifying the
|
|
% extra vertical space between lines.
|
|
%
|
|
% \subsubsection{Customising syntax diagrams}
|
|
%
|
|
% There are two basic styles of syntax diagrams supported:
|
|
%
|
|
% \begin{description}
|
|
%
|
|
% \item [square] Lines in the syntax diagram join at squared-off corners.
|
|
% This appears to be the standard way of displaying syntax diagrams
|
|
% in IBM manuals, and most other documents I've seen.
|
|
%
|
|
% \item [rounded] Lines curve around corners. Also, no arrows are drawn
|
|
% around repeating loops: the curving of the lines provides this
|
|
% information instead. This style is used in various texts on
|
|
% Pascal, and appears to be more popular in academic circles.
|
|
%
|
|
% \end{description}
|
|
%
|
|
% You can specify the style you want to use for syntax diagrams by giving
|
|
% the style name as an option on the |\usepackage| command. For example,
|
|
% to force rounded edges to be used, you could say
|
|
%
|
|
% \begin{listing}
|
|
%\usepackage[rounded]{syntax}
|
|
% \end{listing}
|
|
%
|
|
% \DescribeMacro\sdsize
|
|
% \DescribeMacro\sdlengths
|
|
% The \env{syntdiag} environment takes an option argument, which should
|
|
% contain declarations which are obeyed while the environment is set up.
|
|
% The default value of this argument is `|\sdsize\sdlengths|'. The
|
|
% |\sdsize| command sets the default type size for the environment: this is
|
|
% normally |\small|. |\sdlengths| sets the values of the length parameters
|
|
% used by the environment based on the current text size. These parameters
|
|
% are described below.
|
|
%
|
|
% For example, if you wanted to reduce the type size of the diagrams still
|
|
% further, you could use the command
|
|
% \begin{listing}
|
|
%\begin{syntdiag}[\tiny\sdlengths]
|
|
% \end{listing}
|
|
%
|
|
% The following length parameters may be altered:
|
|
%
|
|
% \begin{description} \def\makelabel{\hskip\labelsep\cmd}
|
|
%
|
|
% \item [\sdstartspace] The length of the rule between the arrows which
|
|
% begin each line of the syntax diagram and the first item on the line.
|
|
% Note that most objects have some space on either side of them as
|
|
% well. This is a rubber length. Its default value is 1\,em, although
|
|
% it can shrink by up to 10\,pt.
|
|
%
|
|
% \item [\sdendspace] The length of the rule between the last item on a
|
|
% line and the arrow at the very end. Note that the final line also
|
|
% has extra rubber space on the end. This is a rubber length. Its
|
|
% default value is 1\,em, although it will shrink by up to 10\,pt.
|
|
%
|
|
% \item [\sdmidskip] The length of the rule on either side of a large
|
|
% construction (either a \env{stack} or a \env{rep}). It is a rubber
|
|
% length. Its default value is \smallf 1/2\,em, with a very small
|
|
% amount of infinite stretch.
|
|
%
|
|
% \item [\sdtokskip] The length of the rule on either side of a |\tok|
|
|
% item or syntax abbreviation. It is a rubber length. Its default
|
|
% value is \smallf 1/4\,em, with a very small amount of inifnite
|
|
% stretch.
|
|
%
|
|
% \item [\sdfinalskip] The length of the rule which finishes the last line
|
|
% of a syntax diagram. It is a rubber length. Its default value is
|
|
% \smallf 1/2\,em, with 10000\,fil of stretch, which will left-align
|
|
% the items on the line.\footnote{^^A
|
|
% This is a little \TeX nical. The idea is that if a stray 1\,fil
|
|
% of stretch is added to the end of the line, it won't be noticed.
|
|
% However, the alignment of the text on the line can still be
|
|
% modified using \cmd{\sd@rule}\cmd{\hfill}, if you're feeling
|
|
% brave.
|
|
% }
|
|
%
|
|
% \item [\sdrulewidth] Half the width of the rules used in the diagram.
|
|
% It is a rigid length. Its default value is 0.2\,pt.
|
|
%
|
|
% \item [\sdcirclediam] The diameter of the circle from which the quadrants
|
|
% used in rounded-style diagrams are taken. This must be a multiple
|
|
% of 4\,pt, or else the lines on the diagram won't match up.
|
|
%
|
|
% \end{description}
|
|
%
|
|
% In addition, you should call |\sdsetstrut| passing it the total height
|
|
% (\({\rm height}+{\rm depth}\)) of a normal line of text at the current
|
|
% size. Normally, the value of |\baselineskip| will be appropriate.
|
|
%
|
|
% You can also alter the appearance of \env{stack}s and \env{rep}s by using
|
|
% their optional positioning arguments. By default, \env{stack}s descend
|
|
% below the main line of the diagram, and \env{rep}s extend above it.
|
|
% Specifying an optional argument of |[b]| for either environment reverses
|
|
% this, putting \env{stack}s above and \env{rep}s below the line.
|
|
%
|
|
% \subsection{Changing the presentation styles}
|
|
%
|
|
% You can change the way in which the syntax items are typeset by altering
|
|
% some simple commands (using |\renewcommand|). Each item (nonterminals,
|
|
% as typeset by |\synt|, and quoted and unquoted terminals, as typeset by
|
|
% |\lit| and |\lit*|) has two style commands associated with it, as shown
|
|
% in the table below.
|
|
%
|
|
% \begin{tab}{lll} \hline
|
|
% \bf Syntax item & \bf Left command & \bf Right command \\ \hline
|
|
% Nonterminals & |\syntleft| & |\syntright| \\
|
|
% Quoted terminals & |\litleft| & |\litright| \\
|
|
% Unquoted terminals & |\ulitleft| & |\ulitright| \\ \hline
|
|
% \end{tab}
|
|
%
|
|
% It's not too hard to see how this works. For example, if you look at
|
|
% the implementation for |\syntleft| and |\syntright| in the implementation
|
|
% section, you'll notice that they're defined like this:
|
|
% \begin{listing}
|
|
%\newcommand{\syntleft}{$\langle$\normalfont\itshape}
|
|
%\newcommand{\syntright}{$\rangle$}
|
|
% \end{listing}
|
|
% I think this is fairly simple, if you understand things like font changing.
|
|
%
|
|
% Note that changing these style commands alters the appearance of all syntax
|
|
% objects of the appropriate types, as created by the |\synt| and |\lit|
|
|
% commands, in \env{grammar} environments, and in syntax diagrams.
|
|
%
|
|
%
|
|
% \section{Change history}
|
|
%
|
|
% \subsection*{Version 1.9}
|
|
%
|
|
% Added abbreviations for syntax diagram constructions. These clobber some
|
|
% common abbreviations for maths, but that's not too worrying really; it's
|
|
% not likely for people to do maths in syntax diagrams.
|
|
%
|
|
% \subsection*{Version 1.8}
|
|
%
|
|
% Added to RCS (so changed version numbering style).
|
|
%
|
|
% \subsection*{Version 1.07}
|
|
%
|
|
% \begin{itemize}
|
|
% \item Fixed problem with underscore hacking in a \env{tabbing} environment.
|
|
% \end{itemize}
|
|
%
|
|
% \subsection*{Version 1.06}
|
|
%
|
|
% \begin{itemize}
|
|
% \item Added style hooks for syntax items.
|
|
% \item Improved colour handling in syntax diagrams, thanks to the |\doafter|
|
|
% package.
|
|
% \item Fixed some nasty bugs in the \env{grammar} environment which confused
|
|
% other lists and ruined the spacing. The \env{grammar} handling is
|
|
% now much tidier in general.
|
|
% \end{itemize}
|
|
%
|
|
% \subsection*{Version 1.05}
|
|
%
|
|
% \begin{itemize}
|
|
% \item Fixed `the bug' in the syntax diagram typesetting. It now breaks
|
|
% lines almost psychically, and doesn't break in the wrong places.
|
|
% \item Almost rewrote the \env{grammar} environment. It now does lots of
|
|
% the list handling itself, to allow more versatile typesetting of the
|
|
% left hand sides. There's lots of evil in there now.
|
|
% \item Added some more configurability. In particular, two new settings
|
|
% have been added to control \env{grammar} environments, and a neat
|
|
% way of adding new syntax diagram structures has been introduced.
|
|
% \end{itemize}
|
|
%
|
|
% \subsection*{Version 1.04}
|
|
%
|
|
% \begin{itemize}
|
|
% \item Changed the vertical positioning of the rules, to make all the text
|
|
% line up properly. While the old version was elegant and simple, it
|
|
% had the drawback of looking nasty.
|
|
% \item Allow line breaks at underscores, but don't if there's another one
|
|
% afterwards. Also, prevent losing following space if underscore is
|
|
% written to a file.
|
|
% \end{itemize}
|
|
%
|
|
% \subsection*{Version 1.02}
|
|
%
|
|
% \begin{itemize}
|
|
% \item Added support for rounded corners in syntax diagrams.
|
|
% \item Changed lots of |\hskip| commands to |\kern|s, to prevent possible
|
|
% line breaks.
|
|
% \end{itemize}
|
|
%
|
|
% \subsection*{Version 1.01}
|
|
%
|
|
% \begin{itemize}
|
|
% \item Allowed disabling of underscore active character, to avoid messing
|
|
% up filenames.
|
|
% \item Added |\grammarparsep| and |\grammarindent| length parameters to
|
|
% control the appearance of grammars.
|
|
% \end{itemize}
|
|
%
|
|
% \implementation
|
|
%
|
|
% \section{Implementation of \syn}
|
|
%
|
|
% \begin{macrocode}
|
|
%<*package>
|
|
% \end{macrocode}
|
|
%
|
|
% \subsection{Options handling}
|
|
%
|
|
% We define all the options we know about, and then see what's been put
|
|
% on the usepackage line.
|
|
%
|
|
% The options we provide currently are as follows:
|
|
%
|
|
% \begin{description}
|
|
% \item [rounded] draws neatly rounded edges on the diagram.
|
|
% \item [square] draws squared-off edges on the diagram. This is the
|
|
% default.
|
|
% \item [nounderscore] disables the undescore active character, The |\_|
|
|
% command still produces the nice version created here.
|
|
% \end{description}
|
|
%
|
|
% \begin{macrocode}
|
|
\DeclareOption{rounded}{\sd@roundtrue}
|
|
\DeclareOption{square}{\sd@roundfalse}
|
|
\DeclareOption{nounderscore}{\@uscorefalse}
|
|
% \end{macrocode}
|
|
%
|
|
% Now process the options:
|
|
%
|
|
% \begin{macrocode}
|
|
\newif\ifsd@round
|
|
\newif\if@uscore\@uscoretrue
|
|
\ExecuteOptions{square}
|
|
\ProcessOptions
|
|
% \end{macrocode}
|
|
%
|
|
% \subsection{Special character handling}
|
|
%
|
|
% A lot of the \syn\ package requires the use special active characters.
|
|
% These must be added to two lists: |\dospecials|, which is used by |\verb|
|
|
% and friends, and |\@sanitize|, which is used by |\index|. The two macros
|
|
% here, |\addspecial| and |\remspecial|, provide these registration
|
|
% facilities.
|
|
%
|
|
% Two similar macros are found in Frank Mittelbach's \package{doc} package:
|
|
% these have the disadvantage of global operation. My macros here are based
|
|
% on Frank's, which in turn appear to be based on Donald Knuth's list
|
|
% handling code presented in Appendix~D of \textit{The \TeX book}.
|
|
%
|
|
% Both these macros take a single argument: a single-character control
|
|
% sequence containing the special character to be added to or removed from
|
|
% the lists.
|
|
%
|
|
% \begin{macro}{\addspecial}
|
|
%
|
|
% This is reasonably straightforward. We remove the sequence from the lists,
|
|
% in case it's already there, and add it in in the obvious way. This
|
|
% requires a little bit of fun with |\expandafter|.
|
|
%
|
|
% \begin{macrocode}
|
|
\def\addspecial#1{%
|
|
\remspecial{#1}%
|
|
\expandafter\def\expandafter\dospecials\expandafter{\dospecials\do#1}%
|
|
\expandafter\def\expandafter\@santize\expandafter{%
|
|
\@sanitize\@makeother#1}%
|
|
}
|
|
% \end{macrocode}
|
|
%
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\remspecial}
|
|
%
|
|
% This is the difficult bit. Since |\dospecials| and |\@sanitize| have the
|
|
% form of list macros, we can redefine |\do| and |\@makeother| to do the
|
|
% job for us. We must be careful to put the old meaning of |\@makeother|
|
|
% back. The current implementation assumes it knows what |\@makeother| does.
|
|
%
|
|
% \begin{macrocode}
|
|
\def\remspecial#1{%
|
|
\def\do##1{\ifnum`#1=`##1 \else\noexpand\do\noexpand##1\fi}%
|
|
\edef\dospecials{\dospecials}%
|
|
\def\@makeother##1{\ifnum`#1=`##1 \else%
|
|
\noexpand\@makeother\noexpand##1\fi}%
|
|
\edef\@sanitize{\@sanitize}%
|
|
\def\@makeother##1{\catcode`##112}%
|
|
}
|
|
% \end{macrocode}
|
|
%
|
|
% \end{macro}
|
|
%
|
|
% \subsection{Underscore handling}
|
|
%
|
|
% When typing a lot of identifiers, it can be irksome to have to escape
|
|
% all `|_|' characters in the manuscript. We make the underscore character
|
|
% active, so that it typesets an underscore in horizontal mode, and does
|
|
% its usual job as a subscript operator in maths mode. Underscore must
|
|
% already be in the special character lists, because of its use as a
|
|
% subscript character, so this doesn't cause us a problem.
|
|
%
|
|
% \begin{macro}{\underscore}
|
|
%
|
|
% The |\underscore| macro typesets an underline character, using a horizontal
|
|
% rule. This is positioned slightly below the baseline, and is also slightly
|
|
% wider than the default \TeX\ underscore. This code is based on a similar
|
|
% implementation found in the \package{lgrind} package.
|
|
%
|
|
% \begin{macrocode}
|
|
\def\underscore{%
|
|
\leavevmode%
|
|
\kern.06em%
|
|
\vbox{%
|
|
\hrule\@width.6em\@depth.4ex\@height-.34ex%
|
|
}%
|
|
\ifdim\fontdimen\@ne\font=\z@%
|
|
\kern.06em%
|
|
\fi%
|
|
}
|
|
% \end{macrocode}
|
|
%
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\@foundunderscore}
|
|
%
|
|
% This macro is called by the `|_|' active character to sort out what to do.
|
|
%
|
|
% If this is maths mode, we use the |\sb| macro, which is already defined
|
|
% to do subscripting. Otherwise, we call |\textunderscore|, which picks the
|
|
% nicest underscore it can find.
|
|
%
|
|
% There's some extra cunningness here, because I'd like to be able to
|
|
% hyphenate after underscores usually, but not when there's another one
|
|
% following. And then, because \env{tabbing} redefines |\_|, there's some
|
|
% more yukkiness to handle that: the usual |\@tabacckludge| mechanism doesn't
|
|
% cope with this particular case.
|
|
%
|
|
% \begin{macrocode}
|
|
\let\usc@builtindischyphen\-
|
|
\def\@uscore.{%
|
|
\ifmmode%
|
|
\expandafter\@firstoftwo%
|
|
\else%
|
|
\expandafter\@secondoftwo%
|
|
\fi%
|
|
\sb%
|
|
{\textunderscore\@ifnextchar_{}{\usc@builtindischyphen}}%
|
|
}
|
|
% \end{macrocode}
|
|
%
|
|
% \end{macro}
|
|
%
|
|
% Now we set up the active character. Note the |\protect|, which makes
|
|
% underscores work reasonably well in moving arguments. Note also the way
|
|
% we end with a some funny stuff to prevent spaces being lost if this is
|
|
% written to a file.
|
|
%
|
|
% \begin{macrocode}
|
|
\if@uscore
|
|
\AtBeginDocument{%
|
|
\catcode`\_\active%
|
|
\begingroup%
|
|
\lccode`\~`\_%
|
|
\lowercase{\endgroup\def~{\protect\@uscore.}}%
|
|
}
|
|
\fi
|
|
% \end{macrocode}
|
|
%
|
|
% Finally, we redefine the |\_| macro to use our own |\underscore|, because
|
|
% it's prettier. Actually, we don't: we just redefine the
|
|
% |\?\textunderscore| command (funny name, isn't it?).
|
|
%
|
|
% \begin{macrocode}
|
|
\expandafter\let\csname?\string\textunderscore\endcsname\underscore
|
|
% \end{macrocode}
|
|
%
|
|
% \subsection{Abbreviated verbatim notation}
|
|
%
|
|
% In similar style to the \package{doc} package, we allow the user to set up
|
|
% characters which delimit verbatim text. Unlike \package{doc}, we make
|
|
% such changes local to the current group. This is performed through the
|
|
% |\shortverb| and |\unverb| commands.
|
|
%
|
|
% The implementations of these commands are based upon the |\MakeShortVerb|
|
|
% and |\DeleteShortVerb| commands of the \package{doc} package, although
|
|
% these versions have effect local to the current grouping level. This
|
|
% prevents their redefinition of |\dospecials| from interfering with the
|
|
% grammar shortcuts, which require local changes only.
|
|
%
|
|
% The command |\shortverb| takes a single argument: a single-character
|
|
% control sequence defining which character to make into the verbatim text
|
|
% delimiter. We store the old meaning of the active character in a control
|
|
% sequence called |\mn@\|\<char>. Note that this control sequence
|
|
% contains a backslash character, which is a little odd. We also define a
|
|
% command |\cc@\|\<char> which will return everything to normal. This
|
|
% is used by the |\unverb| command.
|
|
%
|
|
% \begin{macro}{\shortverb}
|
|
%
|
|
% Here we build the control sequences we need to make everything work nicely.
|
|
% The active character is defined via |\lowercase|, using the |~| character:
|
|
% this is already made active by \TeX\@.
|
|
%
|
|
% The actual code requires lots of fiddling with |\expandafter| and friends.
|
|
%
|
|
% \begin{macrocode}
|
|
\def\shortverb#1{%
|
|
% \end{macrocode}
|
|
%
|
|
% First, we check to see if the command |\cc@\|\<char> has been defined.
|
|
%
|
|
% \begin{macrocode}
|
|
\@ifundefined{cc@\string#1}{%
|
|
% \end{macrocode}
|
|
%
|
|
% If it hasn't been defined, we add the character to the specials list.
|
|
%
|
|
% \begin{macrocode}
|
|
\addspecial#1%
|
|
% \end{macrocode}
|
|
%
|
|
% Now we set our character to be the lowercase version of |~|, which allows
|
|
% us to use it, even though we don't know what it is.
|
|
%
|
|
% \begin{macrocode}
|
|
\begingroup%
|
|
\lccode`\~`#1%
|
|
% \end{macrocode}
|
|
%
|
|
% Finally, we reach the tricky bit. All of this is lowercased, so any
|
|
% occurrences of |~| are replaced by the user's special character.
|
|
%
|
|
% \begin{macrocode}
|
|
\lowercase{%
|
|
\endgroup%
|
|
% \end{macrocode}
|
|
%
|
|
% We remember the current meaning of the character, in case it has one. We
|
|
% have to use |\csname| to build the rather strange name we use for this.
|
|
%
|
|
% \begin{macrocode}
|
|
\expandafter\let\csname mn@\string#1\endcsname~%
|
|
% \end{macrocode}
|
|
%
|
|
% Now we build |\cc@\|\<char>. This is done with |\edef|, since more
|
|
% of this needs to be expanded now than not. In this way, the actual macros
|
|
% we create end up being very short.
|
|
%
|
|
% \begin{macrocode}
|
|
\expandafter\edef\csname cc@\string#1\endcsname{%
|
|
% \end{macrocode}
|
|
%
|
|
% First, add a command to restore the character's old catcode.
|
|
%
|
|
% \begin{macrocode}
|
|
\catcode`\noexpand#1\the\catcode`#1%
|
|
% \end{macrocode}
|
|
%
|
|
% Now we restore the character's old meaning, using the version we saved
|
|
% earlier.
|
|
%
|
|
% \begin{macrocode}
|
|
\let\noexpand~\expandafter\noexpand%
|
|
\csname mn@\string#1\endcsname%
|
|
% \end{macrocode}
|
|
%
|
|
% Now we remove the character from the specials lists.
|
|
%
|
|
% \begin{macrocode}
|
|
\noexpand\remspecial\noexpand#1%
|
|
% \end{macrocode}
|
|
%
|
|
% Finally, we delete this macro, so that |\unverb| will generate a warning
|
|
% if the character is |\unverb|ed again.
|
|
%
|
|
% \begin{macrocode}
|
|
\let\csname cc@\string#1\endcsname\relax%
|
|
}%
|
|
% \end{macrocode}
|
|
%
|
|
% All of that's over now. We set up the new definition of the character,
|
|
% in terms of |\verb|, and make the character active. The nasty |\syn@ttspace|
|
|
% is there to make the spacing come out right. It's all right really. Honest.
|
|
%
|
|
% \begin{macrocode}
|
|
\def~{\verb~\syn@ttspace}%
|
|
}%
|
|
\catcode`#1\active%
|
|
% \end{macrocode}
|
|
%
|
|
% If our magic control sequence already existed, we can assume that the
|
|
% character is already a verbatim delimiter, and raise a warning.
|
|
%
|
|
% \begin{macrocode}
|
|
}{%
|
|
\PackageWarning{syntax}{Character `\expandafter\@gobble\string#1'
|
|
is already a verbatim\MessageBreak
|
|
delimiter}%
|
|
}%
|
|
}
|
|
% \end{macrocode}
|
|
%
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\unverb}
|
|
%
|
|
% This is actually terribly easy: we just use the |\cc@\|\<char> command
|
|
% we definied earlier, after making sure that it's been defined.
|
|
%
|
|
% \begin{macrocode}
|
|
\def\unverb#1{%
|
|
\@ifundefined{cc@\string#1}{%
|
|
\PackageWarning{syntax}{Character `\expandafter\@gobble\string#1'
|
|
is not a verbatim\MessageBreak
|
|
delimiter}%
|
|
}{%
|
|
\csname cc@\string#1\endcsname%
|
|
}%
|
|
}
|
|
% \end{macrocode}
|
|
%
|
|
% \end{macro}
|
|
%
|
|
% \subsection{Style hooks for syntax forms}
|
|
%
|
|
% To allow the appearance of syntax things to be configured, we provide some
|
|
% redefinable bits.
|
|
%
|
|
% The three types of objects (nonterminal symbols, and quoted and unquoted
|
|
% terminals) each have two macros associated with them: one which does the
|
|
% `left' bit of the typesetting, and one which does the `right' bit. The
|
|
% items are typeset as LR~boxes. I'll be extra good while defining these
|
|
% hooks, so that it's obvious what's going on; macho \TeX\ hacker things
|
|
% resume after this section.
|
|
%
|
|
% \begin{macro}{\syntleft}
|
|
% \begin{macro}{\syntright}
|
|
%
|
|
% I can't see why anyone would want to change the typesetting of
|
|
% nonterminals, although I'll provide the hooks for symmetry's sake.
|
|
%
|
|
% \begin{macrocode}
|
|
\newcommand{\syntleft}{$\langle$\normalfont\itshape}
|
|
\newcommand{\syntright}{$\rangle$}
|
|
% \end{macrocode}
|
|
%
|
|
% \end{macro}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\ulitleft}
|
|
% \begin{macro}{\ulitright}
|
|
% \begin{macro}{\litleft}
|
|
% \begin{macro}{\litright}
|
|
%
|
|
% Now we can define the left and right parts of quoted and unquoted
|
|
% terminals. US~readers may want to put double quotes around the quoted
|
|
% terminals, for example.
|
|
%
|
|
% \begin{macrocode}
|
|
\newcommand{\ulitleft}{\normalfont\ttfamily\syn@ttspace\frenchspacing}
|
|
\newcommand{\ulitright}{}
|
|
\newcommand{\litleft}{`\bgroup\ulitleft}
|
|
\newcommand{\litright}{\ulitright\egroup'}
|
|
% \end{macrocode}
|
|
%
|
|
% \end{macro}
|
|
% \end{macro}
|
|
% \end{macro}
|
|
% \end{macro}
|
|
%
|
|
% \subsection{Simple syntax typesetting}
|
|
%
|
|
% In general text, we allow access to our typesetting conventions through
|
|
% standard \LaTeX\ commands.
|
|
%
|
|
% \begin{macro}{\synt}
|
|
%
|
|
% The |\synt| macro typesets its argument as a syntactic quantity. It puts
|
|
% the text of the argument in italics, and sets angle brackets around it.
|
|
% Breaking of a |\synt| object across lines is forbidden.
|
|
%
|
|
% \begin{macrocode}
|
|
\def\synt#1{\mbox{\syntleft{#1\/}\syntright}}
|
|
% \end{macrocode}
|
|
%
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lit}
|
|
%
|
|
% The |\lit| macro typesets its argument as literal text, to be typed in.
|
|
% Normally, this means setting the text in |\tt| font, and putting quotes
|
|
% around it, although the quotes can be suppressed by using the $*$-variant.
|
|
%
|
|
% The |\syn@ttspace| macro sets up the spacing for the text nicely: |\tt|
|
|
% spaces tend to be a little wide.
|
|
%
|
|
% \begin{macrocode}
|
|
\def\lit{\@ifstar{\lit@i\ulitleft\ulitright}{\lit@i\litleft\litright}}
|
|
\def\lit@i#1#2#3{\mbox{#1{#3\/}#2}}
|
|
% \end{macrocode}
|
|
%
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\syn@ttspace}
|
|
%
|
|
% This sets up the |\spaceskip| value for |\tt| text.
|
|
%
|
|
% \begin{macrocode}
|
|
\def\syn@ttspace@{\spaceskip.35em\@plus.2em\@minus.15em\relax}
|
|
% \end{macrocode}
|
|
%
|
|
% However, this isn't always the right thing to do.
|
|
%
|
|
% \begin{macrocode}
|
|
\def\ttthinspace{\let\syn@ttspace\syn@ttspace@}
|
|
\def\ttthickspace{\let\syn@ttspace\@empty}
|
|
% \end{macrocode}
|
|
%
|
|
% I know what I like thoough.
|
|
%
|
|
% \begin{macrocode}
|
|
\ttthinspace
|
|
% \end{macrocode}
|
|
%
|
|
% \end{macro}
|
|
%
|
|
% \subsubsection{The shortcuts}
|
|
%
|
|
% The easy part is over now. The next job is to set up the `grammar
|
|
% shortcuts' which allow easy changing of styles.
|
|
%
|
|
% We support four shortcuts:
|
|
% \begin{itemize}
|
|
% \item |`literal text'| typesets \syntax{`literal text'}
|
|
% \item |<non-terminal>| typesets \syntax{<non-terminal>}
|
|
% \item |"unquoted text"| typesets \syntax{"unquoted text"}
|
|
% \item \verb"|" typesets a \syntax{|} character
|
|
% \end{itemize}
|
|
% These are all implemented through active characters, which are enabled
|
|
% using the |\syntaxShortcuts| macro, described below.
|
|
%
|
|
% \begin{macro}{\readupto}
|
|
%
|
|
% \syntax{"\\readupto{"<char>"}{"<decls>"}{"<command>"}"} will read all
|
|
% characters up until the next occurrence of \<char>. Normally, all
|
|
% special characters will be deactivated. However, you can reactivate some
|
|
% characters, using the \<decls> argument, which is processed before the
|
|
% text is read.
|
|
%
|
|
% The code is borrowed fairly obviously from the \LaTeXe\ source for the
|
|
% |\verb| command.
|
|
%
|
|
% \begin{macrocode}
|
|
\def\readupto#1#2#3{%
|
|
\bgroup%
|
|
\verb@eol@error%
|
|
\let\do\@makeother\dospecials%
|
|
#2%
|
|
\catcode`#1\active%
|
|
\lccode`\~`#1%
|
|
\gdef\verb@balance@group{\verb@egroup%
|
|
\@latex@error{\noexpand\verb illegal in command argument}\@ehc}%
|
|
\def\@vhook{\verb@egroup#3}%
|
|
\aftergroup\verb@balance@group%
|
|
\lowercase{\let~\@vhook}%
|
|
}
|
|
% \end{macrocode}
|
|
%
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\syn@assist}
|
|
%
|
|
% The |\syn@assist| macro is used for defining three of the shortcuts. It
|
|
% is called as
|
|
%
|
|
% \begin{quote}
|
|
% \syntax{"\\syn@assist{"<left-decls>"}{"<actives>"}{"<delimeter>"}" \\
|
|
% \null \quad "{"<right-decls>"}{"<end-cmd>"}"}
|
|
% \end{quote}
|
|
%
|
|
% It creates an hbox, sets up the escape sequences for quoting our magic
|
|
% characters, and then typesets a box containing
|
|
%
|
|
% \begin{quote}
|
|
% \syntax{<left-decls>"{"<delimited-text>"\\/}"<right-decls>}
|
|
% \end{quote}
|
|
%
|
|
% The \<left-decls> and \<right-decls> can be |\relax| if they're not
|
|
% required.
|
|
%
|
|
% The \<actives> argument is passed to |\readupto|, to allow some special
|
|
% characters through. By default, we re-enable |\|, and make `\verb*" "'
|
|
% typeset some space glue, rather than a space character. A macro
|
|
% `\verb*"\ "' is defined to actually print a space character, which yield
|
|
% `\verb*" "' in the `|\tt|' font.
|
|
%
|
|
% Finally, it defines a |\ch| command, which, given a single-character
|
|
% control sequence as its argument, typesets the character. This is useful,
|
|
% since |`| has been made active when we set up these calls, so the
|
|
% direct |\char`\|\<char> doesn't work.
|
|
%
|
|
% \begin{macrocode}
|
|
\def\syn@assist#1#2#3#4#5{%
|
|
% \end{macrocode}
|
|
%
|
|
% First, we start the box, and open a group. We use |\mbox| because it
|
|
% does all the messing with |\leavevmode| which is needed.
|
|
%
|
|
% \begin{macrocode}
|
|
\mbox\bgroup%
|
|
% \end{macrocode}
|
|
%
|
|
% Next job is to set up the escape sequences.
|
|
%
|
|
% \begin{macrocode}
|
|
\chardef\\`\\%
|
|
\chardef\>`\>%
|
|
\chardef\'`\'%
|
|
\chardef\"`\"%
|
|
\chardef\ `\ %
|
|
% \end{macrocode}
|
|
%
|
|
% Now to define |\ch|. This is done the obvious way.
|
|
%
|
|
% \begin{macrocode}
|
|
\def\ch##1{\char`##1}%
|
|
% \end{macrocode}
|
|
%
|
|
% For active characters, we do some fiddling with |\lccode|s.
|
|
%
|
|
% \begin{macrocode}
|
|
\def\act##1{%
|
|
\catcode`##1\active%
|
|
\begingroup%
|
|
\lccode`\~`##1%
|
|
\lowercase{\endgroup\def~}%
|
|
}%
|
|
% \end{macrocode}
|
|
%
|
|
% Finally, we do the real work of setting the text. We use |\readupto| to
|
|
% actually find the text we want.
|
|
%
|
|
% \begin{macrocode}
|
|
#1%
|
|
\begingroup%
|
|
\readupto#3{%
|
|
\catcode`\\0%
|
|
\catcode`\ 10%
|
|
#2%
|
|
}{%
|
|
\/\endgroup#4\egroup#5%
|
|
}%
|
|
}
|
|
% \end{macrocode}
|
|
%
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\syn@shorts}
|
|
%
|
|
% This macro actually defines the expansions for the active characters.
|
|
% We have to do this separately because |`| must be active when we use it
|
|
% in the |\def|, but we can't do that and use |\catcode| at the same time.
|
|
% The arguments are commands to do before and after the actual command.
|
|
% These are passed up from |\syntaxShortcuts|.
|
|
%
|
|
% All of the characters use |\syn@assist| in the obvious way except for
|
|
% \verb"|", which drops into maths mode instead.
|
|
%
|
|
% Note that when changing the catcodes, we must save |`| until last.
|
|
%
|
|
% \begin{macrocode}
|
|
\begingroup
|
|
\catcode`\<\active
|
|
\catcode`\|\active
|
|
\catcode`\"\active
|
|
\catcode`\`\active
|
|
%
|
|
\gdef\syn@shorts#1#2{%
|
|
% \end{macrocode}
|
|
%
|
|
% The `|<|' character must typeset its argument in italics. We make `|_|'
|
|
% do the same as the `|\_|' command.
|
|
%
|
|
% \begin{macrocode}
|
|
\def<{%
|
|
#1%
|
|
\syn@assist%
|
|
\syntleft%
|
|
{\act_{\@foundunderscore}}%
|
|
>%
|
|
\syntright%
|
|
{#2}%
|
|
}%
|
|
% \end{macrocode}
|
|
%
|
|
% The `|`|' and `|"|' characters should print its argument in |\tt| font.
|
|
% We change the `|\tt|' space glue to provide nicer spacing on the line.
|
|
%
|
|
% \begin{macrocode}
|
|
\def`{%
|
|
#1%
|
|
\syn@assist%
|
|
\litleft%
|
|
\relax%
|
|
'%
|
|
\litright%
|
|
{#2}%
|
|
}%
|
|
\def"{%
|
|
#1%
|
|
\syn@assist%
|
|
\ulitleft%
|
|
\relax%
|
|
"%
|
|
\ulitright%
|
|
{#2}%
|
|
}%
|
|
% \end{macrocode}
|
|
%
|
|
% Finally, the `\verb"|"' character is typeset by using the mysterious
|
|
% |\textbar| command.
|
|
%
|
|
% \begin{macrocode}
|
|
\def|{\textbar}%
|
|
% \end{macrocode}
|
|
%
|
|
% We're finished here now.
|
|
%
|
|
% \begin{macrocode}
|
|
}
|
|
%
|
|
\endgroup
|
|
% \end{macrocode}
|
|
%
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\syntaxShortcuts}
|
|
%
|
|
% This is a user-level command which enables the use of our shortcuts in the
|
|
% current group. It uses |\addspecial|, defined below, to register the
|
|
% active characters, sets up their definitions and activates them.
|
|
%
|
|
% The two arguments are commands to be performed before and after the
|
|
% handling of the abbreviation. In this way, you can further process the
|
|
% output.
|
|
%
|
|
% This command is not intended to be used directly by users: it should be
|
|
% used by other macros and packages which wish to take advantage of the
|
|
% facilities offered by this package. We provide a |\synshorts| declaration
|
|
% (which may be used as an environment, of course) which is more `user
|
|
% palatable'.
|
|
%
|
|
% \begin{macrocode}
|
|
\def\syntaxShortcuts#1#2{%
|
|
\syn@shorts{#1}{#2}%
|
|
\addspecial\`%
|
|
\addspecial\<%
|
|
\addspecial\|%
|
|
\addspecial\"%
|
|
\catcode`\|\active%
|
|
\catcode`\<\active%
|
|
\catcode`\"\active%
|
|
\catcode`\`\active%
|
|
}
|
|
%
|
|
\def\synshorts{\syntaxShortcuts\relax\relax}
|
|
% \end{macrocode}
|
|
%
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\synshortsoff}
|
|
%
|
|
% This macro can be useful occasionally: it disables the syntax shortcuts,
|
|
% so you can type normal text for a while.
|
|
%
|
|
% \begin{macrocode}
|
|
\def\synshortsoff{%
|
|
\catcode`\|12%
|
|
\catcode`\<12%
|
|
\catcode`\"12%
|
|
\catcode`\`12%
|
|
}
|
|
% \end{macrocode}
|
|
%
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\syntax}
|
|
%
|
|
% The |\syntax| macro typesets its argument, allowing the use of our
|
|
% shortcuts within the argument.
|
|
%
|
|
% Actually, we go to some trouble to ensure that the argument to |\syntax|
|
|
% \emph{isn't} a real argument so we can change catcodes as we go. We
|
|
% use the |\let\@let@token=| trick from \PlainTeX\ to do this.
|
|
%
|
|
% \begin{macrocode}
|
|
\def\syntax#{\bgroup\syntaxShortcuts\relax\relax\let\@let@token}
|
|
% \end{macrocode}
|
|
%
|
|
% \end{macro}
|
|
%
|
|
% \begin{environment}{grammar}
|
|
%
|
|
% The \env{grammar} environment is the final object we have to define. It
|
|
% allows typesetting of beautiful BNF grammars.
|
|
%
|
|
% First, we define the length parameters we need:
|
|
%
|
|
% \begin{macrocode}
|
|
\newskip\grammarparsep
|
|
\grammarparsep8\p@\@plus\p@\@minus\p@
|
|
\newdimen\grammarindent
|
|
\grammarindent2em
|
|
% \end{macrocode}
|
|
%
|
|
% Now define the default label typesetting. This macro is designed to be
|
|
% replaced by a user, so we'll be extra-well-behaved and use genuine \LaTeX\
|
|
% commands. Well, almost \dots
|
|
%
|
|
% \begin{macrocode}
|
|
\newcommand{\grammarlabel}[2]{%
|
|
\synt{#1} \hfill#2%
|
|
}
|
|
% \end{macrocode}
|
|
%
|
|
% Now for a bit of hacking to make the item stuff work properly. This gets
|
|
% done for every new paragraph that's started without an |\item| command.
|
|
%
|
|
% First, store the left hand side of the production in a box. Then I'll
|
|
% end the paragraph, and insert some nasty glue to take up all the space,
|
|
% so no-one will ever notice that there was a paragraph break there. The
|
|
% strut just makes sure that I know exactly how high the line is.
|
|
%
|
|
% \begin{macrocode}
|
|
\def\gr@implitem<#1> #2 {%
|
|
\sbox\z@{\hskip\labelsep\grammarlabel{#1}{#2}}%
|
|
\strut\@@par%
|
|
\vskip-\parskip%
|
|
\vskip-\baselineskip%
|
|
% \end{macrocode}
|
|
%
|
|
% The |\item| command will notice that I've inserted these funny glues and
|
|
% try to remove them: I'll stymie its efforts by inserting an invisible
|
|
% rule. Then I'll insert the label using |\item| in the normal way.
|
|
%
|
|
% \begin{macrocode}
|
|
\hrule\@height\z@\@depth\z@\relax%
|
|
\item[\unhbox\z@]%
|
|
% \end{macrocode}
|
|
%
|
|
% Just before I go, I'll make \lit{<} back into an active character.
|
|
%
|
|
% \begin{macrocode}
|
|
\catcode`\<\active%
|
|
}
|
|
% \end{macrocode}
|
|
%
|
|
% As an abbreviation for syntax diagrams, I usurp the |\[| and |\]| commands.
|
|
% Here are the old versions.
|
|
%
|
|
% \begin{macrocode}
|
|
\let\gr@leftsq\[
|
|
\let\gr@rightsq\]
|
|
\def\[{\gr@leftsq}
|
|
\def\]{\gr@rightsq}
|
|
% \end{macrocode}
|
|
%
|
|
% Now for the environment proper. Deep down, it's a list environment, with
|
|
% some nasty tricks to stop anyone from noticing.
|
|
%
|
|
% The first job is to set up the list from the parameters I'm given.
|
|
%
|
|
% \begin{macrocode}
|
|
\newenvironment{grammar}{%
|
|
\list{}{%
|
|
\labelwidth\grammarindent%
|
|
\leftmargin\grammarindent%
|
|
\advance\grammarindent\labelsep
|
|
\itemindent\z@%
|
|
\listparindent\z@%
|
|
\parsep\grammarparsep%
|
|
}%
|
|
% \end{macrocode}
|
|
%
|
|
% We have major problems in |\raggedright| layouts, which try to use |\par|
|
|
% to start new lines. We go back to normal |\\| newlines to try and bodge
|
|
% our way around these problems.
|
|
%
|
|
% \begin{macrocode}
|
|
\let\\\@normalcr
|
|
% \end{macrocode}
|
|
%
|
|
% Now to enable the shortcuts.
|
|
%
|
|
% \begin{macrocode}
|
|
\syntaxShortcuts\relax\relax%
|
|
% \end{macrocode}
|
|
%
|
|
% Now a little bit of magic. The |\alt| macro moves us to a new line, and
|
|
% typesets a vertical bar in the margin. This allows typesetting of
|
|
% multiline alternative productions in a pretty way.
|
|
%
|
|
% \begin{macrocode}
|
|
\def\alt{\\\llap{\textbar\quad}}%
|
|
% \end{macrocode}
|
|
%
|
|
% Now for another bit of magic. We set up some |\par| cleverness to spot
|
|
% the start of each production rule and format it in some cunning and
|
|
% user-defined way.
|
|
%
|
|
% \begin{macrocode}
|
|
\def\gr@setpar{%
|
|
\def\par{%
|
|
\parshape\@ne\@totalleftmargin\linewidth%
|
|
\@@par%
|
|
\catcode`\<12%
|
|
\everypar{%
|
|
\everypar{}%
|
|
\catcode`\<\active%
|
|
\gr@implitem%
|
|
}%
|
|
}%
|
|
}%
|
|
\gr@setpar%
|
|
\par%
|
|
% \end{macrocode}
|
|
%
|
|
% Now set up the |\[[| and |\]]| commands to do the right thing. We have
|
|
% to check the next character to see if it's correct, otherwise we'll
|
|
% open a maths display as usual.
|
|
%
|
|
% \begin{macrocode}
|
|
\def\gr@endsyntdiag]{\end{syntdiag}\gr@setpar\par}%
|
|
\def\[{\@ifnextchar[{\begin{syntdiag}\@gobble}\gr@leftsq}%
|
|
\def\]{\@ifnextchar]\gr@endsyntdiag\gr@rightsq}%
|
|
% \end{macrocode}
|
|
%
|
|
% Well, that's it for this side of the environment.
|
|
%
|
|
% \begin{macrocode}
|
|
}{%
|
|
% \end{macrocode}
|
|
%
|
|
% Closing the environment is a simple matter of tidying away the list.
|
|
%
|
|
% \begin{macrocode}
|
|
\@newlistfalse%
|
|
\everypar{}%
|
|
\endlist%
|
|
}
|
|
% \end{macrocode}
|
|
%
|
|
% \end{environment}
|
|
%
|
|
% \subsection{Syntax diagrams}
|
|
%
|
|
% Now we come to the final and most complicated part of the package.
|
|
%
|
|
% Syntax diagrams are drawn using arrow characters from \LaTeX's line font,
|
|
% used in the \env{picture} environment, and rules. The horizontal rules
|
|
% of the diagram are drawn along the baselines of the lines in which they
|
|
% are placed. The text items in the diagram are placed in boxes and lowered
|
|
% below the main baseline. Struts are added throughout to keep the vertical
|
|
% spacing consistent.
|
|
%
|
|
% The vertical structures (stacks and loops) are all implemented with \TeX's
|
|
% primitive |\halign| command.
|
|
%
|
|
% \subsubsection{User-configurable parameters}
|
|
%
|
|
% First, we allocate the \<dimen> and \<skip> arguments needed. Fixed
|
|
% lengths, as the \LaTeX book calls them, are allocated as \<dimen>s, to
|
|
% take some of the load off of all the \<skip> registers.
|
|
%
|
|
% \begin{macrocode}
|
|
\newskip\sdstartspace
|
|
\newskip\sdendspace
|
|
\newskip\sdmidskip
|
|
\newskip\sdtokskip
|
|
\newskip\sdfinalskip
|
|
\newdimen\sdrulewidth
|
|
\newdimen\sdcirclediam
|
|
\newdimen\sdindent
|
|
% \end{macrocode}
|
|
%
|
|
% We need some \TeX\ \<dimen>s for our own purposes, to get everything in
|
|
% the right places. We use labels for the `temporary' \TeX\ parameters
|
|
% which we use, to avoid wasting registers.
|
|
%
|
|
% \begin{macrocode}
|
|
\dimendef\sd@lower\z@
|
|
\dimendef\sd@upper\tw@
|
|
\dimendef\sd@mid4
|
|
\dimendef\sd@topcirc6
|
|
\dimendef\sd@botcirc8
|
|
% \end{macrocode}
|
|
%
|
|
% \begin{macro}{\sd@setsize}
|
|
% When the text size for syntax diagrams changes, it's necessary to work out
|
|
% the height for various rules in the diagram.
|
|
%
|
|
% \begin{macrocode}
|
|
\def\sd@setsize{%
|
|
\sd@mid\ht\strutbox%
|
|
\advance\sd@mid-\dp\strutbox%
|
|
\sd@mid.5\sd@mid%
|
|
\sd@upper\sdrulewidth%
|
|
\advance\sd@upper\sd@mid%
|
|
\sd@lower\sdrulewidth%
|
|
\advance\sd@lower-\sd@mid%
|
|
\sd@topcirc-.5\sdcirclediam%
|
|
\advance\sd@topcirc\sd@mid%
|
|
\sd@botcirc-.5\sdcirclediam%
|
|
\advance\sd@botcirc-\sd@mid%
|
|
}
|
|
% \end{macrocode}
|
|
%
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\sdsize}
|
|
%
|
|
% You can set the default type size used by syntax diagrams by redefining
|
|
% the |\sdsize| command, using the |\renewcommand| command.
|
|
%
|
|
% By default, syntax diagrams are set slightly smaller than the main body
|
|
% text.\footnote{^^A
|
|
% I've used pure \LaTeX\ commands for this and the \cmd\sdlengths\ macro,
|
|
% to try and illustrate how these values might be changed by a user. The
|
|
% rest of the code is almost obfuscted in its use of raw \TeX\ features,
|
|
% in an attempt to dissuade more na\"\i ve users from fiddling with it.
|
|
% I suppose this is what you get when you let assembler hackers loose with
|
|
% something like \LaTeX.
|
|
% }
|
|
%
|
|
% \begin{macrocode}
|
|
\newcommand{\sdsize}{%
|
|
\small%
|
|
}
|
|
% \end{macrocode}
|
|
%
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\sdlengths}
|
|
%
|
|
% Finally, the default length parameters are set in the |\sdlengths| command.
|
|
% You can redefine the command using |\renewcommand|.
|
|
%
|
|
% We set up the length parameters here.
|
|
%
|
|
% \begin{macrocode}
|
|
\newcommand{\sdlengths}{%
|
|
\setlength{\sdstartspace}{1em minus 10pt}%
|
|
\setlength{\sdendspace}{1em minus 10pt}%
|
|
\setlength{\sdmidskip}{0.5em plus 0.0001fil}%
|
|
\setlength{\sdtokskip}{0.25em plus 0.0001fil}%
|
|
\setlength{\sdfinalskip}{0.5em plus 10000fil}%
|
|
\setlength{\sdrulewidth}{0.2pt}%
|
|
\setlength{\sdcirclediam}{8pt}%
|
|
\setlength{\sdindent}{0pt}%
|
|
}
|
|
% \end{macrocode}
|
|
%
|
|
% \end{macro}
|
|
%
|
|
% \subsubsection{Other declarations}
|
|
%
|
|
% We define four switches. The table shows what they're used for.
|
|
%
|
|
% \begin{table}
|
|
% \begin{tab}{lp{3in}} \hline
|
|
%
|
|
% \bf Switch & \bf Meaning \\ \hline
|
|
%
|
|
% |\ifsd@base| & We are at `base level' in the diagram:
|
|
% i.e., not in any other sorts of
|
|
% constructions. This is used to decide
|
|
% whether to allow line breaking. \\[2pt]
|
|
%
|
|
% |\ifsd@top| & The current loop construct is being
|
|
% typeset with the loop arrow above the
|
|
% baseline. \\[2pt]
|
|
%
|
|
% |\ifsd@toplayer| & We are typesetting the top layer of
|
|
% a stack. This is used to ensure that
|
|
% the vertical rules on either side are
|
|
% typeset at the right height. \\[2pt]
|
|
%
|
|
% |\ifsd@backwards| & We're typesetting backwards, because
|
|
% we're in the middle of a loop arrow.
|
|
% the only difference this makes is that
|
|
% any subloops have the arrow on the
|
|
% side. \\ \hline
|
|
%
|
|
% \end{tab}
|
|
% \caption{Syntax diagram switches}
|
|
% \end{table}
|
|
%
|
|
% \begin{macrocode}
|
|
\newif\ifsd@base
|
|
\newif\ifsd@top
|
|
\newif\ifsd@toplayer
|
|
\newif\ifsd@backwards
|
|
% \end{macrocode}
|
|
%
|
|
% \begin{macro}{\sd@err}
|
|
%
|
|
% We output our errors through this macro, which saves a little typing.
|
|
%
|
|
% \begin{macrocode}
|
|
\def\sd@err{\PackageError{syntax}}
|
|
% \end{macrocode}
|
|
%
|
|
% \end{macro}
|
|
%
|
|
% \subsubsection{Arrow-drawing}
|
|
%
|
|
% We need to draw some arrows. \LaTeX\ tries to make this as awkward as
|
|
% possible, so we have to start moving the arrows around in boxes quite a
|
|
% lot.
|
|
%
|
|
% The left and right pointing arrows are fairly simple: we just add some
|
|
% horizontal spacing to prevent the width of the arrow looking odd.
|
|
%
|
|
% \begin{macrocode}
|
|
\def\sd@arrow{%
|
|
\ht\tw@\z@%
|
|
\dp\tw@\z@%
|
|
\raise\sd@mid\box\tw@%
|
|
\egroup%
|
|
}
|
|
\def\sd@rightarr{%
|
|
\bgroup%
|
|
\setbox\tw@\hbox{\kern-6\p@\@linefnt\char'55}%
|
|
\sd@arrow%
|
|
}
|
|
\def\sd@leftarr{%
|
|
\bgroup%
|
|
\raise\sd@mid\hbox{\@linefnt\char'33\kern-6\p@}%
|
|
\sd@arrow%
|
|
}
|
|
% \end{macrocode}
|
|
%
|
|
% The up arrow is very strange. We need to bring the arrow down to base
|
|
% level, and smash its height.
|
|
%
|
|
% \begin{macrocode}
|
|
\def\sd@uparr{%
|
|
\bgroup%
|
|
\setbox\tw@\hb@xt@\z@{\kern-\sdrulewidth\@linefnt\char'66\hss}%
|
|
\setbox\tw@\hbox{\lower10\p@\box\tw@}%
|
|
\sd@arrow%
|
|
}
|
|
% \end{macrocode}
|
|
%
|
|
% The down arrow is similar, although it's already at the right height.
|
|
% Thus, we can just smash the box.
|
|
%
|
|
% \begin{macrocode}
|
|
\def\sd@downarr{%
|
|
\bgroup%
|
|
\setbox\tw@\hb@xt@\z@{\kern-\sdrulewidth\@linefnt\char'77\hss}%
|
|
\sd@arrow%
|
|
}
|
|
% \end{macrocode}
|
|
%
|
|
% \subsubsection{Drawing curves}
|
|
%
|
|
% If the user has selected curved edges, we use the \LaTeX\ features provided
|
|
% to obtain the curves. These are drawn slightly oddly to make it easier
|
|
% to fit them into the diagram.
|
|
%
|
|
% Some explanation about the \LaTeX\ circle font is probably called for
|
|
% before we go any further. The font consists of sets of four quadrants
|
|
% of a particular size (and some other characters, which aren't important
|
|
% at the moment). Each collection of quadrants fit together to form a
|
|
% perfect circle of a given diameter. The individual quadrant characters
|
|
% have strange bounding boxes, as described in the files \textit{lcircle.mf}
|
|
% and \textit{ltpict.dtx}, and also in Appendix~D of \textit{The \TeX book}.
|
|
% Our job here is to make these quadrants useful in the context of
|
|
% drawing syntax diagrams.
|
|
%
|
|
% \begin{macro}{\sd@circ}
|
|
% First, we define |\sd@circ|, which performs the common parts of the four
|
|
% routines. Since the characters in the circle font are grouped together,
|
|
% we can pick out a particular corner piece by specifying its index into
|
|
% the group for the required size. The |\sd@circ| routine will pick out
|
|
% the required character, given this index as an argument, and put it in
|
|
% box~2, after fiddling with the sizes a little:
|
|
% \begin{itemize}
|
|
%
|
|
% \item We clear the width to zero. The individual routines then add a kern
|
|
% of the correct amount, so that the quadrant appears in the right
|
|
% place.
|
|
%
|
|
% \item The piece is lowered by half the rule width. This positions the
|
|
% top and bottom pieces of the circle to be half way over the baseline,
|
|
% which is the correct position for the rest of the diagram.
|
|
%
|
|
% \end{itemize}
|
|
%
|
|
% Finally, we make sure we're in horizontal mode: horrific results occur
|
|
% if this is not the case. I'm sure I don't need to explain this any more
|
|
% graphically.
|
|
%
|
|
% \begin{macrocode}
|
|
\def\sd@circ#1{%
|
|
\@getcirc\sdcirclediam%
|
|
\advance\@tempcnta#1%
|
|
\setbox\tw@\hbox{\lower\sdrulewidth%
|
|
\hbox{\@circlefnt\char\@tempcnta}}%
|
|
\wd\tw@\z@%
|
|
\leavevmode%
|
|
}
|
|
% \end{macrocode}
|
|
%
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\sd@tlcirc}
|
|
% \begin{macro}{\sd@trcirc}
|
|
% \begin{macro}{\sd@blcirc}
|
|
% \begin{macro}{\sd@brcirc}
|
|
%
|
|
% These are the macros which actually draw quadrants of circles. They all
|
|
% call |\sd@circ|, passing an appropriate index, and then fiddle with the
|
|
% box sizes and apply kerning specific to the quadrant positioning.
|
|
%
|
|
% The exact requirements for positioning are as follows:
|
|
%
|
|
% \begin{itemize}
|
|
%
|
|
% \item The horizontal parts of the arcs must lie along the baseline (i.e.,
|
|
% half the line must be above the baseline, and half must be below).
|
|
% This is consistent with the horizontal rules used in the diagram.
|
|
%
|
|
% \item The vertical parts must overlap vertical rules on either side, so
|
|
% that a |\vrule\sd@|\textit{xx}|circ| makes the arc appear to be
|
|
% a real curve in the line. The requirements are actually somewhat
|
|
% inconsistent; for example, the \env{stack} environment uses curves
|
|
% \emph{before} the |\vrule|s. Special requirements like this are
|
|
% handled as special cases later.
|
|
%
|
|
% \item The height and width of the arc are at least roughly correct.
|
|
%
|
|
% \end{itemize}
|
|
%
|
|
% \begin{macrocode}
|
|
\def\sd@tlcirc{{%
|
|
\sd@circ3%
|
|
\ht\tw@\sdrulewidth%
|
|
\dp\tw@.5\sdcirclediam%
|
|
\kern-\tw@\sdrulewidth%
|
|
\raise\sd@mid\box\tw@%
|
|
\kern.5\sdcirclediam%
|
|
}}
|
|
% \end{macrocode}
|
|
%
|
|
% \begin{macrocode}
|
|
\def\sd@trcirc{{%
|
|
\sd@circ0%
|
|
\ht\tw@\sdrulewidth%
|
|
\dp\tw@.5\sdcirclediam%
|
|
\kern.5\sdcirclediam%
|
|
\raise\sd@mid\box\tw@%
|
|
}}
|
|
% \end{macrocode}
|
|
%
|
|
% \begin{macrocode}
|
|
\def\sd@blcirc{{%
|
|
\sd@circ2%
|
|
\ht\tw@.5\sdcirclediam%
|
|
\dp\tw@\sdrulewidth%
|
|
\kern-\tw@\sdrulewidth%
|
|
\raise\sd@mid\box\tw@%
|
|
\kern.5\sdcirclediam%
|
|
}}
|
|
% \end{macrocode}
|
|
%
|
|
% \begin{macrocode}
|
|
\def\sd@brcirc{{%
|
|
\sd@circ1%
|
|
\ht\tw@.5\sdcirclediam%
|
|
\dp\tw@\sdrulewidth%
|
|
\kern.5\sdcirclediam%
|
|
\raise\sd@mid\box\tw@%
|
|
}}
|
|
% \end{macrocode}
|
|
%
|
|
% \end{macro}
|
|
% \end{macro}
|
|
% \end{macro}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\sd@llc}
|
|
% \begin{macro}{\sd@rlc}
|
|
%
|
|
% In the \env{rep} environment, we need to be able to draw arcs with
|
|
% horizontal lines running through them. The two macros here do the job
|
|
% nicely. |\sd@llc| (which is short for left overlapping circle) is
|
|
% analogous to |\llap|: it puts its argument in a box of zero width, sticking
|
|
% out to the left. However, it also draws a rule along the baseline. This
|
|
% is important, as it prevents text from overprinting the arc. |\sd@rlc|
|
|
% is very similar, just the other way around.
|
|
%
|
|
% \begin{macrocode}
|
|
\def\sd@llc#1{%
|
|
\hb@xt@.5\sdcirclediam{%
|
|
\sd@rule\hskip.5\sdcirclediam%
|
|
\hss%
|
|
#1%
|
|
}%
|
|
}
|
|
% \end{macrocode}
|
|
%
|
|
% \begin{macrocode}
|
|
\def\sd@rlc#1{%
|
|
\hb@xt@.5\sdcirclediam{%
|
|
#1%
|
|
\hss%
|
|
\sd@rule\hskip.5\sdcirclediam%
|
|
}%
|
|
}
|
|
% \end{macrocode}
|
|
%
|
|
% \end{macro}
|
|
% \end{macro}
|
|
%
|
|
% \subsubsection{Drawing rules}
|
|
%
|
|
% It's important to draw the rules \emph{along} the baseline, rather than
|
|
% above it: hence, the depth of the rule must be equal to the height.
|
|
%
|
|
% \begin{macro}{\sd@rule}
|
|
%
|
|
% We use rule leaders instead of glue through most of the syntax diagrams.
|
|
% The command \syntax{"\\sd@rule"<skip>} draws a rule of the correct
|
|
% dimensions, which has the behaviour of an \syntax{"\\hskip"<skip>}.
|
|
%
|
|
% \begin{macrocode}
|
|
\def\sd@rule{\leaders\hrule\@height\sd@upper\@depth\sd@lower}
|
|
% \end{macrocode}
|
|
%
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\sd@gap}
|
|
%
|
|
% The gap between elements is added using this macro. It will allow a
|
|
% line break if we're at the top level of the diagram, using a rather
|
|
% strange discretionary.
|
|
%
|
|
% This is called as \syntax{"\\sd@gap{"<skip-register>"}"}.
|
|
%
|
|
% \begin{macrocode}
|
|
\def\sd@gap#1{%
|
|
% \end{macrocode}
|
|
%
|
|
% First, we see if we're at the top level. Within constructs, we avoid the
|
|
% overhead of a |\discretionary|. We put half of the width of the skip on
|
|
% each side of the discretionary break.
|
|
%
|
|
% \begin{macrocode}
|
|
\ifsd@base%
|
|
\skip@#1%
|
|
\divide\skip\z@\tw@%
|
|
\nobreak\sd@rule\hskip\skip@%
|
|
\discretionary{%
|
|
\sd@qarrow{->}%
|
|
}{%
|
|
\hbox{%
|
|
\sd@qarrow{>-}%
|
|
\sd@rule\hskip\sdstartspace%
|
|
\sd@rule\hskip3.5\p@%
|
|
}%
|
|
}{%
|
|
}%
|
|
\nobreak\sd@rule\hskip\skip@%
|
|
% \end{macrocode}
|
|
%
|
|
% If we're not at the base level, we just put in a rule of the correct
|
|
% width.
|
|
%
|
|
% \begin{macrocode}
|
|
\else%
|
|
\sd@rule\hskip#1%
|
|
\fi%
|
|
}
|
|
% \end{macrocode}
|
|
%
|
|
% \end{macro}
|
|
%
|
|
% \subsubsection{The \protect\env{syntdiag} environment}
|
|
%
|
|
% All syntax diagrams are contained within a \env{syntdiag} environment.
|
|
%
|
|
% \begin{environment}{syntdiag}
|
|
%
|
|
% The only argument is a collection of declarations, which by
|
|
% default is
|
|
%
|
|
% \begin{listing}
|
|
%\sdsize\sdlengths
|
|
% \end{listing}
|
|
%
|
|
% However, if the optional argument is not specified, \TeX\ reads the first
|
|
% character of the environment, which may not be catcoded correctly. We set
|
|
% up the catcodes first, using the |\syntaxShortcuts| command, and then read
|
|
% the argument. We don't use |\newcommand|, because that would involve
|
|
% creating yet \emph{another} macro. Time to fiddle with |\@ifnextchar|
|
|
% \dots
|
|
%
|
|
% \begin{macrocode}
|
|
\def\syntdiag{%
|
|
\syntaxShortcuts\sd@tok@i\sd@tok@ii%
|
|
\@ifnextchar[\syntdiag@i{\syntdiag@i[]}%
|
|
}
|
|
% \end{macrocode}
|
|
%
|
|
% Now we actually do the job we're meant to.
|
|
%
|
|
% \begin{macrocode}
|
|
\def\syntdiag@i[#1]{%
|
|
% \end{macrocode}
|
|
%
|
|
% The first thing to do is execute the user's declarations. We then set
|
|
% up things for the font size.
|
|
%
|
|
% \begin{macrocode}
|
|
\sdsize\sdlengths%
|
|
#1%
|
|
\sd@setsize%
|
|
% \end{macrocode}
|
|
%
|
|
% Next, we start a list, to change the text layout.
|
|
%
|
|
% \begin{macrocode}
|
|
\list{}{%
|
|
\leftmargin\sdindent%
|
|
\rightmargin\leftmargin%
|
|
\labelsep\z@%
|
|
\labelwidth\z@%
|
|
}%
|
|
\item[]%
|
|
% \end{macrocode}
|
|
%
|
|
% We reconfigure the paragraph format quite a lot now. We clear
|
|
% |\parfillskip| to avoid any justification at the end of the paragraph.
|
|
% We also turn off paragraph indentation.
|
|
%
|
|
% \begin{macrocode}
|
|
\parfillskip\z@%
|
|
\noindent%
|
|
% \end{macrocode}
|
|
%
|
|
% Next, we add in the arrows on the beginning of the line, and a bit of
|
|
% glue.
|
|
%
|
|
% \begin{macrocode}
|
|
\sd@qarrow{>>-}%
|
|
\nobreak\sd@rule\hskip\sdstartspace%
|
|
% \end{macrocode}
|
|
%
|
|
% This is the base level of the diagram, so we enable line breaking.
|
|
%
|
|
% \begin{macrocode}
|
|
\sd@basetrue%
|
|
% \end{macrocode}
|
|
%
|
|
% Since the objects being broken are rather large, we enable sloppy line
|
|
% breaking. We also try to avoid page breaks in mid-diagram, by upping the
|
|
% |\interlinepenalty|.
|
|
%
|
|
% \begin{macrocode}
|
|
\sloppy%
|
|
\interlinepenalty100%
|
|
\hyphenpenalty0%
|
|
% \end{macrocode}
|
|
%
|
|
% We handle all the spacing within the environment, so we make \TeX\ ignore
|
|
% spaces and newlines.
|
|
%
|
|
% \begin{macrocode}
|
|
\catcode`\ 9%
|
|
\catcode`\^^M9%
|
|
% \end{macrocode}
|
|
%
|
|
% The environment names are rather cumbersome. I'll define some better names
|
|
% for them here.
|
|
%
|
|
% \begin{macrocode}
|
|
\def\gr@leftsq{\begin{stack}\\}%
|
|
\def\gr@rightsq{\end{stack}}%
|
|
\def\({\begin{stack}}%
|
|
\def\){\end{stack}}%
|
|
\def\<{\begin{rep}}%
|
|
\def\>{\end{rep}}%
|
|
% \end{macrocode}
|
|
%
|
|
% We now have to change the behaviour of |\\| to line-break syntax diagrams.
|
|
%
|
|
% \begin{macrocode}
|
|
\let\\\sd@newline%
|
|
\ignorespaces%
|
|
}
|
|
% \end{macrocode}
|
|
%
|
|
% When we end the diagram, we just have to add in the final fillskip, and
|
|
% double arrow.
|
|
%
|
|
% \begin{macrocode}
|
|
\def\endsyntdiag{%
|
|
\unskip%
|
|
\nobreak\sd@rule\hskip\sdmidskip%
|
|
\sd@rule\hskip\sdfinalskip%
|
|
\sd@qarrow{-><}%
|
|
\endlist%
|
|
}
|
|
% \end{macrocode}
|
|
%
|
|
% \end{environment}
|
|
%
|
|
% \begin{environment}{syntdiag*}
|
|
%
|
|
% The starred form of \env{syntdiag} typesets a syntax diagram in LR-mode;
|
|
% this is useful if you're describing parts of syntax diagrams, for example.
|
|
%
|
|
% This is in fact really easy. The first bit which checks for an optional
|
|
% argument is almost identical to the non-$*$ version.
|
|
%
|
|
% \begin{macrocode}
|
|
\@namedef{syntdiag*}{%
|
|
\syntaxShortcuts\sd@tok@i\sd@tok@ii%
|
|
\@ifnextchar[\syntdiag@s@i{\syntdiag@s@i[]}%
|
|
}
|
|
% \end{macrocode}
|
|
%
|
|
% Handle another optional argument giving the width of the box to fill.
|
|
%
|
|
% \begin{macrocode}
|
|
\def\syntdiag@s@i[#1]{%
|
|
\@ifnextchar[{\syntdiag@s@ii{#1}}{\syntdiag@s@iii{#1}{\hbox}}%
|
|
}
|
|
\def\syntdiag@s@ii#1[#2]{\syntdiag@s@iii{#1}{\hb@xt@#2}}
|
|
% \end{macrocode}
|
|
%
|
|
% Now to actually start the display. This is mostly simple. Just to make
|
|
% sure about the LR-ness of the typesetting, I'll put everything in an hbox.
|
|
%
|
|
% \begin{macrocode}
|
|
\def\syntdiag@s@iii#1#2{%
|
|
\leavevmode%
|
|
#2\bgroup%
|
|
% \end{macrocode}
|
|
%
|
|
% Now configure the typesetting according to the user's wishes.
|
|
%
|
|
% \begin{macrocode}
|
|
\let\@@left\left%
|
|
\let\@@right\right%
|
|
\def\left##1{\def\sd@startarr{##1}}%
|
|
\def\right##1{\def\sd@endarr{##1}}%
|
|
\left{>-}\right{->}%
|
|
\sdsize\sdlengths%
|
|
#1%
|
|
\sd@setsize%
|
|
\let\left\@@left%
|
|
\let\right\@@right%
|
|
% \end{macrocode}
|
|
%
|
|
% Put in the initial double-arrow.
|
|
%
|
|
% \begin{macrocode}
|
|
\sd@qarrow\sd@startarr%
|
|
\sd@rule\hskip\sdmidskip%
|
|
% \end{macrocode}
|
|
%
|
|
% We're in horizontal mode, so don't bother with linebreaking.
|
|
%
|
|
% \begin{macrocode}
|
|
\sd@basefalse%
|
|
% \end{macrocode}
|
|
%
|
|
% Finally, disable spaces and things.
|
|
%
|
|
% \begin{macrocode}
|
|
\catcode`\ 9%
|
|
\catcode`\^^M9%
|
|
\ignorespaces%
|
|
}
|
|
% \end{macrocode}
|
|
%
|
|
% Ending the environment is very similar.
|
|
%
|
|
% \begin{macrocode}
|
|
\@namedef{endsyntdiag*}{%
|
|
\unskip%
|
|
\sd@rule\hskip\sdmidskip%
|
|
\sd@rule\hskip\sdfinalskip%
|
|
\sd@qarrow\sd@endarr%
|
|
\egroup%
|
|
}
|
|
% \end{macrocode}
|
|
%
|
|
% \end{environment}
|
|
%
|
|
% \begin{macro}{\sd@qarrow}
|
|
%
|
|
% This typesets the various left and right arrows required in syntax
|
|
% diagrams. The argument is one of \syntax{`>>-', `->', `>-' or `-><'}.
|
|
%
|
|
% \begin{macrocode}
|
|
\def\sd@qarrow#1{%
|
|
\begingroup%
|
|
\lccode`\~=`\<\lowercase{\def~{<}}%
|
|
\hbox{\csname sd@arr@#1\endcsname}%
|
|
\endgroup%
|
|
}
|
|
\@namedef{sd@arr@>>-}{\sd@rightarr\kern-.5\p@\sd@rightarr\kern-\p@}
|
|
\@namedef{sd@arr@>-}{\sd@rightarr\kern-\p@}
|
|
\@namedef{sd@arr@->}{\sd@rightarr}
|
|
\@namedef{sd@arr@-><}{\sd@rightarr\kern-\p@\sd@leftarr}
|
|
\@namedef{sd@arr@...}{$\cdots$}
|
|
\@namedef{sd@arr@-}{}
|
|
% \end{macrocode}
|
|
%
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\sd@newline}
|
|
%
|
|
% The line breaking within a syntax diagram is controlled by the
|
|
% |\sd@newline| command, to which |\\| is assigned.
|
|
%
|
|
% We support all the standard \LaTeX\ features here. The line breaking
|
|
% involves adding a fill skip and arrow, moving to the next line, adding
|
|
% an arrow and a rule, and continuing.
|
|
%
|
|
% \begin{macrocode}
|
|
\def\sd@newline{\@ifstar{\vadjust{\penalty\@M}\sd@nl@i}\sd@nl@i}
|
|
\def\sd@nl@i{\@ifnextchar[\sd@nl@ii\sd@nl@iii}
|
|
\def\sd@nl@ii[#1]{\vspace{#1}\sd@nl@iii}
|
|
\def\sd@nl@iii{%
|
|
\nobreak\sd@rule\hskip\sdmidskip%
|
|
\sd@rule\hskip\sdfinalskip%
|
|
\kern-3\p@%
|
|
\sd@rightarr%
|
|
\newline%
|
|
\sd@rightarr%
|
|
\nobreak\sd@rule\hskip\sdstartspace%
|
|
\sd@rule\hskip3.5\p@%
|
|
}
|
|
% \end{macrocode}
|
|
%
|
|
% \end{macro}
|
|
%
|
|
% \subsubsection{Putting things in the right place}
|
|
%
|
|
% Syntax diagrams have fairly stiff requirements on the positioning of text
|
|
% relative to the diagram's rules. To help people (and me) to write
|
|
% extensions to the syntax diagram typesetting which automatically put things
|
|
% in the right place, I provide some simple macros.
|
|
%
|
|
% \begin{environment}{sdbox}
|
|
%
|
|
% By placing some text in the \env{sdbox} environment, it will be read into a
|
|
% box and then output at the correct height for the syntax diagram. Note
|
|
% that stuff in the box is set in horizontal (LR) mode, so you'll have to use
|
|
% a \env{minipage} if you want formatted text. The macro also supplies rules
|
|
% on either side of the box, with a length given in the environment's
|
|
% argument.
|
|
%
|
|
% Macro writers are given explicit permission to use this environment through
|
|
% the |\sdbox| and |\endsdbox| commands if this makes life easier.
|
|
%
|
|
% The calculation in the |\endsdbox| macro works out how to centre the box
|
|
% vertically over the baseline. If the box's height is~$h$, and its depth
|
|
% is~$d$, then its centre-line is $(h+d)/2$ from the bottom of the box.
|
|
% Since the baseline is already $d$ from the bottom, we need to lower the box
|
|
% by $(h+d)/2 - d$, or $h/2-d/2$.
|
|
%
|
|
% \begin{macrocode}
|
|
\def\sdbox#1{%
|
|
\@tempskipa#1\relax%
|
|
\sd@gap\@tempskipa%
|
|
\setbox\z@\hbox\bgroup%
|
|
\begingroup%
|
|
\catcode`\ 10%
|
|
\catcode`\^^M5%
|
|
\synshortsoff%
|
|
}
|
|
\def\endsdbox{%
|
|
\endgroup%
|
|
\egroup%
|
|
\@tempdima\ht\z@%
|
|
\advance\@tempdima-\dp\z@%
|
|
\advance\@tempdima-\tw@\sd@mid%
|
|
\lower.5\@tempdima\box\z@%
|
|
\sd@gap\@tempskipa%
|
|
}
|
|
% \end{macrocode}
|
|
%
|
|
% \end{environment}
|
|
%
|
|
% \subsubsection{Typesetting syntactic items}
|
|
%
|
|
% Using the hooks built into the syntax abbreviations above, we typeset
|
|
% the text into a box, and write it out, centred over the baseline. A strut
|
|
% helps to keep the actual text baselines level for short pieces of text.
|
|
%
|
|
% \begin{macro}{\sd@tok@i}
|
|
%
|
|
% The preamble for a syntax abbreviation. We start a box, and set the
|
|
% space and return characters to work again. A strut is added to the box to
|
|
% ensure correct vertical spacing for normal text.
|
|
%
|
|
% \begin{macrocode}
|
|
\def\sd@tok@i{%
|
|
\sdbox\sdtokskip%
|
|
\strut%
|
|
\space%
|
|
}
|
|
% \end{macrocode}
|
|
%
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\sd@tok@ii}
|
|
%
|
|
% \begin{macrocode}
|
|
\def\sd@tok@ii{%
|
|
\space%
|
|
\endsdbox%
|
|
}
|
|
% \end{macrocode}
|
|
%
|
|
% \end{macro}
|
|
%
|
|
% \subsubsection{Inserting other pieces of text}
|
|
%
|
|
% Arbitrary text may be put into a syntax diagram through the use of the
|
|
% |\tok| macro. Its `argument' is typeset in the same way as a syntactic
|
|
% item (centred over the baseline). The implementation goes to some effort
|
|
% to ensure that the text is not actually an argument, to allow category
|
|
% codes to change while the text is being typeset.
|
|
%
|
|
% \begin{macro}{\tok}
|
|
%
|
|
% We start a box, and make space and return do their normal jobs. We use
|
|
% |\aftergroup| to regain control once the box is finished. |\doafter| is
|
|
% used to get control after the group finishes.
|
|
%
|
|
% \begin{macrocode}
|
|
\def\tok#{%
|
|
\sdbox\sdtokskip%
|
|
\strut%
|
|
\enspace%
|
|
\syntaxShortcuts\relax\relax%
|
|
\doafter\sd@tok%
|
|
}
|
|
% \end{macrocode}
|
|
%
|
|
% The |\sd@tok| macro is similar to |\sd@tok@ii| above.
|
|
%
|
|
% \begin{macrocode}
|
|
\def\sd@tok{%
|
|
\enspace%
|
|
\endsdbox%
|
|
}
|
|
% \end{macrocode}
|
|
%
|
|
% \end{macro}
|
|
%
|
|
% \subsubsection{The \protect\env{stack} environment}
|
|
%
|
|
% The \env{stack} environment is used to present alternatives in a syntax
|
|
% diagram. The alternatives are separated by |\\| commands.
|
|
%
|
|
% \begin{macro}{\stack}
|
|
%
|
|
% The optional positioning argument is handled using \LaTeX's |\newcommand|
|
|
% mechanism.
|
|
%
|
|
% \begin{macrocode}
|
|
\newcommand\stack[1][t]{%
|
|
% \end{macrocode}
|
|
%
|
|
% First, we add some horizontal space.
|
|
%
|
|
% \begin{macrocode}
|
|
\sd@gap\sdmidskip%
|
|
% \end{macrocode}
|
|
%
|
|
% We're within a complex construction, so we need to clear the |\ifsd@base|
|
|
% flag.
|
|
%
|
|
% \begin{macrocode}
|
|
\begingroup\sd@basefalse%
|
|
% \end{macrocode}
|
|
%
|
|
% The top and bottom rows of the stack are different to the others, since
|
|
% the vertical rules mustn't extend all the way up the side of the item.
|
|
% The bottom row is handled separately by |\endstack| below. The top row
|
|
% must be handled via a flag, |\ifsd@toplayer|.
|
|
%
|
|
% Initially, the flag must be set true.
|
|
%
|
|
% \begin{macrocode}
|
|
\sd@toplayertrue%
|
|
% \end{macrocode}
|
|
%
|
|
% We set the |\\| command to separate the items in the |\halign|.
|
|
%
|
|
% \begin{macrocode}
|
|
\let\\\sd@stackcr%
|
|
% \end{macrocode}
|
|
%
|
|
% The actual structure must be set in vertical mode, so we must place it
|
|
% in a box. The position argument determines whether this must be a
|
|
% |\vbox| or a |\vtop|. We also insert a bit of rounding if the options say
|
|
% we must.
|
|
%
|
|
% \begin{macrocode}
|
|
\if#1t%
|
|
\let\@tempa\vtop%
|
|
\sd@toptrue%
|
|
\ifsd@round\llap{\sd@trcirc\kern\tw@\sdrulewidth}\fi%
|
|
\else\if#1b%
|
|
\let\@tempa\vbox%
|
|
\sd@topfalse%
|
|
\ifsd@round\llap{\sd@brcirc\kern\tw@\sdrulewidth}\fi%
|
|
\else%
|
|
\sd@err{Bad position argument passed to stack}%
|
|
{The positioning argument must be one of `t' or `b'. I%
|
|
have^^Jassumed you meant to type `t'.}%
|
|
\let\@tempa\vtop%
|
|
\fi\fi%
|
|
% \end{macrocode}
|
|
%
|
|
% Now we start the box, which we will complete at the end of the environment.
|
|
%
|
|
% \begin{macrocode}
|
|
\@tempa\bgroup%
|
|
% \end{macrocode}
|
|
%
|
|
% We must remove any extra space between rows of the table, since the rules
|
|
% will not join up correctly. We can use |\offinterlineskip| safely, since
|
|
% each individual row contains a strut.
|
|
%
|
|
% \begin{macrocode}
|
|
\offinterlineskip%
|
|
% \end{macrocode}
|
|
%
|
|
% Now we can start the alignment. We actually use \PlainTeX's |\ialign|
|
|
% macro, which also clears |\tabskip| for us.
|
|
%
|
|
% \begin{macrocode}
|
|
\ialign\bgroup%
|
|
% \end{macrocode}
|
|
%
|
|
% The preamble is trivial, since we must do all of the work ourselves
|
|
%
|
|
% \begin{macrocode}
|
|
##\cr%
|
|
% \end{macrocode}
|
|
%
|
|
% We can now start putting the text into a box ready for typesetting later.
|
|
% The strut makes the vertical spacing correct.
|
|
%
|
|
% \begin{macrocode}
|
|
\setbox\z@\hbox\bgroup%
|
|
\strut%
|
|
}
|
|
% \end{macrocode}
|
|
%
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\endstack}
|
|
%
|
|
% The first part of this is similar to the |\sd@stackcr| macro below, except
|
|
% that the vertical rules are different. We don't support rounded edges
|
|
% on single-row stacks, although this isn't a great loss to humanity.
|
|
%
|
|
% \begin{macrocode}
|
|
\def\endstack{%
|
|
\egroup%
|
|
\ifsd@toplayer%
|
|
\sd@dostack\sd@upper\sd@lower\relax\relax%
|
|
\else%
|
|
\ifsd@round%
|
|
\ifsd@top%
|
|
\sd@dostack{\ht\z@}\sd@botcirc\sd@blcirc\sd@brcirc%
|
|
\else%
|
|
\sd@dostack{\ht\z@}\sd@botcirc\relax\relax%
|
|
\fi%
|
|
\else%
|
|
\sd@dostack{\ht\z@}\sd@lower\relax\relax%
|
|
\fi%
|
|
\fi%
|
|
% \end{macrocode}
|
|
%
|
|
% We now close the |\halign| and the vbox we created.
|
|
%
|
|
% \begin{macrocode}
|
|
\egroup%
|
|
\egroup%
|
|
% \end{macrocode}
|
|
%
|
|
% Deal with any rounding we started off.
|
|
%
|
|
% \begin{macrocode}
|
|
\ifsd@round%
|
|
\ifsd@top
|
|
\rlap{\kern\tw@\sdrulewidth\sd@tlcirc}%
|
|
\else%
|
|
\rlap{\kern\tw@\sdrulewidth\sd@blcirc}%
|
|
\fi%
|
|
\fi%
|
|
% \end{macrocode}
|
|
%
|
|
% Finally, we add some horizontal glue to space the diagram out.
|
|
%
|
|
% \begin{macrocode}
|
|
\endgroup\sd@gap\sdmidskip%
|
|
}
|
|
% \end{macrocode}
|
|
%
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\sd@stackcr}
|
|
%
|
|
% The |\\| command is set to this macro during a \env{stack} environment.
|
|
%
|
|
% \begin{macrocode}
|
|
\def\sd@stackcr{%
|
|
% \end{macrocode}
|
|
%
|
|
% The first job is to close the box containing the previous item.
|
|
%
|
|
% \begin{macrocode}
|
|
\egroup%
|
|
% \end{macrocode}
|
|
%
|
|
% Now we typeset the vertical rules differently depending on whether this is
|
|
% the first item in the stack. This looks quite terrifying initially, but
|
|
% it's just an enumeration of the possible cases for the different values
|
|
% of |\ifsd@toplayer|, |\ifsd@top| and |\ifsd@round|, putting in appropriate
|
|
% rules and arcs in the right places.
|
|
%
|
|
% \begin{macrocode}
|
|
\ifsd@toplayer%
|
|
\ifsd@round%
|
|
\ifsd@top%
|
|
\sd@dostack\sd@topcirc{\dp\z@}\relax\relax%
|
|
\else%
|
|
\sd@dostack\sd@topcirc{\dp\z@}\sd@tlcirc\sd@trcirc%
|
|
\fi%
|
|
\else%
|
|
\sd@dostack\sd@upper{\dp\z@}\relax\relax%
|
|
\fi%
|
|
\else%
|
|
\ifsd@round%
|
|
\ifsd@top%
|
|
\sd@dostack{\ht\z@}{\dp\z@}\sd@blcirc\sd@brcirc%
|
|
\else%
|
|
\sd@dostack{\ht\z@}{\dp\z@}\sd@tlcirc\sd@trcirc%
|
|
\fi%
|
|
\else%
|
|
\sd@dostack{\ht\z@}{\dp\z@}\relax\relax%
|
|
\fi%
|
|
\fi%
|
|
% \end{macrocode}
|
|
%
|
|
% The next item won't be the first, so we clear the flag.
|
|
%
|
|
% \begin{macrocode}
|
|
\sd@toplayerfalse%
|
|
% \end{macrocode}
|
|
%
|
|
% Now we have to set up the next cell. We put the text into a box again.
|
|
%
|
|
% \begin{macrocode}
|
|
\setbox\z@\hbox\bgroup%
|
|
\strut%
|
|
}
|
|
% \end{macrocode}
|
|
%
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\sd@dostack}
|
|
%
|
|
% Actually typesetting the text in a cell is performed here. The macro is
|
|
% called as
|
|
% \begin{quote}\synshorts
|
|
% "\\sd@dostack{"<height>"}{"<depth>"}{"<left-arc>"}{"<right-arc>"}"
|
|
% \end{quote}
|
|
% where \<height> and \<depth> are the height and depth of the vertical
|
|
% rules to put around the item, and \<left-arc> and \<right-arc> are
|
|
% commands to draw rounded edges on the left and right hand sides of the
|
|
% item.
|
|
%
|
|
% The values for the height and depth are quite often going to be the height
|
|
% and depth of box~0. Since we empty box~0 in the course of typesetting the
|
|
% row, we need to cache the sizes on entry.
|
|
%
|
|
% \begin{macrocode}
|
|
\def\sd@dostack#1#2#3#4{%
|
|
\@tempdima#1%
|
|
\@tempdimb#2%
|
|
\kern-\tw@\sdrulewidth%
|
|
\vrule\@height\@tempdima\@depth\@tempdimb\@width\tw@\sdrulewidth%
|
|
#3%
|
|
\sd@rule\hfill%
|
|
\sd@gap\sdtokskip%
|
|
\unhbox\z@%
|
|
\sd@gap\sdtokskip%
|
|
\sd@rule\hfill%
|
|
#4%
|
|
\vrule\@height\@tempdima\@depth\@tempdimb\@width\tw@\sdrulewidth%
|
|
\kern-\tw@\sdrulewidth%
|
|
\cr%
|
|
}
|
|
% \end{macrocode}
|
|
%
|
|
% \end{macro}
|
|
%
|
|
% \subsubsection{The \protect\env{rep} environment}
|
|
%
|
|
% The \env{rep} environment is used for typesetting loops in the diagram.
|
|
% Again, we use |\halign| for the typesetting. Loops are simpler than
|
|
% stacks, however, since there are always two rows. We store both rows in
|
|
% box registers, and build the loop at the end.
|
|
%
|
|
% \begin{macro}{\rep}
|
|
%
|
|
% Again, we use |\newcommand| to process the optional argument.
|
|
%
|
|
% \begin{macrocode}
|
|
\newcommand\rep[1][t]{%
|
|
% \end{macrocode}
|
|
%
|
|
% First, leave a gap on the left side.
|
|
%
|
|
% \begin{macrocode}
|
|
\sd@gap\sdmidskip%
|
|
% \end{macrocode}
|
|
%
|
|
% We're not at base level any more, so disable linebreaking.
|
|
%
|
|
% \begin{macrocode}
|
|
\begingroup\sd@basefalse%
|
|
% \end{macrocode}
|
|
%
|
|
% Remember we're going backwards now.
|
|
%
|
|
% \begin{macrocode}
|
|
\ifsd@backwards\sd@backwardsfalse\else\sd@backwardstrue\fi%
|
|
% \end{macrocode}
|
|
%
|
|
% Define |\\| to separate the two parts of the loop.
|
|
%
|
|
% \begin{macrocode}
|
|
\let\\\sd@loop%
|
|
% \end{macrocode}
|
|
%
|
|
% Now check the argument, and use the appropriate type of box. In addition
|
|
% to changing the typesetting, we must remember which way up to typeset the
|
|
% loop, since the end code must always put the first argument on the
|
|
% baseline, with the loop either above or below.
|
|
%
|
|
% \begin{macrocode}
|
|
\if#1t%
|
|
\let\@tempa\vbox%
|
|
\sd@toptrue%
|
|
\else\if#1b%
|
|
\let\@tempa\vtop%
|
|
\sd@topfalse%
|
|
\else%
|
|
\sd@err{Bad position argument passed to loop}%
|
|
{The positioning argument must be `t' or `b'. I have^^J%
|
|
assumed you meant to type `t'.}%
|
|
\let\@tempa\vbox%
|
|
\sd@toptrue%
|
|
\fi\fi%
|
|
% \end{macrocode}
|
|
%
|
|
% Now we start the box.
|
|
%
|
|
% \begin{macrocode}
|
|
\@tempa\bgroup%
|
|
% \end{macrocode}
|
|
%
|
|
% The loop is by default empty, apart from a strut. This is put into box~1.
|
|
%
|
|
% \begin{macrocode}
|
|
\setbox\tw@\copy\strutbox%
|
|
% \end{macrocode}
|
|
%
|
|
% Now start typesetting the main text in box~0.
|
|
%
|
|
% \begin{macrocode}
|
|
\setbox\z@\hbox\bgroup\strut%
|
|
}
|
|
% \end{macrocode}
|
|
%
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\endrep}
|
|
%
|
|
% The final code must first close whatever box was open.
|
|
%
|
|
% \begin{macrocode}
|
|
\def\endrep{%
|
|
\egroup%
|
|
% \end{macrocode}
|
|
%
|
|
% Now we typeset the loop, depending on which way up it was meant to be.
|
|
% Again, this terrifying piece of code is a simple list of possibile values
|
|
% of our various flags.
|
|
%
|
|
% \begin{macrocode}
|
|
\ifsd@top%
|
|
\ifsd@round%
|
|
\sd@doloop\tw@\z@\relax\relax%
|
|
\sd@tlcirc\sd@trcirc{\sd@rlc\sd@blcirc}{\sd@llc\sd@brcirc}%
|
|
\else%
|
|
\sd@doloop\tw@\z@\relax\sd@downarr\relax\relax\relax\relax%
|
|
\fi%
|
|
\else%
|
|
\ifsd@round%
|
|
\sd@doloop\z@\tw@\relax\relax%
|
|
{\sd@rlc\sd@tlcirc}{\sd@llc\sd@trcirc}\sd@blcirc\sd@brcirc%
|
|
\else%
|
|
\sd@doloop\z@\tw@\sd@uparr\relax\relax\relax\relax\relax%
|
|
\fi%
|
|
\fi%
|
|
% \end{macrocode}
|
|
%
|
|
% Close the vbox we opened.
|
|
%
|
|
% \begin{macrocode}
|
|
\egroup%
|
|
% \end{macrocode}
|
|
%
|
|
% Finally, we leave a gap before the next structure.
|
|
%
|
|
% \begin{macrocode}
|
|
\endgroup\sd@gap\sdmidskip%
|
|
}
|
|
% \end{macrocode}
|
|
%
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\sd@loop}
|
|
%
|
|
% This macro handles the |\\| command within a loop environment. We close
|
|
% the current box, and start filling in box~1. We also redefine |\\| to
|
|
% raise an error when the |\\| command is used again.
|
|
%
|
|
% \begin{macrocode}
|
|
\def\sd@loop{%
|
|
\egroup%
|
|
\def\\{\sd@err{Too many \string\\\space commands in loop}\@ehc}%
|
|
\setbox\tw@\hbox\bgroup\strut%
|
|
}
|
|
% \end{macrocode}
|
|
%
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\sd@doloop}
|
|
%
|
|
% This is the macro which actually creates the |\halign| for the loop. It
|
|
% is called with four arguments, as:
|
|
% \begin{quote}\synshorts
|
|
% "\\sd@doloop{"<top-box>"}{"<bottom-box>"}"^^A
|
|
% "{"<top-arrow>"}{"<btm-arrow>"}" \\
|
|
% \hbox{}\quad "{"<top-left-arc>"}{"<top-right-arc>"}"^^A
|
|
% "{"<bottom-left-arc>"}{"<btm-right-arc>"}"^^A
|
|
% \kern-1in ^^A It may be overfull, but it looks OK to me ;-)
|
|
% \end{quote}
|
|
%
|
|
% The two \<box> arguments give the numbers of boxes to extract in the top
|
|
% and bottom rows of the alignment. The \<arrow> arguments specify
|
|
% characters to typeset at the end of the top and bottom rows for arrows.
|
|
% The various \<arc> arguments are commands which typeset arcs around the
|
|
% various parts of the items.
|
|
%
|
|
% We calculate the height and depth of the two boxes, and store them in
|
|
% \<dimen> registers, because the boxes are emptied before the right-hand
|
|
% rules are typeset.
|
|
%
|
|
% Actually, the two rows of the alignment are typeset in a different macro:
|
|
% we just pass the correct information on.
|
|
%
|
|
% \begin{macrocode}
|
|
\def\sd@doloop#1#2#3#4#5#6#7#8{%
|
|
\@tempdima\dp#1\relax%
|
|
\@tempdimb\ht#2\relax%
|
|
\offinterlineskip%
|
|
\ialign{%
|
|
##\cr%
|
|
\ifsd@round%
|
|
\sd@doloop@i#1#3\sd@topcirc\@tempdima{#5}{#6}%
|
|
\sd@doloop@i#2#4\@tempdimb\sd@botcirc{#7}{#8}%
|
|
\else%
|
|
\sd@doloop@i#1#3\sd@upper\@tempdima{#5}{#6}%
|
|
\sd@doloop@i#2#4\@tempdimb\sd@lower{#7}{#8}%
|
|
\fi%
|
|
}%
|
|
}
|
|
% \end{macrocode}
|
|
%
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\sd@doloop@i}
|
|
%
|
|
% Here we do the actual job of typesetting the rows of a loop alignment.
|
|
% The four arguments are:
|
|
% \begin{quote}\synshorts
|
|
% "\\sd@doloop@i{"<box>"}{"<arrow>"}"^^A
|
|
% "{"<rule-height>"}{"<rule-depth>"}" \\
|
|
% \hbox{}\quad "{"<left-arc>"}{"<right-arc>"}"^^A
|
|
% \end{quote}
|
|
%
|
|
% The arrow position is determined by the |\ifsd@backwards| flag. The rest
|
|
% is fairly simple.
|
|
%
|
|
% \begin{macrocode}
|
|
\def\sd@doloop@i#1#2#3#4#5#6{%
|
|
\ifsd@backwards#2\fi%
|
|
\kern-\tw@\sdrulewidth%
|
|
\vrule\@height#3\@depth#4\@width\tw@\sdrulewidth%
|
|
#5%
|
|
\sd@rule\hfill%
|
|
\sd@gap\sdtokskip%
|
|
\unhbox#1%
|
|
\sd@gap\sdtokskip%
|
|
\sd@rule\hfill%
|
|
#6%
|
|
\vrule\@height#3\@depth#4\@width\tw@\sdrulewidth%
|
|
\ifsd@backwards\else#2\fi%
|
|
\kern-\tw@\sdrulewidth%
|
|
\cr%
|
|
}
|
|
% \end{macrocode}
|
|
%
|
|
% \end{macro}
|
|
%
|
|
% \subsection{The end}
|
|
%
|
|
% Phew! That's all of it completed. I hope this collection of commands
|
|
% and environments is of some help to someone.
|
|
%
|
|
% \begin{macrocode}
|
|
%</package>
|
|
% \end{macrocode}
|
|
%
|
|
% \hfill Mark Wooding, \today
|
|
%
|
|
% \Finale
|
|
%
|
|
\endinput
|