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