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