Commit | Line | Data |
---|---|---|
86f6a31e | 1 | % \begin{meta-comment} |
2 | % | |
3 | % syntax.dtx | |
4 | % | |
5 | % Syntax typesetting package for LaTeX 2e | |
6 | % | |
e1069af1 | 7 | % (c) 2003 Mark Wooding |
86f6a31e | 8 | % |
9 | % \end{meta-comment} | |
10 | % | |
11 | % \begin{meta-comment} <general public licence> | |
12 | %% | |
13 | %% syntax package -- typesetting syntax descriptions | |
e1069af1 | 14 | %% Copyright (c) 2003 Mark Wooding |
86f6a31e | 15 | %% |
16 | %% This program is free software; you can redistribute it and/or modify | |
17 | %% it under the terms of the GNU General Public License as published by | |
18 | %% the Free Software Foundation; either version 2 of the License, or | |
19 | %% (at your option) any later version. | |
20 | %% | |
21 | %% This program is distributed in the hope that it will be useful, | |
22 | %% but WITHOUT ANY WARRANTY; without even the implied warranty of | |
23 | %% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
24 | %% GNU General Public License for more details. | |
25 | %% | |
26 | %% You should have received a copy of the GNU General Public License | |
27 | %% along with this program; if not, write to the Free Software | |
28 | %% Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
29 | %% | |
30 | % \end{meta-comment} | |
31 | % | |
32 | % \begin{meta-comment} <Package preamble> | |
33 | %<+package>\NeedsTeXFormat{LaTeX2e} | |
34 | %<+package>\ProvidesPackage{syntax} | |
e1069af1 | 35 | %<+package> [2003/08/25 1.08 Syntax typesetting (MDW)] |
86f6a31e | 36 | % \end{meta-comment} |
37 | % | |
88ddb950 | 38 | % \CheckSum{1627} |
86f6a31e | 39 | %% \CharacterTable |
40 | %% {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 | |
41 | %% 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 | |
42 | %% Digits \0\1\2\3\4\5\6\7\8\9 | |
43 | %% Exclamation \! Double quote \" Hash (number) \# | |
44 | %% Dollar \$ Percent \% Ampersand \& | |
45 | %% Acute accent \' Left paren \( Right paren \) | |
46 | %% Asterisk \* Plus \+ Comma \, | |
47 | %% Minus \- Point \. Solidus \/ | |
48 | %% Colon \: Semicolon \; Less than \< | |
49 | %% Equals \= Greater than \> Question mark \? | |
50 | %% Commercial at \@ Left bracket \[ Backslash \\ | |
51 | %% Right bracket \] Circumflex \^ Underscore \_ | |
52 | %% Grave accent \` Left brace \{ Vertical bar \| | |
53 | %% Right brace \} Tilde \~} | |
54 | %% | |
55 | % | |
56 | % \begin{meta-comment} <driver> | |
57 | % | |
58 | %<*driver> | |
59 | % | |
60 | % This hacking will remember the old default underscore character. Even if | |
61 | % T1 fonts are being used, it will get the grotty version. Why is it that | |
62 | % all of the encoding handling ends up looking like this? | |
63 | % | |
64 | \expandafter\let\expandafter\oldus\csname?\string\textunderscore\endcsname | |
65 | % | |
66 | \input{mdwtools} | |
67 | \describespackage{syntax} | |
68 | \DeclareRobustCommand\syn{\package{syntax}} | |
69 | \mdwdoc | |
70 | %</driver> | |
71 | % | |
72 | % \end{meta-comment} | |
73 | % | |
74 | % \section{User guide} | |
75 | % | |
76 | % \subsection{Introduction} | |
77 | % | |
78 | % The \syn\ package provides a number of commands and environments which | |
79 | % extend \LaTeX\ and allow you to typeset good expositions of syntax. | |
80 | % | |
81 | % The package provides several different types of features: probably not all | |
82 | % of these will be required by every document which needs the package: | |
83 | % \begin{itemize} | |
84 | % \item A system of abbreviated forms for typesetting syntactic items. | |
85 | % \item An environment for typesetting BNF-type grammars | |
86 | % \item A collection of environments for building syntax diagrams. | |
87 | % \end{itemize} | |
88 | % | |
89 | % The package also includes some other features which, while not necessarily | |
90 | % syntax-related, will probably come in handy for similar types of document: | |
91 | % \begin{itemize} | |
92 | % \item An abbreviated notation for verbatim text, similar to the | |
93 | % \package{shortvrb} package. | |
94 | % \item A slightly different underscore character, which works as expected | |
95 | % in text and maths modes. | |
96 | % \end{itemize} | |
97 | % | |
98 | % \subsection{The abbreviated verbatim notation} | |
99 | % | |
100 | % In documents describing programming languages and libraries, it can become | |
101 | % tedious to type "\verb|...|" every time. Like Frank Mittelbach's | |
102 | % \package{shortvrb} package, \syn\ provides a way of setting up single-^^A | |
103 | % character abbreviations. The only real difference between the two is that | |
104 | % the declarations provided by \syn\ obey \LaTeX's normal scoping rules. | |
105 | % | |
106 | % \DescribeMacro\shortverb | |
107 | % You can set up a character as a `verbatim shorthand' character using the | |
108 | % |\shortverb| command. This takes a single argument, which should be a | |
109 | % single-character control sequence containing the character you want to use. | |
110 | % So, for example, the command | |
111 | % \begin{listing} | |
112 | %\shortverb{\|} | |
113 | % \end{listing} | |
114 | % would set up the `"|"' character to act as a verbatim delimiter. While a | |
115 | % |\shortverb| declaration is in force, any text surrounded by (in this case) | |
116 | % vertical bar characters will be typeset as if using the normal |\verb| | |
117 | % command. | |
118 | % | |
119 | % \DescribeEnv{shortverb} | |
120 | % Since \LaTeX\ allows any declaration to be used as an environment, you can | |
121 | % use a \env{shortverb} environment to delimit the text over which your | |
122 | % character is active: | |
123 | % \begin{listing} | |
124 | %Some text... | |
125 | %\begin{shortverb}{\|} | |
126 | %... | |
127 | %\end{shortverb} | |
128 | % \end{listing} | |
129 | % | |
130 | % \DescribeMacro\unverb | |
131 | % If you want to disable a |\shortverb| character without ending the scope | |
132 | % of other declarations, you can use the |\unverb| command, passing it | |
133 | % a character as a control sequence, in the same way as above. | |
134 | % | |
135 | % The default \TeX/\LaTeX\ underscore character is rather too short for | |
136 | % use in identifiers. For example: | |
137 | % | |
138 | % \begingroup \let\_=\oldus | |
139 | % \begin{demo}{Old-style underscores} | |
140 | %Typing long underscore-filled | |
141 | %names, like big\_function\_name, | |
142 | %is normally tedious. The normal | |
143 | %positioning of the underscore | |
144 | %is wrong, too. | |
145 | % \end{demo} | |
146 | % \endgroup | |
147 | % | |
148 | % The \syn\ package redefines the |\_| command to draw a more attractive | |
149 | % underscore character. It also allows you to use the |_|~character | |
150 | % directly to produce an underscore outside of maths mode: |_|~behaves | |
151 | % as a subscript character as usual inside maths mode. | |
152 | % | |
153 | % \begin{demo}{New \syn\ underscores} | |
154 | %You can use underscore-filled | |
155 | %names, like big_function_name, | |
156 | %simply and naturally. Of | |
157 | %course, subscripts still work | |
158 | %normally in maths mode, e.g., | |
159 | %$x_i$. | |
160 | % \end{demo} | |
161 | % | |
162 | % \subsection{Typesetting syntactic items} | |
163 | % \begin{synshorts} | |
164 | % | |
165 | % The \syn\ package provides some simple commands for typesetting syntactic | |
166 | % items. | |
167 | % | |
168 | % \DescribeMacro\synt | |
169 | % Typing "\\synt{"<text>"}" typesets <text> as a \lq non-terminal', | |
170 | % in italics and surrounded by angle brackets. If you use "\\synt" a lot, | |
171 | % you can use the incantation | |
172 | % \begin{listing} | |
173 | %\def\<#1>{\synt{#1}} | |
174 | % \end{listing} | |
e8e9e5d8 | 175 | % to allow you to type "\\<"<text>">" as an alternative to |
86f6a31e | 176 | % "\\synt{"<text>"}". |
177 | % | |
178 | % \DescribeMacro\lit | |
179 | % You can also display literal text, which the reader should type directly, | |
180 | % using the "\\lit" command. | |
181 | % | |
182 | % \begin{demo}{Use of \cmd\lit} | |
183 | %Type \lit{ls} to display a | |
184 | %list of files. | |
185 | % \end{demo} | |
186 | % | |
187 | % Note that the literal text appears in quotes. To suppress the quotes, | |
188 | % use the `*' variant. | |
189 | % | |
190 | % The "\\lit" command produces slightly better output than "\\verb" for | |
191 | % running text, since the spaces are somewhat narrower. However, "\\verb" | |
192 | % allows you to type arbitrary characters, which are treated literally, | |
193 | % whereas you must use commands such as "\\{" to use special characters | |
194 | % within the argument to "\\lit". Of course, you can use "\\lit" anywhere | |
195 | % in the document: "\\verb" mustn't be used inside a command argument. | |
196 | % \end{synshorts} | |
197 | % | |
198 | % \subsection{Abbreviated forms for syntactic items} | |
199 | % | |
200 | % It would be very tedious to require the use of commands like |\synt| | |
201 | % when building syntax descriptions like BNF grammars. It would also make | |
202 | % your \LaTeX\ source hard to read. Therefore, \syn\ provides some | |
203 | % abbreviated forms which make typesetting syntax quicker and easier. | |
204 | % | |
205 | % Since the abbreviated forms use several characters which you may want to | |
206 | % use in normal text, they aren't enabled by default. They only work | |
207 | % with special commands and environments provided by the \syn\ package. | |
208 | % | |
209 | % The abbreviated forms are shown in the table below: | |
210 | % | |
211 | % \begin{tab}[\synshorts]{ll} \hline | |
212 | % \bf Input & \bf Output \\ \hline | |
213 | % "<some text>" & <some text> \\ | |
214 | % "`some text'" & `some text' \\ | |
215 | % "\"some text\"" & "some text" \\ \hline | |
216 | % \end{tab} | |
217 | % | |
218 | % Within one of these abbreviated forms, text is treated more-or-less | |
219 | % verbatim: | |
220 | % \begin{itemize} | |
221 | % | |
222 | % \item Any |$|, |%|, |^|, |&|, |{|, |}|, |~| or |#| characters are treated | |
223 | % literally: their normal special meanings are ignored. | |
224 | % | |
225 | % \item Other special characters, with the exception of |\|, are also treated | |
226 | % literally: this includes any characters made special by |\shortverb|. | |
227 | % | |
228 | % \end{itemize} | |
229 | % | |
230 | % However, the |\| character retains its meaning. Since the brace | |
231 | % characters are not recognised, most commands can't be used within | |
232 | % abbreviated forms. However, you can use special commands to type some | |
233 | % of the remaining special characters: | |
234 | % | |
235 | % \begin{tab}[\synshorts]{ll} \hline | |
236 | % \bf Command & \bf Result \\ \hline | |
237 | % "\\\\" & A `\\' character \\ | |
238 | % "\\>" & A `>' character \\ | |
239 | % "\\'" & A `\'' character \\ | |
240 | % "\\\"" & A `"' character \\ | |
241 | % "\\\ " & A `\ ' character (not a space) \\ \hline | |
242 | % \end{tab} | |
243 | % | |
244 | % Note that |\\|, |\>|, |\"| and \verb*|\ | are only useful in a |\tt| font, | |
245 | % i.e., inside |`...'| and |"..."| forms, since the characters don't exist | |
246 | % in normal fonts. The |\>|, |\"| and |\'| commands are only provided so | |
247 | % you can use these characters within |<...>|, |"..."| and |`...'| forms | |
248 | % respectively: in the other forms, there is no need to use the special | |
249 | % command. | |
250 | % | |
251 | % In addition, when the above abbreviations are enabled, the character "|" | |
252 | % is set to typeset a \syntax{|} symbol, which is conventionally used to | |
253 | % separate alternatives in syntax descriptions. | |
254 | % | |
255 | % \DescribeMacro\syntax | |
256 | % Normally, these abbreviated forms are enabled only within special | |
257 | % environments, such as \env{grammar} and \env{syntdiag}. To use them | |
258 | % in running text, use the |\syntax| command. The abbreviations are made | |
259 | % active within the argument of the |\syntax| command.\footnote{^^A | |
260 | % The argument of the \cmd\syntax\ command may contain commands such | |
261 | % as \cmd\verb, which are normally not allowed within arguments. | |
262 | % } Note that you cannot use the |\syntax| command within the argument | |
263 | % of another command. | |
264 | % | |
265 | % \DescribeMacro\synshorts | |
266 | % \DescribeEnv{synshorts} | |
267 | % You can also enable the syntax shortcuts using the |\synshorts| declaration | |
268 | % or the \env{synshorts} environment. This enables the syntax shortcuts | |
269 | % until the scope of the declaration ends. | |
270 | % | |
271 | % \DescribeMacro\synshortsoff | |
272 | % If syntax shortcuts are enabled, you can disable them using the | |
273 | % |\synshortsoff| declaration. | |
274 | % | |
275 | % \subsection{The \env{grammar} environment} | |
276 | % | |
277 | % \DescribeEnv{grammar} | |
278 | % For typesetting formal grammars, for example, of programming languages, | |
279 | % the \syn\ package provides a \env{grammar} environment. Within this | |
280 | % environment, the abbreviated forms described above are enabled. | |
281 | % | |
282 | % Within the environment, separate production rules should be separated by | |
283 | % blank lines. You can use the normal |\\| command to perform line-breaking | |
284 | % of a production rule. Note that a production rule must begin with a | |
285 | % nonterminal name enclosed in angle brackets (|<| \dots |>|), followed by | |
88ddb950 MW |
286 | % any decorative material, whitespace, some kind of production operator |
287 | % (usually `::=') and then some more whitespace. You can control how this | |
288 | % text is actually typeset, however. | |
86f6a31e | 289 | % |
290 | % \DescribeMacro{\[[} | |
291 | % \DescribeMacro{\]]} | |
292 | % You can use syntax diagrams (see below) instead of a straight piece of BNF | |
e8e9e5d8 | 293 | % by enclosing it in a |\[[| \dots |\]]| pair. Note that you can't mix |
86f6a31e | 294 | % syntax diagrams and BNF in a production rule, and you will get something |
295 | % which looks very strange if you try. | |
296 | % | |
297 | % \DescribeMacro\alt | |
298 | % In addition, a command |\alt| is provided for splitting long production | |
299 | % rules over several lines: the |\alt| command starts a new line and places | |
300 | % a \syntax{|} character slightly in the left margin. This is useful when | |
301 | % a symbol has many alternative productions. | |
302 | % | |
303 | % \begin{demo}[w]{The \env{grammar} environment} | |
304 | %\begin{grammar} | |
305 | %<statement> ::= <ident> `=' <expr> | |
306 | % \alt `for' <ident> `=' <expr> `to' <expr> `do' <statement> | |
307 | % \alt `{' <stat-list> `}' | |
308 | % \alt <empty> | |
309 | % | |
310 | %<stat-list> ::= <statement> `;' <stat-list> | <statement> | |
311 | %\end{grammar} | |
312 | % \end{demo} | |
313 | % | |
314 | % You can modify the appearance of grammars using three length parameters: | |
315 | % | |
316 | % \begin{description} \def\makelabel{\hskip\labelsep\cmd} | |
317 | % | |
318 | % \item [\grammarparsep] is the amount of space inserted between production | |
319 | % rules. It is a rubber length whose default value is 8\,pt, with | |
320 | % 1\,pt of stretch and shrink. | |
321 | % | |
322 | % \item [\grammarindent] is the amount by which the right hand side of a | |
323 | % production rule is indented from the left margin. It is a rigid | |
324 | % length. Its default value is 2\,em. | |
325 | % | |
326 | % \end{description} | |
327 | % | |
88ddb950 | 328 | % \DescribeMacro\grammarlabelx |
86f6a31e | 329 | % You can also control how the `label' is typeset by redefining the |
88ddb950 MW |
330 | % |\grammarlabelx| command. The command is given three arguments: the name |
331 | % of the nonterminal (which was enclosed in angle brackets), the following | |
332 | % decorative material, and the `production operator'. The command is | |
333 | % expected to produce the label. By default, it typesets the nonterminal | |
334 | % name using |\synt| followed by the decoration, and the operator, at | |
335 | % opposite ends of the label, separated by an |\hfill|. | |
336 | % | |
337 | % \DescribeMacro\grammarlabel | |
338 | % For compatibility, if there is no decorative material, the macro | |
339 | % |\grammarlabel| is called instead, with just two arguments: the nonterminal | |
340 | % name and the operator. The default implementation of |\grammarlabel| just | |
341 | % calls |\grammarlabelx| with empty decoration. | |
86f6a31e | 342 | % |
343 | % \subsection{Syntax diagrams} | |
344 | % | |
345 | % A full formal BNF grammar can be somewhat overwhelming for less technical | |
346 | % readers. Documents aimed at such readers tend to display grammatical | |
347 | % structures as \emph{syntax diagrams}. | |
348 | % | |
349 | % \DescribeEnv{syntdiag} | |
350 | % A syntax diagram is always enclosed in a \env{syntdiag} environment. You | |
351 | % should think of the environment as enclosing a new sort of \LaTeX\ mode: | |
352 | % trying to type normal text into a syntax diagram will result in very ugly | |
353 | % output. \LaTeX\ ignores spaces and return characters while in syntax | |
354 | % diagram mode. | |
355 | % | |
356 | % The syntax of the environment is very simple: | |
357 | % | |
358 | % \begin{grammar} | |
359 | % <synt-diag-env> ::= \[[ | |
360 | % "\\begin{syntdiag}" | |
361 | % \begin{stack} \\ "[" <decls> "]" \end{stack} | |
362 | % <text> | |
363 | % "\\end{syntdiag}" | |
364 | % \]] | |
365 | % \end{grammar} | |
366 | % | |
367 | % The \<decls> contain any declarations you want to insert, to control | |
368 | % the environment. The parameters to tweak are described below. | |
369 | % | |
370 | % Within a syntax diagram, you can include syntactic items using the | |
371 | % abbreviated forms described elsewhere. The output from these forms is | |
372 | % modified slightly in syntax diagram mode so that the diagram looks | |
373 | % right. | |
374 | % | |
375 | % I probably ought to point out now that the syntax diagram typesetting | |
376 | % commands produce beautiful-looking diagrams with all the rules and curves | |
377 | % accurately positioned. Some device drivers don't position these objects | |
378 | % correctly in their output. I've had particular trouble with |dvips|. I'll | |
379 | % say it again: it's not my fault! | |
380 | % | |
381 | % \DescribeEnv{syntdiag*} | |
382 | % The \env{syntdiag} environment only works in paragraph mode, and it acts | |
383 | % rather like a paragraph, splitting over several lines when appropriate. | |
384 | % If you just want to typeset a snippet of a syntax diagram, you can | |
385 | % use the starred environment \env{syntdiag$*$}. | |
386 | % | |
387 | % \begin{grammar} | |
388 | % <synt-diag-star-env> ::= \[[ | |
389 | % "\\begin{syntdiag*}" | |
390 | % \begin{stack} \\ "[" <decls> "]" \end{stack} | |
391 | % \begin{stack} \\ "[" <width> "]" \end{stack} | |
392 | % <text> | |
393 | % "\\end{syntdiag*}" | |
394 | % \]] | |
395 | % \end{grammar} | |
396 | % | |
397 | % When typesetting little demos like this, it's not normal to fully adorn | |
398 | % the syntax diagram with the full double arrows | |
399 | % (`\begin{syntdiag*}[\left{>>-}\right{-><}]\tok{$\cdots$}\end{syntdiag*}'). | |
400 | % The two declarations \syntax{"\\left{"<arrow>"}" and "\\right{"<arrow>"}"} | |
401 | % allow you to choose the arrows on each side of the syntax diagram snippet. | |
402 | % The possible values of \<arrow> are shown in the table-ette below: | |
403 | % | |
404 | % ^^A Time to remember what I learned about tables while writing mdwtab. | |
405 | % ^^A Just for the embarassment factor, here's the number of attempts I | |
406 | % ^^A took to get the table below to look right: __6. Hmm... not as bad | |
407 | % ^^A as I expected. Most of them were fine-tuning things. | |
408 | % | |
eafdddad MW |
409 | % \medskip ^^A Leave a vertical gap |
410 | % \hbox to\columnwidth{\hfil\vbox{\tabskip=0pt ^^A Centre it horizontally | |
411 | % \sdsize \csname sd@setsize\endcsname ^^A Position syntdiag arrows | |
412 | % \halign to .5\columnwidth{ ^^A Set the table width | |
86f6a31e | 413 | % &\ttfamily\ignorespaces#\unskip\hfil\tabskip=0pt ^^A Typeset the name |
eafdddad MW |
414 | % &\quad\csname sd@arr@#\endcsname\hfil ^^A Typeset the arrow |
415 | % &\setbox0=\hbox{#}\tabskip=0pt plus 1fil\cr ^^A Stretch between columns | |
86f6a31e | 416 | % >>-&>>-& &>-&>-& &->&->\cr |
417 | % -><&-><& &...&...& &-&-\cr | |
eafdddad MW |
418 | % }}\hfil} ^^A Close the boxing |
419 | % \medskip ^^A And leave another gap | |
86f6a31e | 420 | % |
421 | % These declarations should be used only in the optional argument to the | |
422 | % \env{syntdiag$*$} command. The second optional argument to the | |
423 | % environment, if specified, fixes the width of the syntax diagram snippet; | |
424 | % if you omit this argument, the diagram is made just wide enough to | |
425 | % fit everything in. | |
426 | % | |
427 | % \begin{figure} | |
428 | % \begin{demo}[w]{Example of \env{syntdiag$*$}} | |
429 | %\newcommand{\bs}[2]{% | |
430 | % \begin{minipage}{1.6in}% | |
431 | % \begin{syntdiag*}[\left{#1}\right{#2}][1.6in]% | |
432 | %} | |
433 | %\newcommand{\es}{\end{syntdiag*}\end{minipage}} | |
434 | % | |
435 | %\begin{center} | |
436 | %\begin{tabular}{cl} \\ \hline | |
437 | %\bf Construction & \bf Meaning \\ \hline | |
438 | %\bs {>>-} {...} \es & Start of syntax diagram \\ | |
439 | %\bs {...} {-><} \es & End of syntax diagram \\ | |
440 | %\bs {>-} {...} \es & Continued on next line \\ | |
441 | %\bs {...} {->} \es & Continued from previous line \\ \hline | |
442 | %\bs {...} {...} | |
443 | % \begin{stack} <option-a> \\ <option-b> \\ <option-c> \end{stack} | |
444 | %\es & Alternatives: choose any one \\ | |
445 | %\bs {...} {...} | |
446 | % \begin{rep} <repeat-me> \\ <separator> \end{rep} | |
447 | %\es & One or more items, with separators \\ \hline | |
448 | %\end{tabular} | |
449 | %\end{center} | |
450 | % \end{demo} | |
451 | % \end{figure} | |
452 | % | |
453 | % \DescribeMacro\tok | |
454 | % You can also include text using the |\tok| command. The argument of this | |
e8e9e5d8 | 455 | % command is typeset in \LaTeX's LR~mode and inserted into the diagram. |
86f6a31e | 456 | % Syntax abbreviations are allowed within the argument, so you can, for |
457 | % example, include textual descriptions like | |
458 | % \begin{listing} | |
459 | %\tok{any <char> except `"'} | |
460 | % \end{listing} | |
461 | % | |
462 | % \DescribeEnv{stack} | |
463 | % Within a syntax diagram, a choice between several different items is | |
464 | % shown by stacking the alternatives vertically. In \LaTeX, this is done | |
465 | % by enclosing the items in a \env{stack} environment. Each individual item | |
466 | % is separated by |\\| commands, as in the \env{array} and \env{tabular} | |
467 | % environments. Each row may contain any syntax diagram material, including | |
468 | % |\tok| commands and other \env{stack} environments. | |
469 | % | |
470 | % Note if you end a \env{stack} environment with a |\\| command, a blank | |
471 | % row is added to the bottom of the stack, indicating that none of the items | |
472 | % need be specified. | |
473 | % | |
474 | % \DescribeEnv{rep} | |
475 | % Text which can be repeated is enclosed in a \env{rep} environment: the | |
476 | % text is displayed with a backwards pointing arrow drawn over it, showing | |
477 | % that it may be repeated. Optionally, you can specify text to be | |
478 | % displayed in the arrow, separating it from the main text with a |\\| | |
479 | % command. | |
480 | % | |
481 | % Note that items on the backwards arrow of a \env{rep} construction should | |
482 | % be displayed \emph{backwards}. You must put the individual items in | |
e8e9e5d8 | 483 | % reverse order when building this part of your diagrams. \syn\ will |
86f6a31e | 484 | % correctly reverse the arrows on \env{rep} structures, but apart from |
485 | % this, you must cope on your own. You are recommended to keep these parts | |
486 | % of your diagrams as simple as possible to avoid confusing readers. | |
487 | % | |
488 | % \begin{demo}[w]{A syntax diagram} | |
489 | %\begin{syntdiag} | |
490 | %<ident> `(' | |
491 | % \begin{rep} \begin{stack} \\ | |
492 | % <type> \begin{stack} \\ <ident> \end{stack} | |
493 | % \end{stack} \\ `,' \end{rep} | |
494 | %\begin{stack} \\ `...' \end{stack} `)' | |
495 | %\end{syntdiag} | |
496 | % \end{demo} | |
497 | % | |
498 | % \DescribeMacro\( | |
499 | % \DescribeMacro\) | |
500 | % \DescribeMacro\< | |
501 | % \DescribeMacro\> | |
502 | % \DescribeMacro\[ | |
503 | % \DescribeMacro\] | |
504 | % The environments \env{stack} and \env{rep} are rather cumbersome to use. | |
505 | % As an alternative, the commands |\(| and |\)| are equivalent to | |
506 | % |\begin{stack}| and |\end{stack}| respectively, and |\<| and |\>| are | |
507 | % equivalent to |\begin{rep}| and |\end{rep}|. Also, |\[| and |\]| are | |
508 | % like |\begin{stack}| and |\end{stack}| except that an empty initial row is | |
509 | % implicitly added. | |
510 | % | |
511 | % \subsubsection{Line breaking in syntax diagrams} | |
512 | % | |
513 | % Syntax diagrams are automatically broken over lines and across pages. | |
514 | % Lines are only broken between items on the outermost level of the diagram: | |
515 | % i.e., not within \env{stack} or \env{rep} environments. | |
516 | % | |
517 | % You can force a line break at a particular place by using the |\\| command | |
518 | % as usual. This supports all the usual \LaTeX\ features: a `|*|' variant | |
519 | % which prohibits page breaking, and an optional argument specifying the | |
520 | % extra vertical space between lines. | |
521 | % | |
522 | % \subsubsection{Customising syntax diagrams} | |
523 | % | |
524 | % There are two basic styles of syntax diagrams supported: | |
525 | % | |
526 | % \begin{description} | |
527 | % | |
528 | % \item [square] Lines in the syntax diagram join at squared-off corners. | |
529 | % This appears to be the standard way of displaying syntax diagrams | |
530 | % in IBM manuals, and most other documents I've seen. | |
531 | % | |
532 | % \item [rounded] Lines curve around corners. Also, no arrows are drawn | |
533 | % around repeating loops: the curving of the lines provides this | |
534 | % information instead. This style is used in various texts on | |
535 | % Pascal, and appears to be more popular in academic circles. | |
536 | % | |
537 | % \end{description} | |
538 | % | |
539 | % You can specify the style you want to use for syntax diagrams by giving | |
540 | % the style name as an option on the |\usepackage| command. For example, | |
541 | % to force rounded edges to be used, you could say | |
542 | % | |
543 | % \begin{listing} | |
544 | %\usepackage[rounded]{syntax} | |
545 | % \end{listing} | |
546 | % | |
547 | % \DescribeMacro\sdsize | |
548 | % \DescribeMacro\sdlengths | |
549 | % The \env{syntdiag} environment takes an option argument, which should | |
550 | % contain declarations which are obeyed while the environment is set up. | |
551 | % The default value of this argument is `|\sdsize\sdlengths|'. The | |
552 | % |\sdsize| command sets the default type size for the environment: this is | |
553 | % normally |\small|. |\sdlengths| sets the values of the length parameters | |
554 | % used by the environment based on the current text size. These parameters | |
555 | % are described below. | |
556 | % | |
557 | % For example, if you wanted to reduce the type size of the diagrams still | |
558 | % further, you could use the command | |
559 | % \begin{listing} | |
560 | %\begin{syntdiag}[\tiny\sdlengths] | |
561 | % \end{listing} | |
562 | % | |
563 | % The following length parameters may be altered: | |
564 | % | |
565 | % \begin{description} \def\makelabel{\hskip\labelsep\cmd} | |
566 | % | |
567 | % \item [\sdstartspace] The length of the rule between the arrows which | |
568 | % begin each line of the syntax diagram and the first item on the line. | |
569 | % Note that most objects have some space on either side of them as | |
570 | % well. This is a rubber length. Its default value is 1\,em, although | |
571 | % it can shrink by up to 10\,pt. | |
572 | % | |
573 | % \item [\sdendspace] The length of the rule between the last item on a | |
574 | % line and the arrow at the very end. Note that the final line also | |
575 | % has extra rubber space on the end. This is a rubber length. Its | |
576 | % default value is 1\,em, although it will shrink by up to 10\,pt. | |
577 | % | |
578 | % \item [\sdmidskip] The length of the rule on either side of a large | |
579 | % construction (either a \env{stack} or a \env{rep}). It is a rubber | |
580 | % length. Its default value is \smallf 1/2\,em, with a very small | |
581 | % amount of infinite stretch. | |
582 | % | |
583 | % \item [\sdtokskip] The length of the rule on either side of a |\tok| | |
584 | % item or syntax abbreviation. It is a rubber length. Its default | |
585 | % value is \smallf 1/4\,em, with a very small amount of inifnite | |
586 | % stretch. | |
587 | % | |
588 | % \item [\sdfinalskip] The length of the rule which finishes the last line | |
589 | % of a syntax diagram. It is a rubber length. Its default value is | |
590 | % \smallf 1/2\,em, with 10000\,fil of stretch, which will left-align | |
591 | % the items on the line.\footnote{^^A | |
592 | % This is a little \TeX nical. The idea is that if a stray 1\,fil | |
593 | % of stretch is added to the end of the line, it won't be noticed. | |
594 | % However, the alignment of the text on the line can still be | |
595 | % modified using \cmd{\sd@rule}\cmd{\hfill}, if you're feeling | |
596 | % brave. | |
597 | % } | |
598 | % | |
599 | % \item [\sdrulewidth] Half the width of the rules used in the diagram. | |
600 | % It is a rigid length. Its default value is 0.2\,pt. | |
601 | % | |
602 | % \item [\sdcirclediam] The diameter of the circle from which the quadrants | |
603 | % used in rounded-style diagrams are taken. This must be a multiple | |
604 | % of 4\,pt, or else the lines on the diagram won't match up. | |
605 | % | |
606 | % \end{description} | |
607 | % | |
608 | % In addition, you should call |\sdsetstrut| passing it the total height | |
609 | % (\({\rm height}+{\rm depth}\)) of a normal line of text at the current | |
610 | % size. Normally, the value of |\baselineskip| will be appropriate. | |
611 | % | |
612 | % You can also alter the appearance of \env{stack}s and \env{rep}s by using | |
613 | % their optional positioning arguments. By default, \env{stack}s descend | |
e8e9e5d8 | 614 | % below the main line of the diagram, and \env{rep}s extend above it. |
86f6a31e | 615 | % Specifying an optional argument of |[b]| for either environment reverses |
616 | % this, putting \env{stack}s above and \env{rep}s below the line. | |
617 | % | |
618 | % \subsection{Changing the presentation styles} | |
619 | % | |
620 | % You can change the way in which the syntax items are typeset by altering | |
621 | % some simple commands (using |\renewcommand|). Each item (nonterminals, | |
622 | % as typeset by |\synt|, and quoted and unquoted terminals, as typeset by | |
623 | % |\lit| and |\lit*|) has two style commands associated with it, as shown | |
624 | % in the table below. | |
625 | % | |
eafdddad MW |
626 | % \begin{tab}{lll} \hline |
627 | % \bf Syntax item & \bf Left command & \bf Right command \\ \hline | |
628 | % Nonterminals & |\syntleft| & |\syntright| \\ | |
629 | % Quoted terminals & |\litleft| & |\litright| \\ | |
630 | % Unquoted terminals & |\ulitleft| & |\ulitright| \\ \hline | |
86f6a31e | 631 | % \end{tab} |
632 | % | |
633 | % It's not too hard to see how this works. For example, if you look at | |
634 | % the implementation for |\syntleft| and |\syntright| in the implementation | |
635 | % section, you'll notice that they're defined like this: | |
636 | % \begin{listing} | |
637 | %\newcommand{\syntleft}{$\langle$\normalfont\itshape} | |
638 | %\newcommand{\syntright}{$\rangle$} | |
639 | % \end{listing} | |
640 | % I think this is fairly simple, if you understand things like font changing. | |
641 | % | |
642 | % Note that changing these style commands alters the appearance of all syntax | |
643 | % objects of the appropriate types, as created by the |\synt| and |\lit| | |
644 | % commands, in \env{grammar} environments, and in syntax diagrams. | |
645 | % | |
646 | % | |
86f6a31e | 647 | % \implementation |
648 | % | |
649 | % \section{Implementation of \syn} | |
650 | % | |
651 | % \begin{macrocode} | |
652 | %<*package> | |
653 | % \end{macrocode} | |
654 | % | |
655 | % \subsection{Options handling} | |
656 | % | |
657 | % We define all the options we know about, and then see what's been put | |
658 | % on the usepackage line. | |
659 | % | |
660 | % The options we provide currently are as follows: | |
661 | % | |
662 | % \begin{description} | |
663 | % \item [rounded] draws neatly rounded edges on the diagram. | |
664 | % \item [square] draws squared-off edges on the diagram. This is the | |
665 | % default. | |
666 | % \item [nounderscore] disables the undescore active character, The |\_| | |
667 | % command still produces the nice version created here. | |
668 | % \end{description} | |
669 | % | |
670 | % \begin{macrocode} | |
671 | \DeclareOption{rounded}{\sd@roundtrue} | |
672 | \DeclareOption{square}{\sd@roundfalse} | |
673 | \DeclareOption{nounderscore}{\@uscorefalse} | |
674 | % \end{macrocode} | |
675 | % | |
676 | % Now process the options: | |
677 | % | |
678 | % \begin{macrocode} | |
679 | \newif\ifsd@round | |
680 | \newif\if@uscore\@uscoretrue | |
681 | \newif\ifsd@left\newif\ifsd@right | |
682 | \ExecuteOptions{square} | |
683 | \ProcessOptions | |
684 | % \end{macrocode} | |
685 | % | |
686 | % \subsection{Special character handling} | |
687 | % | |
688 | % A lot of the \syn\ package requires the use special active characters. | |
689 | % These must be added to two lists: |\dospecials|, which is used by |\verb| | |
690 | % and friends, and |\@sanitize|, which is used by |\index|. The two macros | |
691 | % here, |\addspecial| and |\remspecial|, provide these registration | |
692 | % facilities. | |
693 | % | |
694 | % Two similar macros are found in Frank Mittelbach's \package{doc} package: | |
695 | % these have the disadvantage of global operation. My macros here are based | |
696 | % on Frank's, which in turn appear to be based on Donald Knuth's list | |
697 | % handling code presented in Appendix~D of \textit{The \TeX book}. | |
698 | % | |
699 | % Both these macros take a single argument: a single-character control | |
700 | % sequence containing the special character to be added to or removed from | |
701 | % the lists. | |
702 | % | |
703 | % \begin{macro}{\addspecial} | |
704 | % | |
705 | % This is reasonably straightforward. We remove the sequence from the lists, | |
706 | % in case it's already there, and add it in in the obvious way. This | |
707 | % requires a little bit of fun with |\expandafter|. | |
708 | % | |
709 | % \begin{macrocode} | |
710 | \def\addspecial#1{% | |
711 | \remspecial{#1}% | |
712 | \expandafter\def\expandafter\dospecials\expandafter{\dospecials\do#1}% | |
713 | \expandafter\def\expandafter\@santize\expandafter{% | |
714 | \@sanitize\@makeother#1}% | |
715 | } | |
716 | % \end{macrocode} | |
717 | % | |
718 | % \end{macro} | |
719 | % | |
720 | % \begin{macro}{\remspecial} | |
721 | % | |
722 | % This is the difficult bit. Since |\dospecials| and |\@sanitize| have the | |
723 | % form of list macros, we can redefine |\do| and |\@makeother| to do the | |
724 | % job for us. We must be careful to put the old meaning of |\@makeother| | |
725 | % back. The current implementation assumes it knows what |\@makeother| does. | |
726 | % | |
727 | % \begin{macrocode} | |
728 | \def\remspecial#1{% | |
729 | \def\do##1{\ifnum`#1=`##1 \else\noexpand\do\noexpand##1\fi}% | |
730 | \edef\dospecials{\dospecials}% | |
731 | \def\@makeother##1{\ifnum`#1=`##1 \else% | |
732 | \noexpand\@makeother\noexpand##1\fi}% | |
733 | \edef\@sanitize{\@sanitize}% | |
734 | \def\@makeother##1{\catcode`##112}% | |
735 | } | |
736 | % \end{macrocode} | |
737 | % | |
738 | % \end{macro} | |
739 | % | |
740 | % \subsection{Underscore handling} | |
741 | % | |
742 | % When typing a lot of identifiers, it can be irksome to have to escape | |
743 | % all `|_|' characters in the manuscript. We make the underscore character | |
744 | % active, so that it typesets an underscore in horizontal mode, and does | |
745 | % its usual job as a subscript operator in maths mode. Underscore must | |
746 | % already be in the special character lists, because of its use as a | |
747 | % subscript character, so this doesn't cause us a problem. | |
748 | % | |
749 | % \begin{macro}{\underscore} | |
750 | % | |
751 | % The |\underscore| macro typesets an underline character, using a horizontal | |
752 | % rule. This is positioned slightly below the baseline, and is also slightly | |
753 | % wider than the default \TeX\ underscore. This code is based on a similar | |
754 | % implementation found in the \package{lgrind} package. | |
755 | % | |
756 | % \begin{macrocode} | |
757 | \def\underscore{% | |
758 | \leavevmode% | |
759 | \kern.06em% | |
760 | \vbox{% | |
761 | \hrule\@width.6em\@depth.4ex\@height-.34ex% | |
762 | }% | |
763 | \ifdim\fontdimen\@ne\font=\z@% | |
764 | \kern.06em% | |
765 | \fi% | |
766 | } | |
767 | % \end{macrocode} | |
768 | % | |
769 | % \end{macro} | |
770 | % | |
771 | % \begin{macro}{\@foundunderscore} | |
772 | % | |
773 | % This macro is called by the `|_|' active character to sort out what to do. | |
774 | % | |
775 | % If this is maths mode, we use the |\sb| macro, which is already defined | |
776 | % to do subscripting. Otherwise, we call |\textunderscore|, which picks the | |
777 | % nicest underscore it can find. | |
778 | % | |
779 | % There's some extra cunningness here, because I'd like to be able to | |
780 | % hyphenate after underscores usually, but not when there's another one | |
781 | % following. And then, because \env{tabbing} redefines |\_|, there's some | |
782 | % more yukkiness to handle that: the usual |\@tabacckludge| mechanism doesn't | |
783 | % cope with this particular case. | |
784 | % | |
785 | % \begin{macrocode} | |
786 | \let\usc@builtindischyphen\- | |
787 | \def\@uscore.{% | |
788 | \ifmmode% | |
789 | \expandafter\@firstoftwo% | |
790 | \else% | |
791 | \expandafter\@secondoftwo% | |
792 | \fi% | |
793 | \sb% | |
794 | {\textunderscore\@ifnextchar_{}{\usc@builtindischyphen}}% | |
795 | } | |
796 | % \end{macrocode} | |
797 | % | |
798 | % \end{macro} | |
799 | % | |
800 | % Now we set up the active character. Note the |\protect|, which makes | |
801 | % underscores work reasonably well in moving arguments. Note also the way | |
802 | % we end with a some funny stuff to prevent spaces being lost if this is | |
803 | % written to a file. | |
804 | % | |
805 | % \begin{macrocode} | |
806 | \if@uscore | |
807 | \AtBeginDocument{% | |
808 | \catcode`\_\active% | |
809 | \begingroup% | |
810 | \lccode`\~`\_% | |
811 | \lowercase{\endgroup\def~{\protect\@uscore.}}% | |
812 | } | |
813 | \fi | |
814 | % \end{macrocode} | |
815 | % | |
816 | % Finally, we redefine the |\_| macro to use our own |\underscore|, because | |
817 | % it's prettier. Actually, we don't: we just redefine the | |
818 | % |\?\textunderscore| command (funny name, isn't it?). | |
819 | % | |
820 | % \begin{macrocode} | |
821 | \expandafter\let\csname?\string\textunderscore\endcsname\underscore | |
822 | % \end{macrocode} | |
823 | % | |
824 | % \subsection{Abbreviated verbatim notation} | |
825 | % | |
826 | % In similar style to the \package{doc} package, we allow the user to set up | |
827 | % characters which delimit verbatim text. Unlike \package{doc}, we make | |
828 | % such changes local to the current group. This is performed through the | |
829 | % |\shortverb| and |\unverb| commands. | |
830 | % | |
831 | % The implementations of these commands are based upon the |\MakeShortVerb| | |
832 | % and |\DeleteShortVerb| commands of the \package{doc} package, although | |
833 | % these versions have effect local to the current grouping level. This | |
834 | % prevents their redefinition of |\dospecials| from interfering with the | |
835 | % grammar shortcuts, which require local changes only. | |
836 | % | |
837 | % The command |\shortverb| takes a single argument: a single-character | |
838 | % control sequence defining which character to make into the verbatim text | |
839 | % delimiter. We store the old meaning of the active character in a control | |
840 | % sequence called |\mn@\|\<char>. Note that this control sequence | |
841 | % contains a backslash character, which is a little odd. We also define a | |
842 | % command |\cc@\|\<char> which will return everything to normal. This | |
843 | % is used by the |\unverb| command. | |
844 | % | |
845 | % \begin{macro}{\shortverb} | |
846 | % | |
847 | % Here we build the control sequences we need to make everything work nicely. | |
848 | % The active character is defined via |\lowercase|, using the |~| character: | |
849 | % this is already made active by \TeX\@. | |
850 | % | |
851 | % The actual code requires lots of fiddling with |\expandafter| and friends. | |
852 | % | |
853 | % \begin{macrocode} | |
854 | \def\shortverb#1{% | |
855 | % \end{macrocode} | |
856 | % | |
857 | % First, we check to see if the command |\cc@\|\<char> has been defined. | |
858 | % | |
859 | % \begin{macrocode} | |
860 | \@ifundefined{cc@\string#1}{% | |
861 | % \end{macrocode} | |
862 | % | |
863 | % If it hasn't been defined, we add the character to the specials list. | |
864 | % | |
865 | % \begin{macrocode} | |
866 | \addspecial#1% | |
867 | % \end{macrocode} | |
868 | % | |
869 | % Now we set our character to be the lowercase version of |~|, which allows | |
870 | % us to use it, even though we don't know what it is. | |
871 | % | |
872 | % \begin{macrocode} | |
873 | \begingroup% | |
874 | \lccode`\~`#1% | |
875 | % \end{macrocode} | |
876 | % | |
877 | % Finally, we reach the tricky bit. All of this is lowercased, so any | |
878 | % occurrences of |~| are replaced by the user's special character. | |
879 | % | |
880 | % \begin{macrocode} | |
881 | \lowercase{% | |
882 | \endgroup% | |
883 | % \end{macrocode} | |
884 | % | |
885 | % We remember the current meaning of the character, in case it has one. We | |
886 | % have to use |\csname| to build the rather strange name we use for this. | |
887 | % | |
888 | % \begin{macrocode} | |
889 | \expandafter\let\csname mn@\string#1\endcsname~% | |
890 | % \end{macrocode} | |
891 | % | |
892 | % Now we build |\cc@\|\<char>. This is done with |\edef|, since more | |
893 | % of this needs to be expanded now than not. In this way, the actual macros | |
894 | % we create end up being very short. | |
895 | % | |
896 | % \begin{macrocode} | |
897 | \expandafter\edef\csname cc@\string#1\endcsname{% | |
898 | % \end{macrocode} | |
899 | % | |
900 | % First, add a command to restore the character's old catcode. | |
901 | % | |
902 | % \begin{macrocode} | |
903 | \catcode`\noexpand#1\the\catcode`#1% | |
904 | % \end{macrocode} | |
905 | % | |
906 | % Now we restore the character's old meaning, using the version we saved | |
907 | % earlier. | |
908 | % | |
909 | % \begin{macrocode} | |
910 | \let\noexpand~\expandafter\noexpand% | |
911 | \csname mn@\string#1\endcsname% | |
912 | % \end{macrocode} | |
913 | % | |
914 | % Now we remove the character from the specials lists. | |
915 | % | |
916 | % \begin{macrocode} | |
917 | \noexpand\remspecial\noexpand#1% | |
918 | % \end{macrocode} | |
919 | % | |
920 | % Finally, we delete this macro, so that |\unverb| will generate a warning | |
921 | % if the character is |\unverb|ed again. | |
922 | % | |
923 | % \begin{macrocode} | |
924 | \let\csname cc@\string#1\endcsname\relax% | |
925 | }% | |
926 | % \end{macrocode} | |
927 | % | |
928 | % All of that's over now. We set up the new definition of the character, | |
929 | % in terms of |\verb|, and make the character active. The nasty |\syn@ttspace| | |
930 | % is there to make the spacing come out right. It's all right really. Honest. | |
931 | % | |
932 | % \begin{macrocode} | |
933 | \def~{\verb~\syn@ttspace}% | |
934 | }% | |
935 | \catcode`#1\active% | |
936 | % \end{macrocode} | |
937 | % | |
938 | % If our magic control sequence already existed, we can assume that the | |
939 | % character is already a verbatim delimiter, and raise a warning. | |
940 | % | |
941 | % \begin{macrocode} | |
942 | }{% | |
943 | \PackageWarning{syntax}{Character `\expandafter\@gobble\string#1' | |
944 | is already a verbatim\MessageBreak | |
945 | delimiter}% | |
946 | }% | |
947 | } | |
948 | % \end{macrocode} | |
949 | % | |
950 | % \end{macro} | |
951 | % | |
952 | % \begin{macro}{\unverb} | |
953 | % | |
954 | % This is actually terribly easy: we just use the |\cc@\|\<char> command | |
955 | % we definied earlier, after making sure that it's been defined. | |
956 | % | |
957 | % \begin{macrocode} | |
958 | \def\unverb#1{% | |
959 | \@ifundefined{cc@\string#1}{% | |
960 | \PackageWarning{syntax}{Character `\expandafter\@gobble\string#1' | |
961 | is not a verbatim\MessageBreak | |
962 | delimiter}% | |
963 | }{% | |
964 | \csname cc@\string#1\endcsname% | |
965 | }% | |
966 | } | |
967 | % \end{macrocode} | |
968 | % | |
969 | % \end{macro} | |
970 | % | |
971 | % \subsection{Style hooks for syntax forms} | |
972 | % | |
973 | % To allow the appearance of syntax things to be configured, we provide some | |
974 | % redefinable bits. | |
975 | % | |
976 | % The three types of objects (nonterminal symbols, and quoted and unquoted | |
977 | % terminals) each have two macros associated with them: one which does the | |
978 | % `left' bit of the typesetting, and one which does the `right' bit. The | |
979 | % items are typeset as LR~boxes. I'll be extra good while defining these | |
980 | % hooks, so that it's obvious what's going on; macho \TeX\ hacker things | |
981 | % resume after this section. | |
982 | % | |
983 | % \begin{macro}{\syntleft} | |
984 | % \begin{macro}{\syntright} | |
985 | % | |
986 | % I can't see why anyone would want to change the typesetting of | |
987 | % nonterminals, although I'll provide the hooks for symmetry's sake. | |
988 | % | |
989 | % \begin{macrocode} | |
990 | \newcommand{\syntleft}{$\langle$\normalfont\itshape} | |
991 | \newcommand{\syntright}{$\rangle$} | |
992 | % \end{macrocode} | |
993 | % | |
994 | % \end{macro} | |
995 | % \end{macro} | |
996 | % | |
997 | % \begin{macro}{\ulitleft} | |
998 | % \begin{macro}{\ulitright} | |
999 | % \begin{macro}{\litleft} | |
1000 | % \begin{macro}{\litright} | |
1001 | % | |
1002 | % Now we can define the left and right parts of quoted and unquoted | |
1003 | % terminals. US~readers may want to put double quotes around the quoted | |
1004 | % terminals, for example. | |
1005 | % | |
1006 | % \begin{macrocode} | |
1007 | \newcommand{\ulitleft}{\normalfont\ttfamily\syn@ttspace\frenchspacing} | |
1008 | \newcommand{\ulitright}{} | |
1009 | \newcommand{\litleft}{`\bgroup\ulitleft} | |
1010 | \newcommand{\litright}{\ulitright\egroup'} | |
1011 | % \end{macrocode} | |
1012 | % | |
1013 | % \end{macro} | |
1014 | % \end{macro} | |
1015 | % \end{macro} | |
1016 | % \end{macro} | |
1017 | % | |
1018 | % \subsection{Simple syntax typesetting} | |
1019 | % | |
1020 | % In general text, we allow access to our typesetting conventions through | |
1021 | % standard \LaTeX\ commands. | |
1022 | % | |
1023 | % \begin{macro}{\synt} | |
1024 | % | |
1025 | % The |\synt| macro typesets its argument as a syntactic quantity. It puts | |
1026 | % the text of the argument in italics, and sets angle brackets around it. | |
1027 | % Breaking of a |\synt| object across lines is forbidden. | |
1028 | % | |
1029 | % \begin{macrocode} | |
1030 | \def\synt#1{\mbox{\syntleft{#1\/}\syntright}} | |
1031 | % \end{macrocode} | |
1032 | % | |
1033 | % \end{macro} | |
1034 | % | |
1035 | % \begin{macro}{\lit} | |
1036 | % | |
1037 | % The |\lit| macro typesets its argument as literal text, to be typed in. | |
1038 | % Normally, this means setting the text in |\tt| font, and putting quotes | |
1039 | % around it, although the quotes can be suppressed by using the $*$-variant. | |
1040 | % | |
1041 | % The |\syn@ttspace| macro sets up the spacing for the text nicely: |\tt| | |
1042 | % spaces tend to be a little wide. | |
1043 | % | |
1044 | % \begin{macrocode} | |
1045 | \def\lit{\@ifstar{\lit@i\ulitleft\ulitright}{\lit@i\litleft\litright}} | |
1046 | \def\lit@i#1#2#3{\mbox{#1{#3\/}#2}} | |
1047 | % \end{macrocode} | |
1048 | % | |
1049 | % \end{macro} | |
1050 | % | |
1051 | % \begin{macro}{\syn@ttspace} | |
1052 | % | |
1053 | % This sets up the |\spaceskip| value for |\tt| text. | |
1054 | % | |
1055 | % \begin{macrocode} | |
1056 | \def\syn@ttspace@{\spaceskip.35em\@plus.2em\@minus.15em\relax} | |
1057 | % \end{macrocode} | |
1058 | % | |
1059 | % However, this isn't always the right thing to do. | |
1060 | % | |
1061 | % \begin{macrocode} | |
1062 | \def\ttthinspace{\let\syn@ttspace\syn@ttspace@} | |
1063 | \def\ttthickspace{\let\syn@ttspace\@empty} | |
1064 | % \end{macrocode} | |
1065 | % | |
1066 | % I know what I like thoough. | |
1067 | % | |
1068 | % \begin{macrocode} | |
1069 | \ttthinspace | |
1070 | % \end{macrocode} | |
1071 | % | |
1072 | % \end{macro} | |
1073 | % | |
1074 | % \subsubsection{The shortcuts} | |
1075 | % | |
1076 | % The easy part is over now. The next job is to set up the `grammar | |
1077 | % shortcuts' which allow easy changing of styles. | |
1078 | % | |
1079 | % We support four shortcuts: | |
1080 | % \begin{itemize} | |
1081 | % \item |`literal text'| typesets \syntax{`literal text'} | |
1082 | % \item |<non-terminal>| typesets \syntax{<non-terminal>} | |
1083 | % \item |"unquoted text"| typesets \syntax{"unquoted text"} | |
1084 | % \item \verb"|" typesets a \syntax{|} character | |
1085 | % \end{itemize} | |
1086 | % These are all implemented through active characters, which are enabled | |
1087 | % using the |\syntaxShortcuts| macro, described below. | |
1088 | % | |
1089 | % \begin{macro}{\readupto} | |
1090 | % | |
1091 | % \syntax{"\\readupto{"<char>"}{"<decls>"}{"<command>"}"} will read all | |
1092 | % characters up until the next occurrence of \<char>. Normally, all | |
1093 | % special characters will be deactivated. However, you can reactivate some | |
1094 | % characters, using the \<decls> argument, which is processed before the | |
1095 | % text is read. | |
1096 | % | |
1097 | % The code is borrowed fairly obviously from the \LaTeXe\ source for the | |
1098 | % |\verb| command. | |
1099 | % | |
1100 | % \begin{macrocode} | |
1101 | \def\readupto#1#2#3{% | |
1102 | \bgroup% | |
1103 | \verb@eol@error% | |
1104 | \let\do\@makeother\dospecials% | |
1105 | #2% | |
1106 | \catcode`#1\active% | |
1107 | \lccode`\~`#1% | |
1108 | \gdef\verb@balance@group{\verb@egroup% | |
1109 | \@latex@error{\noexpand\verb illegal in command argument}\@ehc}% | |
1110 | \def\@vhook{\verb@egroup#3}% | |
1111 | \aftergroup\verb@balance@group% | |
1112 | \lowercase{\let~\@vhook}% | |
1113 | } | |
1114 | % \end{macrocode} | |
1115 | % | |
1116 | % \end{macro} | |
1117 | % | |
1118 | % \begin{macro}{\syn@assist} | |
1119 | % | |
1120 | % The |\syn@assist| macro is used for defining three of the shortcuts. It | |
1121 | % is called as | |
1122 | % | |
1123 | % \begin{quote} | |
1124 | % \syntax{"\\syn@assist{"<left-decls>"}{"<actives>"}{"<delimeter>"}" \\ | |
1125 | % \null \quad "{"<right-decls>"}{"<end-cmd>"}"} | |
1126 | % \end{quote} | |
1127 | % | |
1128 | % It creates an hbox, sets up the escape sequences for quoting our magic | |
1129 | % characters, and then typesets a box containing | |
1130 | % | |
1131 | % \begin{quote} | |
1132 | % \syntax{<left-decls>"{"<delimited-text>"\\/}"<right-decls>} | |
1133 | % \end{quote} | |
1134 | % | |
1135 | % The \<left-decls> and \<right-decls> can be |\relax| if they're not | |
1136 | % required. | |
1137 | % | |
1138 | % The \<actives> argument is passed to |\readupto|, to allow some special | |
1139 | % characters through. By default, we re-enable |\|, and make `\verb*" "' | |
1140 | % typeset some space glue, rather than a space character. A macro | |
1141 | % `\verb*"\ "' is defined to actually print a space character, which yield | |
e8e9e5d8 | 1142 | % `\verb*" "' in the `|\tt|' font. |
86f6a31e | 1143 | % |
1144 | % Finally, it defines a |\ch| command, which, given a single-character | |
1145 | % control sequence as its argument, typesets the character. This is useful, | |
1146 | % since |`| has been made active when we set up these calls, so the | |
1147 | % direct |\char`\|\<char> doesn't work. | |
1148 | % | |
1149 | % \begin{macrocode} | |
1150 | \def\syn@assist#1#2#3#4#5{% | |
1151 | % \end{macrocode} | |
1152 | % | |
1153 | % First, we start the box, and open a group. We use |\mbox| because it | |
1154 | % does all the messing with |\leavevmode| which is needed. | |
1155 | % | |
1156 | % \begin{macrocode} | |
1157 | \leavevmode\hbox\bgroup% | |
1158 | % \end{macrocode} | |
1159 | % | |
1160 | % Next job is to set up the escape sequences. | |
1161 | % | |
1162 | % \begin{macrocode} | |
1163 | \chardef\\`\\% | |
1164 | \chardef\>`\>% | |
1165 | \chardef\'`\'% | |
1166 | \chardef\"`\"% | |
1167 | \chardef\ `\ % | |
1168 | % \end{macrocode} | |
1169 | % | |
1170 | % Now to define |\ch|. This is done the obvious way. | |
1171 | % | |
1172 | % \begin{macrocode} | |
1173 | \def\ch##1{\char`##1}% | |
1174 | % \end{macrocode} | |
1175 | % | |
1176 | % For active characters, we do some fiddling with |\lccode|s. | |
1177 | % | |
1178 | % \begin{macrocode} | |
1179 | \def\act##1{% | |
1180 | \catcode`##1\active% | |
1181 | \begingroup% | |
1182 | \lccode`\~`##1% | |
1183 | \lowercase{\endgroup\def~}% | |
1184 | }% | |
1185 | % \end{macrocode} | |
1186 | % | |
1187 | % Finally, we do the real work of setting the text. We use |\readupto| to | |
1188 | % actually find the text we want. | |
1189 | % | |
1190 | % \begin{macrocode} | |
1191 | #1% | |
1192 | \begingroup% | |
1193 | \readupto#3{% | |
1194 | \catcode`\\0% | |
1195 | \catcode`\ 10% | |
1196 | #2% | |
1197 | }{% | |
1198 | \/\endgroup#4\egroup#5% | |
1199 | }% | |
1200 | } | |
1201 | % \end{macrocode} | |
1202 | % | |
1203 | % \end{macro} | |
1204 | % | |
1205 | % \begin{macro}{\syn@shorts} | |
1206 | % | |
1207 | % This macro actually defines the expansions for the active characters. | |
1208 | % We have to do this separately because |`| must be active when we use it | |
1209 | % in the |\def|, but we can't do that and use |\catcode| at the same time. | |
1210 | % The arguments are commands to do before and after the actual command. | |
1211 | % These are passed up from |\syntaxShortcuts|. | |
1212 | % | |
1213 | % All of the characters use |\syn@assist| in the obvious way except for | |
1214 | % \verb"|", which drops into maths mode instead. | |
1215 | % | |
1216 | % Note that when changing the catcodes, we must save |`| until last. | |
1217 | % | |
1218 | % \begin{macrocode} | |
1219 | \begingroup | |
1220 | \catcode`\<\active | |
1221 | \catcode`\|\active | |
1222 | \catcode`\"\active | |
1223 | \catcode`\`\active | |
1224 | % | |
1225 | \gdef\syn@shorts#1#2{% | |
1226 | % \end{macrocode} | |
1227 | % | |
1228 | % The `|<|' character must typeset its argument in italics. We make `|_|' | |
1229 | % do the same as the `|\_|' command. | |
1230 | % | |
1231 | % \begin{macrocode} | |
1232 | \def<{% | |
1233 | #1% | |
1234 | \syn@assist% | |
1235 | \syntleft% | |
1236 | {\act_{\@uscore.}}% | |
1237 | >% | |
1238 | \syntright% | |
1239 | {#2}% | |
1240 | }% | |
1241 | % \end{macrocode} | |
1242 | % | |
1243 | % The `|`|' and `|"|' characters should print its argument in |\tt| font. | |
1244 | % We change the `|\tt|' space glue to provide nicer spacing on the line. | |
1245 | % | |
1246 | % \begin{macrocode} | |
1247 | \def`{% | |
1248 | #1% | |
1249 | \syn@assist% | |
1250 | \litleft% | |
1251 | \relax% | |
1252 | '% | |
1253 | \litright% | |
1254 | {#2}% | |
1255 | }% | |
1256 | \def"{% | |
1257 | #1% | |
1258 | \syn@assist% | |
1259 | \ulitleft% | |
1260 | \relax% | |
1261 | "% | |
1262 | \ulitright% | |
1263 | {#2}% | |
1264 | }% | |
1265 | % \end{macrocode} | |
1266 | % | |
1267 | % Finally, the `\verb"|"' character is typeset by using the mysterious | |
1268 | % |\textbar| command. | |
1269 | % | |
1270 | % \begin{macrocode} | |
1271 | \def|{\textbar}% | |
1272 | % \end{macrocode} | |
1273 | % | |
1274 | % We're finished here now. | |
1275 | % | |
1276 | % \begin{macrocode} | |
1277 | } | |
1278 | % | |
1279 | \endgroup | |
1280 | % \end{macrocode} | |
1281 | % | |
1282 | % \end{macro} | |
1283 | % | |
1284 | % \begin{macro}{\syntaxShortcuts} | |
1285 | % | |
1286 | % This is a user-level command which enables the use of our shortcuts in the | |
1287 | % current group. It uses |\addspecial|, defined below, to register the | |
1288 | % active characters, sets up their definitions and activates them. | |
1289 | % | |
1290 | % The two arguments are commands to be performed before and after the | |
1291 | % handling of the abbreviation. In this way, you can further process the | |
1292 | % output. | |
1293 | % | |
1294 | % This command is not intended to be used directly by users: it should be | |
1295 | % used by other macros and packages which wish to take advantage of the | |
1296 | % facilities offered by this package. We provide a |\synshorts| declaration | |
1297 | % (which may be used as an environment, of course) which is more `user | |
1298 | % palatable'. | |
1299 | % | |
1300 | % \begin{macrocode} | |
1301 | \def\syntaxShortcuts#1#2{% | |
1302 | \syn@shorts{#1}{#2}% | |
1303 | \addspecial\`% | |
1304 | \addspecial\<% | |
1305 | \addspecial\|% | |
1306 | \addspecial\"% | |
1307 | \catcode`\|\active% | |
e8e9e5d8 | 1308 | \catcode`\<\active% |
86f6a31e | 1309 | \catcode`\"\active% |
1310 | \catcode`\`\active% | |
1311 | } | |
1312 | % | |
1313 | \def\synshorts{\syntaxShortcuts\relax\relax} | |
1314 | % \end{macrocode} | |
1315 | % | |
1316 | % \end{macro} | |
1317 | % | |
1318 | % \begin{macro}{\synshortsoff} | |
1319 | % | |
1320 | % This macro can be useful occasionally: it disables the syntax shortcuts, | |
1321 | % so you can type normal text for a while. | |
1322 | % | |
1323 | % \begin{macrocode} | |
1324 | \def\synshortsoff{% | |
1325 | \catcode`\|12% | |
1326 | \catcode`\<12% | |
1327 | \catcode`\"12% | |
1328 | \catcode`\`12% | |
1329 | } | |
1330 | % \end{macrocode} | |
1331 | % | |
1332 | % \end{macro} | |
1333 | % | |
1334 | % \begin{macro}{\syntax} | |
1335 | % | |
1336 | % The |\syntax| macro typesets its argument, allowing the use of our | |
1337 | % shortcuts within the argument. | |
1338 | % | |
1339 | % Actually, we go to some trouble to ensure that the argument to |\syntax| | |
1340 | % \emph{isn't} a real argument so we can change catcodes as we go. We | |
1341 | % use the |\let\@let@token=| trick from \PlainTeX\ to do this. | |
1342 | % | |
1343 | % \begin{macrocode} | |
1344 | \def\syntax#{\bgroup\syntaxShortcuts\relax\relax\let\@let@token} | |
1345 | % \end{macrocode} | |
1346 | % | |
1347 | % \end{macro} | |
1348 | % | |
1349 | % \begin{environment}{grammar} | |
1350 | % | |
1351 | % The \env{grammar} environment is the final object we have to define. It | |
1352 | % allows typesetting of beautiful BNF grammars. | |
1353 | % | |
1354 | % First, we define the length parameters we need: | |
1355 | % | |
1356 | % \begin{macrocode} | |
1357 | \newskip\grammarparsep | |
1358 | \grammarparsep8\p@\@plus\p@\@minus\p@ | |
1359 | \newdimen\grammarindent | |
1360 | \grammarindent2em | |
1361 | % \end{macrocode} | |
1362 | % | |
1363 | % Now define the default label typesetting. This macro is designed to be | |
1364 | % replaced by a user, so we'll be extra-well-behaved and use genuine \LaTeX\ | |
1365 | % commands. Well, almost \dots | |
1366 | % | |
1367 | % \begin{macrocode} | |
88ddb950 MW |
1368 | \newcommand{\grammarlabel}[2]{\grammarlabelx{#1}{}{#2}} |
1369 | \newcommand{\grammarlabelx}[3]{\synt{#1}#2 \hfill#3} | |
86f6a31e | 1370 | % \end{macrocode} |
1371 | % | |
1372 | % Now for a bit of hacking to make the item stuff work properly. This gets | |
1373 | % done for every new paragraph that's started without an |\item| command. | |
1374 | % | |
1375 | % First, store the left hand side of the production in a box. Then I'll | |
1376 | % end the paragraph, and insert some nasty glue to take up all the space, | |
1377 | % so no-one will ever notice that there was a paragraph break there. The | |
1378 | % strut just makes sure that I know exactly how high the line is. | |
1379 | % | |
1380 | % \begin{macrocode} | |
f5e7b9ec | 1381 | \def\gr@implitem<#1>#2 #3 {% |
88ddb950 MW |
1382 | \sbox\z@{% |
1383 | \hskip\labelsep% | |
1384 | \def\@tempa{#2}% | |
1385 | \ifx\@tempa\@empty\grammarlabel{#1}{#3}% | |
1386 | \else\grammarlabelx{#1}{#2}{#3}\fi% | |
1387 | }% | |
86f6a31e | 1388 | \strut\@@par% |
1389 | \vskip-\parskip% | |
1390 | \vskip-\baselineskip% | |
1391 | % \end{macrocode} | |
1392 | % | |
1393 | % The |\item| command will notice that I've inserted these funny glues and | |
1394 | % try to remove them: I'll stymie its efforts by inserting an invisible | |
1395 | % rule. Then I'll insert the label using |\item| in the normal way. | |
1396 | % | |
1397 | % \begin{macrocode} | |
1398 | \hrule\@height\z@\@depth\z@\relax% | |
1399 | \item[\unhbox\z@]% | |
1400 | % \end{macrocode} | |
1401 | % | |
1402 | % Just before I go, I'll make \lit{<} back into an active character. | |
1403 | % | |
1404 | % \begin{macrocode} | |
1405 | \catcode`\<\active% | |
1406 | } | |
1407 | % \end{macrocode} | |
1408 | % | |
1409 | % Now for the environment proper. Deep down, it's a list environment, with | |
1410 | % some nasty tricks to stop anyone from noticing. | |
1411 | % | |
1412 | % The first job is to set up the list from the parameters I'm given. | |
1413 | % | |
1414 | % \begin{macrocode} | |
1415 | \newenvironment{grammar}{% | |
1416 | \list{}{% | |
1417 | \labelwidth\grammarindent% | |
1418 | \leftmargin\grammarindent% | |
1419 | \advance\grammarindent\labelsep | |
1420 | \itemindent\z@% | |
1421 | \listparindent\z@% | |
1422 | \parsep\grammarparsep% | |
1423 | }% | |
1424 | % \end{macrocode} | |
1425 | % | |
1426 | % We have major problems in |\raggedright| layouts, which try to use |\par| | |
1427 | % to start new lines. We go back to normal |\\| newlines to try and bodge | |
1428 | % our way around these problems. | |
1429 | % | |
1430 | % \begin{macrocode} | |
1431 | \let\\\@normalcr | |
1432 | % \end{macrocode} | |
1433 | % | |
1434 | % Now to enable the shortcuts. | |
1435 | % | |
1436 | % \begin{macrocode} | |
1437 | \syntaxShortcuts\relax\relax% | |
1438 | % \end{macrocode} | |
1439 | % | |
1440 | % Now a little bit of magic. The |\alt| macro moves us to a new line, and | |
1441 | % typesets a vertical bar in the margin. This allows typesetting of | |
1442 | % multiline alternative productions in a pretty way. | |
1443 | % | |
1444 | % \begin{macrocode} | |
1445 | \def\alt{\\\llap{\textbar\quad}}% | |
1446 | % \end{macrocode} | |
1447 | % | |
1448 | % Now for another bit of magic. We set up some |\par| cleverness to spot | |
1449 | % the start of each production rule and format it in some cunning and | |
1450 | % user-defined way. | |
1451 | % | |
1452 | % \begin{macrocode} | |
1453 | \def\gr@setpar{% | |
1454 | \def\par{% | |
1455 | \parshape\@ne\@totalleftmargin\linewidth% | |
1456 | \@@par% | |
1457 | \catcode`\<12% | |
1458 | \everypar{% | |
1459 | \everypar{}% | |
1460 | \catcode`\<\active% | |
1461 | \gr@implitem% | |
1462 | }% | |
1463 | }% | |
1464 | }% | |
1465 | \gr@setpar% | |
1466 | \par% | |
1467 | % \end{macrocode} | |
1468 | % | |
1469 | % Now set up the |\[[| and |\]]| commands to do the right thing. We have | |
1470 | % to check the next character to see if it's correct, otherwise we'll | |
1471 | % open a maths display as usual. | |
1472 | % | |
1473 | % \begin{macrocode} | |
1474 | \let\gr@leftsq\[% | |
1475 | \let\gr@rightsq\]% | |
1476 | \def\gr@endsyntdiag]{\end{syntdiag}\gr@setpar\par}% | |
1477 | \def\[{\@ifnextchar[{\begin{syntdiag}\@gobble}\gr@leftsq}% | |
1478 | \def\]{\@ifnextchar]\gr@endsyntdiag\gr@rightsq}% | |
1479 | % \end{macrocode} | |
1480 | % | |
1481 | % Well, that's it for this side of the environment. | |
1482 | % | |
1483 | % \begin{macrocode} | |
1484 | }{% | |
1485 | % \end{macrocode} | |
1486 | % | |
1487 | % Closing the environment is a simple matter of tidying away the list. | |
1488 | % | |
1489 | % \begin{macrocode} | |
1490 | \@newlistfalse% | |
1491 | \everypar{}% | |
1492 | \endlist% | |
1493 | } | |
1494 | % \end{macrocode} | |
1495 | % | |
1496 | % \end{environment} | |
1497 | % | |
1498 | % \subsection{Syntax diagrams} | |
1499 | % | |
1500 | % Now we come to the final and most complicated part of the package. | |
1501 | % | |
1502 | % Syntax diagrams are drawn using arrow characters from \LaTeX's line font, | |
1503 | % used in the \env{picture} environment, and rules. The horizontal rules | |
1504 | % of the diagram are drawn along the baselines of the lines in which they | |
1505 | % are placed. The text items in the diagram are placed in boxes and lowered | |
1506 | % below the main baseline. Struts are added throughout to keep the vertical | |
1507 | % spacing consistent. | |
1508 | % | |
1509 | % The vertical structures (stacks and loops) are all implemented with \TeX's | |
1510 | % primitive |\halign| command. | |
1511 | % | |
1512 | % \subsubsection{User-configurable parameters} | |
1513 | % | |
1514 | % First, we allocate the \<dimen> and \<skip> arguments needed. Fixed | |
1515 | % lengths, as the \LaTeX book calls them, are allocated as \<dimen>s, to | |
1516 | % take some of the load off of all the \<skip> registers. | |
1517 | % | |
1518 | % \begin{macrocode} | |
1519 | \newskip\sdstartspace | |
1520 | \newskip\sdendspace | |
1521 | \newskip\sdmidskip | |
1522 | \newskip\sdtokskip | |
1523 | \newskip\sdfinalskip | |
1524 | \newdimen\sdrulewidth | |
1525 | \newdimen\sdcirclediam | |
1526 | \newdimen\sdindent | |
1527 | % \end{macrocode} | |
1528 | % | |
1529 | % We need some \TeX\ \<dimen>s for our own purposes, to get everything in | |
1530 | % the right places. We use labels for the `temporary' \TeX\ parameters | |
1531 | % which we use, to avoid wasting registers. | |
1532 | % | |
1533 | % \begin{macrocode} | |
1534 | \dimendef\sd@lower\z@ | |
1535 | \dimendef\sd@upper\tw@ | |
1536 | \dimendef\sd@mid4 | |
1537 | \dimendef\sd@topcirc6 | |
1538 | \dimendef\sd@botcirc8 | |
1539 | \skipdef\sd@qskip2 | |
1540 | % \end{macrocode} | |
1541 | % | |
1542 | % \begin{macro}{\sd@setsize} | |
1543 | % When the text size for syntax diagrams changes, it's necessary to work out | |
1544 | % the height for various rules in the diagram. | |
1545 | % | |
1546 | % \begin{macrocode} | |
1547 | \def\sd@setsize{% | |
1548 | \sd@mid\ht\strutbox% | |
1549 | \advance\sd@mid-\dp\strutbox% | |
1550 | \sd@mid.5\sd@mid% | |
1551 | \sd@upper\sdrulewidth% | |
1552 | \advance\sd@upper\sd@mid% | |
1553 | \sd@lower\sdrulewidth% | |
1554 | \advance\sd@lower-\sd@mid% | |
1555 | \sd@topcirc-.5\sdcirclediam% | |
1556 | \advance\sd@topcirc\sd@mid% | |
1557 | \sd@botcirc-.5\sdcirclediam% | |
1558 | \advance\sd@botcirc-\sd@mid% | |
1559 | } | |
1560 | % \end{macrocode} | |
1561 | % | |
1562 | % \end{macro} | |
1563 | % | |
1564 | % \begin{macro}{\sdsize} | |
1565 | % | |
1566 | % You can set the default type size used by syntax diagrams by redefining | |
1567 | % the |\sdsize| command, using the |\renewcommand| command. | |
1568 | % | |
1569 | % By default, syntax diagrams are set slightly smaller than the main body | |
1570 | % text.\footnote{^^A | |
1571 | % I've used pure \LaTeX\ commands for this and the \cmd\sdlengths\ macro, | |
1572 | % to try and illustrate how these values might be changed by a user. The | |
1573 | % rest of the code is almost obfuscted in its use of raw \TeX\ features, | |
1574 | % in an attempt to dissuade more na\"\i ve users from fiddling with it. | |
1575 | % I suppose this is what you get when you let assembler hackers loose with | |
1576 | % something like \LaTeX. | |
1577 | % } | |
1578 | % | |
1579 | % \begin{macrocode} | |
1580 | \newcommand{\sdsize}{% | |
1581 | \small% | |
1582 | } | |
1583 | % \end{macrocode} | |
1584 | % | |
1585 | % \end{macro} | |
1586 | % | |
1587 | % \begin{macro}{\sdlengths} | |
1588 | % | |
1589 | % Finally, the default length parameters are set in the |\sdlengths| command. | |
1590 | % You can redefine the command using |\renewcommand|. | |
1591 | % | |
1592 | % We set up the length parameters here. | |
1593 | % | |
1594 | % \begin{macrocode} | |
1595 | \newcommand{\sdlengths}{% | |
1596 | \setlength{\sdstartspace}{1em minus 10pt}% | |
1597 | \setlength{\sdendspace}{1em minus 10pt}% | |
1598 | \setlength{\sdmidskip}{0.5em plus 1em}% | |
1599 | \setlength{\sdtokskip}{0.25em plus 1em}% | |
1600 | \setlength{\sdfinalskip}{0.5em plus 10000fil}% | |
1601 | \setlength{\sdrulewidth}{0.2pt}% | |
1602 | \setlength{\sdcirclediam}{8pt}% | |
1603 | \setlength{\sdindent}{0pt}% | |
1604 | } | |
1605 | % \end{macrocode} | |
1606 | % | |
1607 | % \end{macro} | |
1608 | % | |
1609 | % \subsubsection{Other declarations} | |
1610 | % | |
1611 | % We define four switches. The table shows what they're used for. | |
1612 | % | |
1613 | % \begin{table} | |
1614 | % \begin{tab}{lp{3in}} \hline | |
1615 | % | |
1616 | % \bf Switch & \bf Meaning \\ \hline | |
1617 | % | |
1618 | % |\ifsd@base| & We are at `base level' in the diagram: | |
1619 | % i.e., not in any other sorts of | |
1620 | % constructions. This is used to decide | |
1621 | % whether to allow line breaking. \\[2pt] | |
1622 | % | |
1623 | % |\ifsd@top| & The current loop construct is being | |
1624 | % typeset with the loop arrow above the | |
1625 | % baseline. \\[2pt] | |
1626 | % | |
1627 | % |\ifsd@toplayer| & We are typesetting the top layer of | |
1628 | % a stack. This is used to ensure that | |
1629 | % the vertical rules on either side are | |
1630 | % typeset at the right height. \\[2pt] | |
1631 | % | |
1632 | % |\ifsd@backwards| & We're typesetting backwards, because | |
1633 | % we're in the middle of a loop arrow. | |
1634 | % the only difference this makes is that | |
1635 | % any subloops have the arrow on the | |
1636 | % side. \\ \hline | |
1637 | % | |
1638 | % \end{tab} | |
1639 | % \caption{Syntax diagram switches} | |
1640 | % \end{table} | |
1641 | % | |
1642 | % \begin{macrocode} | |
1643 | \newif\ifsd@base | |
1644 | \newif\ifsd@top | |
1645 | \newif\ifsd@toplayer | |
1646 | \newif\ifsd@backwards | |
1647 | % \end{macrocode} | |
1648 | % | |
1649 | % \begin{macro}{\sd@err} | |
1650 | % | |
1651 | % We output our errors through this macro, which saves a little typing. | |
1652 | % | |
1653 | % \begin{macrocode} | |
1654 | \def\sd@err{\PackageError{syntax}} | |
1655 | % \end{macrocode} | |
1656 | % | |
1657 | % \end{macro} | |
1658 | % | |
1659 | % \subsubsection{Arrow-drawing} | |
1660 | % | |
1661 | % We need to draw some arrows. \LaTeX\ tries to make this as awkward as | |
1662 | % possible, so we have to start moving the arrows around in boxes quite a | |
1663 | % lot. | |
1664 | % | |
1665 | % The left and right pointing arrows are fairly simple: we just add some | |
1666 | % horizontal spacing to prevent the width of the arrow looking odd. | |
1667 | % | |
1668 | % \begin{macrocode} | |
1669 | \def\sd@arrow{% | |
1670 | \ht\tw@\z@% | |
1671 | \dp\tw@\z@% | |
1672 | \raise\sd@mid\box\tw@% | |
1673 | \egroup% | |
1674 | } | |
1675 | \def\sd@rightarr{% | |
1676 | \bgroup% | |
1677 | \setbox\tw@\hbox{\kern-6\p@\@linefnt\char'55}% | |
1678 | \sd@arrow% | |
1679 | } | |
1680 | \def\sd@leftarr{% | |
1681 | \bgroup% | |
e1069af1 | 1682 | \setbox\tw@\hbox{\@linefnt\char'33\kern-6\p@}% |
86f6a31e | 1683 | \sd@arrow% |
1684 | } | |
1685 | % \end{macrocode} | |
1686 | % | |
1687 | % The up arrow is very strange. We need to bring the arrow down to base | |
1688 | % level, and smash its height. | |
1689 | % | |
1690 | % \begin{macrocode} | |
1691 | \def\sd@uparr{% | |
1692 | \bgroup% | |
1693 | \setbox\tw@\hb@xt@\z@{\kern-\sdrulewidth\@linefnt\char'66\hss}% | |
1694 | \setbox\tw@\hbox{\lower10\p@\box\tw@}% | |
1695 | \sd@arrow% | |
1696 | } | |
1697 | % \end{macrocode} | |
1698 | % | |
1699 | % The down arrow is similar, although it's already at the right height. | |
1700 | % Thus, we can just smash the box. | |
1701 | % | |
1702 | % \begin{macrocode} | |
1703 | \def\sd@downarr{% | |
1704 | \bgroup% | |
1705 | \setbox\tw@\hb@xt@\z@{\kern-\sdrulewidth\@linefnt\char'77\hss}% | |
1706 | \sd@arrow% | |
1707 | } | |
1708 | % \end{macrocode} | |
1709 | % | |
1710 | % \subsubsection{Drawing curves} | |
1711 | % | |
1712 | % If the user has selected curved edges, we use the \LaTeX\ features provided | |
1713 | % to obtain the curves. These are drawn slightly oddly to make it easier | |
1714 | % to fit them into the diagram. | |
1715 | % | |
1716 | % Some explanation about the \LaTeX\ circle font is probably called for | |
1717 | % before we go any further. The font consists of sets of four quadrants | |
1718 | % of a particular size (and some other characters, which aren't important | |
1719 | % at the moment). Each collection of quadrants fit together to form a | |
1720 | % perfect circle of a given diameter. The individual quadrant characters | |
1721 | % have strange bounding boxes, as described in the files \textit{lcircle.mf} | |
1722 | % and \textit{ltpict.dtx}, and also in Appendix~D of \textit{The \TeX book}. | |
1723 | % Our job here is to make these quadrants useful in the context of | |
1724 | % drawing syntax diagrams. | |
1725 | % | |
1726 | % \begin{macro}{\sd@circ} | |
1727 | % First, we define |\sd@circ|, which performs the common parts of the four | |
1728 | % routines. Since the characters in the circle font are grouped together, | |
1729 | % we can pick out a particular corner piece by specifying its index into | |
1730 | % the group for the required size. The |\sd@circ| routine will pick out | |
1731 | % the required character, given this index as an argument, and put it in | |
1732 | % box~2, after fiddling with the sizes a little: | |
1733 | % \begin{itemize} | |
1734 | % | |
1735 | % \item We clear the width to zero. The individual routines then add a kern | |
1736 | % of the correct amount, so that the quadrant appears in the right | |
1737 | % place. | |
1738 | % | |
1739 | % \item The piece is lowered by half the rule width. This positions the | |
1740 | % top and bottom pieces of the circle to be half way over the baseline, | |
1741 | % which is the correct position for the rest of the diagram. | |
1742 | % | |
1743 | % \end{itemize} | |
1744 | % | |
1745 | % Finally, we make sure we're in horizontal mode: horrific results occur | |
1746 | % if this is not the case. I'm sure I don't need to explain this any more | |
1747 | % graphically. | |
1748 | % | |
1749 | % \begin{macrocode} | |
1750 | \def\sd@circ#1{% | |
1751 | \@getcirc\sdcirclediam% | |
1752 | \advance\@tempcnta#1% | |
1753 | \setbox\tw@\hbox{\lower\sdrulewidth% | |
1754 | \hbox{\@circlefnt\char\@tempcnta}}% | |
1755 | \wd\tw@\z@% | |
1756 | \leavevmode% | |
1757 | } | |
1758 | % \end{macrocode} | |
1759 | % | |
1760 | % \end{macro} | |
1761 | % | |
1762 | % \begin{macro}{\sd@tlcirc} | |
1763 | % \begin{macro}{\sd@trcirc} | |
1764 | % \begin{macro}{\sd@blcirc} | |
1765 | % \begin{macro}{\sd@brcirc} | |
1766 | % | |
1767 | % These are the macros which actually draw quadrants of circles. They all | |
1768 | % call |\sd@circ|, passing an appropriate index, and then fiddle with the | |
1769 | % box sizes and apply kerning specific to the quadrant positioning. | |
1770 | % | |
1771 | % The exact requirements for positioning are as follows: | |
1772 | % | |
1773 | % \begin{itemize} | |
1774 | % | |
1775 | % \item The horizontal parts of the arcs must lie along the baseline (i.e., | |
1776 | % half the line must be above the baseline, and half must be below). | |
1777 | % This is consistent with the horizontal rules used in the diagram. | |
1778 | % | |
1779 | % \item The vertical parts must overlap vertical rules on either side, so | |
1780 | % that a |\vrule\sd@|\textit{xx}|circ| makes the arc appear to be | |
1781 | % a real curve in the line. The requirements are actually somewhat | |
1782 | % inconsistent; for example, the \env{stack} environment uses curves | |
1783 | % \emph{before} the |\vrule|s. Special requirements like this are | |
1784 | % handled as special cases later. | |
1785 | % | |
1786 | % \item The height and width of the arc are at least roughly correct. | |
1787 | % | |
1788 | % \end{itemize} | |
1789 | % | |
1790 | % \begin{macrocode} | |
1791 | \def\sd@tlcirc{{% | |
1792 | \sd@circ3% | |
1793 | \ht\tw@\sdrulewidth% | |
1794 | \dp\tw@.5\sdcirclediam% | |
1795 | \kern-\tw@\sdrulewidth% | |
1796 | \raise\sd@mid\box\tw@% | |
1797 | \kern.5\sdcirclediam% | |
1798 | }} | |
1799 | % \end{macrocode} | |
1800 | % | |
1801 | % \begin{macrocode} | |
1802 | \def\sd@trcirc{{% | |
1803 | \sd@circ0% | |
1804 | \ht\tw@\sdrulewidth% | |
1805 | \dp\tw@.5\sdcirclediam% | |
1806 | \kern.5\sdcirclediam% | |
1807 | \raise\sd@mid\box\tw@% | |
1808 | }} | |
1809 | % \end{macrocode} | |
1810 | % | |
1811 | % \begin{macrocode} | |
1812 | \def\sd@blcirc{{% | |
1813 | \sd@circ2% | |
1814 | \ht\tw@.5\sdcirclediam% | |
1815 | \dp\tw@\sdrulewidth% | |
1816 | \kern-\tw@\sdrulewidth% | |
1817 | \raise\sd@mid\box\tw@% | |
1818 | \kern.5\sdcirclediam% | |
1819 | }} | |
1820 | % \end{macrocode} | |
1821 | % | |
1822 | % \begin{macrocode} | |
1823 | \def\sd@brcirc{{% | |
1824 | \sd@circ1% | |
1825 | \ht\tw@.5\sdcirclediam% | |
1826 | \dp\tw@\sdrulewidth% | |
1827 | \kern.5\sdcirclediam% | |
1828 | \raise\sd@mid\box\tw@% | |
1829 | }} | |
1830 | % \end{macrocode} | |
1831 | % | |
1832 | % \begin{macrocode} | |
1833 | \def\sd@nocirc{\sd@rule\hskip.5\sdcirclediam\relax} | |
1834 | % \end{macrocode} | |
1835 | % | |
1836 | % \end{macro} | |
1837 | % \end{macro} | |
1838 | % \end{macro} | |
1839 | % \end{macro} | |
1840 | % | |
1841 | % \begin{macro}{\sd@llc} | |
1842 | % \begin{macro}{\sd@rlc} | |
1843 | % | |
1844 | % In the \env{rep} environment, we need to be able to draw arcs with | |
1845 | % horizontal lines running through them. The two macros here do the job | |
1846 | % nicely. |\sd@llc| (which is short for left overlapping circle) is | |
1847 | % analogous to |\llap|: it puts its argument in a box of zero width, sticking | |
1848 | % out to the left. However, it also draws a rule along the baseline. This | |
1849 | % is important, as it prevents text from overprinting the arc. |\sd@rlc| | |
1850 | % is very similar, just the other way around. | |
1851 | % | |
1852 | % \begin{macrocode} | |
1853 | \def\sd@llc#1{% | |
1854 | \hb@xt@.5\sdcirclediam{% | |
1855 | \sd@rule\hskip.5\sdcirclediam% | |
1856 | \hss% | |
1857 | #1% | |
1858 | }% | |
1859 | } | |
1860 | % \end{macrocode} | |
1861 | % | |
1862 | % \begin{macrocode} | |
1863 | \def\sd@rlc#1{% | |
1864 | \hb@xt@.5\sdcirclediam{% | |
1865 | #1% | |
1866 | \hss% | |
1867 | \sd@rule\hskip.5\sdcirclediam% | |
1868 | }% | |
1869 | } | |
1870 | % \end{macrocode} | |
1871 | % | |
1872 | % \end{macro} | |
1873 | % \end{macro} | |
1874 | % | |
1875 | % \subsubsection{Drawing rules} | |
1876 | % | |
1877 | % It's important to draw the rules \emph{along} the baseline, rather than | |
1878 | % above it: hence, the depth of the rule must be equal to the height. | |
1879 | % | |
1880 | % \begin{macro}{\sd@rule} | |
1881 | % | |
1882 | % We use rule leaders instead of glue through most of the syntax diagrams. | |
1883 | % The command \syntax{"\\sd@rule"<skip>} draws a rule of the correct | |
1884 | % dimensions, which has the behaviour of an \syntax{"\\hskip"<skip>}. | |
1885 | % | |
1886 | % \begin{macrocode} | |
1887 | \def\sd@rule{\leaders\hrule\@height\sd@upper\@depth\sd@lower} | |
1888 | % \end{macrocode} | |
1889 | % | |
1890 | % \end{macro} | |
1891 | % | |
1892 | % \begin{macro}{\sd@gap} | |
1893 | % | |
1894 | % The gap between elements is added using this macro. It will allow a | |
1895 | % line break if we're at the top level of the diagram, using a rather | |
1896 | % strange discretionary. | |
1897 | % | |
1898 | % This is called as \syntax{"\\sd@gap{"<skip-register>"}"}. | |
1899 | % | |
1900 | % \begin{macrocode} | |
1901 | \def\sd@gap#1{% | |
1902 | % \end{macrocode} | |
1903 | % | |
1904 | % First, we see if we're at the top level. Within constructs, we avoid the | |
1905 | % overhead of a |\discretionary|. We put half of the width of the skip on | |
1906 | % each side of the discretionary break. | |
1907 | % | |
1908 | % \begin{macrocode} | |
1909 | \ifsd@left% | |
1910 | \ifsd@base% | |
1911 | \skip@#1% | |
1912 | \divide\skip\z@\tw@% | |
1913 | \nobreak\sd@rule\hskip\skip@% | |
1914 | \discretionary{% | |
1915 | \sd@qarrow{->}% | |
1916 | }{% | |
1917 | \hbox{% | |
1918 | \sd@qarrow{>-}% | |
1919 | \sd@rule\hskip\sdstartspace% | |
1920 | \sd@rule\hskip3.5\p@% | |
1921 | }% | |
1922 | }{% | |
1923 | }% | |
1924 | \nobreak\sd@rule\hskip\skip@% | |
1925 | % \end{macrocode} | |
1926 | % | |
1927 | % If we're not at the base level, we just put in a rule of the correct | |
1928 | % width. | |
1929 | % | |
1930 | % \begin{macrocode} | |
1931 | \else% | |
1932 | \sd@rule\hskip#1% | |
1933 | \fi% | |
1934 | \fi% | |
1935 | } | |
1936 | % \end{macrocode} | |
1937 | % | |
1938 | % \end{macro} | |
1939 | % | |
1940 | % \begin{macro}{\sd@qgap} | |
1941 | % \begin{macro}{\sd@dequeue} | |
1942 | % | |
1943 | % This is the high-level interface to spacing in syntax diagrams. Stuff only | |
1944 | % gets printed if the diagram's actually started yet, and hasn't finished. | |
1945 | % | |
1946 | % \begin{macrocode} | |
1947 | \def\sd@qgap#1{% | |
1948 | \ifsd@left% | |
1949 | \ifsd@right\advance\sd@qskip#1\relax% | |
1950 | \else\sd@gap#1\fi% | |
1951 | \fi% | |
1952 | } | |
1953 | \def\sd@dequeue{\ifsd@left\sd@gap\sd@qskip\sd@qskip\z@\fi} | |
1954 | % \end{macrocode} | |
1955 | % | |
1956 | % \end{macro} | |
1957 | % \end{macro} | |
1958 | % | |
1959 | % \begin{macro}{\sd@abbrev} | |
1960 | % | |
1961 | % Sets up syntax diagram abbreviations. | |
1962 | % | |
1963 | % \begin{macrocode} | |
1964 | \def\sd@abbrev{% | |
1965 | \def\({\begin{stack}}% | |
1966 | \def\){\end{stack}}% | |
1967 | \def\<{\begin{rep}}% | |
1968 | \def\>{\end{rep}}% | |
1969 | \expandafter\def% | |
1970 | \csname\ifx\gr@leftsq\@@undefined[\else gr@leftsq\fi\endcsname% | |
1971 | {\begin{stack}\\}% | |
1972 | \expandafter\let% | |
1973 | \csname\ifx\gr@rightsq\@@undefined]\else gr@rightsq\fi\endcsname% | |
1974 | \)% | |
1975 | } | |
1976 | % \end{macrocode} | |
1977 | % | |
1978 | % \end{macro} | |
1979 | % | |
1980 | % \subsubsection{The \protect\env{syntdiag} environment} | |
1981 | % | |
1982 | % All syntax diagrams are contained within a \env{syntdiag} environment. | |
1983 | % | |
1984 | % \begin{environment}{syntdiag} | |
1985 | % | |
1986 | % The only argument is a collection of declarations, which by | |
1987 | % default is | |
1988 | % | |
1989 | % \begin{listing} | |
1990 | %\sdsize\sdlengths | |
1991 | % \end{listing} | |
1992 | % | |
1993 | % However, if the optional argument is not specified, \TeX\ reads the first | |
1994 | % character of the environment, which may not be catcoded correctly. We set | |
1995 | % up the catcodes first, using the |\syntaxShortcuts| command, and then read | |
1996 | % the argument. We don't use |\newcommand|, because that would involve | |
1997 | % creating yet \emph{another} macro. Time to fiddle with |\@ifnextchar| | |
1998 | % \dots | |
1999 | % | |
2000 | % \begin{macrocode} | |
2001 | \def\syntdiag{% | |
2002 | \syntaxShortcuts\sd@tok@i\sd@tok@ii% | |
2003 | \sd@abbrev% | |
2004 | \@ifnextchar[\syntdiag@i{\syntdiag@i[]}% | |
2005 | } | |
2006 | \def\syntdiag@i[#1]{\@ifnextchar[{\syntdiag@ii{#1}}{\syntdiag@ii{#1}[b]}} | |
2007 | % \end{macrocode} | |
2008 | % | |
2009 | % Now we actually do the job we're meant to. | |
2010 | % | |
2011 | % \begin{macrocode} | |
2012 | \def\syntdiag@ii#1[#2]{% | |
2013 | % \end{macrocode} | |
2014 | % | |
2015 | % The first thing to do is execute the user's declarations. We then set | |
2016 | % up things for the font size. | |
2017 | % | |
2018 | % \begin{macrocode} | |
2019 | \sdsize\sdlengths% | |
2020 | #1% | |
2021 | \sd@setsize% | |
2022 | % \end{macrocode} | |
2023 | % | |
2024 | % Sort out the omission of left or right sides. | |
2025 | % | |
2026 | % \begin{macrocode} | |
2027 | \sd@lefttrue\sd@righttrue% | |
2028 | \if#2l\sd@rightfalse\fi% | |
2029 | \if#2r\sd@leftfalse\fi% | |
2030 | % \end{macrocode} | |
2031 | % | |
2032 | % Next, we start a list, to change the text layout. | |
2033 | % | |
2034 | % \begin{macrocode} | |
2035 | \list{}{% | |
2036 | \leftmargin\sdindent% | |
2037 | \rightmargin\leftmargin% | |
2038 | \labelsep\z@% | |
2039 | \labelwidth\z@% | |
2040 | }% | |
2041 | \item[]% | |
2042 | % \end{macrocode} | |
2043 | % | |
2044 | % We reconfigure the paragraph format quite a lot now. We clear | |
2045 | % |\parfillskip| to avoid any justification at the end of the paragraph. | |
2046 | % We also turn off paragraph indentation. | |
2047 | % | |
2048 | % \begin{macrocode} | |
2049 | \parfillskip\z@% | |
2050 | \noindent% | |
2051 | % \end{macrocode} | |
2052 | % | |
2053 | % Next, we add in the arrows on the beginning of the line, and a bit of | |
2054 | % glue. | |
2055 | % | |
2056 | % \begin{macrocode} | |
2057 | \ifsd@left% | |
2058 | \sd@qarrow{>>-}% | |
2059 | \nobreak\sd@rule\hskip\sdstartspace% | |
2060 | \fi% | |
2061 | % \end{macrocode} | |
2062 | % | |
2063 | % This is the base level of the diagram, so we enable line breaking. | |
2064 | % | |
2065 | % \begin{macrocode} | |
2066 | \sd@basetrue% | |
2067 | % \end{macrocode} | |
2068 | % | |
2069 | % Since the objects being broken are rather large, we enable sloppy line | |
2070 | % breaking. We also try to avoid page breaks in mid-diagram, by upping the | |
2071 | % |\interlinepenalty|. | |
2072 | % | |
2073 | % \begin{macrocode} | |
2074 | \sloppy% | |
2075 | \interlinepenalty100% | |
2076 | \hyphenpenalty0% | |
2077 | % \end{macrocode} | |
2078 | % | |
2079 | % We handle all the spacing within the environment, so we make \TeX\ ignore | |
2080 | % spaces and newlines. | |
2081 | % | |
2082 | % \begin{macrocode} | |
2083 | \catcode`\ 9% | |
2084 | \catcode`\^^M9% | |
2085 | % \end{macrocode} | |
2086 | % | |
2087 | % We now have to change the behaviour of |\\| to line-break syntax diagrams. | |
2088 | % | |
2089 | % \begin{macrocode} | |
2090 | \let\\\sd@newline% | |
2091 | \ignorespaces% | |
2092 | } | |
2093 | % \end{macrocode} | |
2094 | % | |
2095 | % When we end the diagram, we just have to add in the final fillskip, and | |
2096 | % double arrow. | |
2097 | % | |
2098 | % \begin{macrocode} | |
2099 | \def\endsyntdiag{% | |
2100 | \unskip% | |
2101 | \ifsd@right% | |
2102 | \nobreak\sd@rule\hskip\sdmidskip% | |
2103 | \sd@rule\hskip\sdfinalskip% | |
2104 | \sd@qarrow{-><}% | |
2105 | \else% | |
2106 | \hskip\sdfinalskip% | |
2107 | \vadjust{}% | |
2108 | \fi% | |
2109 | \endlist% | |
2110 | } | |
2111 | % \end{macrocode} | |
2112 | % | |
2113 | % \end{environment} | |
2114 | % | |
2115 | % \begin{environment}{syntdiag*} | |
2116 | % | |
2117 | % The starred form of \env{syntdiag} typesets a syntax diagram in LR-mode; | |
2118 | % this is useful if you're describing parts of syntax diagrams, for example. | |
2119 | % | |
2120 | % This is in fact really easy. The first bit which checks for an optional | |
2121 | % argument is almost identical to the non-$*$ version. | |
2122 | % | |
2123 | % \begin{macrocode} | |
2124 | \@namedef{syntdiag*}{% | |
2125 | \syntaxShortcuts\sd@tok@i\sd@tok@ii% | |
2126 | \sd@abbrev% | |
2127 | \@tempswatrue% | |
2128 | \@ifnextchar[\syntdiag@s@i{\syntdiag@s@i[]}% | |
2129 | } | |
2130 | % \end{macrocode} | |
2131 | % | |
2132 | % Handle another optional argument giving the width of the box to fill. | |
2133 | % | |
2134 | % \begin{macrocode} | |
2135 | \def\syntdiag@s@i[#1]{% | |
2136 | \@ifnextchar[{\syntdiag@s@ii{#1}}{\syntdiag@s@iii{#1}{\hbox}}% | |
2137 | } | |
2138 | \def\syntdiag@s@ii#1[#2]{% | |
2139 | \def\@tempa{#2}\def\@tempb{*}% | |
2140 | \ifx\@tempa\@tempb% | |
2141 | \@tempswafalse% | |
2142 | \syntdiag@s@iii{#1}{}% | |
2143 | \else% | |
2144 | \syntdiag@s@iii{#1}{\hb@xt@#2}% | |
2145 | \fi% | |
2146 | } | |
2147 | % \end{macrocode} | |
2148 | % | |
2149 | % Now to actually start the display. This is mostly simple. Just to make | |
2150 | % sure about the LR-ness of the typesetting, I'll put everything in an hbox. | |
2151 | % | |
2152 | % \begin{macrocode} | |
2153 | \def\syntdiag@s@iii#1#2{% | |
2154 | \leavevmode% | |
2155 | #2\bgroup% | |
2156 | % \end{macrocode} | |
2157 | % | |
2158 | % Now configure the typesetting according to the user's wishes. | |
2159 | % | |
2160 | % \begin{macrocode} | |
2161 | \let\@@left\left% | |
2162 | \let\@@right\right% | |
2163 | \def\left##1{\def\sd@startarr{##1}}% | |
2164 | \def\right##1{\def\sd@endarr{##1}}% | |
2165 | \left{>-}\right{->}% | |
2166 | \sdsize\sdlengths% | |
2167 | #1% | |
2168 | \sd@setsize% | |
2169 | \let\left\@@left% | |
2170 | \let\right\@@right% | |
2171 | \sd@lefttrue\sd@righttrue% | |
2172 | \ifx\sd@startarr\@empty\sd@leftfalse\fi% | |
2173 | \ifx\sd@endarr\@empty\sd@rightfalse\fi% | |
2174 | % \end{macrocode} | |
2175 | % | |
2176 | % Put in the initial double-arrow. | |
2177 | % | |
2178 | % \begin{macrocode} | |
2179 | \ifsd@left% | |
2180 | \sd@qarrow\sd@startarr% | |
2181 | \sd@rule\hskip\sdmidskip% | |
2182 | \fi% | |
2183 | % \end{macrocode} | |
2184 | % | |
2185 | % We're in horizontal mode, so don't bother with linebreaking. | |
2186 | % | |
2187 | % \begin{macrocode} | |
2188 | \if@tempswa\sd@basefalse\else\sd@basetrue\fi% | |
2189 | % \end{macrocode} | |
2190 | % | |
2191 | % Finally, disable spaces and things. | |
2192 | % | |
2193 | % \begin{macrocode} | |
2194 | \catcode`\ 9% | |
2195 | \catcode`\^^M9% | |
2196 | \ignorespaces% | |
2197 | } | |
2198 | % \end{macrocode} | |
2199 | % | |
2200 | % Ending the environment is very similar. | |
2201 | % | |
2202 | % \begin{macrocode} | |
2203 | \@namedef{endsyntdiag*}{% | |
2204 | \unskip% | |
2205 | \ifsd@right% | |
2206 | \sd@rule\hskip\sdmidskip% | |
2207 | \ifsd@base\else\sd@rule\hskip\sdfinalskip\fi% | |
2208 | \sd@qarrow\sd@endarr% | |
2209 | \else% | |
2210 | \hskip\sdmidskip% | |
2211 | \ifsd@base\else\hskip\sdfinalskip\fi% | |
2212 | \fi% | |
2213 | \egroup% | |
2214 | } | |
2215 | % \end{macrocode} | |
2216 | % | |
2217 | % \end{environment} | |
2218 | % | |
2219 | % \begin{macro}{\sd@qarrow} | |
2220 | % | |
2221 | % This typesets the various left and right arrows required in syntax | |
2222 | % diagrams. The argument is one of \syntax{`>>-', `->', `>-' or `-><'}. | |
2223 | % | |
2224 | % \begin{macrocode} | |
2225 | \def\sd@qarrow#1{% | |
2226 | \begingroup% | |
2227 | \lccode`\~=`\<\lowercase{\def~{<}}% | |
2228 | \hbox{\csname sd@arr@#1\endcsname}% | |
2229 | \endgroup% | |
2230 | } | |
2231 | \@namedef{sd@arr@>>-}{\sd@rightarr\kern-.5\p@\sd@rightarr\kern-\p@} | |
2232 | \@namedef{sd@arr@>-}{\sd@rightarr\kern-\p@} | |
2233 | \@namedef{sd@arr@->}{\sd@rightarr} | |
2234 | \@namedef{sd@arr@-><}{\sd@rightarr\kern-\p@\sd@leftarr} | |
2235 | \@namedef{sd@arr@...}{$\cdots$} | |
2236 | \@namedef{sd@arr@-}{} | |
2237 | \@namedef{sd@arr@}{} | |
2238 | % \end{macrocode} | |
2239 | % | |
2240 | % \end{macro} | |
2241 | % | |
2242 | % \begin{macro}{\sd@newline} | |
2243 | % | |
2244 | % The line breaking within a syntax diagram is controlled by the | |
2245 | % |\sd@newline| command, to which |\\| is assigned. | |
2246 | % | |
2247 | % We support all the standard \LaTeX\ features here. The line breaking | |
2248 | % involves adding a fill skip and arrow, moving to the next line, adding | |
2249 | % an arrow and a rule, and continuing. | |
2250 | % | |
2251 | % \begin{macrocode} | |
2252 | \def\sd@newline{\@ifstar{\vadjust{\penalty\@M}\sd@nl@i}\sd@nl@i} | |
2253 | \def\sd@nl@i{\@ifnextchar[\sd@nl@ii\sd@nl@iii} | |
2254 | \def\sd@nl@ii[#1]{\vspace{#1}\sd@nl@iii} | |
2255 | \def\sd@nl@iii{% | |
2256 | \nobreak\sd@rule\hskip\sdmidskip% | |
2257 | \sd@rule\hskip\sdfinalskip% | |
2258 | \kern-3\p@% | |
2259 | \sd@rightarr% | |
2260 | \newline% | |
2261 | \sd@rightarr% | |
2262 | \nobreak\sd@rule\hskip\sdstartspace% | |
2263 | \sd@rule\hskip3.5\p@% | |
2264 | } | |
2265 | % \end{macrocode} | |
2266 | % | |
2267 | % \end{macro} | |
2268 | % | |
2269 | % \subsubsection{Putting things in the right place} | |
2270 | % | |
2271 | % Syntax diagrams have fairly stiff requirements on the positioning of text | |
2272 | % relative to the diagram's rules. To help people (and me) to write | |
2273 | % extensions to the syntax diagram typesetting which automatically put things | |
2274 | % in the right place, I provide some simple macros. | |
2275 | % | |
2276 | % \begin{environment}{sdbox} | |
2277 | % | |
2278 | % By placing some text in the \env{sdbox} environment, it will be read into a | |
2279 | % box and then output at the correct height for the syntax diagram. Note | |
2280 | % that stuff in the box is set in horizontal (LR) mode, so you'll have to use | |
2281 | % a \env{minipage} if you want formatted text. The macro also supplies rules | |
2282 | % on either side of the box, with a length given in the environment's | |
2283 | % argument. | |
2284 | % | |
2285 | % Macro writers are given explicit permission to use this environment through | |
2286 | % the |\sdbox| and |\endsdbox| commands if this makes life easier. | |
2287 | % | |
2288 | % The calculation in the |\endsdbox| macro works out how to centre the box | |
2289 | % vertically over the baseline. If the box's height is~$h$, and its depth | |
2290 | % is~$d$, then its centre-line is $(h+d)/2$ from the bottom of the box. | |
2291 | % Since the baseline is already $d$ from the bottom, we need to lower the box | |
2292 | % by $(h+d)/2 - d$, or $h/2-d/2$. | |
2293 | % | |
2294 | % \begin{macrocode} | |
2295 | \def\sdbox#1{% | |
2296 | \@tempskipa#1\relax% | |
2297 | \sd@gap\@tempskipa% | |
2298 | \setbox\z@\hbox\bgroup% | |
2299 | \begingroup% | |
2300 | \catcode`\ 10% | |
2301 | \catcode`\^^M5% | |
2302 | \synshortsoff% | |
2303 | } | |
2304 | \def\endsdbox{% | |
2305 | \endgroup% | |
2306 | \egroup% | |
2307 | \@tempdima\ht\z@% | |
2308 | \advance\@tempdima-\dp\z@% | |
2309 | \advance\@tempdima-\tw@\sd@mid% | |
2310 | \lower.5\@tempdima\box\z@% | |
2311 | \sd@lefttrue% | |
2312 | \sd@gap\@tempskipa% | |
2313 | } | |
2314 | % \end{macrocode} | |
2315 | % | |
2316 | % \end{environment} | |
2317 | % | |
2318 | % \subsubsection{Typesetting syntactic items} | |
2319 | % | |
2320 | % Using the hooks built into the syntax abbreviations above, we typeset | |
2321 | % the text into a box, and write it out, centred over the baseline. A strut | |
2322 | % helps to keep the actual text baselines level for short pieces of text. | |
2323 | % | |
2324 | % \begin{macro}{\sd@tok@i} | |
2325 | % | |
2326 | % The preamble for a syntax abbreviation. We start a box, and set the | |
2327 | % space and return characters to work again. A strut is added to the box to | |
2328 | % ensure correct vertical spacing for normal text. | |
2329 | % | |
2330 | % \begin{macrocode} | |
2331 | \def\sd@tok@i{% | |
2332 | \sdbox\sdtokskip% | |
2333 | \strut% | |
2334 | \space% | |
2335 | } | |
2336 | % \end{macrocode} | |
2337 | % | |
2338 | % \end{macro} | |
2339 | % | |
2340 | % \begin{macro}{\sd@tok@ii} | |
2341 | % | |
2342 | % \begin{macrocode} | |
2343 | \def\sd@tok@ii{% | |
2344 | \space% | |
2345 | \endsdbox% | |
2346 | } | |
2347 | % \end{macrocode} | |
2348 | % | |
2349 | % \end{macro} | |
2350 | % | |
2351 | % \subsubsection{Inserting other pieces of text} | |
2352 | % | |
2353 | % Arbitrary text may be put into a syntax diagram through the use of the | |
2354 | % |\tok| macro. Its `argument' is typeset in the same way as a syntactic | |
2355 | % item (centred over the baseline). The implementation goes to some effort | |
2356 | % to ensure that the text is not actually an argument, to allow category | |
2357 | % codes to change while the text is being typeset. | |
2358 | % | |
2359 | % \begin{macro}{\tok} | |
2360 | % | |
2361 | % We start a box, and make space and return do their normal jobs. We use | |
2362 | % |\aftergroup| to regain control once the box is finished. |\doafter| is | |
2363 | % used to get control after the group finishes. | |
2364 | % | |
2365 | % \begin{macrocode} | |
2366 | \def\tok#{% | |
2367 | \sdbox\sdtokskip% | |
2368 | \strut% | |
2369 | \enspace% | |
2370 | \syntaxShortcuts\relax\relax% | |
2371 | \doafter\sd@tok% | |
2372 | } | |
2373 | % \end{macrocode} | |
2374 | % | |
2375 | % The |\sd@tok| macro is similar to |\sd@tok@ii| above. | |
2376 | % | |
2377 | % \begin{macrocode} | |
2378 | \def\sd@tok{% | |
2379 | \enspace% | |
2380 | \endsdbox% | |
2381 | } | |
2382 | % \end{macrocode} | |
2383 | % | |
2384 | % \end{macro} | |
2385 | % | |
2386 | % \subsubsection{The \protect\env{stack} environment} | |
2387 | % | |
2388 | % The \env{stack} environment is used to present alternatives in a syntax | |
2389 | % diagram. The alternatives are separated by |\\| commands. | |
2390 | % | |
2391 | % \begin{macro}{\stack} | |
2392 | % | |
2393 | % Handle the optional arguments. | |
2394 | % | |
2395 | % \begin{macrocode} | |
2396 | \def\stack{\@ifnextchar[\stack@i{\stack@i[t]}} | |
2397 | \def\stack@i[#1]{\@ifnextchar[{\stack@ii{#1}}{\stack@ii{#1}[b]}} | |
2398 | \def\stack@ii#1[#2]{% | |
2399 | % \end{macrocode} | |
2400 | % | |
2401 | % First, we add some horizontal space. | |
2402 | % | |
2403 | % \begin{macrocode} | |
2404 | \sd@gap\sdmidskip% | |
2405 | % \end{macrocode} | |
2406 | % | |
2407 | % We're within a complex construction, so we need to clear the |\ifsd@base| | |
2408 | % flag. | |
2409 | % | |
2410 | % \begin{macrocode} | |
2411 | \begingroup\sd@basefalse% | |
2412 | % \end{macrocode} | |
2413 | % | |
2414 | % The top and bottom rows of the stack are different to the others, since | |
2415 | % the vertical rules mustn't extend all the way up the side of the item. | |
2416 | % The bottom row is handled separately by |\endstack| below. The top row | |
2417 | % must be handled via a flag, |\ifsd@toplayer|. | |
2418 | % | |
2419 | % Initially, the flag must be set true. | |
2420 | % | |
2421 | % \begin{macrocode} | |
2422 | \sd@toplayertrue% | |
2423 | % \end{macrocode} | |
2424 | % | |
2425 | % We set the |\\| command to separate the items in the |\halign|. | |
2426 | % | |
2427 | % \begin{macrocode} | |
2428 | \let\\\sd@stackcr% | |
2429 | % \end{macrocode} | |
2430 | % | |
2431 | % Sort out which sides of the construction are actually emitted. | |
2432 | % | |
2433 | % \begin{macrocode} | |
2434 | \sd@righttrue\if#2l\sd@rightfalse\fi% | |
2435 | % \end{macrocode} | |
2436 | % | |
2437 | % The actual structure must be set in vertical mode, so we must place it | |
2438 | % in a box. The position argument determines whether this must be a | |
2439 | % |\vbox| or a |\vtop|. We also insert a bit of rounding if the options say | |
2440 | % we must. | |
2441 | % | |
2442 | % \begin{macrocode} | |
2443 | \if#1t% | |
2444 | \let\@tempa\vtop% | |
2445 | \sd@toptrue% | |
2446 | \ifsd@left\ifsd@round\llap{\sd@trcirc\kern\tw@\sdrulewidth}\fi\fi% | |
2447 | \else\if#1b% | |
2448 | \let\@tempa\vbox% | |
2449 | \sd@topfalse% | |
2450 | \ifsd@left\ifsd@round\llap{\sd@brcirc\kern\tw@\sdrulewidth}\fi\fi% | |
2451 | \else% | |
2452 | \sd@err{Bad position argument passed to stack}% | |
2453 | {The positioning argument must be one of `t' or `b'. I% | |
2454 | have^^Jassumed you meant to type `t'.}% | |
2455 | \let\@tempa\vtop% | |
2456 | \fi\fi% | |
2457 | % \end{macrocode} | |
2458 | % | |
2459 | % Now we start the box, which we will complete at the end of the environment. | |
2460 | % | |
2461 | % \begin{macrocode} | |
2462 | \@tempa\bgroup% | |
2463 | % \end{macrocode} | |
2464 | % | |
2465 | % We must remove any extra space between rows of the table, since the rules | |
2466 | % will not join up correctly. We can use |\offinterlineskip| safely, since | |
2467 | % each individual row contains a strut. | |
2468 | % | |
2469 | % \begin{macrocode} | |
2470 | \offinterlineskip% | |
2471 | % \end{macrocode} | |
2472 | % | |
2473 | % Now we can start the alignment. We actually use \PlainTeX's |\ialign| | |
2474 | % macro, which also clears |\tabskip| for us. | |
2475 | % | |
2476 | % \begin{macrocode} | |
2477 | \ialign\bgroup% | |
2478 | % \end{macrocode} | |
2479 | % | |
2480 | % The preamble is trivial, since we must do all of the work ourselves | |
2481 | % | |
2482 | % \begin{macrocode} | |
2483 | ##\cr% | |
2484 | % \end{macrocode} | |
2485 | % | |
2486 | % We can now start putting the text into a box ready for typesetting later. | |
2487 | % The strut makes the vertical spacing correct. | |
2488 | % | |
2489 | % \begin{macrocode} | |
2490 | \setbox\z@\hbox\bgroup% | |
2491 | \strut% | |
2492 | } | |
2493 | % \end{macrocode} | |
2494 | % | |
2495 | % \end{macro} | |
2496 | % | |
2497 | % \begin{macro}{\endstack} | |
2498 | % | |
2499 | % The first part of this is similar to the |\sd@stackcr| macro below, except | |
2500 | % that the vertical rules are different. We don't support rounded edges | |
2501 | % on single-row stacks, although this isn't a great loss to humanity. | |
2502 | % | |
2503 | % \begin{macrocode} | |
2504 | \def\endstack{% | |
2505 | \ifsd@right\else\unskip\fi% | |
2506 | \egroup% | |
2507 | \ifsd@toplayer% | |
2508 | \sd@dostack\sd@upper\sd@lower\sd@nocirc\sd@nocirc% | |
2509 | \else% | |
2510 | \ifsd@round% | |
2511 | \ifsd@top% | |
2512 | \sd@dostack{\ht\z@}\sd@botcirc\sd@blcirc\sd@brcirc% | |
2513 | \else% | |
2514 | \sd@dostack{\ht\z@}\sd@botcirc\sd@nocirc\sd@nocirc% | |
2515 | \fi% | |
2516 | \else% | |
2517 | \sd@dostack{\ht\z@}\sd@lower\relax\relax% | |
2518 | \fi% | |
2519 | \fi% | |
2520 | % \end{macrocode} | |
2521 | % | |
2522 | % We now close the |\halign| and the vbox we created. | |
2523 | % | |
2524 | % \begin{macrocode} | |
2525 | \egroup% | |
2526 | \egroup% | |
2527 | % \end{macrocode} | |
2528 | % | |
2529 | % Deal with any rounding we started off. | |
2530 | % | |
2531 | % \begin{macrocode} | |
2532 | \ifsd@right\ifsd@round% | |
2533 | \ifsd@top | |
2534 | \rlap{\kern\tw@\sdrulewidth\sd@tlcirc}% | |
2535 | \else% | |
2536 | \rlap{\kern\tw@\sdrulewidth\sd@blcirc}% | |
2537 | \fi% | |
2538 | \fi\fi% | |
2539 | % \end{macrocode} | |
2540 | % | |
2541 | % Finally, we add some horizontal glue to space the diagram out. | |
2542 | % | |
2543 | % \begin{macrocode} | |
2544 | \endgroup\sd@lefttrue\ifsd@right\sd@gap\sdmidskip\fi% | |
2545 | } | |
2546 | % \end{macrocode} | |
2547 | % | |
2548 | % \end{macro} | |
2549 | % | |
2550 | % \begin{macro}{\sd@stackcr} | |
2551 | % | |
2552 | % The |\\| command is set to this macro during a \env{stack} environment. | |
2553 | % | |
2554 | % \begin{macrocode} | |
2555 | \def\sd@stackcr{% | |
2556 | % \end{macrocode} | |
2557 | % | |
2558 | % The first job is to close the box containing the previous item. | |
2559 | % | |
2560 | % \begin{macrocode} | |
2561 | \ifsd@right\else\unskip\fi% | |
2562 | \egroup% | |
2563 | % \end{macrocode} | |
2564 | % | |
2565 | % Now we typeset the vertical rules differently depending on whether this is | |
2566 | % the first item in the stack. This looks quite terrifying initially, but | |
2567 | % it's just an enumeration of the possible cases for the different values | |
2568 | % of |\ifsd@toplayer|, |\ifsd@top| and |\ifsd@round|, putting in appropriate | |
2569 | % rules and arcs in the right places. | |
2570 | % | |
2571 | % \begin{macrocode} | |
2572 | \ifsd@toplayer% | |
2573 | \ifsd@round% | |
2574 | \ifsd@top% | |
2575 | \sd@dostack\sd@topcirc{\dp\z@}\sd@nocirc\sd@nocirc% | |
2576 | \else% | |
2577 | \sd@dostack\sd@topcirc{\dp\z@}\sd@tlcirc\sd@trcirc% | |
2578 | \fi% | |
2579 | \else% | |
2580 | \sd@dostack\sd@upper{\dp\z@}\relax\relax% | |
2581 | \fi% | |
2582 | \else% | |
2583 | \ifsd@round% | |
2584 | \ifsd@top% | |
2585 | \sd@dostack{\ht\z@}{\dp\z@}\sd@blcirc\sd@brcirc% | |
2586 | \else% | |
2587 | \sd@dostack{\ht\z@}{\dp\z@}\sd@tlcirc\sd@trcirc% | |
2588 | \fi% | |
2589 | \else% | |
2590 | \sd@dostack{\ht\z@}{\dp\z@}\relax\relax% | |
2591 | \fi% | |
2592 | \fi% | |
2593 | % \end{macrocode} | |
2594 | % | |
2595 | % The next item won't be the first, so we clear the flag. | |
2596 | % | |
2597 | % \begin{macrocode} | |
2598 | \sd@toplayerfalse% | |
2599 | % \end{macrocode} | |
2600 | % | |
2601 | % Now we have to set up the next cell. We put the text into a box again. | |
2602 | % | |
2603 | % \begin{macrocode} | |
2604 | \setbox\z@\hbox\bgroup% | |
2605 | \strut% | |
2606 | } | |
2607 | % \end{macrocode} | |
2608 | % | |
2609 | % \end{macro} | |
2610 | % | |
2611 | % \begin{macro}{\sd@dostack} | |
2612 | % | |
2613 | % Actually typesetting the text in a cell is performed here. The macro is | |
2614 | % called as | |
2615 | % \begin{quote}\synshorts | |
2616 | % "\\sd@dostack{"<height>"}{"<depth>"}{"<left-arc>"}{"<right-arc>"}" | |
2617 | % \end{quote} | |
2618 | % where \<height> and \<depth> are the height and depth of the vertical | |
2619 | % rules to put around the item, and \<left-arc> and \<right-arc> are | |
2620 | % commands to draw rounded edges on the left and right hand sides of the | |
2621 | % item. | |
2622 | % | |
2623 | % The values for the height and depth are quite often going to be the height | |
2624 | % and depth of box~0. Since we empty box~0 in the course of typesetting the | |
2625 | % row, we need to cache the sizes on entry. | |
2626 | % | |
2627 | % \begin{macrocode} | |
2628 | \def\sd@dostack#1#2#3#4{% | |
2629 | \@tempdima#1% | |
2630 | \@tempdimb#2% | |
2631 | \ifsd@left% | |
2632 | \kern-\tw@\sdrulewidth% | |
2633 | \vrule\@height\@tempdima\@depth\@tempdimb\@width\tw@\sdrulewidth% | |
2634 | #3% | |
2635 | \sd@rule\hfil% | |
2636 | \sd@gap\sdtokskip% | |
2637 | \else% | |
2638 | \hfill% | |
2639 | \fi% | |
2640 | \unhbox\z@% | |
2641 | \ifsd@right% | |
2642 | \sd@gap\sdtokskip% | |
2643 | \sd@rule\hfil% | |
2644 | #4% | |
2645 | \vrule\@height\@tempdima\@depth\@tempdimb\@width\tw@\sdrulewidth% | |
2646 | \kern-\tw@\sdrulewidth% | |
2647 | \else% | |
2648 | \hfill% | |
2649 | \fi% | |
2650 | \cr% | |
2651 | } | |
2652 | % \end{macrocode} | |
2653 | % | |
2654 | % \end{macro} | |
2655 | % | |
2656 | % \subsubsection{The \protect\env{rep} environment} | |
2657 | % | |
2658 | % The \env{rep} environment is used for typesetting loops in the diagram. | |
2659 | % Again, we use |\halign| for the typesetting. Loops are simpler than | |
2660 | % stacks, however, since there are always two rows. We store both rows in | |
2661 | % box registers, and build the loop at the end. | |
2662 | % | |
2663 | % \begin{macro}{\rep} | |
2664 | % | |
2665 | % Again, we use |\newcommand| to process the optional argument. | |
2666 | % | |
2667 | % \begin{macrocode} | |
2668 | \newcommand\rep[1][t]{% | |
2669 | % \end{macrocode} | |
2670 | % | |
2671 | % First, leave a gap on the left side. | |
2672 | % | |
2673 | % \begin{macrocode} | |
2674 | \sd@gap\sdmidskip% | |
2675 | % \end{macrocode} | |
2676 | % | |
2677 | % We're not at base level any more, so disable linebreaking. | |
2678 | % | |
2679 | % \begin{macrocode} | |
2680 | \begingroup\sd@basefalse% | |
2681 | % \end{macrocode} | |
2682 | % | |
2683 | % Remember we're going backwards now. | |
2684 | % | |
2685 | % \begin{macrocode} | |
2686 | \ifsd@backwards\sd@backwardsfalse\else\sd@backwardstrue\fi% | |
2687 | % \end{macrocode} | |
2688 | % | |
2689 | % Define |\\| to separate the two parts of the loop. | |
2690 | % | |
2691 | % \begin{macrocode} | |
2692 | \let\\\sd@loop% | |
2693 | % \end{macrocode} | |
2694 | % | |
2695 | % Now check the argument, and use the appropriate type of box. In addition | |
2696 | % to changing the typesetting, we must remember which way up to typeset the | |
2697 | % loop, since the end code must always put the first argument on the | |
2698 | % baseline, with the loop either above or below. | |
2699 | % | |
2700 | % \begin{macrocode} | |
2701 | \if#1t% | |
2702 | \let\@tempa\vbox% | |
2703 | \sd@toptrue% | |
2704 | \else\if#1b% | |
2705 | \let\@tempa\vtop% | |
2706 | \sd@topfalse% | |
2707 | \else% | |
2708 | \sd@err{Bad position argument passed to loop}% | |
2709 | {The positioning argument must be `t' or `b'. I have^^J% | |
2710 | assumed you meant to type `t'.}% | |
2711 | \let\@tempa\vbox% | |
2712 | \sd@toptrue% | |
2713 | \fi\fi% | |
2714 | % \end{macrocode} | |
2715 | % | |
2716 | % Now we start the box. | |
2717 | % | |
2718 | % \begin{macrocode} | |
2719 | \@tempa\bgroup% | |
2720 | % \end{macrocode} | |
2721 | % | |
2722 | % The loop is by default empty, apart from a strut. This is put into box~1. | |
2723 | % | |
2724 | % \begin{macrocode} | |
2725 | \setbox\tw@\copy\strutbox% | |
2726 | % \end{macrocode} | |
2727 | % | |
2728 | % Now start typesetting the main text in box~0. | |
2729 | % | |
2730 | % \begin{macrocode} | |
2731 | \setbox\z@\hbox\bgroup\strut% | |
2732 | } | |
2733 | % \end{macrocode} | |
2734 | % | |
2735 | % \end{macro} | |
2736 | % | |
2737 | % \begin{macro}{\endrep} | |
2738 | % | |
2739 | % The final code must first close whatever box was open. | |
2740 | % | |
2741 | % \begin{macrocode} | |
2742 | \def\endrep{% | |
2743 | \egroup% | |
2744 | % \end{macrocode} | |
2745 | % | |
2746 | % Now we typeset the loop, depending on which way up it was meant to be. | |
2747 | % Again, this terrifying piece of code is a simple list of possibile values | |
2748 | % of our various flags. | |
2749 | % | |
2750 | % \begin{macrocode} | |
2751 | \ifsd@top% | |
2752 | \ifsd@round% | |
2753 | \sd@doloop\tw@\z@\relax\relax% | |
2754 | \sd@tlcirc\sd@trcirc{\sd@rlc\sd@blcirc}{\sd@llc\sd@brcirc}% | |
2755 | \else% | |
2756 | \sd@doloop\tw@\z@\relax\sd@downarr\relax\relax\relax\relax% | |
2757 | \fi% | |
2758 | \else% | |
2759 | \ifsd@round% | |
2760 | \sd@doloop\z@\tw@\relax\relax% | |
2761 | {\sd@rlc\sd@tlcirc}{\sd@llc\sd@trcirc}\sd@blcirc\sd@brcirc% | |
2762 | \else% | |
2763 | \sd@doloop\z@\tw@\sd@uparr\relax\relax\relax\relax\relax% | |
2764 | \fi% | |
2765 | \fi% | |
2766 | % \end{macrocode} | |
2767 | % | |
2768 | % Close the vbox we opened. | |
2769 | % | |
2770 | % \begin{macrocode} | |
2771 | \egroup% | |
2772 | % \end{macrocode} | |
2773 | % | |
2774 | % Finally, we leave a gap before the next structure. | |
2775 | % | |
2776 | % \begin{macrocode} | |
2777 | \endgroup\sd@gap\sdmidskip% | |
2778 | } | |
2779 | % \end{macrocode} | |
2780 | % | |
2781 | % \end{macro} | |
2782 | % | |
2783 | % \begin{macro}{\sd@loop} | |
2784 | % | |
2785 | % This macro handles the |\\| command within a loop environment. We close | |
2786 | % the current box, and start filling in box~1. We also redefine |\\| to | |
2787 | % raise an error when the |\\| command is used again. | |
2788 | % | |
2789 | % \begin{macrocode} | |
2790 | \def\sd@loop{% | |
2791 | \egroup% | |
2792 | \def\\{\sd@err{Too many \string\\\space commands in loop}\@ehc}% | |
2793 | \setbox\tw@\hbox\bgroup\strut% | |
2794 | } | |
2795 | % \end{macrocode} | |
2796 | % | |
2797 | % \end{macro} | |
2798 | % | |
2799 | % \begin{macro}{\sd@doloop} | |
2800 | % | |
2801 | % This is the macro which actually creates the |\halign| for the loop. It | |
2802 | % is called with four arguments, as: | |
2803 | % \begin{quote}\synshorts | |
2804 | % "\\sd@doloop{"<top-box>"}{"<bottom-box>"}"^^A | |
2805 | % "{"<top-arrow>"}{"<btm-arrow>"}" \\ | |
2806 | % \hbox{}\quad "{"<top-left-arc>"}{"<top-right-arc>"}"^^A | |
2807 | % "{"<bottom-left-arc>"}{"<btm-right-arc>"}"^^A | |
2808 | % \kern-1in ^^A It may be overfull, but it looks OK to me ;-) | |
2809 | % \end{quote} | |
2810 | % | |
2811 | % The two \<box> arguments give the numbers of boxes to extract in the top | |
2812 | % and bottom rows of the alignment. The \<arrow> arguments specify | |
2813 | % characters to typeset at the end of the top and bottom rows for arrows. | |
2814 | % The various \<arc> arguments are commands which typeset arcs around the | |
2815 | % various parts of the items. | |
2816 | % | |
2817 | % We calculate the height and depth of the two boxes, and store them in | |
2818 | % \<dimen> registers, because the boxes are emptied before the right-hand | |
2819 | % rules are typeset. | |
2820 | % | |
2821 | % Actually, the two rows of the alignment are typeset in a different macro: | |
2822 | % we just pass the correct information on. | |
2823 | % | |
2824 | % \begin{macrocode} | |
2825 | \def\sd@doloop#1#2#3#4#5#6#7#8{% | |
2826 | \@tempdima\dp#1\relax% | |
2827 | \@tempdimb\ht#2\relax% | |
2828 | \offinterlineskip% | |
2829 | \ialign{% | |
2830 | ##\cr% | |
2831 | \ifsd@round% | |
2832 | \sd@doloop@i#1#3\sd@topcirc\@tempdima{#5}{#6}% | |
2833 | \sd@doloop@i#2#4\@tempdimb\sd@botcirc{#7}{#8}% | |
2834 | \else% | |
2835 | \sd@doloop@i#1#3\sd@upper\@tempdima{#5}{#6}% | |
2836 | \sd@doloop@i#2#4\@tempdimb\sd@lower{#7}{#8}% | |
2837 | \fi% | |
2838 | }% | |
2839 | } | |
2840 | % \end{macrocode} | |
2841 | % | |
2842 | % \end{macro} | |
2843 | % | |
2844 | % \begin{macro}{\sd@doloop@i} | |
2845 | % | |
2846 | % Here we do the actual job of typesetting the rows of a loop alignment. | |
2847 | % The four arguments are: | |
2848 | % \begin{quote}\synshorts | |
2849 | % "\\sd@doloop@i{"<box>"}{"<arrow>"}"^^A | |
2850 | % "{"<rule-height>"}{"<rule-depth>"}" \\ | |
2851 | % \hbox{}\quad "{"<left-arc>"}{"<right-arc>"}"^^A | |
2852 | % \end{quote} | |
2853 | % | |
2854 | % The arrow position is determined by the |\ifsd@backwards| flag. The rest | |
2855 | % is fairly simple. | |
2856 | % | |
2857 | % \begin{macrocode} | |
2858 | \def\sd@doloop@i#1#2#3#4#5#6{% | |
2859 | \ifsd@backwards#2\fi% | |
2860 | \kern-\tw@\sdrulewidth% | |
2861 | \vrule\@height#3\@depth#4\@width\tw@\sdrulewidth% | |
2862 | #5% | |
2863 | \sd@rule\hfill% | |
2864 | \sd@gap\sdtokskip% | |
2865 | \unhbox#1% | |
2866 | \sd@gap\sdtokskip% | |
2867 | \sd@rule\hfill% | |
2868 | #6% | |
2869 | \vrule\@height#3\@depth#4\@width\tw@\sdrulewidth% | |
2870 | \ifsd@backwards\else#2\fi% | |
2871 | \kern-\tw@\sdrulewidth% | |
2872 | \cr% | |
2873 | } | |
2874 | % \end{macrocode} | |
2875 | % | |
2876 | % \end{macro} | |
2877 | % | |
2878 | % \subsection{The end} | |
2879 | % | |
2880 | % Phew! That's all of it completed. I hope this collection of commands | |
2881 | % and environments is of some help to someone. | |
2882 | % | |
2883 | % \begin{macrocode} | |
2884 | %</package> | |
2885 | % \end{macrocode} | |
2886 | % | |
2887 | % \hfill Mark Wooding, \today | |
2888 | % | |
2889 | % \Finale | |
2890 | % | |
2891 | \endinput |