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