1 %{ 2 /* Written by Pace Willisson (pace@blitz.com) 3 * and placed in the public domain 4 * 5 * $Header: /cvsroot/src/bin/expr/expr.y,v 1.5 1993/06/05 22:25:44 cgd Exp $ 6 */ 7 #include <stdio.h> 8 #include <stdlib.h> 9 #include <string.h> 10 #include <ctype.h> 11 12 enum valtype { 13 integer, string 14 } ; 15 16 struct val { 17 enum valtype type; 18 union { 19 char *s; 20 int i; 21 } u; 22 } ; 23 24 struct val *result; 25 struct val *op_or (); 26 struct val *op_and (); 27 struct val *op_eq (); 28 struct val *op_gt (); 29 struct val *op_lt (); 30 struct val *op_ge (); 31 struct val *op_le (); 32 struct val *op_ne (); 33 struct val *op_plus (); 34 struct val *op_minus (); 35 struct val *op_times (); 36 struct val *op_div (); 37 struct val *op_rem (); 38 struct val *op_colon (); 39 40 char **av; 41 %} 42 43 %union 44 { 45 struct val *val; 46 } 47 48 %left <val> '|' 49 %left <val> '&' 50 %left <val> '=' '>' '<' GE LE NE 51 %left <val> '+' '-' 52 %left <val> '*' '/' '%' 53 %left <val> ':' 54 %left UNARY 55 56 %token <val> TOKEN 57 %type <val> start expr 58 59 %% 60 61 start: expr { result = $$; } 62 63 expr: TOKEN 64 | '(' expr ')' { $$ = $2; } 65 | expr '|' expr { $$ = op_or ($1, $3); } 66 | expr '&' expr { $$ = op_and ($1, $3); } 67 | expr '=' expr { $$ = op_eq ($1, $3); } 68 | expr '>' expr { $$ = op_gt ($1, $3); } 69 | expr '<' expr { $$ = op_lt ($1, $3); } 70 | expr GE expr { $$ = op_ge ($1, $3); } 71 | expr LE expr { $$ = op_le ($1, $3); } 72 | expr NE expr { $$ = op_ne ($1, $3); } 73 | expr '+' expr { $$ = op_plus ($1, $3); } 74 | expr '-' expr { $$ = op_minus ($1, $3); } 75 | expr '*' expr { $$ = op_times ($1, $3); } 76 | expr '/' expr { $$ = op_div ($1, $3); } 77 | expr '%' expr { $$ = op_rem ($1, $3); } 78 | expr ':' expr { $$ = op_colon ($1, $3); } 79 | '-' expr %prec UNARY { $$ = op_minus (NULL, $2); } 80 ; 81 82 83 %% 84 85 struct val * 86 make_integer (i) 87 int i; 88 { 89 struct val *vp; 90 91 vp = (struct val *) malloc (sizeof (*vp)); 92 if (vp == NULL) { 93 fprintf (stderr, "expr: out of memory\n"); 94 exit (2); 95 } 96 97 vp->type = integer; 98 vp->u.i = i; 99 return vp; 100 } 101 102 struct val * 103 make_str (s) 104 char *s; 105 { 106 struct val *vp; 107 108 vp = (struct val *) malloc (sizeof (*vp)); 109 if (vp == NULL || ((vp->u.s = strdup (s)) == NULL)) { 110 fprintf (stderr, "expr: out of memory\n"); 111 exit (2); 112 } 113 114 vp->type = string; 115 return vp; 116 } 117 118 119 void 120 free_value (vp) 121 struct val *vp; 122 { 123 if (vp->type == string) 124 free (vp->u.s); 125 } 126 127 128 int 129 to_integer (vp) 130 struct val *vp; 131 { 132 char *s; 133 int neg; 134 int i; 135 136 if (vp->type == integer) 137 return 1; 138 139 s = vp->u.s; 140 i = 0; 141 142 neg = (*s == '-'); 143 if (neg) 144 s++; 145 146 for (;*s; s++) { 147 if (!isdigit (*s)) 148 return 0; 149 150 i *= 10; 151 i += *s - '0'; 152 } 153 154 free (vp->u.s); 155 if (neg) 156 i *= -1; 157 158 vp->type = integer; 159 vp->u.i = i; 160 return 1; 161 } 162 163 void 164 to_string (vp) 165 struct val *vp; 166 { 167 char *tmp; 168 169 if (vp->type == string) 170 return; 171 172 tmp = malloc (25); 173 if (tmp == NULL) { 174 fprintf (stderr, "expr: out of memory\n"); 175 exit (2); 176 } 177 178 sprintf (tmp, "%d", vp->u.i); 179 vp->type = string; 180 vp->u.s = tmp; 181 } 182 183 184 int 185 isstring (vp) 186 struct val *vp; 187 { 188 return (vp->type == string); 189 } 190 191 192 int 193 yylex () 194 { 195 struct val *vp; 196 char *p; 197 198 if (*av == NULL) 199 return (0); 200 201 p = *av++; 202 203 if (strlen (p) == 1) { 204 if (strchr ("|&=<>+-*/%:()", *p)) 205 return (*p); 206 } else if (strlen (p) == 2 && p[1] == '=') { 207 switch (*p) { 208 case '>': return (GE); 209 case '<': return (LE); 210 case '!': return (NE); 211 } 212 } 213 214 yylval.val = make_str (p); 215 return (TOKEN); 216 } 217 218 int 219 is_zero_or_null (vp) 220 struct val *vp; 221 { 222 /* Like most other versions of expr, this version will return 223 false for a string value of multiple zeros.*/ 224 225 if (vp->type == integer) { 226 return (vp->u.i == 0); 227 } else { 228 return (*vp->u.s == 0 || strcmp (vp->u.s, "0") == 0); 229 } 230 /* NOTREACHED */ 231 } 232 233 void 234 main (argc, argv) 235 int argc; 236 char **argv; 237 { 238 av = argv + 1; 239 240 yyparse (); 241 242 if (result->type == integer) 243 printf ("%d\n", result->u.i); 244 else 245 printf ("%s\n", result->u.s); 246 247 if (is_zero_or_null (result)) 248 exit (1); 249 else 250 exit (0); 251 } 252 253 int 254 yyerror (s) 255 char *s; 256 { 257 fprintf (stderr, "expr: syntax error\n"); 258 exit (2); 259 } 260 261 262 struct val * 263 op_or (a, b) 264 struct val *a, *b; 265 { 266 if (is_zero_or_null (a)) { 267 free_value (a); 268 return (b); 269 } else { 270 free_value (b); 271 return (a); 272 } 273 } 274 275 struct val * 276 op_and (a, b) 277 struct val *a, *b; 278 { 279 if (is_zero_or_null (a) || is_zero_or_null (b)) { 280 free_value (a); 281 free_value (b); 282 return (make_integer (0)); 283 } else { 284 free_value (b); 285 return (a); 286 } 287 } 288 289 struct val * 290 op_eq (a, b) 291 struct val *a, *b; 292 { 293 struct val *r; 294 295 /* attempt to coerce both arguments to integers */ 296 (void) to_integer (a); 297 (void) to_integer (b); 298 299 /* But if either one of them really is a string, do 300 a string comparison */ 301 if (isstring (a) || isstring (b)) { 302 to_string (a); 303 to_string (b); 304 r = make_integer (strcmp (a->u.s, b->u.s) == 0); 305 } else { 306 r = make_integer (a->u.i == b->u.i); 307 } 308 309 free_value (a); 310 free_value (b); 311 return r; 312 } 313 314 struct val * 315 op_gt (a, b) 316 struct val *a, *b; 317 { 318 struct val *r; 319 320 /* attempt to coerce both arguments to integers */ 321 (void) to_integer (a); 322 (void) to_integer (b); 323 324 /* But if either one of them really is a string, do 325 a string comparison */ 326 if (isstring (a) || isstring (b)) { 327 to_string (a); 328 to_string (b); 329 r = make_integer (strcmp (a->u.s, b->u.s) > 0); 330 } else { 331 r= make_integer (a->u.i > b->u.i); 332 } 333 334 free_value (a); 335 free_value (b); 336 return r; 337 } 338 339 struct val * 340 op_lt (a, b) 341 struct val *a, *b; 342 { 343 struct val *r; 344 345 /* attempt to coerce both arguments to integers */ 346 (void) to_integer (a); 347 (void) to_integer (b); 348 349 /* But if either one of them really is a string, do 350 a string comparison */ 351 if (isstring (a) || isstring (b)) { 352 to_string (a); 353 to_string (b); 354 r = make_integer (strcmp (a->u.s, b->u.s) < 0); 355 } else { 356 r = make_integer (a->u.i < b->u.i); 357 } 358 359 free_value (a); 360 free_value (b); 361 return r; 362 } 363 364 struct val * 365 op_ge (a, b) 366 struct val *a, *b; 367 { 368 struct val *r; 369 370 /* attempt to coerce both arguments to integers */ 371 (void) to_integer (a); 372 (void) to_integer (b); 373 374 /* But if either one of them really is a string, do 375 a string comparison */ 376 if (isstring (a) || isstring (b)) { 377 to_string (a); 378 to_string (b); 379 r = make_integer (strcmp (a->u.s, b->u.s) >= 0); 380 } else { 381 r = make_integer (a->u.i >= b->u.i); 382 } 383 384 free_value (a); 385 free_value (b); 386 return r; 387 } 388 389 struct val * 390 op_le (a, b) 391 struct val *a, *b; 392 { 393 struct val *r; 394 395 /* attempt to coerce both arguments to integers */ 396 (void) to_integer (a); 397 (void) to_integer (b); 398 399 /* But if either one of them really is a string, do 400 a string comparison */ 401 if (isstring (a) || isstring (b)) { 402 to_string (a); 403 to_string (b); 404 r = make_integer (strcmp (a->u.s, b->u.s) <= 0); 405 } else { 406 r = make_integer (a->u.i <= b->u.i); 407 } 408 409 free_value (a); 410 free_value (b); 411 return r; 412 } 413 414 struct val * 415 op_ne (a, b) 416 struct val *a, *b; 417 { 418 struct val *r; 419 420 /* attempt to coerce both arguments to integers */ 421 (void) to_integer (a); 422 (void) to_integer (b); 423 424 /* But if either one of them really is a string, do 425 a string comparison */ 426 if (isstring (a) || isstring (b)) { 427 to_string (a); 428 to_string (b); 429 r = make_integer (strcmp (a->u.s, b->u.s) != 0); 430 } else { 431 r = make_integer (a->u.i != b->u.i); 432 } 433 434 free_value (a); 435 free_value (b); 436 return r; 437 } 438 439 struct val * 440 op_plus (a, b) 441 struct val *a, *b; 442 { 443 struct val *r; 444 445 if (!to_integer (a) || !to_integer (b)) { 446 fprintf (stderr, "expr: non-numeric argument\n"); 447 exit (2); 448 } 449 450 r = make_integer (a->u.i + b->u.i); 451 free_value (a); 452 free_value (b); 453 return r; 454 } 455 456 struct val * 457 op_minus (a, b) 458 struct val *a, *b; 459 { 460 struct val *r; 461 462 if (!to_integer (a) || !to_integer (b)) { 463 fprintf (stderr, "expr: non-numeric argument\n"); 464 exit (2); 465 } 466 467 r = make_integer (a->u.i - b->u.i); 468 free_value (a); 469 free_value (b); 470 return r; 471 } 472 473 struct val * 474 op_times (a, b) 475 struct val *a, *b; 476 { 477 struct val *r; 478 479 if (!to_integer (a) || !to_integer (b)) { 480 fprintf (stderr, "expr: non-numeric argument\n"); 481 exit (2); 482 } 483 484 r = make_integer (a->u.i * b->u.i); 485 free_value (a); 486 free_value (b); 487 return (r); 488 } 489 490 struct val * 491 op_div (a, b) 492 struct val *a, *b; 493 { 494 struct val *r; 495 496 if (!to_integer (a) || !to_integer (b)) { 497 fprintf (stderr, "expr: non-numeric argument\n"); 498 exit (2); 499 } 500 501 if (b->u.i == 0) { 502 fprintf (stderr, "expr: division by zero\n"); 503 exit (2); 504 } 505 506 r = make_integer (a->u.i / b->u.i); 507 free_value (a); 508 free_value (b); 509 return r; 510 } 511 512 struct val * 513 op_rem (a, b) 514 struct val *a, *b; 515 { 516 struct val *r; 517 518 if (!to_integer (a) || !to_integer (b)) { 519 fprintf (stderr, "expr: non-numeric argument\n"); 520 exit (2); 521 } 522 523 if (b->u.i == 0) { 524 fprintf (stderr, "expr: division by zero\n"); 525 exit (2); 526 } 527 528 r = make_integer (a->u.i % b->u.i); 529 free_value (a); 530 free_value (b); 531 return r; 532 } 533 534 #include <regexp.h> 535 536 struct val * 537 op_colon (a, b) 538 struct val *a, *b; 539 { 540 regexp *rp; 541 char *newexp; 542 char *p; 543 char *q; 544 545 newexp = malloc (3 * strlen (b->u.s)); 546 p = b->u.s; 547 q = newexp; 548 549 *q++ = '^'; 550 while (*p) { 551 if (*p == '\\') { 552 p++; 553 if (*p == '(' || *p == ')') { 554 *q++ = *p++; 555 } else { 556 *q++ = '\\'; 557 *q++ = *p++; 558 } 559 } else if (*p == '(' || *p == ')') { 560 *q++ = '\\'; 561 *q++ = *p++; 562 } else { 563 *q++ = *p++; 564 } 565 } 566 *q = 0; 567 568 if ((rp = regcomp (newexp)) == NULL) 569 yyerror ("invalid regular expression"); 570 571 if (regexec (rp, a->u.s)) { 572 if (rp->startp[1]) { 573 rp->endp[1][0] = 0; 574 return (make_str (rp->startp[1])); 575 } else { 576 return (make_integer (rp->endp[0] - rp->startp[0])); 577 } 578 } else { 579 return (make_integer (0)); 580 } 581 } 582 583 void 584 regerror (s) 585 const char *s; 586 { 587 fprintf (stderr, "expr: %s\n", s); 588 exit (2); 589 } 590