% TODO: look at core-tab.tex to see how to make | (;) and " work better
% XXX: there's a problem with \doifnextcharelse{} in that it won't allow the
% character read to be \catcode:d
\writestatus{loading}{BNF Macros / Initialization}

\unprotect

\definesystemvariable{bnf}

\startconstants english
     terminalstart: terminalstart
      terminalstop: terminalstop
  nonterminalstart: nonterminalstart
   nonterminalstop: nonterminalstop
	     colon: colon
	 semicolon: semicolon
	    period: period
	     comma: comma
\stopconstants

\startvariables english
	bnfgrammar: bnfgrammar
       bnfgrammars: bnfgrammars
\stopvariables

\startcommands english
   setupbnfgrammar: setupbnfgrammar
   startbnfgrammar: startbnfgrammar
    stopbnfgrammar: stopbnfgrammar
\stopcommands

\def\setcatcodes%
  {\catcode`\"\@@active%
   \catcode`\:\@@active%
   \catcode`\,\@@active%
   \catcode`\;\@@active%
   \catcode`\.\@@active%
   \catcode`\<\@@active%
   \catcode`\>\@@active}

\def\uncatcodecharacters%
  {\catcode`\"\@@other%
   \catcode`\:\@@other%
   \catcode`\,\@@other%
   \catcode`\;\@@other%
   \catcode`\.\@@other%
   \catcode`\<\@@other%
   \catcode`\>\@@other}

\let\escapegrammar=\uncatcodecharacters

\bgroup
  \uncatcodecharacters
  \glet\quotesymbol="
  \glet\lessthan=<
  \glet\greaterthan=>
\egroup

\newif\ifoutsidestring \outsidestringtrue

\newif\iffirstrule \firstruletrue
\newif\ifnewrule \newruletrue
\newif\ifdonerule \donerulefalse

\bgroup
\setcatcodes
\gdef\defcolon#1%
  {\catcode`\:\@@active
   \def:{\NC {\uncatcodecharacters #1} \NC}
   \catcode`\:\@@other}
\gdef\defcomma#1%
  {\catcode`\,\@@active
   \def,{{\uncatcodecharacters #1}}
   \catcode`\,\@@other}
\gdef\defsemicolon#1%
  {\catcode`\;\@@active
   \def;{{\uncatcodecharacters #1}}
   \catcode`\;\@@other}
\gdef\defperiod#1%
  {\catcode`\.\@@active
   \def.{{\uncatcodecharacters #1}
	 \NC%
	 \global\newruletrue%
	 \global\doneruletrue}
   \catcode`\.\@@other}
\gdef\defnonterminal#1#2%
  {\catcode`\<\@@active
   \catcode`\>\@@active
   \def<%
     {\ifnewrule
        \ifdonerule
	  \iffirstrule
	    \FR%
	    \global\firstrulefalse%
	  \else
	    \MR%
	  \fi
	\fi
	\global\newrulefalse%
        \NC%
      \fi
      \begingroup%
        #1%
        \uncatcodecharacters%
	\catcode`\>\@@active}
   \def>%
     {#2%
      \endgroup}
   \catcode`\<\@@other
   \catcode`\>\@@other}
\gdef\defterminal#1#2%
  {\catcode`\"\@@active
   \def"%
     {\ifoutsidestring
        \global\outsidestringfalse%
        \begingroup%
          \uncatcodecharacters%
	  \catcode`\"\@@active%
	  #1%
      \else
	  #2%
        \endgroup%
        \global\outsidestringtrue%
      \fi}
   \catcode`\"\@@other}
\egroup

% TODO: it's probably enough to call \getparameters[\??bnf][#1]% instead of
% \setupbnfgrammar[#1]% here
\def\complexstartbnfgrammar[#1]%
  {\bgroup%
   \global\firstruletrue%
   \global\newruletrue%
   \global\donerulefalse%
   \setupbnfgrammar[#1]%
   \setcatcodes%
   \starttable[|r|c|l|]}

\definecomplexorsimpleempty\startbnfgrammar

\def\stopbnfgrammar
  {\LR%
   \stoptable%
   \uncatcodecharacters%
   \egroup}

\def\dosetupbnfgrammar[#1]%
  {\getparameters[\??bnf][#1]%
   \defterminal{\@@bnfterminalstart}{\@@bnfterminalstop}%
   \defnonterminal{\@@bnfnonterminalstart}{\@@bnfnonterminalstop}%
   \defcolon{\@@bnfcolon}%
   \defsemicolon{\@@bnfsemicolon}%
   \defperiod{\@@bnfperiod}%
   \defcomma{\@@bnfcomma}}

\def\setupbnfgrammar%
  {\dosingleargument\dosetupbnfgrammar}

\setupbnfgrammar
  [\c!terminalstart={\{\bf},
   \c!terminalstop={\}},
   \c!nonterminalstart={$\langle$},
   \c!nonterminalstop={$\rangle$},
   \c!colon={$\rightarrow$},
   \c!semicolon={$|$},
   \c!period={},
   \c!comma={}]

\abbreviation{BNF}{Backus-Naur Form}

\setupheadtext [\s!en] [\v!bnfgrammar=\BNF\ Grammar]
\setupheadtext [\s!en] [\v!bnfgrammars=\BNF\ Grammars]
\setuplabeltext [\s!en] [\v!bnfgrammar=\BNF\ Grammar ]

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

\protect \endinput
