1 /*	$NetBSD: varsyntax_calc1.y,v 1.1.1.1 2015/01/03 22:58:23 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 
13 typedef struct interval
14 {
15     double lo, hi;
16 }
17 INTERVAL;
18 
19 INTERVAL vmul(double, double, INTERVAL);
20 INTERVAL vdiv(double, double, INTERVAL);
21 
22 extern int yylex(void);
23 static void yyerror(const char *s);
24 
25 int dcheck(INTERVAL);
26 
27 double dreg[26];
28 INTERVAL 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 
56 lines   : // empty */
57 	| lines line
58 	;
59 
60 line	: 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 
82 dexp	: 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 
113 vexp	: 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 
186 static void
187 yyerror(const char *s)
188 {
189     fprintf(stderr, "%s\n", s);
190 }
191 
192 int
193 yylex(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 
253 static INTERVAL
254 hilo(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 
288 INTERVAL
289 vmul(double a, double b, INTERVAL v)
290 {
291     return (hilo(a * v.hi, a * v.lo, b * v.hi, b * v.lo));
292 }
293 
294 int
295 dcheck(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 
305 INTERVAL
306 vdiv(double a, double b, INTERVAL v)
307 {
308     return (hilo(a / v.hi, a / v.lo, b / v.hi, b / v.lo));
309 }
310