expr.y revision 31
1%{ 2/* Written by Pace Willisson (pace@blitz.com) 3 * and placed in the public domain 4 * 5 * /b/source/CVS/src/bin/expr/expr.y,v 1.6 1993/06/14 19:59:07 jtc Exp 6 */ 7#include <stdio.h> 8#include <stdlib.h> 9#include <string.h> 10#include <ctype.h> 11 12enum valtype { 13 integer, string 14} ; 15 16struct val { 17 enum valtype type; 18 union { 19 char *s; 20 int i; 21 } u; 22} ; 23 24struct val *result; 25struct val *op_or (); 26struct val *op_and (); 27struct val *op_eq (); 28struct val *op_gt (); 29struct val *op_lt (); 30struct val *op_ge (); 31struct val *op_le (); 32struct val *op_ne (); 33struct val *op_plus (); 34struct val *op_minus (); 35struct val *op_times (); 36struct val *op_div (); 37struct val *op_rem (); 38struct val *op_colon (); 39 40char **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 61start: expr { result = $$; } 62 63expr: 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 85struct val * 86make_integer (i) 87int 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 102struct val * 103make_str (s) 104char *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 119void 120free_value (vp) 121struct val *vp; 122{ 123 if (vp->type == string) 124 free (vp->u.s); 125} 126 127 128int 129to_integer (vp) 130struct 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 163void 164to_string (vp) 165struct 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 184int 185isstring (vp) 186struct val *vp; 187{ 188 return (vp->type == string); 189} 190 191 192int 193yylex () 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 218int 219is_zero_or_null (vp) 220struct 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 233void 234main (argc, argv) 235int argc; 236char **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 253int 254yyerror (s) 255char *s; 256{ 257 fprintf (stderr, "expr: syntax error\n"); 258 exit (2); 259} 260 261 262struct val * 263op_or (a, b) 264struct 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 275struct val * 276op_and (a, b) 277struct 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 289struct val * 290op_eq (a, b) 291struct 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 314struct val * 315op_gt (a, b) 316struct 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 339struct val * 340op_lt (a, b) 341struct 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 364struct val * 365op_ge (a, b) 366struct 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 389struct val * 390op_le (a, b) 391struct 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 414struct val * 415op_ne (a, b) 416struct 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 439struct val * 440op_plus (a, b) 441struct 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 456struct val * 457op_minus (a, b) 458struct 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 473struct val * 474op_times (a, b) 475struct 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 490struct val * 491op_div (a, b) 492struct 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 512struct val * 513op_rem (a, b) 514struct 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 <regex.h> 535#define SE_MAX 30 536 537struct val * 538op_colon (a, b) 539struct val *a, *b; 540{ 541 regex_t rp; 542 regmatch_t rm[SE_MAX]; 543 char errbuf[256]; 544 int eval; 545 char *newpat; 546 struct val *v; 547 548 /* patterns are anchored to the beginning of the line */ 549 newpat = malloc (strlen (b->u.s) + 2); 550 strcpy (newpat, "^"); 551 strcat (newpat, b->u.s); 552 553 /* compile regular expression */ 554 if ((eval = regcomp (&rp, newpat, 0)) != 0) { 555 regerror (eval, &rp, errbuf, sizeof(errbuf)); 556 fprintf (stderr, "expr: %s\n", errbuf); 557 exit (2); 558 } 559 free (newpat); 560 561 /* compare string against pattern */ 562 if (regexec(&rp, a->u.s, SE_MAX, rm, 0) == 0) { 563 if (rm[1].rm_so >= 0) { 564 *(a->u.s + rm[1].rm_eo) = 0; 565 v = make_str (a->u.s + rm[1].rm_so); 566 567 } else { 568 v = make_integer (rm[0].rm_eo - rm[0].rm_so); 569 } 570 } else { 571 v = make_integer (0); 572 } 573 574 /* free arguments and pattern buffer */ 575 free_value (a); 576 free_value (b); 577 regfree (&rp); 578 579 return v; 580} 581