1 /* $NetBSD: varsyntax_calc1.y,v 1.1.1.1 2015/01/03 22:58:23 christos Exp $ */ 2 3 %IDENT "check variant syntax features" 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 13 typedef struct interval 14 { 15 double lo, hi; 16 } 17 INTERVAL; 18 19 INTERVAL vmul(double, double, INTERVAL); 20 INTERVAL vdiv(double, double, INTERVAL); 21 22 extern int yylex(void); 23 static void yyerror(const char *s); 24 25 int dcheck(INTERVAL); 26 27 double dreg[26]; 28 INTERVAL vreg[26]; 29 30 %} 31 %expect 18 32 33 %start line 34 %union 35 { 36 int ival; // dreg & vreg array index values 37 double dval; // floating point values 38 INTERVAL vval; // interval values 39 } 40 41 %token <ival> DREG VREG // indices into dreg, vreg arrays */ 42 %token <dval> CONST // floating point constant */ 43 44 %type <dval> dexp // expression */ 45 %type <vval> vexp // interval expression */ 46 47 // precedence information about the operators */ 48 49 %< '+' '-' // %< is an obsolete synonym for %left 50 %< '*' '/' 51 %> UMINUS // precedence for unary minus; 52 // %> is an obsolete synonym for %right 53 54 \\ // beginning of rules section; \\ is an obsolete synonym for %% 55 56 lines : // empty */ 57 | lines line 58 ; 59 60 line : dexp '\n' 61 { 62 (void) printf("%15.8f\n", $1); 63 } 64 | vexp '\n' 65 { 66 (void) printf("(%15.8f, %15.8f)\n", $1.lo, $1.hi); 67 } 68 | DREG '=' dexp '\n' 69 { 70 dreg[$1] = $3; 71 } 72 | VREG '=' vexp '\n' 73 { 74 vreg[$1] = $3; 75 } 76 | error '\n' 77 { 78 yyerrok; 79 } 80 ; 81 82 dexp : CONST 83 | DREG 84 { 85 $<dval>$ = dreg[$<ival>1]; // $$ & $1 are sufficient here 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 '/' dexp 100 { 101 $$ = $1 / $3; 102 } 103 | '-' dexp %prec UMINUS 104 { 105 $$ = -$2; 106 } 107 | '(' dexp ')' 108 { 109 $$ = $2; 110 } 111 ; 112 113 vexp : dexp 114 { 115 $$.hi = $$.lo = $1; 116 } 117 | '(' dexp ',' dexp ')' 118 { 119 $$.lo = $2; 120 $$.hi = $4; 121 if ( $$.lo > $$.hi ) 122 { 123 (void) printf("interval out of order\n"); 124 YYERROR; 125 } 126 } 127 | VREG 128 { 129 $$ = vreg[$1]; 130 } 131 | vexp '+' vexp 132 { 133 $$.hi = $1.hi + $3.hi; 134 $$.lo = $1.lo + $3.lo; 135 } 136 | dexp '+' vexp 137 { 138 $$.hi = $1 + $3.hi; 139 $$.lo = $1 + $3.lo; 140 } 141 | vexp '-' vexp 142 { 143 $$.hi = $1.hi - $3.lo; 144 $$.lo = $1.lo - $3.hi; 145 } 146 | dexp '-' vexp 147 { 148 $$.hi = $1 - $3.lo; 149 $$.lo = $1 - $3.hi; 150 } 151 | vexp '*' vexp 152 { 153 $$ = vmul( $1.lo, $1.hi, $3 ); 154 } 155 | dexp '*' vexp 156 { 157 $$ = vmul ($1, $1, $3 ); 158 } 159 | vexp '/' vexp 160 { 161 if (dcheck($3)) YYERROR; 162 $$ = vdiv ( $1.lo, $1.hi, $3 ); 163 } 164 | dexp '/' vexp 165 { 166 if (dcheck ( $3 )) YYERROR; 167 $$ = vdiv ($1, $1, $3 ); 168 } 169 | '-' vexp %prec UMINUS 170 { 171 $$.hi = -$2.lo; 172 $$.lo = -$2.hi; 173 } 174 | '(' vexp ')' 175 { 176 $$ = $2; 177 } 178 ; 179 180 \\ /* beginning of subroutines section */ 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 = (char) 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