1/* $NetBSD: varsyntax_calc1.y,v 1.1.1.3 2016/01/09 21:59:45 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 13typedef struct interval 14{ 15 double lo, hi; 16} 17INTERVAL; 18 19INTERVAL vmul(double, double, INTERVAL); 20INTERVAL vdiv(double, double, INTERVAL); 21 22extern int yylex(void); 23static void yyerror(const char *s); 24 25int dcheck(INTERVAL); 26 27double dreg[26]; 28INTERVAL 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 56lines : // empty */ 57 | lines line 58 ; 59 60line : 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 82dexp : 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 113vexp : 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 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 = (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 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