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