1185377Ssam/*- 2187831Ssam * Copyright (c) 2015 Netflix Inc. 3185377Ssam * All rights reserved. 4185377Ssam * 5185377Ssam * Redistribution and use in source and binary forms, with or without 6185377Ssam * modification, are permitted provided that the following conditions 7185377Ssam * are met: 8185377Ssam * 1. Redistributions of source code must retain the above copyright 9185377Ssam * notice, this list of conditions and the following disclaimer, 10185377Ssam * in this position and unchanged. 11185377Ssam * 2. Redistributions in binary form must reproduce the above copyright 12185377Ssam * notice, this list of conditions and the following disclaimer in the 13185377Ssam * documentation and/or other materials provided with the distribution. 14185377Ssam * 3. The name of the author may not be used to endorse or promote products 15185377Ssam * derived from this software without specific prior written permission 16185377Ssam * 17187831Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18185377Ssam * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19185377Ssam * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20185377Ssam * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21185377Ssam * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22185377Ssam * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23185377Ssam * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24185377Ssam * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25185377Ssam * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26185377Ssam * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27185377Ssam */ 28185377Ssam#include <sys/types.h> 29185377Ssam#include <stdio.h> 30185377Ssam#include <stdlib.h> 31185377Ssam#include <unistd.h> 32185377Ssam#include <string.h> 33185377Ssam#include <strings.h> 34185377Ssam#include <ctype.h> 35185377Ssam#include "eval_expr.h" 36185377Ssam__FBSDID("$FreeBSD$"); 37185377Ssam 38185377Ssamstatic struct expression * 39185377Ssamalloc_and_hook_expr(struct expression **exp_p, struct expression **last_p) 40185377Ssam{ 41185377Ssam struct expression *ex, *at; 42185377Ssam 43185377Ssam ex = malloc(sizeof(struct expression)); 44185377Ssam if (ex == NULL) { 45185377Ssam printf("Out of memory in exp allocation\n"); 46185377Ssam exit(-2); 47185377Ssam } 48185377Ssam memset(ex, 0, sizeof(struct expression)); 49185377Ssam if (*exp_p == NULL) { 50185377Ssam *exp_p = ex; 51185377Ssam } 52185377Ssam at = *last_p; 53185377Ssam if (at == NULL) { 54185377Ssam /* First one, its last */ 55185377Ssam *last_p = ex; 56185377Ssam } else { 57185377Ssam /* Chain it to the end and update last */ 58185377Ssam at->next = ex; 59185377Ssam ex->prev = at; 60185377Ssam *last_p = ex; 61185377Ssam } 62185377Ssam return (ex); 63185377Ssam} 64185377Ssam 65185377Ssam 66185377Ssamstatic int 67185377Ssamvalidate_expr(struct expression *exp, int val1_is_set, int op_is_set, int val2_is_set, 68185377Ssam int *op_cnt) 69185377Ssam{ 70185377Ssam int val1, op, val2; 71185377Ssam int open_cnt; 72185377Ssam val1 = op = val2 = 0; 73185377Ssam if (val1_is_set) { 74185377Ssam val1 = 1; 75185377Ssam } 76185377Ssam if (op_is_set) { 77185377Ssam op = 1; 78185377Ssam } 79185377Ssam if (val2_is_set) { 80185377Ssam val2 = 1; 81185377Ssam } 82185377Ssam open_cnt = *op_cnt; 83185377Ssam if (exp == NULL) { 84185377Ssam /* End of the road */ 85185377Ssam if (val1 && op && val2 && (open_cnt == 0)) { 86185377Ssam return(0); 87185377Ssam } else { 88185377Ssam return(1); 89185377Ssam } 90185377Ssam } 91185377Ssam switch(exp->type) { 92185377Ssam case TYPE_OP_PLUS: 93185377Ssam case TYPE_OP_MINUS: 94185377Ssam case TYPE_OP_MULT: 95185377Ssam case TYPE_OP_DIVIDE: 96185377Ssam if (val1 && op && val2) { 97185377Ssam /* We are at x + y + 98185377Ssam * collapse back to val/op 99185377Ssam */ 100185377Ssam val1 = 1; 101185377Ssam op = 1; 102185377Ssam val2 = 0; 103185377Ssam } else if ((op == 0) && (val1)) { 104185377Ssam op = 1; 105185377Ssam } else { 106185377Ssam printf("Op but no val1 set\n"); 107185377Ssam return(-1); 108185377Ssam } 109185377Ssam break; 110185377Ssam case TYPE_PARN_OPEN: 111185377Ssam if (exp->next == NULL) { 112185377Ssam printf("NULL after open paren\n"); 113185377Ssam exit(-1); 114185377Ssam } 115185377Ssam if ((exp->next->type == TYPE_OP_PLUS) || 116185377Ssam (exp->next->type == TYPE_OP_MINUS) || 117185377Ssam (exp->next->type == TYPE_OP_DIVIDE) || 118185377Ssam (exp->next->type == TYPE_OP_MULT)) { 119185377Ssam printf("'( OP' -- not allowed\n"); 120185377Ssam return(-1); 121185377Ssam } 122185377Ssam if (val1 && (op == 0)) { 123185377Ssam printf("'Val (' -- not allowed\n"); 124185377Ssam return(-1); 125185377Ssam } 126185377Ssam if (val1 && op && val2) { 127185377Ssam printf("'Val OP Val (' -- not allowed\n"); 128185377Ssam return(-1); 129185377Ssam } 130185377Ssam open_cnt++; 131185377Ssam *op_cnt = open_cnt; 132185377Ssam if (val1) { 133185377Ssam if (validate_expr(exp->next, 0, 0, 0, op_cnt) == 0) { 134185377Ssam val2 = 1; 135187831Ssam } else { 136185377Ssam return(-1); 137187831Ssam } 138187831Ssam } else { 139185377Ssam return(validate_expr(exp->next, 0, 0, 0, op_cnt)); 140187831Ssam } 141185377Ssam break; 142185377Ssam case TYPE_PARN_CLOSE: 143185377Ssam open_cnt--; 144187831Ssam *op_cnt = open_cnt; 145187831Ssam if (val1 && op && val2) { 146187831Ssam return(0); 147185377Ssam } else { 148185377Ssam printf("Found close paren and not complete\n"); 149185377Ssam return(-1); 150185377Ssam } 151185377Ssam break; 152185377Ssam case TYPE_VALUE_CON: 153185377Ssam case TYPE_VALUE_PMC: 154185377Ssam if (val1 == 0) { 155185377Ssam val1 = 1; 156185377Ssam } else if (val1 && op) { 157185377Ssam val2 = 1; 158185377Ssam } else { 159185377Ssam printf("val1 set, val2 about to be set op empty\n"); 160185377Ssam return(-1); 161185377Ssam } 162185377Ssam break; 163185377Ssam default: 164185377Ssam printf("unknown type %d\n", exp->type); 165185377Ssam exit(-5); 166185377Ssam break; 167185377Ssam } 168185377Ssam return(validate_expr(exp->next, val1, op, val2, op_cnt)); 169185377Ssam} 170185377Ssam 171185377Ssamvoid 172185377Ssamprint_exp(struct expression *exp) 173185377Ssam{ 174185377Ssam if (exp == NULL) { 175185377Ssam printf("\n"); 176185377Ssam return; 177185377Ssam } 178185377Ssam switch(exp->type) { 179185377Ssam case TYPE_OP_PLUS: 180185377Ssam printf(" + "); 181185377Ssam break; 182185377Ssam case TYPE_OP_MINUS: 183185377Ssam printf(" - "); 184185377Ssam break; 185185377Ssam case TYPE_OP_MULT: 186185377Ssam printf(" * "); 187185377Ssam break; 188185377Ssam case TYPE_OP_DIVIDE: 189185377Ssam printf(" / "); 190185377Ssam break; 191185377Ssam case TYPE_PARN_OPEN: 192185377Ssam printf(" ( "); 193185377Ssam break; 194185377Ssam case TYPE_PARN_CLOSE: 195185377Ssam printf(" ) "); 196185377Ssam break; 197185377Ssam case TYPE_VALUE_CON: 198185377Ssam printf("%f", exp->value); 199185377Ssam break; 200185377Ssam case TYPE_VALUE_PMC: 201185377Ssam printf("%s", exp->name); 202185377Ssam break; 203185377Ssam default: 204185377Ssam printf("Unknown op %d\n", exp->type); 205185377Ssam break; 206185377Ssam } 207185377Ssam print_exp(exp->next); 208185377Ssam} 209185377Ssam 210185377Ssamstatic void 211185377Ssamwalk_back_and_insert_paren(struct expression **beg, struct expression *frm) 212185377Ssam{ 213185377Ssam struct expression *at, *ex; 214185377Ssam 215185377Ssam /* Setup our new open paren */ 216185377Ssam ex = malloc(sizeof(struct expression)); 217185377Ssam if (ex == NULL) { 218185377Ssam printf("Out of memory in exp allocation\n"); 219185377Ssam exit(-2); 220185377Ssam } 221185377Ssam memset(ex, 0, sizeof(struct expression)); 222185377Ssam ex->type = TYPE_PARN_OPEN; 223185377Ssam /* Now lets place it */ 224185377Ssam at = frm->prev; 225185377Ssam if (at == *beg) { 226185377Ssam /* We are inserting at the head of the list */ 227185377Ssam in_beg: 228185377Ssam ex->next = at; 229185377Ssam at->prev = ex; 230185377Ssam *beg = ex; 231185377Ssam return; 232185377Ssam } else if ((at->type == TYPE_VALUE_CON) || 233185377Ssam (at->type == TYPE_VALUE_PMC)) { 234185377Ssam /* Simple case we have a value in the previous position */ 235185377Ssam in_mid: 236185377Ssam ex->prev = at->prev; 237185377Ssam ex->prev->next = ex; 238185377Ssam ex->next = at; 239185377Ssam at->prev = ex; 240185377Ssam return; 241185377Ssam } else if (at->type == TYPE_PARN_CLOSE) { 242185377Ssam /* Skip through until we reach beg or all ( closes */ 243185377Ssam int par_cnt=1; 244185377Ssam 245185377Ssam at = at->prev; 246185377Ssam while(par_cnt) { 247185377Ssam if (at->type == TYPE_PARN_CLOSE) { 248185377Ssam par_cnt++; 249185377Ssam } else if (at->type == TYPE_PARN_OPEN) { 250185377Ssam par_cnt--; 251185377Ssam if (par_cnt == 0) { 252185377Ssam break; 253185377Ssam } 254185377Ssam } 255226760Sadrian at = at->prev; 256185377Ssam } 257185377Ssam if (at == *beg) { 258185377Ssam /* At beginning we insert */ 259185377Ssam goto in_beg; 260185377Ssam } else { 261185377Ssam goto in_mid; 262185377Ssam } 263185377Ssam } else { 264185377Ssam printf("%s:Unexpected type:%d?\n", 265185377Ssam __FUNCTION__, at->type); 266185377Ssam exit(-1); 267185377Ssam } 268185377Ssam} 269185377Ssam 270185380Ssamstatic void 271185377Ssamwalk_fwd_and_insert_paren(struct expression *frm, struct expression **added) 272185380Ssam{ 273185377Ssam struct expression *at, *ex; 274185380Ssam /* Setup our new close paren */ 275185380Ssam ex = malloc(sizeof(struct expression)); 276185377Ssam if (ex == NULL) { 277185377Ssam printf("Out of memory in exp allocation\n"); 278185377Ssam exit(-2); 279185377Ssam } 280185377Ssam memset(ex, 0, sizeof(struct expression)); 281185377Ssam ex->type = TYPE_PARN_CLOSE; 282185377Ssam *added = ex; 283185377Ssam /* Now lets place it */ 284185377Ssam at = frm->next; 285185377Ssam if ((at->type == TYPE_VALUE_CON) || 286185377Ssam (at->type == TYPE_VALUE_PMC)) { 287185377Ssam /* Simple case we have a value in the previous position */ 288185380Ssam insertit: 289185380Ssam ex->next = at->next; 290185377Ssam ex->prev = at; 291185377Ssam at->next = ex; 292185377Ssam return; 293185377Ssam } else if (at->type == TYPE_PARN_OPEN) { 294185377Ssam int par_cnt=1; 295185377Ssam at = at->next; 296185377Ssam while(par_cnt) { 297185377Ssam if (at->type == TYPE_PARN_OPEN) { 298185377Ssam par_cnt++; 299185377Ssam } else if (at->type == TYPE_PARN_CLOSE) { 300185377Ssam par_cnt--; 301185377Ssam if (par_cnt == 0) { 302185377Ssam break; 303185377Ssam } 304185377Ssam } 305185377Ssam at = at->next; 306185377Ssam } 307185377Ssam goto insertit; 308185377Ssam } else { 309185377Ssam printf("%s:Unexpected type:%d?\n", 310185377Ssam __FUNCTION__, 311185377Ssam at->type); 312185377Ssam exit(-1); 313185377Ssam } 314185377Ssam} 315185377Ssam 316185377Ssam 317185377Ssamstatic void 318185377Ssamadd_precendence(struct expression **beg, struct expression *start, struct expression *end) 319185377Ssam{ 320185377Ssam /* 321185377Ssam * Between start and end add () around any * or /. This 322187831Ssam * is quite tricky since if there is a () set inside the 323234774Sadrian * list we need to skip over everything in the ()'s considering 324185377Ssam * that just a value. 325222265Sadrian */ 326222265Sadrian struct expression *at, *newone; 327222265Sadrian int open_cnt; 328185377Ssam 329185377Ssam at = start; 330185377Ssam open_cnt = 0; 331185377Ssam while(at != end) { 332185377Ssam if (at->type == TYPE_PARN_OPEN) { 333185377Ssam open_cnt++; 334218012Sadrian } 335204579Srpaulo if (at->type == TYPE_PARN_CLOSE) { 336204579Srpaulo open_cnt--; 337204579Srpaulo } 338185377Ssam if (open_cnt == 0) { 339185377Ssam if ((at->type == TYPE_OP_MULT) || 340185377Ssam (at->type == TYPE_OP_DIVIDE)) { 341185380Ssam walk_back_and_insert_paren(beg, at); 342185380Ssam walk_fwd_and_insert_paren(at, &newone); 343185380Ssam at = newone->next; 344185380Ssam continue; 345185380Ssam } 346185380Ssam } 347185380Ssam at = at->next; 348185377Ssam } 349185377Ssam 350185377Ssam} 351185377Ssam 352185377Ssamstatic void 353185377Ssamset_math_precidence(struct expression **beg, struct expression *exp, struct expression **stopped) 354185377Ssam{ 355185377Ssam struct expression *at, *start, *end; 356185377Ssam int cnt_lower, cnt_upper; 357185377Ssam /* 358185377Ssam * Walk through and set any math precedence to 359185377Ssam * get proper precedence we insert () around * / over + - 360185377Ssam */ 361185377Ssam end = NULL; 362185377Ssam start = at = exp; 363185377Ssam cnt_lower = cnt_upper = 0; 364185377Ssam while(at) { 365185377Ssam if (at->type == TYPE_PARN_CLOSE) { 366185377Ssam /* Done with that paren */ 367185380Ssam if (stopped) { 368185380Ssam *stopped = at; 369185380Ssam } 370185380Ssam if (cnt_lower && cnt_upper) { 371185380Ssam /* We have a mixed set ... add precedence between start/end */ 372185380Ssam add_precendence(beg, start, end); 373185380Ssam } 374185380Ssam return; 375185380Ssam } 376185380Ssam if (at->type == TYPE_PARN_OPEN) { 377185380Ssam set_math_precidence(beg, at->next, &end); 378185380Ssam at = end; 379185380Ssam continue; 380185380Ssam } else if ((at->type == TYPE_OP_PLUS) || 381185380Ssam (at->type == TYPE_OP_MINUS)) { 382185380Ssam cnt_lower++; 383185380Ssam } else if ((at->type == TYPE_OP_DIVIDE) || 384185380Ssam (at->type == TYPE_OP_MULT)) { 385185380Ssam cnt_upper++; 386185380Ssam } 387185380Ssam at = at->next; 388185380Ssam } 389185380Ssam if (cnt_lower && cnt_upper) { 390185377Ssam add_precendence(beg, start, NULL); 391185377Ssam } 392185377Ssam} 393185377Ssam 394185377Ssamextern char **valid_pmcs; 395185377Ssamextern int valid_pmc_cnt; 396185377Ssam 397185377Ssamstatic void 398185377Ssampmc_name_set(struct expression *at) 399185377Ssam{ 400185377Ssam int i, idx, fnd; 401185377Ssam 402185377Ssam if (at->name[0] == '%') { 403187831Ssam /* Special number after $ gives index */ 404187831Ssam idx = strtol(&at->name[1], NULL, 0); 405187831Ssam if (idx >= valid_pmc_cnt) { 406185377Ssam printf("Unknown PMC %s -- largest we have is $%d -- can't run your expression\n", 407188012Ssam at->name, valid_pmc_cnt); 408188012Ssam exit(-1); 409185377Ssam } 410185377Ssam strcpy(at->name, valid_pmcs[idx]); 411188012Ssam } else { 412187831Ssam for(i=0, fnd=0; i<valid_pmc_cnt; i++) { 413187831Ssam if (strcmp(valid_pmcs[i], at->name) == 0) { 414185377Ssam fnd = 1; 415185377Ssam break; 416185377Ssam } 417185377Ssam } 418185377Ssam if (!fnd) { 419185377Ssam printf("PMC %s does not exist on this machine -- can't run your expression\n", 420185377Ssam at->name); 421185377Ssam exit(-1); 422185377Ssam } 423185377Ssam } 424185377Ssam} 425185377Ssam 426185377Ssamstruct expression * 427185377Ssamparse_expression(char *str) 428185377Ssam{ 429185377Ssam struct expression *exp=NULL, *last=NULL, *at; 430185377Ssam int open_par, close_par; 431185377Ssam int op_cnt=0; 432185377Ssam size_t siz, i, x; 433185377Ssam /* 434185377Ssam * Walk through a string expression and convert 435225444Sadrian * it to a linked list of actions. We do this by: 436185377Ssam * a) Counting the open/close paren's, there must 437185377Ssam * be a matching number. 438185377Ssam * b) If we have balanced paren's then create a linked list 439185377Ssam * of the operators, then we validate that expression further. 440185377Ssam * c) Validating that we have: 441185377Ssam * val OP val <or> 442185377Ssam * val OP ( <and> 443185377Ssam * inside every paran you have a: 444185377Ssam * val OP val <or> 445185377Ssam * val OP ( <recursively> 446185377Ssam * d) A final optional step (not implemented yet) would be 447185377Ssam * to insert the mathematical precedence paran's. For 448185377Ssam * the start we will just do the left to right evaluation and 449185377Ssam * then later we can add this guy to add paran's to make it 450185377Ssam * mathimatically correct... i.e instead of 1 + 2 * 3 we 451185377Ssam * would translate it into 1 + ( 2 * 3). 452185377Ssam */ 453185377Ssam open_par = close_par = 0; 454185377Ssam siz = strlen(str); 455185377Ssam /* No trailing newline please */ 456185377Ssam if (str[(siz-1)] == '\n') { 457185377Ssam str[(siz-1)] = 0; 458185377Ssam siz--; 459185377Ssam } 460188974Ssam for(i=0; i<siz; i++) { 461188974Ssam if (str[i] == '(') { 462185377Ssam open_par++; 463185377Ssam } else if (str[i] == ')') { 464185377Ssam close_par++; 465185377Ssam } 466185377Ssam } 467185377Ssam if (open_par != close_par) { 468185377Ssam printf("Invalid expression '%s' %d open paren's and %d close?\n", 469185377Ssam str, open_par, close_par); 470185377Ssam exit(-1); 471219419Sadrian } 472185377Ssam for(i=0; i<siz; i++) { 473185377Ssam if (str[i] == '(') { 474185377Ssam at = alloc_and_hook_expr(&exp, &last); 475185377Ssam at->type = TYPE_PARN_OPEN; 476185377Ssam } else if (str[i] == ')') { 477185377Ssam at = alloc_and_hook_expr(&exp, &last); 478185377Ssam at->type = TYPE_PARN_CLOSE; 479185377Ssam } else if (str[i] == ' ') { 480185377Ssam /* Extra blank */ 481185377Ssam continue; 482185377Ssam } else if (str[i] == '\t') { 483185377Ssam /* Extra tab */ 484185377Ssam continue; 485185377Ssam } else if (str[i] == '+') { 486185377Ssam at = alloc_and_hook_expr(&exp, &last); 487185377Ssam at->type = TYPE_OP_PLUS; 488185377Ssam } else if (str[i] == '-') { 489185377Ssam at = alloc_and_hook_expr(&exp, &last); 490185377Ssam at->type = TYPE_OP_MINUS; 491185377Ssam } else if (str[i] == '/') { 492185377Ssam at = alloc_and_hook_expr(&exp, &last); 493185377Ssam at->type = TYPE_OP_DIVIDE; 494185377Ssam } else if (str[i] == '*') { 495185377Ssam at = alloc_and_hook_expr(&exp, &last); 496185377Ssam at->type = TYPE_OP_MULT; 497185377Ssam } else { 498185377Ssam /* Its a value or PMC constant */ 499185377Ssam at = alloc_and_hook_expr(&exp, &last); 500185377Ssam if (isdigit(str[i]) || (str[i] == '.')) { 501185377Ssam at->type = TYPE_VALUE_CON; 502185377Ssam } else { 503185377Ssam at->type = TYPE_VALUE_PMC; 504185377Ssam } 505185377Ssam x = 0; 506185377Ssam while ((str[i] != ' ') && 507185377Ssam (str[i] != '\t') && 508185377Ssam (str[i] != 0) && 509185377Ssam (str[i] != ')') && 510185377Ssam (str[i] != '(')) { 511185377Ssam /* We collect the constant until a space or tab */ 512222644Sadrian at->name[x] = str[i]; 513222644Sadrian i++; 514185377Ssam x++; 515185377Ssam if (x >=(sizeof(at->name)-1)) { 516185377Ssam printf("Value/Constant too long %d max:%d\n", 517185377Ssam (int)x, (int)(sizeof(at->name)-1)); 518185377Ssam exit(-3); 519185377Ssam } 520185377Ssam } 521185377Ssam if (str[i] != 0) { 522185377Ssam /* Need to back up and see the last char since 523185377Ssam * the for will increment the loop. 524185377Ssam */ 525185377Ssam i--; 526185377Ssam } 527185377Ssam /* Now we have pulled the string, set it up */ 528185377Ssam if (at->type == TYPE_VALUE_CON) { 529185377Ssam at->state = STATE_FILLED; 530185377Ssam at->value = strtod(at->name, NULL); 531185377Ssam } else { 532185377Ssam pmc_name_set(at); 533185377Ssam } 534185377Ssam } 535185377Ssam } 536185377Ssam /* Now lets validate its a workable expression */ 537185377Ssam if (validate_expr(exp, 0, 0, 0, &op_cnt)) { 538185377Ssam printf("Invalid expression\n"); 539187831Ssam exit(-4); 540187831Ssam } 541187831Ssam set_math_precidence(&exp, exp, NULL); 542187831Ssam return (exp); 543185377Ssam} 544185377Ssam 545185377Ssam 546187831Ssam 547187831Ssamstatic struct expression * 548187831Ssamgather_exp_to_paren_close(struct expression *exp, double *val_fill) 549187831Ssam{ 550187831Ssam /* 551187831Ssam * I have been given ( ??? 552187831Ssam * so I could see either 553187831Ssam * ( 554187831Ssam * or 555185377Ssam * Val Op 556185377Ssam * 557185377Ssam */ 558187831Ssam struct expression *lastproc; 559187831Ssam double val; 560185377Ssam 561187831Ssam if (exp->type == TYPE_PARN_OPEN) { 562185377Ssam lastproc = gather_exp_to_paren_close(exp->next, &val); 563185377Ssam *val_fill = val; 564187831Ssam } else { 565185377Ssam *val_fill = run_expr(exp, 0, &lastproc); 566185377Ssam } 567185380Ssam return(lastproc); 568185377Ssam} 569185377Ssam 570185377Ssam 571185377Ssamdouble 572185377Ssamrun_expr(struct expression *exp, int initial_call, struct expression **lastone) 573185377Ssam{ 574185377Ssam /* 575185377Ssam * We expect to find either 576185377Ssam * a) A Open Paren 577185377Ssam * or 578185377Ssam * b) Val-> Op -> Val 579185377Ssam * or 580185377Ssam * c) Val-> Op -> Open Paren 581185377Ssam */ 582185377Ssam double val1, val2, res; 583185377Ssam struct expression *op, *other_half, *rest; 584185377Ssam 585185377Ssam if (exp->type == TYPE_PARN_OPEN) { 586185377Ssam op = gather_exp_to_paren_close(exp->next, &val1); 587185377Ssam } else if(exp->type == TYPE_VALUE_CON) { 588185377Ssam val1 = exp->value; 589185377Ssam op = exp->next; 590185377Ssam } else if (exp->type == TYPE_VALUE_PMC) { 591185377Ssam val1 = exp->value; 592185377Ssam op = exp->next; 593185377Ssam } else { 594185377Ssam printf("Illegal value in %s huh?\n", __FUNCTION__); 595185377Ssam exit(-1); 596185377Ssam } 597185377Ssam if (op == NULL) { 598185377Ssam return (val1); 599185377Ssam } 600185377Ssammore_to_do: 601217621Sadrian other_half = op->next; 602217621Sadrian if (other_half->type == TYPE_PARN_OPEN) { 603185377Ssam rest = gather_exp_to_paren_close(other_half->next, &val2); 604185377Ssam } else if(other_half->type == TYPE_VALUE_CON) { 605185377Ssam val2 = other_half->value; 606185377Ssam rest = other_half->next; 607185377Ssam } else if (other_half->type == TYPE_VALUE_PMC) { 608185377Ssam val2 = other_half->value; 609185377Ssam rest = other_half->next; 610185377Ssam } else { 611185377Ssam printf("Illegal2 value in %s huh?\n", __FUNCTION__); 612185377Ssam exit(-1); 613185377Ssam } 614185377Ssam switch(op->type) { 615185377Ssam case TYPE_OP_PLUS: 616185377Ssam res = val1 + val2; 617185377Ssam break; 618217684Sadrian case TYPE_OP_MINUS: 619187831Ssam res = val1 - val2; 620217684Sadrian break; 621187831Ssam case TYPE_OP_MULT: 622185377Ssam res = val1 * val2; 623211206Sadrian break; 624211206Sadrian case TYPE_OP_DIVIDE: 625211206Sadrian if (val2 != 0.0) 626222584Sadrian res = val1 / val2; 627222584Sadrian else { 628222815Sadrian printf("Division by zero averted\n"); 629222815Sadrian res = 1.0; 630222815Sadrian } 631224709Sadrian break; 632230791Sadrian default: 633211206Sadrian printf("Op is not an operator -- its %d\n", 634185377Ssam 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 672static double 673calc_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 703int 704main(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