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