1/* $NetBSD: btyacc_calc1.y,v 1.1.1.3 2016/01/09 21:59:45 christos Exp $ */ 2 3%PURE_PARSER 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 13typedef struct interval 14{ 15 double lo, hi; 16} 17INTERVAL; 18 19INTERVAL vmul(double, double, INTERVAL); 20INTERVAL vdiv(double, double, INTERVAL); 21 22int dcheck(INTERVAL); 23 24double dreg[26]; 25INTERVAL vreg[26]; 26 27%} 28%expect 17 29 30%start lines 31%union 32{ 33 int ival; 34 double dval; 35 INTERVAL vval; 36} 37 38%token <ival> DREG VREG /* indices into dreg, vreg arrays */ 39%token <dval> CONST /* floating point constant */ 40 41%type <dval> dexp /* expression */ 42%type <vval> vexp /* interval expression */ 43 44 /* precedence information about the operators */ 45 46%left '+' '-' 47%left '*' '/' 48%right UMINUS /* precedence for unary minus */ 49 50%% /* beginning of rules section */ 51 52lines : /* empty */ 53 | lines line '\n' [YYVALID;] 54 | lines error '\n' [YYVALID;] 55 { 56 yyerrok; 57 } 58 ; 59 60line : dexp 61 { 62 (void) printf("%15.8f\n", $1); 63 } 64 | vexp 65 { 66 (void) printf("(%15.8f, %15.8f)\n", $1.lo, $1.hi); 67 } 68 | DREG '=' dexp 69 { 70 dreg[$1] = $3; 71 } 72 | VREG '=' vexp 73 { 74 vreg[$1] = $3; 75 } 76 ; 77 78dexp : CONST 79 | DREG 80 { 81 $$ = dreg[$1]; 82 } 83 | dexp '+' dexp 84 { 85 $$ = $1 + $3; 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 %prec UMINUS 100 { 101 $$ = -$2; 102 } 103 | '(' dexp ')' 104 { 105 $$ = $2; 106 } 107 ; 108 109vexp : dexp 110 { 111 $$.hi = $$.lo = $1; 112 } 113 | '(' dexp ',' dexp ')' 114 { 115 $$.lo = $2; 116 $$.hi = $4; 117 if ( $$.lo > $$.hi ) 118 { 119 (void) printf("interval out of order\n"); 120 YYERROR; 121 } 122 } 123 | VREG 124 { 125 $$ = vreg[$1]; 126 } 127 | vexp '+' vexp 128 { 129 $$.hi = $1.hi + $3.hi; 130 $$.lo = $1.lo + $3.lo; 131 } 132 | dexp '+' vexp 133 { 134 $$.hi = $1 + $3.hi; 135 $$.lo = $1 + $3.lo; 136 } 137 | vexp '-' vexp 138 { 139 $$.hi = $1.hi - $3.lo; 140 $$.lo = $1.lo - $3.hi; 141 } 142 | dexp '-' vexp 143 { 144 $$.hi = $1 - $3.lo; 145 $$.lo = $1 - $3.hi; 146 } 147 | vexp '*' vexp 148 { 149 $$ = vmul( $1.lo, $1.hi, $3 ); 150 } 151 | dexp '*' vexp 152 { 153 $$ = vmul ($1, $1, $3 ); 154 } 155 | vexp '/' vexp 156 { 157 if (dcheck($3)) YYERROR; 158 $$ = vdiv ( $1.lo, $1.hi, $3 ); 159 } 160 | dexp '/' vexp 161 { 162 if (dcheck ( $3 )) YYERROR; 163 $$ = vdiv ($1, $1, $3 ); 164 } 165 | '-' vexp %prec UMINUS 166 { 167 $$.hi = -$2.lo; 168 $$.lo = -$2.hi; 169 } 170 | '(' vexp ')' 171 { 172 $$ = $2; 173 } 174 ; 175 176%% /* beginning of subroutines section */ 177 178int 179main (void) 180{ 181 while(!feof(stdin)) { 182 yyparse(); 183 } 184 return 0; 185} 186 187#define BSZ 50 /* buffer size for floating point numbers */ 188 189static void 190YYERROR_DECL() 191{ 192 fprintf(stderr, "%s\n", s); 193} 194 195 /* lexical analysis */ 196 197static int 198YYLEX_DECL() 199{ 200 int c; 201 202 while ((c = getchar()) == ' ') 203 { /* skip over blanks */ 204 } 205 206 if (isupper(c)) 207 { 208#if YYPURE 209 (*yylval).ival = c - 'A'; 210#else 211 yylval.ival = c - 'A'; 212#endif 213 return (VREG); 214 } 215 if (islower(c)) 216 { 217#if YYPURE 218 (*yylval).ival = c - 'a'; 219#else 220 yylval.ival = c - 'a'; 221#endif 222 return (DREG); 223 } 224 225 if (isdigit(c) || c == '.') 226 { 227 /* gobble up digits, points, exponents */ 228 char buf[BSZ + 1], *cp = buf; 229 int dot = 0, expr = 0; 230 231 for (; (cp - buf) < BSZ; ++cp, c = getchar()) 232 { 233 234 *cp = (char) c; 235 if (isdigit(c)) 236 continue; 237 if (c == '.') 238 { 239 if (dot++ || expr) 240 return ('.'); /* will cause syntax error */ 241 continue; 242 } 243 244 if (c == 'e') 245 { 246 if (expr++) 247 return ('e'); /* will cause syntax error */ 248 continue; 249 } 250 251 /* end of number */ 252 break; 253 } 254 *cp = '\0'; 255 256 if ((cp - buf) >= BSZ) 257 printf("constant too long: truncated\n"); 258 else 259 ungetc(c, stdin); /* push back last char read */ 260#if YYPURE 261 (*yylval).dval = atof(buf); 262#else 263 yylval.dval = atof(buf); 264#endif 265 return (CONST); 266 } 267 return (c); 268} 269 270static INTERVAL 271hilo(double a, double b, double c, double d) 272{ 273 /* returns the smallest interval containing a, b, c, and d */ 274 /* used by *, / routines */ 275 INTERVAL v; 276 277 if (a > b) 278 { 279 v.hi = a; 280 v.lo = b; 281 } 282 else 283 { 284 v.hi = b; 285 v.lo = a; 286 } 287 288 if (c > d) 289 { 290 if (c > v.hi) 291 v.hi = c; 292 if (d < v.lo) 293 v.lo = d; 294 } 295 else 296 { 297 if (d > v.hi) 298 v.hi = d; 299 if (c < v.lo) 300 v.lo = c; 301 } 302 return (v); 303} 304 305INTERVAL 306vmul(double a, double b, INTERVAL v) 307{ 308 return (hilo(a * v.hi, a * v.lo, b * v.hi, b * v.lo)); 309} 310 311int 312dcheck(INTERVAL v) 313{ 314 if (v.hi >= 0. && v.lo <= 0.) 315 { 316 printf("divisor interval contains 0.\n"); 317 return (1); 318 } 319 return (0); 320} 321 322INTERVAL 323vdiv(double a, double b, INTERVAL v) 324{ 325 return (hilo(a / v.hi, a / v.lo, b / v.hi, b / v.lo)); 326} 327