Both the formula parser and the estimator use the stack instead of the Expression Tree.
FormulaEvaluator formula estimator class
File: FormulaEvaluator. js
// JScript Source Code <br/> // ----------- formulaevaluator ----------- <br/> function formulaevaluator () {<br/> This. derivefrom (new object (); <br/> This. set_classname ("formulaevaluator"); </P> <p> This. _ parser = new formulaparser (); <br/> This. _ expression = NULL; <br/> This. _ operands = []; <br/> This. _ tokens = []; </P> <p> // Evaluates an expression and return the result from the operands stack. <br/> This. _ evaluateexpression = function (tokens) {<br/> var token; </P> <p> while (tokens. length> 0) {<br/> token = tokens. pop (); </P> <p> // operand? <Br/> If (token. hasancestor ("operandbase") <br/> This. _ operands. push (token); <br/> else {// operator <br/> If (token. hasancestor ("operatorbase") {</P> <p> switch ($ T (token. get_type () {<br/> case "unarytype": This. _ evaluateunary (token, tokens); break; <br/> case "binarytype": This. _ evaluatebinary (token, tokens); break; <br/> case "functiontype": This. _ evaluatefunction (token, tokens); break; <br /> Default: Throw new exception (this, "_ evaluateexpression", "unsupported operator type:" + $ T (token )); <br/>}< br/>}// If <br/> // other unknown. <br/> else <br/> throw new exception (this, "_ evaluateexpression", "unknown token:" + $ T (token )); <br/>} // if... else <br/>}// while </P> <p> $ assert (this. _ operands. length = 1); </P> <p> If (this. _ operands. length! = 1) <br/> throw new exception (this, "_ evaluateexpression", "failed to evaluate expression: no result "); </P> <p> // result <br/> return this. _ operands. pop (); <br/>}; </P> <p> // evaluate a binary operator. <br/> This. _ evaluatebinary = function (operator, tokens) {<br/> This. _ operands. push (operator. evaluate (this. _ operands); <br/>}; </P> <p> // evaluate an unary operator. <br/> This. _ evaluateunary = Fu Nction (operator, tokens) {<br/> This. _ operands. push (operator. evaluate (this. _ operands); <br/>}; </P> <p> // evaluate a function. <br/> This. _ evaluatefunction = function (func, tokens) {<br/> var argnum = This. _ operands. pop (). get_value (); <br/> var requiredargnum = func. get_requiredargumentsnum (); </P> <p> // check arguments number requirements <br/> If (requiredargnum>-1) <br/>{< br/> If (argnum> Requiredargnum) <br/> throw new exception (<br/> This, <br/> "_ evaluatefunction", <br/> "Too implements arguments, needs "+ requiredargnum + <br/>", but gets "+ argnum); <br/> else <br/> If (argnum <requiredargnum) <br/> throw new exception (<br/> This, <br/> "_ evaluatefunction", <br/> func. get_functionname () + "Needs" + requiredargnum + <br/> "arguments, but gets only" + argnum); <br/>}</P> <P> var ARGs = []; </P> <p> for (VAR I = 0; I <argnum; I ++) <br/> args. push (this. _ operands. pop (); </P> <p> This. _ operands. push (func. evaluate (ARGs. reverse (); <br/>}; </P> <p> // attempt to convert initial functinunknown to registered function. <br/> This. _ convertfunction = function (expression) {<br/> var func; </P> <p> for (VAR I = 0; I <this. _ expression. tokens. length; I ++) <br/>{< br/> If (this. _ exp Ression. tokens [I]. hasancestor ("functionbase") <br/>{< br/> func = $ getregisterfunction (this. _ expression. tokens [I]. get_functionname (); </P> <p> If (func! = NULL) <br/> This. _ expression. tokens [I] = func; <br/>}< br/>}; </P> <p> formulaevaluator. prototype = {<br/> // set formula and initialize the expression. <br/> set_formula: function (formula) {<br/> var exp = This. _ parser. parse (formula); </P> <p> This. _ expression = exp; <br/> This. _ convertfunction (this. _ expression); <br/>}, <br/> // access original formula content. <br/> get_origina Lformula: function () {return this. _ expression. originalformula ;}, <br/> // access formated formula. <br/> get_formula: function () {return this. _ expression. formula ;}, <br/> // evaluate the formula if specified or evaluate original expression. <br/> evaluate: function (formula) {</P> <p> If (formula! = NULL) <br/> This. set_formula (formula); </P> <p> This. _ operands = []; <br/> This. _ tokens = []; </P> <p> // always perform evaluation on a copy of expression. <br/> // It shocould be reversed for evaluation. <br/> // You can output the expression before and after to compare <br/> // the differences. <br/> for (VAR I = This. _ expression. tokens. length-1; I> = 0; I --) <br/> This. _ tokens. push (this. _ expression. tokens [I]); </P> <p> return this. _ evaluateexpression (this. _ tokens); <br/>}, // function evaluate <br/> // unit test. <br/> test: function () {<br/> $ debug. writeline ("====================" + this. get_classname () + "========================= "); </P> <p> var formula = [<br/> "= 1", <br/> "= 1 + 2 ", <br/> "= 1 + 2 + 3", <br/> "=-1", <br/> "= true ", <br/> "= false", <br/> "= 1 + 2-3 + 4*5 + 6/7 ", <br/> "= (1 + 2-3 + 4) * 5", <br/> "= sum (1, 2 )", <br/> "= average (1, 2, 3)", <br/> "= adev (1, 2 )", <br/> "= 1 + 2 + 3*4 + 5/6 + sum (7, 8, average (9, 10, 11)" <br/>]; </P> <p> var evaluator = new formulaevaluator (); </P> <p> for (VAR I = 0; I <formula. length; I ++) <br/>{< br/> try <br/>{< br/> $ debug. writeline ("Evaluating:" + formula [I]); </P> <p> evaluator. set_formula (formula [I]); </P> <p> $ debug. writeline ("original formula:" + evaluator. get_originalformula (); <br/> $ debug. writeline ("formula:" + evaluator. get_formula (); </P> <p> var result = evaluator. evaluate (); </P> <p> $ debug. writeline ("result =" + result. get_value () + "/T [" + $ T (result) + "]"); <br/>}< br/> catch (E) <br/>{< br/> $ debug. writeline ("failed to evaluate" + formula [I] + "/nerror:" + E. description); <br/>}< br/>}// for <br/>}// test <br/>}; <br/>