基於JavaScript的公式解譯器 – 13 【公式估值器的實現】

來源:互聯網
上載者:User

公式解析器和估值器都沒有使用運算式樹狀架構,而是使用棧。

FormulaEvaluator公式估值器類

檔案: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 = function(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 many 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._expression.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 /> }<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_OriginalFormula: 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 should 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 />

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.