@q Copyright 2012-2024, Alexander Shibakov@> @q This file is part of SPLinT@> @q SPLinT is free software: you can redistribute it and/or modify@> @q it under the terms of the GNU General Public License as published by@> @q the Free Software Foundation, either version 3 of the License, or@> @q (at your option) any later version.@> @q SPLinT is distributed in the hope that it will be useful,@> @q but WITHOUT ANY WARRANTY; without even the implied warranty of@> @q MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the@> @q GNU General Public License for more details.@> @q You should have received a copy of the GNU General Public License@> @q along with SPLinT. If not, see .@> \input limbo.sty \def\optimization{5} \input yy.sty \input dcols.sty \modenormal \initauxstream @** Parser file. This is an example parser for expressions. It takes advantage of some of the features of \splint\ generated parsers, although anything that takes more than a straightforward setup is omitted. The top-level structure of the input file presents no surprises and is presented below. \let\currentparsernamespace\parsernamespace \def\parsernamespace{[edisplay]} \def\hostparsernamespace{[edisplay]} \input etoks.sty \let\parsernamespace\currentparsernamespace \def\texnspace{[other]}% no pretty printing of \TeX @s TeX_ TeX @(expp.yy@>= @G Switch to generic mode. %{@> @<\.{expression} parser \Cee\ preamble@> @=%} @> @ @= %union {@> @ @=} %{@> @<\.{expression} parser \Cee\ postamble@> @=%} @> @ @= %% @> @ @= %% @g @ The \prodstyle{\%token-table} option is not merely a debugging help, as it is in the case of the `real' \bison\ parsers and cannot be omitted . The name table it is responsible for setting up is used as a set of keys for various associative arrays. Token declarations are parsed by a bootstrap parser during the \TeX\ processing stage to establish equivalences between the names kept in |yytname| and the macro names used internally by the parsers built by \bison. The reason this is necessary is not very complicated: either version of the token name can be used in the grammar while the `driver' program (\.{mkeparser.c}) only has access to the names in |yytname|. In general, this is important whenever the grammar uses a different set of token names from the lexer or when diagnostics messages are output. An important case is the symbolic name switch: before the rules can be listed to create the switch, the token numerical values must be known. If the parser is only aware of the |yytname| listed names and the grammar being parsed uses the `internal' names, the listing macros will fail. The array, |yytname| is used in a few functions inside the `driver', as well, so omitting this option would make building the parser impossible. @= @G %token-table %debug %start value @g @ To continue the token name discussion, this parser uses internal names only so this is what will appear in the |yytname| array. No bootstrapping is necessary. The typesetting of the tokens can be adjusted using \.{\\prettywordpair} macros (see the included \.{etoks.sty} file for examples). @= @G %token IDENTIFIER %token INTEGER %token BOGUS @g @ Here is the whole grammar, simply additive expressions with two levels of precedence. @= @G value: expression {@> TeX_( "/yy0{/the/yy(1)}" ); @=} ; expression: term {@> TeX_( "/yy0{/the/yy(1)}" ); @=} | expression '+' term {@> @ @=} ; term: atom {@> TeX_( "/yy0{/the/yy(1)}" ); @=} | term '*' atom {@> @ @=} ; atom: IDENTIFIER {@> @ @=} | INTEGER {@> @ @=} | '(' expression ')' {@> TeX_( "/yy0{/the/yy(2)}" ); @=} ; @g @ @= @[TeX_( "/tempca/the/yy(1)/relax" );@]@; @[TeX_( "/tempcb/the/yy(3)/relax" );@]@; @[TeX_( "/advance/tempca by /tempcb" );@]@; @[TeX_( "/yy0{/the/tempca}" );@]@; @ @= @[TeX_( "/tempca/the/yy(1)/relax" );@]@; @[TeX_( "/tempcb/the/yy(3)/relax" );@]@; @[TeX_( "/multiply/tempca by /tempcb" );@]@; @[TeX_( "/yy0{/the/tempca}" );@]@; @ @= @[TeX_( "/getsecond{/yy(1)}/to/toksa" );@]@; @[TeX_( "/toksb/expandafter/expandafter/expandafter{/expandafter" );@]@; @[TeX_( " /number/csname/the/toksa/endcsname}" );@]@; @[TeX_( "/yy0{/the/toksb}" );@]@; @ @= @[TeX_( "/getfirst{/yy(1)}/to/toksa" );@]@; @[TeX_( "/yy0{/the/toksa}" );@]@; @ \Cee\ preamble. In this case, there are no `real' actions that our grammar performs, only \TeX\ output, so this section is empty. @<\.{expression} parser \Cee\ preamble@>= @ \Cee\ postamble. It is tricky to insert function definitions that use \bison's internal types, as they have to be inserted in a place that is aware of the internal definitions but before said definitions are used. @<\.{expression} parser \Cee\ postamble@>= @ Union of types. Empty as well. @= @** The lexer file. The scanner for the grammar above is even simpler. Identifiers are interpreted as variable names that expand to appropriate values. %\checktabletrue @(expl.ll@>= @G @> @ @= %{@> @ @=%} @> @ @= %% @> @ @= %% @ @= @G(fs1) letter [_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ] id {letter}({letter}|[-0-9])* int [0-9]+ @g @ @= #include #include void define_all_states( void ){} @ @= @G(fs1) %option bison-bridge %option noyywrap nounput noinput reentrant %option noyy_top_state %option debug %option stack %option outfile="expl.c" @g @ @= @@; @@; @ White space skipping. @= @G(fs2) [ \f\n\t\v] {@> @[TeX_( "/yylexnext" );@]@=} @g @ @= @G(fs2) {id} {@> @[TeX_( "/yylexreturnval{IDENTIFIER}" );@]@=} {int} {@> @[TeX_( "/yylexreturnval{INTEGER}" );@]@=} [+*()] {@> @[TeX_( "/yylexreturnchar" );@]@=} . {@> @[@@]@=} @g @ @= @[TeX_( "/iftracebadchars" );@]@; @[TeX_( " /yycomplain{invalid character(s): /the/yytext}" );@]@; @[TeX_( "/fi" );@]@; @[TeX_( "/yyerrterminate" );@]@; @*Test file. The test file includes a handy list of debugging options that can be activated to see the inner workings of the parser and scanner routines. @(test.txx@>= @G \chardef\other=12 % needed for some macros to work \input expression.sty \iffalse \tracedfatrue \traceparserstatestrue \tracestackstrue \tracerulestrue \traceactionstrue \tracelookaheadtrue \traceparseresultstrue \tracebadcharstrue \yyflexdebugtrue \yyinputdebugtrue \fi \def\varone{10} \def\expression{1 + 3 * ( 5 + 7 ) + varone} \basicparserinit\expandafter\yyparse \expression \yyeof\yyeof\endparseinput\endparse { \newlinechar`^^J \immediate\write16{^^Jexpression: \expression^^Jthe value: \the\yyval^^J^^J} } \bye @g @**Index.\global\let\secrangedisplay\empty% do not show the current section range anymore \global\topskip=9pt \def\Tex{\TeX\ output} \def\TeXx{\TeX\ output}