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