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