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