1/*	$NetBSD: varsyntax_calc1.y,v 1.1.1.3 2016/01/09 21:59:45 christos Exp $	*/
2
3%IDENT "check variant syntax features"
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
22extern int yylex(void);
23static void yyerror(const char *s);
24
25int dcheck(INTERVAL);
26
27double dreg[26];
28INTERVAL vreg[26];
29
30%}
31%expect 18
32
33%start line
34%union
35{
36	int ival;	// dreg & vreg array index values
37	double dval;	// floating point values
38	INTERVAL vval;	// interval values
39}
40
41%token <ival> DREG VREG		// indices into dreg, vreg arrays */
42%token <dval> CONST		// floating point constant */
43
44%type <dval> dexp		// expression */
45%type <vval> vexp		// interval expression */
46
47	// precedence information about the operators */
48
49%< '+' '-'			// %< is an obsolete synonym for %left
50%< '*' '/'
51%> UMINUS			// precedence for unary minus;
52				// %> is an obsolete synonym for %right
53
54\\	// beginning of rules section; \\ is an obsolete synonym for %%
55
56lines   : // empty */
57	| lines line
58	;
59
60line	: dexp '\n'
61	{
62		(void) printf("%15.8f\n", $1);
63	}
64	| vexp '\n'
65	{
66		(void) printf("(%15.8f, %15.8f)\n", $1.lo, $1.hi);
67	}
68	| DREG '=' dexp '\n'
69	{
70		dreg[$1] = $3;
71	}
72	| VREG '=' vexp '\n'
73	{
74		vreg[$1] = $3;
75	}
76	| error '\n'
77	{
78		yyerrok;
79	}
80	;
81
82dexp	: CONST
83	| DREG
84	{
85		$<dval>$ = dreg[$<ival>1]; // $$ & $1 are sufficient here
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 '/' dexp
100	{
101		$$ = $1 / $3;
102	}
103	| '-' dexp %prec UMINUS
104	{
105		$$ = -$2;
106	}
107	| '(' dexp ')'
108	{
109		$$ = $2;
110	}
111	;
112
113vexp	: dexp
114	{
115		$$.hi = $$.lo = $1;
116	}
117	| '(' dexp ',' dexp ')'
118	{
119		$$.lo = $2;
120		$$.hi = $4;
121		if ( $$.lo > $$.hi )
122		{
123			(void) printf("interval out of order\n");
124			YYERROR;
125		}
126	}
127	| VREG
128	{
129		$$ = vreg[$1];
130	}
131	| vexp '+' vexp
132	{
133		$$.hi = $1.hi + $3.hi;
134		$$.lo = $1.lo + $3.lo;
135	}
136	| dexp '+' vexp
137	{
138		$$.hi = $1 + $3.hi;
139		$$.lo = $1 + $3.lo;
140	}
141	| vexp '-' vexp
142	{
143		$$.hi = $1.hi - $3.lo;
144		$$.lo = $1.lo - $3.hi;
145	}
146	| dexp '-' vexp
147	{
148		$$.hi = $1 - $3.lo;
149		$$.lo = $1 - $3.hi;
150	}
151	| vexp '*' vexp
152	{
153		$$ = vmul( $1.lo, $1.hi, $3 );
154	}
155	| dexp '*' vexp
156	{
157		$$ = vmul ($1, $1, $3 );
158	}
159	| vexp '/' vexp
160	{
161		if (dcheck($3)) YYERROR;
162		$$ = vdiv ( $1.lo, $1.hi, $3 );
163	}
164	| dexp '/' vexp
165	{
166		if (dcheck ( $3 )) YYERROR;
167		$$ = vdiv ($1, $1, $3 );
168	}
169	| '-' vexp %prec UMINUS
170	{
171		$$.hi = -$2.lo;
172		$$.lo = -$2.hi;
173	}
174	| '(' vexp ')'
175	{
176		$$ = $2;
177	}
178	;
179
180\\	/* beginning of subroutines section */
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 = (char) 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