1234949Sbapt%{
2234949Sbapt
3234949Sbapt/* http://dinosaur.compilertools.net/yacc/index.html */
4234949Sbapt
5234949Sbapt#include <stdlib.h>
6234949Sbapt#include <stdio.h>
7234949Sbapt#include <ctype.h>
8234949Sbapt#include <math.h>
9234949Sbapt
10234949Sbapttypedef struct interval
11234949Sbapt{
12234949Sbapt    double lo, hi;
13234949Sbapt}
14234949SbaptINTERVAL;
15234949Sbapt
16234949SbaptINTERVAL vmul(double, double, INTERVAL);
17234949SbaptINTERVAL vdiv(double, double, INTERVAL);
18234949Sbapt
19234949Sbaptextern int yylex(void);
20234949Sbaptstatic void yyerror(const char *s);
21234949Sbapt
22234949Sbaptint dcheck(INTERVAL);
23234949Sbapt
24234949Sbaptdouble dreg[26];
25234949SbaptINTERVAL vreg[26];
26234949Sbapt
27234949Sbapt%}
28234949Sbapt%expect 18
29234949Sbapt
30234949Sbapt%start line
31234949Sbapt%union
32234949Sbapt{
33234949Sbapt	int ival;
34234949Sbapt	double dval;
35234949Sbapt	INTERVAL vval;
36234949Sbapt}
37234949Sbapt
38234949Sbapt%token <ival> DREG VREG		/* indices into dreg, vreg arrays */
39234949Sbapt%token <dval> CONST		/* floating point constant */
40234949Sbapt
41234949Sbapt%type <dval> dexp		/* expression */
42234949Sbapt%type <vval> vexp		/* interval expression */
43234949Sbapt
44234949Sbapt	/* precedence information about the operators */
45234949Sbapt
46234949Sbapt%left '+' '-'
47234949Sbapt%left '*' '/'
48234949Sbapt%left UMINUS			/* precedence for unary minus */
49234949Sbapt
50234949Sbapt%%	/* beginning of rules section */
51234949Sbapt
52234949Sbaptlines   : /* empty */
53234949Sbapt	| lines line
54234949Sbapt	;
55234949Sbapt
56234949Sbaptline	: dexp '\n'
57234949Sbapt	{
58234949Sbapt		(void) printf("%15.8f\n", $1);
59234949Sbapt	}
60234949Sbapt	| vexp '\n'
61234949Sbapt	{
62234949Sbapt		(void) printf("(%15.8f, %15.8f)\n", $1.lo, $1.hi);
63234949Sbapt	}
64234949Sbapt	| DREG '=' dexp '\n'
65234949Sbapt	{
66234949Sbapt		dreg[$1] = $3;
67234949Sbapt	}
68234949Sbapt	| VREG '=' vexp '\n'
69234949Sbapt	{
70234949Sbapt		vreg[$1] = $3;
71234949Sbapt	}
72234949Sbapt	| error '\n'
73234949Sbapt	{
74234949Sbapt		yyerrok;
75234949Sbapt	}
76234949Sbapt	;
77234949Sbapt
78234949Sbaptdexp	: CONST
79234949Sbapt	| DREG
80234949Sbapt	{
81234949Sbapt		$$ = dreg[$1];
82234949Sbapt	}
83234949Sbapt	| dexp '+' dexp
84234949Sbapt	{
85234949Sbapt		$$ = $1 + $3;
86234949Sbapt	}
87234949Sbapt	| dexp '-' dexp
88234949Sbapt	{
89234949Sbapt		$$ = $1 - $3;
90234949Sbapt	}
91234949Sbapt	| dexp '*' dexp
92234949Sbapt	{
93234949Sbapt		$$ = $1 * $3;
94234949Sbapt	}
95234949Sbapt	| dexp '/' dexp
96234949Sbapt	{
97234949Sbapt		$$ = $1 / $3;
98234949Sbapt	}
99234949Sbapt	| '-' dexp %prec UMINUS
100234949Sbapt	{
101234949Sbapt		$$ = -$2;
102234949Sbapt	}
103234949Sbapt	| '(' dexp ')'
104234949Sbapt	{
105234949Sbapt		$$ = $2;
106234949Sbapt	}
107234949Sbapt	;
108234949Sbapt
109234949Sbaptvexp	: dexp
110234949Sbapt	{
111234949Sbapt		$$.hi = $$.lo = $1;
112234949Sbapt	}
113234949Sbapt	| '(' dexp ',' dexp ')'
114234949Sbapt	{
115234949Sbapt		$$.lo = $2;
116234949Sbapt		$$.hi = $4;
117234949Sbapt		if ( $$.lo > $$.hi )
118234949Sbapt		{
119234949Sbapt			(void) printf("interval out of order\n");
120234949Sbapt			YYERROR;
121234949Sbapt		}
122234949Sbapt	}
123234949Sbapt	| VREG
124234949Sbapt	{
125234949Sbapt		$$ = vreg[$1];
126234949Sbapt	}
127234949Sbapt	| vexp '+' vexp
128234949Sbapt	{
129234949Sbapt		$$.hi = $1.hi + $3.hi;
130234949Sbapt		$$.lo = $1.lo + $3.lo;
131234949Sbapt	}
132234949Sbapt	| dexp '+' vexp
133234949Sbapt	{
134234949Sbapt		$$.hi = $1 + $3.hi;
135234949Sbapt		$$.lo = $1 + $3.lo;
136234949Sbapt	}
137234949Sbapt	| vexp '-' vexp
138234949Sbapt	{
139234949Sbapt		$$.hi = $1.hi - $3.lo;
140234949Sbapt		$$.lo = $1.lo - $3.hi;
141234949Sbapt	}
142234949Sbapt	| dexp '-' vexp
143234949Sbapt	{
144234949Sbapt		$$.hi = $1 - $3.lo;
145234949Sbapt		$$.lo = $1 - $3.hi;
146234949Sbapt	}
147234949Sbapt	| vexp '*' vexp
148234949Sbapt	{
149234949Sbapt		$$ = vmul( $1.lo, $1.hi, $3 );
150234949Sbapt	}
151234949Sbapt	| dexp '*' vexp
152234949Sbapt	{
153234949Sbapt		$$ = vmul ($1, $1, $3 );
154234949Sbapt	}
155234949Sbapt	| vexp '/' vexp
156234949Sbapt	{
157234949Sbapt		if (dcheck($3)) YYERROR;
158234949Sbapt		$$ = vdiv ( $1.lo, $1.hi, $3 );
159234949Sbapt	}
160234949Sbapt	| dexp '/' vexp
161234949Sbapt	{
162234949Sbapt		if (dcheck ( $3 )) YYERROR;
163234949Sbapt		$$ = vdiv ($1, $1, $3 );
164234949Sbapt	}
165234949Sbapt	| '-' vexp %prec UMINUS
166234949Sbapt	{
167234949Sbapt		$$.hi = -$2.lo;
168234949Sbapt		$$.lo = -$2.hi;
169234949Sbapt	}
170234949Sbapt	| '(' vexp ')'
171234949Sbapt	{
172234949Sbapt		$$ = $2;
173234949Sbapt	}
174234949Sbapt	;
175234949Sbapt
176234949Sbapt%%	/* beginning of subroutines section */
177234949Sbapt
178234949Sbapt#define BSZ 50			/* buffer size for floating point numbers */
179234949Sbapt
180234949Sbapt	/* lexical analysis */
181234949Sbapt
182234949Sbaptstatic void
183234949Sbaptyyerror(const char *s)
184234949Sbapt{
185234949Sbapt    fprintf(stderr, "%s\n", s);
186234949Sbapt}
187234949Sbapt
188234949Sbaptint
189234949Sbaptyylex(void)
190234949Sbapt{
191234949Sbapt    int c;
192234949Sbapt
193234949Sbapt    while ((c = getchar()) == ' ')
194234949Sbapt    {				/* skip over blanks */
195234949Sbapt    }
196234949Sbapt
197234949Sbapt    if (isupper(c))
198234949Sbapt    {
199234949Sbapt	yylval.ival = c - 'A';
200234949Sbapt	return (VREG);
201234949Sbapt    }
202234949Sbapt    if (islower(c))
203234949Sbapt    {
204234949Sbapt	yylval.ival = c - 'a';
205234949Sbapt	return (DREG);
206234949Sbapt    }
207234949Sbapt
208234949Sbapt    if (isdigit(c) || c == '.')
209234949Sbapt    {
210234949Sbapt	/* gobble up digits, points, exponents */
211234949Sbapt	char buf[BSZ + 1], *cp = buf;
212234949Sbapt	int dot = 0, expr = 0;
213234949Sbapt
214234949Sbapt	for (; (cp - buf) < BSZ; ++cp, c = getchar())
215234949Sbapt	{
216234949Sbapt
217251143Sbapt	    *cp = (char) c;
218234949Sbapt	    if (isdigit(c))
219234949Sbapt		continue;
220234949Sbapt	    if (c == '.')
221234949Sbapt	    {
222234949Sbapt		if (dot++ || expr)
223234949Sbapt		    return ('.');	/* will cause syntax error */
224234949Sbapt		continue;
225234949Sbapt	    }
226234949Sbapt
227234949Sbapt	    if (c == 'e')
228234949Sbapt	    {
229234949Sbapt		if (expr++)
230234949Sbapt		    return ('e');	/*  will  cause  syntax  error  */
231234949Sbapt		continue;
232234949Sbapt	    }
233234949Sbapt
234234949Sbapt	    /*  end  of  number  */
235234949Sbapt	    break;
236234949Sbapt	}
237234949Sbapt	*cp = '\0';
238234949Sbapt
239234949Sbapt	if ((cp - buf) >= BSZ)
240234949Sbapt	    printf("constant  too  long:  truncated\n");
241234949Sbapt	else
242234949Sbapt	    ungetc(c, stdin);	/*  push  back  last  char  read  */
243234949Sbapt	yylval.dval = atof(buf);
244234949Sbapt	return (CONST);
245234949Sbapt    }
246234949Sbapt    return (c);
247234949Sbapt}
248234949Sbapt
249234949Sbaptstatic INTERVAL
250234949Sbapthilo(double a, double b, double c, double d)
251234949Sbapt{
252234949Sbapt    /*  returns  the  smallest  interval  containing  a,  b,  c,  and  d  */
253234949Sbapt    /*  used  by  *,  /  routines  */
254234949Sbapt    INTERVAL v;
255234949Sbapt
256234949Sbapt    if (a > b)
257234949Sbapt    {
258234949Sbapt	v.hi = a;
259234949Sbapt	v.lo = b;
260234949Sbapt    }
261234949Sbapt    else
262234949Sbapt    {
263234949Sbapt	v.hi = b;
264234949Sbapt	v.lo = a;
265234949Sbapt    }
266234949Sbapt
267234949Sbapt    if (c > d)
268234949Sbapt    {
269234949Sbapt	if (c > v.hi)
270234949Sbapt	    v.hi = c;
271234949Sbapt	if (d < v.lo)
272234949Sbapt	    v.lo = d;
273234949Sbapt    }
274234949Sbapt    else
275234949Sbapt    {
276234949Sbapt	if (d > v.hi)
277234949Sbapt	    v.hi = d;
278234949Sbapt	if (c < v.lo)
279234949Sbapt	    v.lo = c;
280234949Sbapt    }
281234949Sbapt    return (v);
282234949Sbapt}
283234949Sbapt
284234949SbaptINTERVAL
285234949Sbaptvmul(double a, double b, INTERVAL v)
286234949Sbapt{
287234949Sbapt    return (hilo(a * v.hi, a * v.lo, b * v.hi, b * v.lo));
288234949Sbapt}
289234949Sbapt
290234949Sbaptint
291234949Sbaptdcheck(INTERVAL v)
292234949Sbapt{
293234949Sbapt    if (v.hi >= 0. && v.lo <= 0.)
294234949Sbapt    {
295234949Sbapt	printf("divisor  interval  contains  0.\n");
296234949Sbapt	return (1);
297234949Sbapt    }
298234949Sbapt    return (0);
299234949Sbapt}
300234949Sbapt
301234949SbaptINTERVAL
302234949Sbaptvdiv(double a, double b, INTERVAL v)
303234949Sbapt{
304234949Sbapt    return (hilo(a / v.hi, a / v.lo, b / v.hi, b / v.lo));
305234949Sbapt}
306