calc1.y revision 1.1.1.3
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 12typedef struct interval 13{ 14 double lo, hi; 15} 16INTERVAL; 17 18INTERVAL vmul(double, double, INTERVAL); 19INTERVAL vdiv(double, double, INTERVAL); 20 21int dcheck(INTERVAL); 22 23double dreg[26]; 24INTERVAL 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 51lines : /* empty */ 52 | lines line 53 ; 54 55line : 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 77dexp : 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 108vexp : 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 178extern int YYLEX_DECL(); 179static void YYERROR_DECL(); 180#endif 181 182#define BSZ 50 /* buffer size for floating point numbers */ 183 184 /* lexical analysis */ 185 186static void 187yyerror(const char *s) 188{ 189 fprintf(stderr, "%s\n", s); 190} 191 192int 193yylex(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 253static INTERVAL 254hilo(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 288INTERVAL 289vmul(double a, double b, INTERVAL v) 290{ 291 return (hilo(a * v.hi, a * v.lo, b * v.hi, b * v.lo)); 292} 293 294int 295dcheck(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 305INTERVAL 306vdiv(double a, double b, INTERVAL v) 307{ 308 return (hilo(a / v.hi, a / v.lo, b / v.hi, b / v.lo)); 309} 310