%D \module %D [ file=t-bnf, %D version=2004.6.23, %D title=\CONTEXT\ BNF Grammar Module, %D subtitle=Grammars, %D author={Nikolai Weibull}, %D date=\currentdate, %D copyright={Nikolai Weibull}] %C %C This module is NOT part of the \CONTEXT\ macro||package. %C This module is free software; you can redistribute it and/or modify %C it under the terms of the GNU General Public License as published by %C the Free Software Foundation; either version 2 of the License, or %C (at your option) any later version. %C %C This module is distributed in the hope that it will be useful, %C but WITHOUT ANY WARRANTY; without even the implied warranty of %C MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %C GNU General Public License for more details. %C %C You should have received a copy of the GNU General Public License %C along with this program; if not, write to the Free Software %C Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \writestatus{loading}{BNF Macros / Initialization} \unprotect %M \usemodule[bnf] %D We define a new system variable for our settings: \definesystemvariable{bnf} %D We need some constants for the multi||lingual interface, \startconstants english dutch terminalstart: terminalstart terminalstart terminalstop: terminalstop terminalstop nonterminalstart: nonterminalstart nonterminalstart nonterminalstop: nonterminalstop nonterminalstop is: is worden \stopconstants %D and while we're at it, lets define some variables. \startvariables english dutch bnfgrammar: bnfgrammar bnfspraakleer bnfgrammars: bnfgrammars bnfspraakleer \stopvariables %D Finally, we want the commands to be multi||lingually accessible, so we set %D that up as well: \startcommands english dutch setupbnfgrammar: setupbnfgrammar stelbnfspraakleer startbnfgrammar: startbnfgrammar startbnfspraakleer stopbnfgrammar: stopbnfgrammar startbnfspraakleer \stopcommands %D \macros %D {startbnfgrammar, stopbnfgrammar} %D %D Now to the interesting parts, those that are actually useful to the outside %D world. First we have the \type{\startbnfgrammar} and \type{\stopbnfgrammar} %D pairs, which are of course used to delimit \BNF\ grammars. We would like to %D define \type{\startbnfgrammar} as \type{\def\startbnfgrammar[#1]}, but a bug %D in \CONTEXT\ prevents us from doing this, as the first character in the %D grammar may be active, for example \type{<}, but while checking for the %D presence of \type{[}, it gets ruined. A way around it is of course to %D require that the user pass an empty \type{[]} pair, and we will use this %D method at the moment. \def\complexstartbnfgrammar[#1]% {\endgraf\nobreak\medskip \begingroup \setupbnfgrammar[#1]% \chardef\bnfsinglequote=`' \defineactivecharacter : {\@@bnfis} \defineactivecharacter | {\@@bnfoption} \defineactivecharacter " % {\thinspace\bgroup\@@bnfterminalstart\setupinlineverbatim% \defineactivecharacter " {\@@bnfterminalstop\egroup\thinspace}} \defineactivecharacter ' % {\thinspace\bgroup\@@bnfterminalstart\setupinlineverbatim% \defineactivecharacter ' {\@@bnfterminalstop\egroup\thinspace}} \catcode`<=13 \let\par=\bnfgrammarline \obeylines} \def\stopbnfgrammar{\medbreak\checknextindentation[\@@bnfindentnext]} \definecomplexorsimpleempty\startbnfgrammar %D \macros %D {<>,bnfgrammarrule} %D %D We need a couple more macros to deal with the interior of a \BNF\ grammar. %D \type{\<>} is used for non||terminals, and \type{\bnfgrammarrule} is used %D later on in \type{\bnfgrammarswitch} for continuing a line. \def\<#1>{\leavevmode\hbox{\@@bnfnonterminalstart#1\/\@@bnfnonterminalstop}} \bgroup \catcode`<=13 \global\let<=\< \gdef\bnfgrammarrule<#1>{\endgraf\indent\<#1>} \egroup %D \macros %D {bnfgrammarline, bnfgrammarswitch, bnfgrammarcont} %D %D These macros deal with the ending of a line in a grammar. %D \type{\bnfgrammarline} is called whenever a new line begins, and invokes %D \type{\bnfgrammarswitch} to determine what to do next. If the next token is %D \type{\<}, we will call upon \type{\bnfgrammarrule} to deal with the new %D rule. If it is \type{\stopbnfgrammar}, we end the top||level group, and let %D it process \type{\stopbnfgrammar} afterwards. Otherwise we invoke %D \type{\bnfgrammarcont}, which will end the line and add some indentation to %D the continuing line. \def\bnfgrammarline{\futurelet\next\bnfgrammarswitch} \def\bnfgrammarswitch% {\ifx\next\< \let\next=\bnfgrammarrule \else\ifx\next\stopbnfgrammar \let\next=\endgroup \else \let\next=\bnfgrammarcont \fi\fi \next} \def\bnfgrammarcont{\hfil\break\indent\qquad} %D \macros %D {setupbnfgrammar} %D %D We want to allow our users to change the way the \BNF\ grammars are typeset, %D so we define a setup command for them to use. %D %D It allows you to define the start and stop sequence for terminals and %D non||terminals, as well as colons (lhs / rhs separator) and vertical bars %D (alternative), and commas. This has been multi||lingualized above, so %D choose your language. \def\dosetupbnfgrammar[#1]% {\getparameters[\??bnf][#1]} \def\setupbnfgrammar% {\dosingleargument\dosetupbnfgrammar} \setupbnfgrammar [\c!terminalstart=\tttf, \c!terminalstop=, \c!nonterminalstart=\mathematics{\langle}, \c!nonterminalstop=\mathematics{\rangle}, \c!is={ \mathematics{\longrightarrow}}, \c!option=\mathematics{\vert}, \c!indentnext=\v!no] %D \macros %D {BNF} %D %D We also define a useful abbreviation to be used for header texts and labels. \logo[BNF]{bnf} %D And we use it here: \setupheadtext[\s!en][\v!bnfgrammar=\BNF\ Grammar] \setupheadtext[\s!en][\v!bnfgrammars=\BNF\ Grammars] \setuplabeltext[\s!en][\v!bnfgrammar=\BNF\ Grammar ] %D Finally we define a float to be use with \BNF\ grammars, so that we can %D finish off with something like this: %D %D \startbuffer %D \placebnfgrammar %D [][] %D {An example of a placed grammar.} %D {\startbnfgrammar[] %D : | "+" %D : "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" %D \stopbnfgrammar} %D \stopbuffer %D %D \typebuffer %D %D \getbuffer %D %D which looks kind of nice. \definefloat [\v!bnfgrammar] [\v!bnfgrammars] \protect \endinput