xref: /netbsd-src/external/bsd/byacc/dist/test/btyacc_calc1.y (revision 781cc16b73421ffc44afa4f3c196f4c42bce8c5c)
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