1 /*- 2 * Copyright (c) 2015 Netflix Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer, 10 * in this position and unchanged. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 #include <sys/types.h> 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <unistd.h> 32 #include <string.h> 33 #include <strings.h> 34 #include <ctype.h> 35 #include "eval_expr.h" 36 __FBSDID("$FreeBSD$"); 37 38 static struct expression * 39 alloc_and_hook_expr(struct expression **exp_p, struct expression **last_p) 40 { 41 struct expression *ex, *at; 42 43 ex = malloc(sizeof(struct expression)); 44 if (ex == NULL) { 45 printf("Out of memory in exp allocation\n"); 46 exit(-2); 47 } 48 memset(ex, 0, sizeof(struct expression)); 49 if (*exp_p == NULL) { 50 *exp_p = ex; 51 } 52 at = *last_p; 53 if (at == NULL) { 54 /* First one, its last */ 55 *last_p = ex; 56 } else { 57 /* Chain it to the end and update last */ 58 at->next = ex; 59 ex->prev = at; 60 *last_p = ex; 61 } 62 return (ex); 63 } 64 65 66 static int 67 validate_expr(struct expression *exp, int val1_is_set, int op_is_set, int val2_is_set, 68 int *op_cnt) 69 { 70 int val1, op, val2; 71 int open_cnt; 72 val1 = op = val2 = 0; 73 if (val1_is_set) { 74 val1 = 1; 75 } 76 if (op_is_set) { 77 op = 1; 78 } 79 if (val2_is_set) { 80 val2 = 1; 81 } 82 open_cnt = *op_cnt; 83 if (exp == NULL) { 84 /* End of the road */ 85 if (val1 && op && val2 && (open_cnt == 0)) { 86 return(0); 87 } else { 88 return(1); 89 } 90 } 91 switch(exp->type) { 92 case TYPE_OP_PLUS: 93 case TYPE_OP_MINUS: 94 case TYPE_OP_MULT: 95 case TYPE_OP_DIVIDE: 96 if (val1 && op && val2) { 97 /* We are at x + y + 98 * collapse back to val/op 99 */ 100 val1 = 1; 101 op = 1; 102 val2 = 0; 103 } else if ((op == 0) && (val1)) { 104 op = 1; 105 } else { 106 printf("Op but no val1 set\n"); 107 return(-1); 108 } 109 break; 110 case TYPE_PARN_OPEN: 111 if (exp->next == NULL) { 112 printf("NULL after open paren\n"); 113 exit(-1); 114 } 115 if ((exp->next->type == TYPE_OP_PLUS) || 116 (exp->next->type == TYPE_OP_MINUS) || 117 (exp->next->type == TYPE_OP_DIVIDE) || 118 (exp->next->type == TYPE_OP_MULT)) { 119 printf("'( OP' -- not allowed\n"); 120 return(-1); 121 } 122 if (val1 && (op == 0)) { 123 printf("'Val (' -- not allowed\n"); 124 return(-1); 125 } 126 if (val1 && op && val2) { 127 printf("'Val OP Val (' -- not allowed\n"); 128 return(-1); 129 } 130 open_cnt++; 131 *op_cnt = open_cnt; 132 if (val1) { 133 if (validate_expr(exp->next, 0, 0, 0, op_cnt) == 0) { 134 val2 = 1; 135 } else { 136 return(-1); 137 } 138 } else { 139 return(validate_expr(exp->next, 0, 0, 0, op_cnt)); 140 } 141 break; 142 case TYPE_PARN_CLOSE: 143 open_cnt--; 144 *op_cnt = open_cnt; 145 if (val1 && op && val2) { 146 return(0); 147 } else { 148 printf("Found close paren and not complete\n"); 149 return(-1); 150 } 151 break; 152 case TYPE_VALUE_CON: 153 case TYPE_VALUE_PMC: 154 if (val1 == 0) { 155 val1 = 1; 156 } else if (val1 && op) { 157 val2 = 1; 158 } else { 159 printf("val1 set, val2 about to be set op empty\n"); 160 return(-1); 161 } 162 break; 163 default: 164 printf("unknown type %d\n", exp->type); 165 exit(-5); 166 break; 167 } 168 return(validate_expr(exp->next, val1, op, val2, op_cnt)); 169 } 170 171 void 172 print_exp(struct expression *exp) 173 { 174 if (exp == NULL) { 175 printf("\n"); 176 return; 177 } 178 switch(exp->type) { 179 case TYPE_OP_PLUS: 180 printf(" + "); 181 break; 182 case TYPE_OP_MINUS: 183 printf(" - "); 184 break; 185 case TYPE_OP_MULT: 186 printf(" * "); 187 break; 188 case TYPE_OP_DIVIDE: 189 printf(" / "); 190 break; 191 case TYPE_PARN_OPEN: 192 printf(" ( "); 193 break; 194 case TYPE_PARN_CLOSE: 195 printf(" ) "); 196 break; 197 case TYPE_VALUE_CON: 198 printf("%f", exp->value); 199 break; 200 case TYPE_VALUE_PMC: 201 printf("%s", exp->name); 202 break; 203 default: 204 printf("Unknown op %d\n", exp->type); 205 break; 206 } 207 print_exp(exp->next); 208 } 209 210 static void 211 walk_back_and_insert_paren(struct expression **beg, struct expression *frm) 212 { 213 struct expression *at, *ex; 214 215 /* Setup our new open paren */ 216 ex = malloc(sizeof(struct expression)); 217 if (ex == NULL) { 218 printf("Out of memory in exp allocation\n"); 219 exit(-2); 220 } 221 memset(ex, 0, sizeof(struct expression)); 222 ex->type = TYPE_PARN_OPEN; 223 /* Now lets place it */ 224 at = frm->prev; 225 if (at == *beg) { 226 /* We are inserting at the head of the list */ 227 in_beg: 228 ex->next = at; 229 at->prev = ex; 230 *beg = ex; 231 return; 232 } else if ((at->type == TYPE_VALUE_CON) || 233 (at->type == TYPE_VALUE_PMC)) { 234 /* Simple case we have a value in the previous position */ 235 in_mid: 236 ex->prev = at->prev; 237 ex->prev->next = ex; 238 ex->next = at; 239 at->prev = ex; 240 return; 241 } else if (at->type == TYPE_PARN_CLOSE) { 242 /* Skip through until we reach beg or all ( closes */ 243 int par_cnt=1; 244 245 at = at->prev; 246 while(par_cnt) { 247 if (at->type == TYPE_PARN_CLOSE) { 248 par_cnt++; 249 } else if (at->type == TYPE_PARN_OPEN) { 250 par_cnt--; 251 if (par_cnt == 0) { 252 break; 253 } 254 } 255 at = at->prev; 256 } 257 if (at == *beg) { 258 /* At beginning we insert */ 259 goto in_beg; 260 } else { 261 goto in_mid; 262 } 263 } else { 264 printf("%s:Unexpected type:%d?\n", 265 __FUNCTION__, at->type); 266 exit(-1); 267 } 268 } 269 270 static void 271 walk_fwd_and_insert_paren(struct expression *frm, struct expression **added) 272 { 273 struct expression *at, *ex; 274 /* Setup our new close paren */ 275 ex = malloc(sizeof(struct expression)); 276 if (ex == NULL) { 277 printf("Out of memory in exp allocation\n"); 278 exit(-2); 279 } 280 memset(ex, 0, sizeof(struct expression)); 281 ex->type = TYPE_PARN_CLOSE; 282 *added = ex; 283 /* Now lets place it */ 284 at = frm->next; 285 if ((at->type == TYPE_VALUE_CON) || 286 (at->type == TYPE_VALUE_PMC)) { 287 /* Simple case we have a value in the previous position */ 288 insertit: 289 ex->next = at->next; 290 ex->prev = at; 291 at->next = ex; 292 return; 293 } else if (at->type == TYPE_PARN_OPEN) { 294 int par_cnt=1; 295 at = at->next; 296 while(par_cnt) { 297 if (at->type == TYPE_PARN_OPEN) { 298 par_cnt++; 299 } else if (at->type == TYPE_PARN_CLOSE) { 300 par_cnt--; 301 if (par_cnt == 0) { 302 break; 303 } 304 } 305 at = at->next; 306 } 307 goto insertit; 308 } else { 309 printf("%s:Unexpected type:%d?\n", 310 __FUNCTION__, 311 at->type); 312 exit(-1); 313 } 314 } 315 316 317 static void 318 add_precendence(struct expression **beg, struct expression *start, struct expression *end) 319 { 320 /* 321 * Between start and end add () around any * or /. This 322 * is quite tricky since if there is a () set inside the 323 * list we need to skip over everything in the ()'s considering 324 * that just a value. 325 */ 326 struct expression *at, *newone; 327 int open_cnt; 328 329 at = start; 330 open_cnt = 0; 331 while(at != end) { 332 if (at->type == TYPE_PARN_OPEN) { 333 open_cnt++; 334 } 335 if (at->type == TYPE_PARN_CLOSE) { 336 open_cnt--; 337 } 338 if (open_cnt == 0) { 339 if ((at->type == TYPE_OP_MULT) || 340 (at->type == TYPE_OP_DIVIDE)) { 341 walk_back_and_insert_paren(beg, at); 342 walk_fwd_and_insert_paren(at, &newone); 343 at = newone->next; 344 continue; 345 } 346 } 347 at = at->next; 348 } 349 350 } 351 352 static void 353 set_math_precidence(struct expression **beg, struct expression *exp, struct expression **stopped) 354 { 355 struct expression *at, *start, *end; 356 int cnt_lower, cnt_upper; 357 /* 358 * Walk through and set any math precedence to 359 * get proper precedence we insert () around * / over + - 360 */ 361 end = NULL; 362 start = at = exp; 363 cnt_lower = cnt_upper = 0; 364 while(at) { 365 if (at->type == TYPE_PARN_CLOSE) { 366 /* Done with that paren */ 367 if (stopped) { 368 *stopped = at; 369 } 370 if (cnt_lower && cnt_upper) { 371 /* We have a mixed set ... add precedence between start/end */ 372 add_precendence(beg, start, end); 373 } 374 return; 375 } 376 if (at->type == TYPE_PARN_OPEN) { 377 set_math_precidence(beg, at->next, &end); 378 at = end; 379 continue; 380 } else if ((at->type == TYPE_OP_PLUS) || 381 (at->type == TYPE_OP_MINUS)) { 382 cnt_lower++; 383 } else if ((at->type == TYPE_OP_DIVIDE) || 384 (at->type == TYPE_OP_MULT)) { 385 cnt_upper++; 386 } 387 at = at->next; 388 } 389 if (cnt_lower && cnt_upper) { 390 add_precendence(beg, start, NULL); 391 } 392 } 393 394 extern char **valid_pmcs; 395 extern int valid_pmc_cnt; 396 397 static void 398 pmc_name_set(struct expression *at) 399 { 400 int i, idx, fnd; 401 402 if (at->name[0] == '%') { 403 /* Special number after $ gives index */ 404 idx = strtol(&at->name[1], NULL, 0); 405 if (idx >= valid_pmc_cnt) { 406 printf("Unknown PMC %s -- largest we have is $%d -- can't run your expression\n", 407 at->name, valid_pmc_cnt); 408 exit(-1); 409 } 410 strcpy(at->name, valid_pmcs[idx]); 411 } else { 412 for(i=0, fnd=0; i<valid_pmc_cnt; i++) { 413 if (strcmp(valid_pmcs[i], at->name) == 0) { 414 fnd = 1; 415 break; 416 } 417 } 418 if (!fnd) { 419 printf("PMC %s does not exist on this machine -- can't run your expression\n", 420 at->name); 421 exit(-1); 422 } 423 } 424 } 425 426 struct expression * 427 parse_expression(char *str) 428 { 429 struct expression *exp=NULL, *last=NULL, *at; 430 int open_par, close_par; 431 int op_cnt=0; 432 size_t siz, i, x; 433 /* 434 * Walk through a string expression and convert 435 * it to a linked list of actions. We do this by: 436 * a) Counting the open/close paren's, there must 437 * be a matching number. 438 * b) If we have balanced paren's then create a linked list 439 * of the operators, then we validate that expression further. 440 * c) Validating that we have: 441 * val OP val <or> 442 * val OP ( <and> 443 * inside every paran you have a: 444 * val OP val <or> 445 * val OP ( <recursively> 446 * d) A final optional step (not implemented yet) would be 447 * to insert the mathimatical precedence paran's. For 448 * the start we will just do the left to right evaluation and 449 * then later we can add this guy to add paran's to make it 450 * mathimatically correct... i.e instead of 1 + 2 * 3 we 451 * would translate it into 1 + ( 2 * 3). 452 */ 453 open_par = close_par = 0; 454 siz = strlen(str); 455 /* No trailing newline please */ 456 if (str[(siz-1)] == '\n') { 457 str[(siz-1)] = 0; 458 siz--; 459 } 460 for(i=0; i<siz; i++) { 461 if (str[i] == '(') { 462 open_par++; 463 } else if (str[i] == ')') { 464 close_par++; 465 } 466 } 467 if (open_par != close_par) { 468 printf("Invalid expression '%s' %d open paren's and %d close?\n", 469 str, open_par, close_par); 470 exit(-1); 471 } 472 for(i=0; i<siz; i++) { 473 if (str[i] == '(') { 474 at = alloc_and_hook_expr(&exp, &last); 475 at->type = TYPE_PARN_OPEN; 476 } else if (str[i] == ')') { 477 at = alloc_and_hook_expr(&exp, &last); 478 at->type = TYPE_PARN_CLOSE; 479 } else if (str[i] == ' ') { 480 /* Extra blank */ 481 continue; 482 } else if (str[i] == '\t') { 483 /* Extra tab */ 484 continue; 485 } else if (str[i] == '+') { 486 at = alloc_and_hook_expr(&exp, &last); 487 at->type = TYPE_OP_PLUS; 488 } else if (str[i] == '-') { 489 at = alloc_and_hook_expr(&exp, &last); 490 at->type = TYPE_OP_MINUS; 491 } else if (str[i] == '/') { 492 at = alloc_and_hook_expr(&exp, &last); 493 at->type = TYPE_OP_DIVIDE; 494 } else if (str[i] == '*') { 495 at = alloc_and_hook_expr(&exp, &last); 496 at->type = TYPE_OP_MULT; 497 } else { 498 /* Its a value or PMC constant */ 499 at = alloc_and_hook_expr(&exp, &last); 500 if (isdigit(str[i]) || (str[i] == '.')) { 501 at->type = TYPE_VALUE_CON; 502 } else { 503 at->type = TYPE_VALUE_PMC; 504 } 505 x = 0; 506 while ((str[i] != ' ') && 507 (str[i] != '\t') && 508 (str[i] != 0) && 509 (str[i] != ')') && 510 (str[i] != '(')) { 511 /* We collect the constant until a space or tab */ 512 at->name[x] = str[i]; 513 i++; 514 x++; 515 if (x >=(sizeof(at->name)-1)) { 516 printf("Value/Constant too long %d max:%d\n", 517 (int)x, (int)(sizeof(at->name)-1)); 518 exit(-3); 519 } 520 } 521 if (str[i] != 0) { 522 /* Need to back up and see the last char since 523 * the for will increment the loop. 524 */ 525 i--; 526 } 527 /* Now we have pulled the string, set it up */ 528 if (at->type == TYPE_VALUE_CON) { 529 at->state = STATE_FILLED; 530 at->value = strtod(at->name, NULL); 531 } else { 532 pmc_name_set(at); 533 } 534 } 535 } 536 /* Now lets validate its a workable expression */ 537 if (validate_expr(exp, 0, 0, 0, &op_cnt)) { 538 printf("Invalid expression\n"); 539 exit(-4); 540 } 541 set_math_precidence(&exp, exp, NULL); 542 return (exp); 543 } 544 545 546 547 static struct expression * 548 gather_exp_to_paren_close(struct expression *exp, double *val_fill) 549 { 550 /* 551 * I have been given ( ??? 552 * so I could see either 553 * ( 554 * or 555 * Val Op 556 * 557 */ 558 struct expression *lastproc; 559 double val; 560 561 if (exp->type == TYPE_PARN_OPEN) { 562 lastproc = gather_exp_to_paren_close(exp->next, &val); 563 *val_fill = val; 564 } else { 565 *val_fill = run_expr(exp, 0, &lastproc); 566 } 567 return(lastproc); 568 } 569 570 571 double 572 run_expr(struct expression *exp, int initial_call, struct expression **lastone) 573 { 574 /* 575 * We expect to find either 576 * a) A Open Paren 577 * or 578 * b) Val-> Op -> Val 579 * or 580 * c) Val-> Op -> Open Paren 581 */ 582 double val1, val2, res; 583 struct expression *op, *other_half, *rest; 584 585 if (exp->type == TYPE_PARN_OPEN) { 586 op = gather_exp_to_paren_close(exp->next, &val1); 587 } else if(exp->type == TYPE_VALUE_CON) { 588 val1 = exp->value; 589 op = exp->next; 590 } else if (exp->type == TYPE_VALUE_PMC) { 591 val1 = exp->value; 592 op = exp->next; 593 } else { 594 printf("Illegal value in %s huh?\n", __FUNCTION__); 595 exit(-1); 596 } 597 if (op == NULL) { 598 return (val1); 599 } 600 more_to_do: 601 other_half = op->next; 602 if (other_half->type == TYPE_PARN_OPEN) { 603 rest = gather_exp_to_paren_close(other_half->next, &val2); 604 } else if(other_half->type == TYPE_VALUE_CON) { 605 val2 = other_half->value; 606 rest = other_half->next; 607 } else if (other_half->type == TYPE_VALUE_PMC) { 608 val2 = other_half->value; 609 rest = other_half->next; 610 } else { 611 printf("Illegal2 value in %s huh?\n", __FUNCTION__); 612 exit(-1); 613 } 614 switch(op->type) { 615 case TYPE_OP_PLUS: 616 res = val1 + val2; 617 break; 618 case TYPE_OP_MINUS: 619 res = val1 - val2; 620 break; 621 case TYPE_OP_MULT: 622 res = val1 * val2; 623 break; 624 case TYPE_OP_DIVIDE: 625 if (val2 != 0.0) 626 res = val1 / val2; 627 else { 628 printf("Division by zero averted\n"); 629 res = 1.0; 630 } 631 break; 632 default: 633 printf("Op is not an operator -- its %d\n", 634 op->type); 635 exit(-1); 636 break; 637 } 638 if (rest == NULL) { 639 if (lastone) { 640 *lastone = NULL; 641 } 642 return (res); 643 } 644 if ((rest->type == TYPE_PARN_CLOSE) && (initial_call == 0)) { 645 if (lastone) { 646 *lastone = rest->next; 647 } 648 return(res); 649 } 650 /* There is more, as in 651 * a + b + c 652 * where we just did a + b 653 * so now it becomes val1 is set to res and 654 * we need to proceed with the rest of it. 655 */ 656 val1 = res; 657 op = rest; 658 if ((op->type != TYPE_OP_PLUS) && 659 (op->type != TYPE_OP_MULT) && 660 (op->type != TYPE_OP_MINUS) && 661 (op->type != TYPE_OP_DIVIDE)) { 662 printf("%s ending on type:%d not an op??\n", __FUNCTION__, op->type); 663 return(res); 664 } 665 if (op) 666 goto more_to_do; 667 return (res); 668 } 669 670 #ifdef STAND_ALONE_TESTING 671 672 static double 673 calc_expr(struct expression *exp) 674 { 675 struct expression *at; 676 double xx; 677 678 /* First clear PMC's setting */ 679 for(at = exp; at != NULL; at = at->next) { 680 if (at->type == TYPE_VALUE_PMC) { 681 at->state = STATE_UNSET; 682 } 683 } 684 /* Now for all pmc's make up values .. here is where I would pull them */ 685 for(at = exp; at != NULL; at = at->next) { 686 if (at->type == TYPE_VALUE_PMC) { 687 at->value = (random() * 1.0); 688 at->state = STATE_FILLED; 689 if (at->value == 0.0) { 690 /* So we don't have div by 0 */ 691 at->value = 1.0; 692 } 693 } 694 } 695 /* Now lets calculate the expression */ 696 print_exp(exp); 697 xx = run_expr(exp, 1, NULL); 698 printf("Answer is %f\n", xx); 699 return(xx); 700 } 701 702 703 int 704 main(int argc, char **argv) 705 { 706 struct expression *exp; 707 if (argc < 2) { 708 printf("Use %s expression\n", argv[0]); 709 return(-1); 710 } 711 exp = parse_expression(argv[1]); 712 printf("Now the calc\n"); 713 calc_expr(exp); 714 return(0); 715 } 716 717 #endif 718