% \begin{meta-comment} % % syntax.dtx % % Syntax typesetting package for LaTeX 2e % % (c) 1996 Mark Wooding % % \end{meta-comment} % % \begin{meta-comment} %% %% 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>\NeedsTeXFormat{LaTeX2e} %<+package>\ProvidesPackage{syntax} %<+package> [1996/05/17 1.07 Syntax typesetting (MDW)] % \end{meta-comment} % % \CheckSum{1439} %% \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> % % 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 % % % \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{""}" typesets 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 "\\<"">" as an alternative to % "\\synt{""}". % % \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" \\ \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} % ::= `=' % \alt `for' `=' `to' `do' % \alt `{' `}' % \alt % % ::= `;' | %\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} % ::= \[[ % "\\begin{syntdiag}" % \begin{stack} \\ "[" "]" \end{stack} % % "\\end{syntdiag}" % \]] % \end{grammar} % % The \ 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} % ::= \[[ % "\\begin{syntdiag*}" % \begin{stack} \\ "[" "]" \end{stack} % \begin{stack} \\ "[" "]" \end{stack} % % "\\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{""}" and "\\right{""}"} % allow you to choose the arrows on each side of the syntax diagram snippet. % The possible values of \ 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} \\ \\ \end{stack} %\es & Alternatives: choose any one \\ %\bs {...} {...} % \begin{rep} \\ \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 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. % % \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. % % \begin{demo}[w]{A syntax diagram} %\begin{syntdiag} % `(' % \begin{rep} \begin{stack} \\ % \begin{stack} \\ \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.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}{\@uscore} % % 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@\|\. Note that this control sequence % contains a backslash character, which is a little odd. We also define a % command |\cc@\|\ 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@\|\ 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@\|\. 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@\|\ 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 || typesets \syntax{} % \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{""}{""}{""}"} will read all % characters up until the next occurrence of \. Normally, all % special characters will be deactivated. However, you can reactivate some % characters, using the \ 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{""}{""}{""}" \\ % \null \quad "{""}{""}"} % \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{"{""\\/}"} % \end{quote} % % The \ and \ can be |\relax| if they're not % required. % % The \ 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`\|\ 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_{\@uscore.}}% >% \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} % % 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} \let\gr@leftsq\[% \let\gr@rightsq\]% \def\gr@endsyntdiag]{\end{syntdiag}\gr@setpar\par}% \def\[{\@ifnextchar[{\begin{syntdiag}\@gobble}\gr@leftsq}% \def\]{\@ifnextchar]\gr@endsyntdiag\gr@rightsq}% % \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 \ and \ arguments needed. Fixed % lengths, as the \LaTeX book calls them, are allocated as \s, to % take some of the load off of all the \ 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\ \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"} draws a rule of the correct % dimensions, which has the behaviour of an \syntax{"\\hskip"}. % % \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{""}"}. % % \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} % % 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{""}{""}{""}{""}" % \end{quote} % where \ and \ are the height and depth of the vertical % rules to put around the item, and \ and \ 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{""}{""}"^^A % "{""}{""}" \\ % \hbox{}\quad "{""}{""}"^^A % "{""}{""}"^^A % \kern-1in ^^A It may be overfull, but it looks OK to me ;-) % \end{quote} % % The two \ arguments give the numbers of boxes to extract in the top % and bottom rows of the alignment. The \ arguments specify % characters to typeset at the end of the top and bottom rows for arrows. % The various \ 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 % \ 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{""}{""}"^^A % "{""}{""}" \\ % \hbox{}\quad "{""}{""}"^^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} % % \end{macrocode} % % \hfill Mark Wooding, \today % % \Finale % \endinput