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
13typedef struct interval
14{
15    double lo, hi;
16}
17INTERVAL;
18
19INTERVAL vmul(double, double, INTERVAL);
20INTERVAL vdiv(double, double, INTERVAL);
21
22int dcheck(INTERVAL);
23
24double dreg[26];
25INTERVAL 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
52lines   : /* empty */
53	| lines line '\n' [YYVALID;]
54	| lines error '\n' [YYVALID;]
55	{
56		yyerrok;
57	}
58	;
59
60line	: 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
78dexp	: 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
109vexp	: 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
178int
179main (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
189static void
190YYERROR_DECL()
191{
192    fprintf(stderr, "%s\n", s);
193}
194
195	/* lexical analysis */
196
197static int
198YYLEX_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
270static INTERVAL
271hilo(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
305INTERVAL
306vmul(double a, double b, INTERVAL v)
307{
308    return (hilo(a * v.hi, a * v.lo, b * v.hi, b * v.lo));
309}
310
311int
312dcheck(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
322INTERVAL
323vdiv(double a, double b, INTERVAL v)
324{
325    return (hilo(a / v.hi, a / v.lo, b / v.hi, b / v.lo));
326}
327