summaryrefslogtreecommitdiff
path: root/support/splint/examples/expression/expression.w
blob: 9e96ea44d0add4b0e1d04889686225a71eb431ed (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
@q Copyright 2012-2020, 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/>.@>
\input limbo.sty
\def\optimization{5}
\input yy.sty
\modenormal

@** 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@> @=%}
  @> @<Bison options@> @= 
%union {@> @<Union of parser types@> @=}
%{@> @<\.{expression} parser \Cee\ postamble@> @=%}
  @> @<Token and types ...@> @= 
%%
  @> @<Parser productions@> @= 
%%
@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.
@<Bison options@>=
@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).
@<Token and types declarations@>=
@G
%token IDENTIFIER
%token INTEGER
%token BOGUS
@g

@ Here is the whole grammar, simply additive expressions with two
levels of precedence.
@<Parser productions@>=
@G
value:
  expression                      {@> TeX_( "/yy0{/the/yy(1)}" ); @=}
;

expression:
  term                            {@> TeX_( "/yy0{/the/yy(1)}" ); @=}
| expression '+' term             {@> @<Add a term@> @=}
;

term:
  atom                            {@> TeX_( "/yy0{/the/yy(1)}" ); @=}
| term '*' atom                   {@> @<Multiply by an atom@> @=}
;

atom:
  IDENTIFIER                      {@> @<Assign variable value to an atom@> @=}
| INTEGER                         {@> @<Assign value to an atom@> @=}
| '(' expression ')'              {@> TeX_( "/yy0{/the/yy(2)}" ); @=}
;
@g

@ @<Add a term@>=
  @[TeX_( "/tempca/the/yy(1)/relax" );@]@;
  @[TeX_( "/tempcb/the/yy(3)/relax" );@]@;
  @[TeX_( "/advance/tempca by /tempcb" );@]@;
  @[TeX_( "/yy0{/the/tempca}" );@]@;

@ @<Multiply by an atom@>=
  @[TeX_( "/tempca/the/yy(1)/relax" );@]@;
  @[TeX_( "/tempcb/the/yy(3)/relax" );@]@;
  @[TeX_( "/multiply/tempca by /tempcb" );@]@;
  @[TeX_( "/yy0{/the/tempca}" );@]@;

@ @<Assign variable value to an atom@>=
  @[TeX_( "/getsecond{/yy(1)}/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(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@>=
#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 even
simpler. Identifiers are interpreted as variable names that expand to
appropriate values.
%\checktabletrue
@(expl.ll@>=
@G
 @> @<Lexer definitions@> @= 
%{@> @<Lexer \Cee\ preamble@> @=%}
  @> @<Lexer options@> @= 
%%
  @> @<Regular expressions@> @= 
%%

@ @<Lexer definitions@>=
@G(fs1)
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="expl.c"
@g

@ @<Regular expressions@>=
  @<Scan white space@>@;
  @<Scan identifiers@>@;

@ White space skipping. 
@<Scan white space@>=
@G(fs2)
[ \f\n\t\v]                        {@> @[TeX_( "/yylexnext" );@]@=}
@g

@ @<Scan identifiers@>=
@G(fs2)
{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}" );@]@;

@*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 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.
\immediate\closeout\exampletable
\def\Tex{\TeX\ output}
\def\TeXx{\TeX\ output}