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