using System; using System.Collections.Generic; using System.Text; namespace Microsoft.HaniA.MathEvluater { class Parser { MathEngine _mathEngine; ScopeFrame _scope; Scanner _scn; public Parser(ScopeFrame scope, Scanner scn) { _scope = scope; _mathEngine = scope.TopLevelScope as MathEngine; _scn = scn; } /// /// expression -> null | addition /// addition -> multi | addition [+,-] multi /// multi -> power | multi [*,/] power /// power -> term | power ^ term /// term -> (addition) | id | constant /// /// public ParserTree.ParserNode ParseExpresssion() { if (!_scn.ReadNext()) return null; return ParseAddition(); } ParserTree.ParserNode ParseAddition() { ParserTree.ParserNode left = ParseMultiplication(); while (true) { if (_scn.CurrentToken == Token.Addition) { _scn.ReadNext(); left = new ParserTree.AdditionOp(left, ParseMultiplication()); } else if (_scn.CurrentToken == Token.Subtraction) { _scn.ReadNext(); left = new ParserTree.SubtractionOp(left, ParseMultiplication()); } else { return left; } } } ParserTree.ParserNode ParseMultiplication() { ParserTree.ParserNode left = ParsePower(); while (true) { if (_scn.CurrentToken == Token.Multiplication) { _scn.ReadNext(); left = new ParserTree.MultiplicationOp(left, ParsePower()); } else if (_scn.CurrentToken == Token.Division) { _scn.ReadNext(); left = new ParserTree.DivisionOp(left, ParsePower()); } else { return left; } } } ParserTree.ParserNode ParsePower() { ParserTree.ParserNode left = ParseTerm(); while (_scn.CurrentToken == Token.Power) { _scn.ReadNext(); left = new ParserTree.PowerOp(left, ParseTerm()); } return left; } public ParserTree.ParserNode ParseTerm() { switch (_scn.CurrentToken) { case Token.OpenParenthesis: { _scn.ReadNext(); ParserTree.ParserNode paraNode = ParseAddition(); if (_scn.CurrentToken == Token.CloseParenthesis) { _scn.ReadNext(); return paraNode; } else { throw new ApplicationException(string.Format("Expecting a closing parenthesis at {0}.", _scn.TokenIndex + 1)); } } case Token.Addition: // Positive symbol [ +term ] _scn.ReadNext(); return ParseTerm(); case Token.Subtraction: // Negative symbol [ -term ] _scn.ReadNext(); return new ParserTree.NegateOp(ParseTerm()); case Token.Number: // [ 1234.33 ] double value = Double.Parse(_scn.Value); _scn.ReadNext(); return new ParserTree.Number(value); case Token.Symbol: // constant | variable | function_call ... function_call = symbol param_list string symbolName = _scn.Value; _scn.ReadNext(); List funcParamList; if (ParseParamList(out funcParamList)) { // function_call EquationBase eq; if (!_mathEngine.Equations.TryGetEquation(symbolName, out eq)) throw new ApplicationException(string.Format("Unknown function name '{0}'.", symbolName)); return new ParserTree.FunctionCall(eq, funcParamList); } else { // constant | variable // Look up in constant Constant constant; if (_mathEngine.Constants.TryGetValue(symbolName, out constant)) { return new ParserTree.Number(constant.Value); } else // else look up variable { Vairable variable = _scope.LookUpVariable(symbolName); if (variable == null) throw new ApplicationException(string.Format("Couldn't resolve the variable '{0}'.", symbolName)); return new ParserTree.VariableRef(variable); } } default: throw new ApplicationException(string.Format("Expecting a literal at {0}.", _scn.TokenIndex + 1)); } } bool ParseParamList(out List funcParamList) { funcParamList = null; if (_scn.CurrentToken != Token.OpenParenthesis) return false; funcParamList = new List(); _scn.ReadNext(); if (_scn.CurrentToken != Token.CloseParenthesis) { do { funcParamList.Add(ParseAddition()); // The parameter value can be anything if (_scn.CurrentToken == Token.Comma) { _scn.ReadNext(); } else if (_scn.CurrentToken == Token.CloseParenthesis) { _scn.ReadNext(); break; // done reading paranths } else { throw new ApplicationException(string.Format("Expecting a comma or close paranthesis at {0}.", _scn.TokenIndex)); } } while (true); } return true; } } }