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