calc1.y revision 1.1.1.3
1/*	$NetBSD: calc1.y,v 1.1.1.3 2011/09/10 21:22:09 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
12typedef struct interval
13{
14    double lo, hi;
15}
16INTERVAL;
17
18INTERVAL vmul(double, double, INTERVAL);
19INTERVAL vdiv(double, double, INTERVAL);
20
21int dcheck(INTERVAL);
22
23double dreg[26];
24INTERVAL vreg[26];
25
26%}
27%expect 18
28
29%start line
30%union
31{
32	int ival;
33	double dval;
34	INTERVAL vval;
35}
36
37%token <ival> DREG VREG		/* indices into dreg, vreg arrays */
38%token <dval> CONST		/* floating point constant */
39
40%type <dval> dexp		/* expression */
41%type <vval> vexp		/* interval expression */
42
43	/* precedence information about the operators */
44
45%left '+' '-'
46%left '*' '/'
47%left UMINUS			/* precedence for unary minus */
48
49%%	/* beginning of rules section */
50
51lines   : /* empty */
52	| lines line
53	;
54
55line	: dexp '\n'
56	{
57		(void) printf("%15.8f\n", $1);
58	}
59	| vexp '\n'
60	{
61		(void) printf("(%15.8f, %15.8f)\n", $1.lo, $1.hi);
62	}
63	| DREG '=' dexp '\n'
64	{
65		dreg[$1] = $3;
66	}
67	| VREG '=' vexp '\n'
68	{
69		vreg[$1] = $3;
70	}
71	| error '\n'
72	{
73		yyerrok;
74	}
75	;
76
77dexp	: CONST
78	| DREG
79	{
80		$$ = dreg[$1];
81	}
82	| dexp '+' dexp
83	{
84		$$ = $1 + $3;
85	}
86	| dexp '-' dexp
87	{
88		$$ = $1 - $3;
89	}
90	| dexp '*' dexp
91	{
92		$$ = $1 * $3;
93	}
94	| dexp '/' dexp
95	{
96		$$ = $1 / $3;
97	}
98	| '-' dexp %prec UMINUS
99	{
100		$$ = -$2;
101	}
102	| '(' dexp ')'
103	{
104		$$ = $2;
105	}
106	;
107
108vexp	: dexp
109	{
110		$$.hi = $$.lo = $1;
111	}
112	| '(' dexp ',' dexp ')'
113	{
114		$$.lo = $2;
115		$$.hi = $4;
116		if ( $$.lo > $$.hi )
117		{
118			(void) printf("interval out of order\n");
119			YYERROR;
120		}
121	}
122	| VREG
123	{
124		$$ = vreg[$1];
125	}
126	| vexp '+' vexp
127	{
128		$$.hi = $1.hi + $3.hi;
129		$$.lo = $1.lo + $3.lo;
130	}
131	| dexp '+' vexp
132	{
133		$$.hi = $1 + $3.hi;
134		$$.lo = $1 + $3.lo;
135	}
136	| vexp '-' vexp
137	{
138		$$.hi = $1.hi - $3.lo;
139		$$.lo = $1.lo - $3.hi;
140	}
141	| dexp '-' vexp
142	{
143		$$.hi = $1 - $3.lo;
144		$$.lo = $1 - $3.hi;
145	}
146	| vexp '*' vexp
147	{
148		$$ = vmul( $1.lo, $1.hi, $3 );
149	}
150	| dexp '*' vexp
151	{
152		$$ = vmul ($1, $1, $3 );
153	}
154	| vexp '/' vexp
155	{
156		if (dcheck($3)) YYERROR;
157		$$ = vdiv ( $1.lo, $1.hi, $3 );
158	}
159	| dexp '/' vexp
160	{
161		if (dcheck ( $3 )) YYERROR;
162		$$ = vdiv ($1, $1, $3 );
163	}
164	| '-' vexp %prec UMINUS
165	{
166		$$.hi = -$2.lo;
167		$$.lo = -$2.hi;
168	}
169	| '(' vexp ')'
170	{
171		$$ = $2;
172	}
173	;
174
175%%	/* beginning of subroutines section */
176
177#ifdef YYBYACC
178extern int YYLEX_DECL();
179static void YYERROR_DECL();
180#endif
181
182#define BSZ 50			/* buffer size for floating point numbers */
183
184	/* lexical analysis */
185
186static void
187yyerror(const char *s)
188{
189    fprintf(stderr, "%s\n", s);
190}
191
192int
193yylex(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 = 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
253static INTERVAL
254hilo(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
288INTERVAL
289vmul(double a, double b, INTERVAL v)
290{
291    return (hilo(a * v.hi, a * v.lo, b * v.hi, b * v.lo));
292}
293
294int
295dcheck(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
305INTERVAL
306vdiv(double a, double b, INTERVAL v)
307{
308    return (hilo(a / v.hi, a / v.lo, b / v.hi, b / v.lo));
309}
310