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