expr.y revision 50471
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 50471 1999-08-27 23:15:48Z peter $ 8 */ 9 10#include <stdio.h> 11#include <stdlib.h> 12#include <string.h> 13#include <locale.h> 14#include <ctype.h> 15#include <err.h> 16 17enum valtype { 18 integer, numeric_string, 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 60%token <val> TOKEN 61%type <val> start expr 62 63%% 64 65start: expr { result = $$; } 66 67expr: TOKEN 68 | '(' expr ')' { $$ = $2; } 69 | expr '|' expr { $$ = op_or ($1, $3); } 70 | expr '&' expr { $$ = op_and ($1, $3); } 71 | expr '=' expr { $$ = op_eq ($1, $3); } 72 | expr '>' expr { $$ = op_gt ($1, $3); } 73 | expr '<' expr { $$ = op_lt ($1, $3); } 74 | expr GE expr { $$ = op_ge ($1, $3); } 75 | expr LE expr { $$ = op_le ($1, $3); } 76 | expr NE expr { $$ = op_ne ($1, $3); } 77 | expr '+' expr { $$ = op_plus ($1, $3); } 78 | expr '-' expr { $$ = op_minus ($1, $3); } 79 | expr '*' expr { $$ = op_times ($1, $3); } 80 | expr '/' expr { $$ = op_div ($1, $3); } 81 | expr '%' expr { $$ = op_rem ($1, $3); } 82 | expr ':' expr { $$ = op_colon ($1, $3); } 83 ; 84 85 86%% 87 88struct val * 89make_integer (i) 90int i; 91{ 92 struct val *vp; 93 94 vp = (struct val *) malloc (sizeof (*vp)); 95 if (vp == NULL) { 96 errx (2, "malloc() failed"); 97 } 98 99 vp->type = integer; 100 vp->u.i = i; 101 return vp; 102} 103 104struct val * 105make_str (s) 106char *s; 107{ 108 struct val *vp; 109 int i, isint; 110 111 vp = (struct val *) malloc (sizeof (*vp)); 112 if (vp == NULL || ((vp->u.s = strdup (s)) == NULL)) { 113 errx (2, "malloc() failed"); 114 } 115 116 for(i = 1, isint = isdigit(s[0]) || s[0] == '-'; 117 isint && i < strlen(s); 118 i++) 119 { 120 if(!isdigit(s[i])) 121 isint = 0; 122 } 123 124 if (isint) 125 vp->type = numeric_string; 126 else 127 vp->type = string; 128 129 return vp; 130} 131 132 133void 134free_value (vp) 135struct val *vp; 136{ 137 if (vp->type == string || vp->type == numeric_string) 138 free (vp->u.s); 139} 140 141 142int 143to_integer (vp) 144struct val *vp; 145{ 146 int i; 147 148 if (vp->type == integer) 149 return 1; 150 151 if (vp->type == string) 152 return 0; 153 154 /* vp->type == numeric_string, make it numeric */ 155 i = atoi(vp->u.s); 156 free (vp->u.s); 157 vp->u.i = i; 158 vp->type = integer; 159 return 1; 160} 161 162void 163to_string (vp) 164struct val *vp; 165{ 166 char *tmp; 167 168 if (vp->type == string || vp->type == numeric_string) 169 return; 170 171 tmp = malloc (25); 172 if (tmp == NULL) { 173 errx (2, "malloc() failed"); 174 } 175 176 sprintf (tmp, "%d", vp->u.i); 177 vp->type = string; 178 vp->u.s = tmp; 179} 180 181 182int 183isstring (vp) 184struct val *vp; 185{ 186 /* only TRUE if this string is not a valid integer */ 187 return (vp->type == string); 188} 189 190 191int 192yylex () 193{ 194 char *p; 195 196 if (*av == NULL) 197 return (0); 198 199 p = *av++; 200 201 if (strlen (p) == 1) { 202 if (strchr ("|&=<>+-*/%:()", *p)) 203 return (*p); 204 } else if (strlen (p) == 2 && p[1] == '=') { 205 switch (*p) { 206 case '>': return (GE); 207 case '<': return (LE); 208 case '!': return (NE); 209 } 210 } 211 212 yylval.val = make_str (p); 213 return (TOKEN); 214} 215 216int 217is_zero_or_null (vp) 218struct val *vp; 219{ 220 if (vp->type == integer) { 221 return (vp->u.i == 0); 222 } else { 223 return (*vp->u.s == 0 || (to_integer (vp) && vp->u.i == 0)); 224 } 225 /* NOTREACHED */ 226} 227 228int yyparse (); 229 230int 231main (argc, argv) 232int argc; 233char **argv; 234{ 235 setlocale (LC_ALL, ""); 236 237 av = argv + 1; 238 239 yyparse (); 240 241 if (result->type == integer) 242 printf ("%d\n", result->u.i); 243 else 244 printf ("%s\n", result->u.s); 245 246 return (is_zero_or_null (result)); 247} 248 249int 250yyerror (s) 251char *s; 252{ 253 errx (2, "syntax error"); 254} 255 256 257struct val * 258op_or (a, b) 259struct val *a, *b; 260{ 261 if (is_zero_or_null (a)) { 262 free_value (a); 263 return (b); 264 } else { 265 free_value (b); 266 return (a); 267 } 268} 269 270struct val * 271op_and (a, b) 272struct val *a, *b; 273{ 274 if (is_zero_or_null (a) || is_zero_or_null (b)) { 275 free_value (a); 276 free_value (b); 277 return (make_integer (0)); 278 } else { 279 free_value (b); 280 return (a); 281 } 282} 283 284struct val * 285op_eq (a, b) 286struct val *a, *b; 287{ 288 struct val *r; 289 290 if (isstring (a) || isstring (b)) { 291 to_string (a); 292 to_string (b); 293 r = make_integer (strcoll (a->u.s, b->u.s) == 0); 294 } else { 295 (void)to_integer(a); 296 (void)to_integer(b); 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 (strcoll (a->u.s, b->u.s) > 0); 315 } else { 316 (void)to_integer(a); 317 (void)to_integer(b); 318 r= make_integer (a->u.i > b->u.i); 319 } 320 321 free_value (a); 322 free_value (b); 323 return r; 324} 325 326struct val * 327op_lt (a, b) 328struct val *a, *b; 329{ 330 struct val *r; 331 332 if (isstring (a) || isstring (b)) { 333 to_string (a); 334 to_string (b); 335 r = make_integer (strcoll (a->u.s, b->u.s) < 0); 336 } else { 337 (void)to_integer(a); 338 (void)to_integer(b); 339 r = make_integer (a->u.i < b->u.i); 340 } 341 342 free_value (a); 343 free_value (b); 344 return r; 345} 346 347struct val * 348op_ge (a, b) 349struct val *a, *b; 350{ 351 struct val *r; 352 353 if (isstring (a) || isstring (b)) { 354 to_string (a); 355 to_string (b); 356 r = make_integer (strcoll (a->u.s, b->u.s) >= 0); 357 } else { 358 (void)to_integer(a); 359 (void)to_integer(b); 360 r = make_integer (a->u.i >= b->u.i); 361 } 362 363 free_value (a); 364 free_value (b); 365 return r; 366} 367 368struct val * 369op_le (a, b) 370struct val *a, *b; 371{ 372 struct val *r; 373 374 if (isstring (a) || isstring (b)) { 375 to_string (a); 376 to_string (b); 377 r = make_integer (strcoll (a->u.s, b->u.s) <= 0); 378 } else { 379 (void)to_integer(a); 380 (void)to_integer(b); 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_ne (a, b) 391struct val *a, *b; 392{ 393 struct val *r; 394 395 if (isstring (a) || isstring (b)) { 396 to_string (a); 397 to_string (b); 398 r = make_integer (strcoll (a->u.s, b->u.s) != 0); 399 } else { 400 (void)to_integer(a); 401 (void)to_integer(b); 402 r = make_integer (a->u.i != b->u.i); 403 } 404 405 free_value (a); 406 free_value (b); 407 return r; 408} 409 410struct val * 411op_plus (a, b) 412struct val *a, *b; 413{ 414 struct val *r; 415 416 if (!to_integer (a) || !to_integer (b)) { 417 errx (2, "non-numeric argument"); 418 } 419 420 r = make_integer (a->u.i + b->u.i); 421 free_value (a); 422 free_value (b); 423 return r; 424} 425 426struct val * 427op_minus (a, b) 428struct val *a, *b; 429{ 430 struct val *r; 431 432 if (!to_integer (a) || !to_integer (b)) { 433 errx (2, "non-numeric argument"); 434 } 435 436 r = make_integer (a->u.i - b->u.i); 437 free_value (a); 438 free_value (b); 439 return r; 440} 441 442struct val * 443op_times (a, b) 444struct val *a, *b; 445{ 446 struct val *r; 447 448 if (!to_integer (a) || !to_integer (b)) { 449 errx (2, "non-numeric argument"); 450 } 451 452 r = make_integer (a->u.i * b->u.i); 453 free_value (a); 454 free_value (b); 455 return (r); 456} 457 458struct val * 459op_div (a, b) 460struct val *a, *b; 461{ 462 struct val *r; 463 464 if (!to_integer (a) || !to_integer (b)) { 465 errx (2, "non-numeric argument"); 466 } 467 468 if (b->u.i == 0) { 469 errx (2, "division by zero"); 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_rem (a, b) 480struct val *a, *b; 481{ 482 struct val *r; 483 484 if (!to_integer (a) || !to_integer (b)) { 485 errx (2, "non-numeric argument"); 486 } 487 488 if (b->u.i == 0) { 489 errx (2, "division by zero"); 490 } 491 492 r = make_integer (a->u.i % b->u.i); 493 free_value (a); 494 free_value (b); 495 return r; 496} 497 498#include <sys/types.h> 499#include <regex.h> 500 501struct val * 502op_colon (a, b) 503struct val *a, *b; 504{ 505 regex_t rp; 506 regmatch_t rm[2]; 507 char errbuf[256]; 508 int eval; 509 struct val *v; 510 511 /* coerce to both arguments to strings */ 512 to_string(a); 513 to_string(b); 514 515 /* compile regular expression */ 516 if ((eval = regcomp (&rp, b->u.s, 0)) != 0) { 517 regerror (eval, &rp, errbuf, sizeof(errbuf)); 518 errx (2, "%s", errbuf); 519 } 520 521 /* compare string against pattern */ 522 /* remember that patterns are anchored to the beginning of the line */ 523 if (regexec(&rp, a->u.s, 2, rm, 0) == 0 && rm[0].rm_so == 0) { 524 if (rm[1].rm_so >= 0) { 525 *(a->u.s + rm[1].rm_eo) = '\0'; 526 v = make_str (a->u.s + rm[1].rm_so); 527 528 } else { 529 v = make_integer (rm[0].rm_eo - rm[0].rm_so); 530 } 531 } else { 532 if (rp.re_nsub == 0) { 533 v = make_integer (0); 534 } else { 535 v = make_str (""); 536 } 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