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