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;
}
}
}