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