4

I would like to write BNF rules with ConTeXt. I found this BNF module and tried to load it:

\usemodule[bnf]

However, right at loading, ConTeXt breaks with the following error:

tex error       > tex error on line 157 in file /usr/local/texlive/2016/texmf-dist/tex/context/third/bnf/t-bnf.tex: ! Undefined control sequence

<argument> \c!terminalstart
                 =\tttf
\syst_helpers_process_comma_item #1,#2->\if ,#1
                                               ,\expandafter \syst_helpers_p...
<argument> \c!terminalstart =\tttf , \c!terminalstop
                                          =, \c!nonterminalstart =\mathematics
\syst_helpers_get_parameters ...cess_comma_item #1
                                                  ,],\_e_o_p_
l.157    \c!indentnext=\v!no]


147     \def\setupbnfgrammar%
148       {\dosingleargument\dosetupbnfgrammar}
149
150     \setupbnfgrammar
151       [\c!terminalstart=\tttf,
152        \c!terminalstop=,
153        \c!nonterminalstart=\mathematics{\langle},
154        \c!nonterminalstop=\mathematics{\rangle},
155        \c!is={ \mathematics{\longrightarrow}},
156        \c!option=\mathematics{\vert},
157 >>     \c!indentnext=\v!no]
158
159     %D \macros
160     %D   {BNF}
161     %D
162     %D We also define a useful abbreviation to be used for header texts and labels.
163
164     \logo[BNF]{bnf}
165
166     %D And we use it here:
167

I assume this happens because the BNF module has been written for an older version of ConTeXt. Is there a way to fix this?

  • try with texec command (it calls mkii instead of default's mkiv) – tuxador Mar 14 '18 at 19:52
6

Looks like this module was make for MKII. You can get it to work somewhat with MKIV by rewriting a couple of macros. The module is completely broken because it does not even work with MKII.

% Missing constants
\setinterfaceconstant{terminalstart}{terminalstart}
\setinterfaceconstant{terminalstop}{terminalstop}
\setinterfaceconstant{nonterminalstart}{nonterminalstart}
\setinterfaceconstant{nonterminalstop}{nonterminalstop}
\setinterfaceconstant{is}{is}
% Missing variables
\setinterfacevariable{bnfgrammar}{bnfgrammar}
\setinterfacevariable{bnfgrammars}{bnfgrammars}

\usemodule[bnf]

\unprotect

\bgroup

\catcode`:\activecatcode
\catcode`|\activecatcode
\catcode`"\activecatcode
\catcode`'\activecatcode

\gdef:{\@@bnfis}
\gdef|{\@@bnfoption}
\gdef"{\thinspace\bgroup\@@bnfterminalstart\tt%
      \def"{\@@bnfterminalstop\egroup\thinspace}}
\gdef'{\thinspace\bgroup\@@bnfterminalstart\tt%
      \def'{\@@bnfterminalstop\egroup\thinspace}}

\egroup

\def\complexstartbnfgrammar[#1]%
  {\endgraf\nobreak\medskip
   \begingroup
   \setupbnfgrammar[#1]%
   \chardef\bnfsinglequote=`'
   \catcode`:\activecatcode
   \catcode`|\activecatcode
   \catcode`"\activecatcode
   \catcode`'\activecatcode
   \catcode`<=13
   \let\par=\bnfgrammarline
   \obeylines}

\protect

\starttext

\startplacebnfgrammar[title={An example of a placed grammar.}]
  \startbnfgrammar
    <exp>: <num> | <num> "+" <num>
    <num>: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
  \stopbnfgrammar
\stopplacebnfgrammar

\stoptext

enter image description here

Here is my humble attempt to port the module to MKIV.

\startmodule [bnf-mkiv]
\unprotect

\startinterface all
  \setinterfaceconstant {terminalstart}    {terminalstart}
  \setinterfaceconstant {terminalstop}     {terminalstop}
  \setinterfaceconstant {nonterminalstart} {nonterminalstart}
  \setinterfaceconstant {nonterminalstop}  {nonterminalstop}
  \setinterfaceconstant {is}               {is}
  \setinterfacevariable {bnfgrammar}       {bnfgrammar}
  \setinterfacevariable {bnfgrammars}      {bnfgrammars}
\stopinterface

\installnamespace{bnfgrammar}

\installcommandhandler \????bnfgrammar {bnfgrammar} \????bnfgrammar

\unexpanded\def\bnf_grammar_non_terminal#1>%
  {\bnfgrammarparameter{\c!nonterminalstart}#1\/\bnfgrammarparameter{\c!nonterminalstop}}

\bgroup

\catcode`:\activecatcode
\unexpanded\gdef:{\bnfgrammarparameter{\c!is}}

\catcode`|\activecatcode
\unexpanded\gdef|{\bnfgrammarparameter{\c!option}}

\catcode`"\activecatcode
\unexpanded\gdef"%
  {\thinspace\bgroup\bnfgrammarparameter{\c!terminalstart}%
   \unexpanded\def"{\bnfgrammarparameter{\c!terminalstop}\egroup\thinspace}}

\catcode`'\activecatcode
\unexpanded\gdef'%
  {\thinspace\bgroup\bnfgrammarparameter{\c!terminalstart}%
   \unexpanded\def'{\bnfgrammarparameter{\c!terminalstop}\egroup\thinspace}}

\catcode`<\activecatcode
\global\let<=\bnf_grammar_non_terminal

\unexpanded\gdef\bnf_grammar_rule<#1>{\endgraf<#1>}

\egroup

\unexpanded\def\bnf_grammar_line
  {\futurelet\next\bnf_grammar_switch}

\unexpanded\def\bnf_grammar_cont
  {\endgraf\qquad}

\unexpanded\def\bnf_grammar_switch
  {\ifx\next\bnf_grammar_non_terminal
    \let\next=\bnf_grammar_rule
  \else\expandafter\ifx\expandafter\next\csname stop\currentbnfgrammar\endcsname
    \let\next=\relax
  \else
    \let\next=\bnf_grammar_cont
    \fi\fi
  \next}

\unexpanded\def\bnf_grammar_start%
  {\dodoubleempty\bnf_grammar_start_indeed}

\unexpanded\def\bnf_grammar_start_indeed[#1][#2]%
  {\begingroup
   \edef\currentbnfgrammar{#1}
   \setupcurrentbnfgrammar[#2]
   \catcode`:\activecatcode
   \catcode`|\activecatcode
   \catcode`"\activecatcode
   \catcode`'\activecatcode
   \catcode`<\activecatcode
   \let\par=\bnf_grammar_line
   \obeylines}

\unexpanded\def\bnf_grammar_stop
  {\endgroup
   \blank
   \checknextindentation[\bnfgrammarparameter{\c!indentnext}]}

\appendtoks
   \setuevalue{start\currentbnfgrammar}{\bnf_grammar_start[\currentbnfgrammar]}%
   \setuevalue{stop\currentbnfgrammar}{\bnf_grammar_stop}%
\to \everydefinebnfgrammar

\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]

\definebnfgrammar
  [\v!bnfgrammar]

\logo[BNF]{BNF}
\setuplabeltext[\s!en][\v!bnfgrammar=\BNF\ Grammar ]

\definefloat
  [\v!bnfgrammar]
  [\v!bnfgrammars]

\protect
\stopmodule

Example:

\usemodule[bnf-mkiv]

\starttext

\startplacebnfgrammar[title={An example of a placed grammar.}]
  \startbnfgrammar[] % <-- empty brackets are important
    <exp>: <num> | <num> "+" <num>
    <num>: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
  \stopbnfgrammar
\stopplacebnfgrammar

\stoptext

enter image description here

  • This works just great! If I add [] after \startbnfgrammar, the <exp> also renders properly. – flyx Mar 14 '18 at 21:10
  • The updated version is just great! I am trying to figure out whether I can modify it to make the long arrows aligned. – flyx Mar 15 '18 at 9:39
  • @flyx Why though? I don't think there is a point in that. Also famous references like the TeXbook do not align the arrows in the grammar. Also imagine you have one rule called <def> and another one called <horizontal list>. Do you really want to have the right arrows aligned with an enourmous gap between <def> and the arrow? – Henri Menke Mar 15 '18 at 10:01
  • Good point. I'll see how happy I am without it. – flyx Mar 15 '18 at 10:07
  • I noticed the rule \bnf_grammar_cont adds an empty line at the end because \qquad is generated if \stopbnfgrammar is on a new line. Any idea how to fix that? – flyx Mar 15 '18 at 10:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.