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