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