/* This file is part of exprparser, a lex/yacc based expression parser Copyright (C) 2002-6 Toby Thain, toby@telegraphics.com.au This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include "node.h" #include "y.tab.h" /* maintain a linked list of allocations, in case we have to non-recursively (i.e., not using the parse tree) undo them */ struct node *node_list; struct node *newnode(int k){ struct node *p ; NEW(p); p->kind = k; p->child[0] = p->child[1] = p->child[2] = NULL; /* add this new node to the list of allocated nodes */ p->next = node_list; node_list = p; // printf("ALLOC %#x\n",p); return p; } void freenodes(struct node *p){ /* undo recorded allocations */ if(p){ // printf("FREE %#x\n",p); freenodes(p->next); free(p); } } void freeallnodes(){ freenodes(node_list); node_list = 0; } /* pretty-print the tree */ void dumptree(struct node *t,int level){ int i; if(t){ for(i=level;i--;) putchar('\t'); switch(t->kind){ case TOK_NUM: printf("constant: %g\n", t->v.value); break; case TOK_VAR: printf("variable: %s (%g)\n", t->v.sym->name, *t->v.sym->pvar); break; case TOK_FN1: case TOK_FN2: case TOK_FN3: printf("function: %s\n", t->v.sym->name); break; default: printf("operator: %c\n", t->kind); } ++level; dumptree(t->child[0],level); dumptree(t->child[1],level); dumptree(t->child[2],level); } } /* evaluate the expression tree (using current values of variables) */ double eval(struct node *t){ if(t){ switch(t->kind){ case TOK_NUM: return t->v.value; case TOK_VAR: return *t->v.sym->pvar; case '+': return eval(t->child[0]) + eval(t->child[1]); case '-': return eval(t->child[0]) - eval(t->child[1]); case '*': return eval(t->child[0]) * eval(t->child[1]); case '/': return eval(t->child[0]) / eval(t->child[1]); case '^': return pow(eval(t->child[0]),eval(t->child[1])); case EQ: return eval(t->child[0]) == eval(t->child[1]); case NE: return eval(t->child[0]) != eval(t->child[1]); case '<': return eval(t->child[0]) < eval(t->child[1]); case LE: return eval(t->child[0]) <= eval(t->child[1]); case '>': return eval(t->child[0]) > eval(t->child[1]); case GE: return eval(t->child[0]) >= eval(t->child[1]); case LOGAND: return eval(t->child[0]) && eval(t->child[1]); case LOGOR: return eval(t->child[0]) || eval(t->child[1]); case '!': return ! eval(t->child[0]); case '?': return eval(t->child[0]) ? eval(t->child[1]) : eval(t->child[2]); case ',': eval(t->child[0]); return eval(t->child[1]); case TOK_FN1: return t->v.sym->fn1(eval(t->child[0])); case TOK_FN2: return t->v.sym->fn2(eval(t->child[0]), eval(t->child[1])); case TOK_FN3: return t->v.sym->fn3(eval(t->child[0]), eval(t->child[1]), eval(t->child[2])); } } return 0.; } /* set a flag vector (26 elements) for any single character variables */ void checkv(struct node *t,int varused[]){ if(t){ if(t->kind == TOK_VAR && t->v.sym->name[1] == 0) // it's a single character name varused[t->v.sym->name[0] - 'a'] = 1; checkv(t->child[0],varused); checkv(t->child[1],varused); checkv(t->child[2],varused); } } void checkvars(struct node *t,int varused[]){ int i; for(i=26;i--;) varused[i] = 0; checkv(t,varused); } /* free the memory for a tree's nodes */ void freetree(struct node *t){ if(t){ freetree(t->child[0]); freetree(t->child[1]); freetree(t->child[2]); // printf("FREE %#x\n",t); free(t); } }