diff options
Diffstat (limited to 'support/splint/examples/xxpression/xxpression.w')
-rw-r--r-- | support/splint/examples/xxpression/xxpression.w | 365 |
1 files changed, 365 insertions, 0 deletions
diff --git a/support/splint/examples/xxpression/xxpression.w b/support/splint/examples/xxpression/xxpression.w new file mode 100644 index 0000000000..00834b4436 --- /dev/null +++ b/support/splint/examples/xxpression/xxpression.w @@ -0,0 +1,365 @@ +@q Copyright 2012-2014, 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 <http://www.gnu.org/licenses/>.@> + +% The scheme for extracting token equivalences below does not use a +% bootstrap parser, which would be easier. +% To use a different parser (the `prologue' parser, \.{dyytab.tex} in +% this case), some extra steps have to be inserted in +% \.{yybootstrap.sty}. First, the token equivalence table for the `main' +% parser (rather, for the `main' scanner) had to be loaded +% (\.{yybootstrap.sty} usually relies on the tokens that are +% `hard-coded' with the bootstrap parser). Second, it was necessary to +% define \.{\\let\\yylexreturn\\yylexregular} to use the scanner. One +% advantage of using a different parser is the ability to intermix token +% definitions with grammar productions (the bootstrap mode macros in +% \.{\\yyunion} will simply ignore the extra definitions). +% Note also, that the `grammar rule' parser cannot be used in this +% case since the token definitions as they are used in this file fit +% the `prologue' parser syntax only (there are no semicolons at the +% end of the definitions). A more elaborate scheme (similar to how the +% typesetting of rules is set up) using several parsers can be used +% instead. +\newwrite\gindex +\input limbo.sty +\input dcols.sty +\def\optimization{5} +\newread\testeof +\immediate\openin\testeof=\jobname.tok +\ifeof\testeof % make the local token equivalence table + \def\drvname{bo} + \csname newwrite\endcsname\tokendefs + \let\nx\noexpand + \edef\tokendeffile{\jobname.tok} % where to put the token equivalence table + \edef\bstrapparser{dyytab.tex} + \def\bootstraplexersetup{% + \let\yylexreturn\yylexreturnregular + \bootstrapmodetrue + \input \drvname.tok % use token equivalence table to set the values of non-string tokens + % this has to be added if a non-bootstrap parser is used to + % extract token information (see the comments above) + } + \toks0{% + \input yycommon.sty % general routines for stack and array access + \input yymisc.sty % helper macros (stack manipulation, table processing, value stack pointers) + \input yyinput.sty % input functions + \input yyparse.sty % parser machinery + \input flex.sty % lexer functions + \input yyboth.sty % parser initialization, optimization + \input yyfaststack.sty + \input yystype.sty % scanner auxiliary types and functions + \input yyunion.sty % parser data structures + % the main parser + \let\parsernamespace\empty + % create token equivalence table (making, say, \tokenID the same as \csname token"identifier"\endcsname) + \input yybootstrap.sty + } +\else + \toks0{% + \input yy.sty + \let\currentparsernamespace\parsernamespace + \let\parsernamespace\smallnamespace + \let\hostparsernamespace\smallnamespace + \input xtoks.sty + \let\parsernamespace\currentparsernamespace + } +\fi +\immediate\closein\testeof +\the\toks0 + +@**Parser file. \setupfootnotes +This an enhanced parser for expressions. It takes +advantage of the `symbolic term name' mechanism and extends the basic +expression syntax. + +The top-level structure of the input file is an exact copy of the one +for the expression parser. +@s TeX_ TeX + +@(xxpp.yy@>= +@G Switch to generic mode. +%{@> @<Extended \.{expression} parser \Cee\ preamble@> @=%} + @> @<Bison options@> @= +%union {@> @<Union of parser types@> @=} +%{@> @<Extended \.{expression} parser \Cee\ postamble@> @=%} + @> @<Token and types ...@> @= +%% + @> @<Parser productions@> @= +%% +@g + +@ The following is reproduced from the simple expression example. + +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. +@<Bison options@>= +@G +%token-table +%debug +%start value +@g + +@ To continue the token name discussion, this parser uses internal +names only but the |yytname| array contains a string equivalent of +\prodstyle{IDENTIFIER}. Thus, bootstrapping is necessary. The beginning +of this file contains a simple scheme for producing a token +equivalence table. +The typesetting of the tokens can be adjusted using \.{\\prettywordpair} +macros (see the included \.{xtoks.sty} file for examples and the way +\prodstyle{IDENTIFIER} is typeset). +@<Token and types declarations@>= +@G +%token IDENTIFIER "identifier" +%token INTEGER +@g + +@ Here is the whole grammar, simply additive expressions with two +levels of precedence. We have added `divide' and `subtract' operations. +The use of \prodstyle{IDENTIFIER} instead of \.{"identifier"} below +necessitates `harvesting' of token equivalences in \.{xxpression.tok} +at the beginning of this file. +\showlastactiontrue +\input yynested.sty +@<Parser productions@>= +@G +value: + expression[exp] {@> TeX_( "/yy0{/the/yy]exp[}" ); @=} +; + +expression: + term {@> TeX_( "/yy0{/the/yy]term[}" ); @=} +| expression[exp] add_op term {@> @<Add a term@> @=} +; + +term: + atom {@> TeX_( "/yy0{/the/yy]atom[}" ); @=} +| term mult_op atom {@> @<Make a term@> @=} +; +@t}\vb{\inline\flatten}{@> +mult_op: + '*' {@> TeX_( "/yy0{/multiply}" ); @=} +| '/' {@> TeX_( "/yy0{/divide}" ); @=} +; + +add_op: + '+' {@> TeX_( "/yy0{}" ); @=} +| '-' {@> TeX_( "/yy0{-}" ); @=} +; +@t}\vb{\resetf}{@> +atom: +@t}\vb{\inputboundary{\boundarylower}}{@> + IDENTIFIER[id] {@> @<Assign variable value to an atom@> @=} +| INTEGER[int] {@> @<Assign value to an atom@> @=} +| '(' expression[exp] ')' {@> TeX_( "/yy0{/the/yy]exp[}" ); @=} +; +@t}\vb{\inputboundary{\boundaryupper}}{@> +@g + +@ @<Add a term@>= + @[TeX_( "/tempca/the/yy]exp[/relax" );@]@; + @[TeX_( "/tempcb/the/yy]term[/relax" );@]@; + @[TeX_( "/advance/tempca by /the/yy]add_op[/tempcb" );@]@; + @[TeX_( "/yy0{/the/tempca}" );@]@; + +@ @<Make a term@>= + @[TeX_( "/tempca/the/yy]term[/relax" );@]@; + @[TeX_( "/tempcb/the/yy]atom[/relax" );@]@; + @[TeX_( "/the/yy]mult_op[/tempca by /tempcb" );@]@; + @[TeX_( "/yy0{/the/tempca}" );@]@; + +@ @<Assign variable value to an atom@>= + @[TeX_( "/getsecond{/yy]id[}/to/toksa" );@]@; + @[TeX_( "/toksb/expandafter/expandafter/expandafter{/expandafter" );@]@; + @[TeX_( " /number/csname/the/toksa/endcsname}" );@]@; + @[TeX_( "/yy0{/the/toksb}" );@]@; + +@ @<Assign value to an atom@>= + @[TeX_( "/getfirst{/yy]int[}/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. + +@<Extended \.{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. + +@<Extended \.{expression} parser \Cee\ postamble@>= +#define YYPRINT(file, type, value) @[yyprint (file, type, value)@] + static void yyprint (FILE *file, int type, YYSTYPE value){} + +@ Union of types. Empty as well. + +@<Union of parser types@>= + +@**The lexer file. The scanner for the grammar above is the same as +for a regular expression parser. Identifiers are interpreted as +variable names that expand to appropriate values. +%\checktabletrue +@(xxpl.ll@>= +@G + @> @<Lexer definitions@>@= +%{@> @<Lexer \Cee\ preamble@> @=%} + @> @<Lexer options@> @= +%% + @> @<Regular expressions@> @= +%% +@g + +@ @<Lexer definitions@>= +@G +letter [_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ] +id {letter}({letter}|[-0-9])* +int [0-9]+ +@g + +@ @<Lexer \Cee\ preamble@>= + +#include <stdint.h> +#include <stdbool.h> + + void define_all_states( void ){} + +@ @<Lexer options@>= +@G +%option bison-bridge +%option noyywrap nounput noinput reentrant +%option noyy_top_state +%option debug +%option stack +%option outfile="xxpl.c" +@g + +@ @<Regular expressions@>= + @<Scan white space@>@; + @<Scan identifiers@>@; + +@ White space skipping. +\traceparserstatestrue +\tracestackstrue +\tracerulestrue +\traceactionstrue +\tracelookaheadtrue +\traceparseresultstrue +\tracebadcharstrue +\yyflexdebugtrue +% +\traceparserstatesfalse +\tracestacksfalse +\tracerulesfalse +\traceactionsfalse +\tracelookaheadfalse +\traceparseresultsfalse +\tracebadcharsfalse +\yyflexdebugfalse +@<Scan white space@>= +@G +[ \f\n\t\v] {@> @[TeX_( "/yylexnext" );@]@=} +@g + +@ @<Scan identifiers@>= +@G +{id} {@> @[TeX_( "/yylexreturnval{IDENTIFIER}" );@]@=} +{int} {@> @[TeX_( "/yylexreturnval{INTEGER}" );@]@=} +[-+*/()] {@> @[TeX_( "/yylexreturnchar" );@]@=} +. {@> @[@<React to a bad character@>@]@=} +@g + +@ @<React to a bad character@>= + @[TeX_( "/iftracebadchars" );@]@; + @[TeX_( " /yycomplain{invalid character(s): /the/yytext}" );@]@; + @[TeX_( "/fi" );@]@; + @[TeX_( "/yylexreturn{$undefined}" );@]@; + +@**Generating symbols. This is the routine that creates symbolic name +assignments for the grammar. The internal mechanics of creating such +assignments is inside \.{xymmap.sty} which should be consulted if +any adjustments are needed. +@(xymbols.txx@>= +@G +\def\optimization{5} % this can be omitted +\input yy.sty +\input xymmap.sty +\end +@g + +@**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 +\input xxpression.sty + +\iftrue + \tracedfatrue + \traceparserstatestrue + \tracestackstrue + \tracerulestrue + \traceactionstrue + \tracelookaheadtrue + \traceparseresultstrue + \tracebadcharstrue + \yyflexdebugtrue + \yyinputdebugtrue +\fi + +\newread\ssw +\immediate\openin\ssw = xymbols.sns +\ifeof\ssw +\else + \immediate\closein\ssw + \input xymbols.sns + \let\yysymswitch\symswitch + \let\yysymcleanup\symswitchoff +\fi + +\def\varone{10} +\def\expression{1 + 3 * ( 5 + 7 ) + varone - 10} + +\basicparserinit\expandafter\yyparse \expression \yyeof\yyeof\endparseinput\endparse + +{ + \newlinechar`^^J + \immediate\write16{^^Jexpression: \expression^^Jthe value: \the\yyval^^J^^J} +} + +\bye +@g + +@**Index. +\let\inx\inxmod +\let\fin\finmod +\immediate\closeout\exampletable +\def\Tex{\TeX\ output} +\def\TeXx{\TeX\ output} |