expr.y revision 181
1%{ 2/* Written by Pace Willisson (pace@blitz.com) 3 * and placed in the public domain 4 * 5 * $Header: /b/source/CVS/src/bin/expr/expr.y,v 1.9 1993/07/20 01:10:55 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 if (vp->type == integer) { 223 return (vp->u.i == 0); 224 } else { 225 return (*vp->u.s == 0 || (to_integer (vp) && vp->u.i == 0)); 226 } 227 /* NOTREACHED */ 228} 229 230void 231main (argc, argv) 232int argc; 233char **argv; 234{ 235 av = argv + 1; 236 237 yyparse (); 238 239 if (result->type == integer) 240 printf ("%d\n", result->u.i); 241 else 242 printf ("%s\n", result->u.s); 243 244 if (is_zero_or_null (result)) 245 exit (1); 246 else 247 exit (0); 248} 249 250int 251yyerror (s) 252char *s; 253{ 254 fprintf (stderr, "expr: syntax error\n"); 255 exit (2); 256} 257 258 259struct val * 260op_or (a, b) 261struct val *a, *b; 262{ 263 if (is_zero_or_null (a)) { 264 free_value (a); 265 return (b); 266 } else { 267 free_value (b); 268 return (a); 269 } 270} 271 272struct val * 273op_and (a, b) 274struct val *a, *b; 275{ 276 if (is_zero_or_null (a) || is_zero_or_null (b)) { 277 free_value (a); 278 free_value (b); 279 return (make_integer (0)); 280 } else { 281 free_value (b); 282 return (a); 283 } 284} 285 286struct val * 287op_eq (a, b) 288struct val *a, *b; 289{ 290 struct val *r; 291 292 if (isstring (a) || isstring (b)) { 293 to_string (a); 294 to_string (b); 295 r = make_integer (strcmp (a->u.s, b->u.s) == 0); 296 } else { 297 r = make_integer (a->u.i == b->u.i); 298 } 299 300 free_value (a); 301 free_value (b); 302 return r; 303} 304 305struct val * 306op_gt (a, b) 307struct val *a, *b; 308{ 309 struct val *r; 310 311 if (isstring (a) || isstring (b)) { 312 to_string (a); 313 to_string (b); 314 r = make_integer (strcmp (a->u.s, b->u.s) > 0); 315 } else { 316 r= make_integer (a->u.i > b->u.i); 317 } 318 319 free_value (a); 320 free_value (b); 321 return r; 322} 323 324struct val * 325op_lt (a, b) 326struct val *a, *b; 327{ 328 struct val *r; 329 330 if (isstring (a) || isstring (b)) { 331 to_string (a); 332 to_string (b); 333 r = make_integer (strcmp (a->u.s, b->u.s) < 0); 334 } else { 335 r = make_integer (a->u.i < b->u.i); 336 } 337 338 free_value (a); 339 free_value (b); 340 return r; 341} 342 343struct val * 344op_ge (a, b) 345struct val *a, *b; 346{ 347 struct val *r; 348 349 if (isstring (a) || isstring (b)) { 350 to_string (a); 351 to_string (b); 352 r = make_integer (strcmp (a->u.s, b->u.s) >= 0); 353 } else { 354 r = make_integer (a->u.i >= b->u.i); 355 } 356 357 free_value (a); 358 free_value (b); 359 return r; 360} 361 362struct val * 363op_le (a, b) 364struct val *a, *b; 365{ 366 struct val *r; 367 368 if (isstring (a) || isstring (b)) { 369 to_string (a); 370 to_string (b); 371 r = make_integer (strcmp (a->u.s, b->u.s) <= 0); 372 } else { 373 r = make_integer (a->u.i <= b->u.i); 374 } 375 376 free_value (a); 377 free_value (b); 378 return r; 379} 380 381struct val * 382op_ne (a, b) 383struct val *a, *b; 384{ 385 struct val *r; 386 387 if (isstring (a) || isstring (b)) { 388 to_string (a); 389 to_string (b); 390 r = make_integer (strcmp (a->u.s, b->u.s) != 0); 391 } else { 392 r = make_integer (a->u.i != b->u.i); 393 } 394 395 free_value (a); 396 free_value (b); 397 return r; 398} 399 400struct val * 401op_plus (a, b) 402struct val *a, *b; 403{ 404 struct val *r; 405 406 if (!to_integer (a) || !to_integer (b)) { 407 fprintf (stderr, "expr: non-numeric argument\n"); 408 exit (2); 409 } 410 411 r = make_integer (a->u.i + b->u.i); 412 free_value (a); 413 free_value (b); 414 return r; 415} 416 417struct val * 418op_minus (a, b) 419struct val *a, *b; 420{ 421 struct val *r; 422 423 if (!to_integer (a) || !to_integer (b)) { 424 fprintf (stderr, "expr: non-numeric argument\n"); 425 exit (2); 426 } 427 428 r = make_integer (a->u.i - b->u.i); 429 free_value (a); 430 free_value (b); 431 return r; 432} 433 434struct val * 435op_times (a, b) 436struct val *a, *b; 437{ 438 struct val *r; 439 440 if (!to_integer (a) || !to_integer (b)) { 441 fprintf (stderr, "expr: non-numeric argument\n"); 442 exit (2); 443 } 444 445 r = make_integer (a->u.i * b->u.i); 446 free_value (a); 447 free_value (b); 448 return (r); 449} 450 451struct val * 452op_div (a, b) 453struct val *a, *b; 454{ 455 struct val *r; 456 457 if (!to_integer (a) || !to_integer (b)) { 458 fprintf (stderr, "expr: non-numeric argument\n"); 459 exit (2); 460 } 461 462 if (b->u.i == 0) { 463 fprintf (stderr, "expr: division by zero\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_rem (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 if (b->u.i == 0) { 485 fprintf (stderr, "expr: division by zero\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 495#include <regex.h> 496#define SE_MAX 30 497 498struct val * 499op_colon (a, b) 500struct val *a, *b; 501{ 502 regex_t rp; 503 regmatch_t rm[SE_MAX]; 504 char errbuf[256]; 505 int eval; 506 struct val *v; 507 char *newpat; 508 509 /* coerce to both arguments to strings */ 510 to_string(a); 511 to_string(b); 512 513 /* patterns are anchored to the beginning of the line */ 514 newpat = malloc (strlen (b->u.s) + 2); 515 strcpy (newpat, "^"); 516 strcat (newpat, b->u.s); 517 518 /* compile regular expression */ 519 if ((eval = regcomp (&rp, newpat, 0)) != 0) { 520 regerror (eval, &rp, errbuf, sizeof(errbuf)); 521 fprintf (stderr, "expr: %s\n", errbuf); 522 exit (2); 523 } 524 free (newpat); 525 526 /* compare string against pattern */ 527 if (regexec(&rp, a->u.s, SE_MAX, rm, 0) == 0) { 528 if (rm[1].rm_so >= 0) { 529 *(a->u.s + rm[1].rm_eo) = 0; 530 v = make_str (a->u.s + rm[1].rm_so); 531 532 } else { 533 v = make_integer (rm[0].rm_eo - rm[0].rm_so); 534 } 535 } else { 536 v = make_integer (0); 537 } 538 539 /* free arguments and pattern buffer */ 540 free_value (a); 541 free_value (b); 542 regfree (&rp); 543 544 return v; 545} 546