1 /* $NetBSD: btyacc_calc1.y,v 1.1.1.3 2016/01/09 21:59:45 christos Exp $ */
2
3 %PURE_PARSER
4 %{
5
6 /* http://dinosaur.compilertools.net/yacc/index.html */
7
8 #include <stdlib.h>
9 #include <stdio.h>
10 #include <ctype.h>
11 #include <math.h>
12
13 typedef struct interval
14 {
15 double lo, hi;
16 }
17 INTERVAL;
18
19 INTERVAL vmul(double, double, INTERVAL);
20 INTERVAL vdiv(double, double, INTERVAL);
21
22 int dcheck(INTERVAL);
23
24 double dreg[26];
25 INTERVAL vreg[26];
26
27 %}
28 %expect 17
29
30 %start lines
31 %union
32 {
33 int ival;
34 double dval;
35 INTERVAL vval;
36 }
37
38 %token <ival> DREG VREG /* indices into dreg, vreg arrays */
39 %token <dval> CONST /* floating point constant */
40
41 %type <dval> dexp /* expression */
42 %type <vval> vexp /* interval expression */
43
44 /* precedence information about the operators */
45
46 %left '+' '-'
47 %left '*' '/'
48 %right UMINUS /* precedence for unary minus */
49
50 %% /* beginning of rules section */
51
52 lines : /* empty */
53 | lines line '\n' [YYVALID;]
54 | lines error '\n' [YYVALID;]
55 {
56 yyerrok;
57 }
58 ;
59
60 line : dexp
61 {
62 (void) printf("%15.8f\n", $1);
63 }
64 | vexp
65 {
66 (void) printf("(%15.8f, %15.8f)\n", $1.lo, $1.hi);
67 }
68 | DREG '=' dexp
69 {
70 dreg[$1] = $3;
71 }
72 | VREG '=' vexp
73 {
74 vreg[$1] = $3;
75 }
76 ;
77
78 dexp : CONST
79 | DREG
80 {
81 $$ = dreg[$1];
82 }
83 | dexp '+' dexp
84 {
85 $$ = $1 + $3;
86 }
87 | dexp '-' dexp
88 {
89 $$ = $1 - $3;
90 }
91 | dexp '*' dexp
92 {
93 $$ = $1 * $3;
94 }
95 | dexp '/' dexp
96 {
97 $$ = $1 / $3;
98 }
99 | '-' dexp %prec UMINUS
100 {
101 $$ = -$2;
102 }
103 | '(' dexp ')'
104 {
105 $$ = $2;
106 }
107 ;
108
109 vexp : dexp
110 {
111 $$.hi = $$.lo = $1;
112 }
113 | '(' dexp ',' dexp ')'
114 {
115 $$.lo = $2;
116 $$.hi = $4;
117 if ( $$.lo > $$.hi )
118 {
119 (void) printf("interval out of order\n");
120 YYERROR;
121 }
122 }
123 | VREG
124 {
125 $$ = vreg[$1];
126 }
127 | vexp '+' vexp
128 {
129 $$.hi = $1.hi + $3.hi;
130 $$.lo = $1.lo + $3.lo;
131 }
132 | dexp '+' vexp
133 {
134 $$.hi = $1 + $3.hi;
135 $$.lo = $1 + $3.lo;
136 }
137 | vexp '-' vexp
138 {
139 $$.hi = $1.hi - $3.lo;
140 $$.lo = $1.lo - $3.hi;
141 }
142 | dexp '-' vexp
143 {
144 $$.hi = $1 - $3.lo;
145 $$.lo = $1 - $3.hi;
146 }
147 | vexp '*' vexp
148 {
149 $$ = vmul( $1.lo, $1.hi, $3 );
150 }
151 | dexp '*' vexp
152 {
153 $$ = vmul ($1, $1, $3 );
154 }
155 | vexp '/' vexp
156 {
157 if (dcheck($3)) YYERROR;
158 $$ = vdiv ( $1.lo, $1.hi, $3 );
159 }
160 | dexp '/' vexp
161 {
162 if (dcheck ( $3 )) YYERROR;
163 $$ = vdiv ($1, $1, $3 );
164 }
165 | '-' vexp %prec UMINUS
166 {
167 $$.hi = -$2.lo;
168 $$.lo = -$2.hi;
169 }
170 | '(' vexp ')'
171 {
172 $$ = $2;
173 }
174 ;
175
176 %% /* beginning of subroutines section */
177
178 int
179 main (void)
180 {
181 while(!feof(stdin)) {
182 yyparse();
183 }
184 return 0;
185 }
186
187 #define BSZ 50 /* buffer size for floating point numbers */
188
189 static void
YYERROR_DECL()190 YYERROR_DECL()
191 {
192 fprintf(stderr, "%s\n", s);
193 }
194
195 /* lexical analysis */
196
197 static int
YYLEX_DECL()198 YYLEX_DECL()
199 {
200 int c;
201
202 while ((c = getchar()) == ' ')
203 { /* skip over blanks */
204 }
205
206 if (isupper(c))
207 {
208 #if YYPURE
209 (*yylval).ival = c - 'A';
210 #else
211 yylval.ival = c - 'A';
212 #endif
213 return (VREG);
214 }
215 if (islower(c))
216 {
217 #if YYPURE
218 (*yylval).ival = c - 'a';
219 #else
220 yylval.ival = c - 'a';
221 #endif
222 return (DREG);
223 }
224
225 if (isdigit(c) || c == '.')
226 {
227 /* gobble up digits, points, exponents */
228 char buf[BSZ + 1], *cp = buf;
229 int dot = 0, expr = 0;
230
231 for (; (cp - buf) < BSZ; ++cp, c = getchar())
232 {
233
234 *cp = (char) c;
235 if (isdigit(c))
236 continue;
237 if (c == '.')
238 {
239 if (dot++ || expr)
240 return ('.'); /* will cause syntax error */
241 continue;
242 }
243
244 if (c == 'e')
245 {
246 if (expr++)
247 return ('e'); /* will cause syntax error */
248 continue;
249 }
250
251 /* end of number */
252 break;
253 }
254 *cp = '\0';
255
256 if ((cp - buf) >= BSZ)
257 printf("constant too long: truncated\n");
258 else
259 ungetc(c, stdin); /* push back last char read */
260 #if YYPURE
261 (*yylval).dval = atof(buf);
262 #else
263 yylval.dval = atof(buf);
264 #endif
265 return (CONST);
266 }
267 return (c);
268 }
269
270 static INTERVAL
hilo(double a,double b,double c,double d)271 hilo(double a, double b, double c, double d)
272 {
273 /* returns the smallest interval containing a, b, c, and d */
274 /* used by *, / routines */
275 INTERVAL v;
276
277 if (a > b)
278 {
279 v.hi = a;
280 v.lo = b;
281 }
282 else
283 {
284 v.hi = b;
285 v.lo = a;
286 }
287
288 if (c > d)
289 {
290 if (c > v.hi)
291 v.hi = c;
292 if (d < v.lo)
293 v.lo = d;
294 }
295 else
296 {
297 if (d > v.hi)
298 v.hi = d;
299 if (c < v.lo)
300 v.lo = c;
301 }
302 return (v);
303 }
304
305 INTERVAL
vmul(double a,double b,INTERVAL v)306 vmul(double a, double b, INTERVAL v)
307 {
308 return (hilo(a * v.hi, a * v.lo, b * v.hi, b * v.lo));
309 }
310
311 int
dcheck(INTERVAL v)312 dcheck(INTERVAL v)
313 {
314 if (v.hi >= 0. && v.lo <= 0.)
315 {
316 printf("divisor interval contains 0.\n");
317 return (1);
318 }
319 return (0);
320 }
321
322 INTERVAL
vdiv(double a,double b,INTERVAL v)323 vdiv(double a, double b, INTERVAL v)
324 {
325 return (hilo(a / v.hi, a / v.lo, b / v.hi, b / v.lo));
326 }
327