public static Expression Parse( string expression, IEnumerable<string> vars )
{
expression.ToLower();
int pos = 0;
Stack<FuncData> tmpStack = new Stack<FuncData>();
Expression e = new Expression( vars );
bool noBOperatorExpected = true;
bool lParenthExpected = false;
while ( pos < expression.Length ) {
string term = ReadTerm( expression, ref pos );
if ( lParenthExpected && term != "(" )
throw new ArgumentException( "expected '(' at " + pos );
lParenthExpected = false; //checked, can be turn off
//if a number or const or variable, append to the expression
double num;
if ( double.TryParse( term, out num ) ) //number
{
e.Append( new Variable() { Value = num, Name = num.ToString() } );
noBOperatorExpected = false;
continue;
}
IExpressionElement el;
if ( _consts.TryGetValue( term, out el ) ) //const
{
e.Append( el );
noBOperatorExpected = false;
continue;
}
Variable v;
if ( e.Vars.TryGetValue( term, out v ) ) //variable
{
e.Append( v );
noBOperatorExpected = false;
continue;
}
//if function -> push to stack
FuncData fd;
if ( _functions.TryGetValue( term, out fd ) ) {
tmpStack.Push( fd );
lParenthExpected = true; //dont need to set/reset noBOperatorExpected
continue;
}
if ( term.Length == 1 ) //operators
{
char termch = term[0];
if ( _soperators.TryGetValue( termch, out fd ) ) {
switch ( fd.SpecialKind ) {
case SpecialOperandKind.LeftParenthesis:
tmpStack.Push( fd );
noBOperatorExpected = true;
break;
case SpecialOperandKind.RightParenthesis:
noBOperatorExpected = false;
ProcessRightParenth( e, tmpStack, pos );
break;
case SpecialOperandKind.Comma:
noBOperatorExpected = true;
ProcessComma( e, tmpStack, pos );
break;
}
continue;
}
if ( noBOperatorExpected ) {
if ( _uoperators.TryGetValue( termch, out fd ) ) {
tmpStack.Push( fd );
//noBOperatorExpected = true; - is already
continue;
}
} else {
if ( _operators.TryGetValue( termch, out fd ) ) {
ProcessOperator( fd, e, tmpStack );
noBOperatorExpected = true;
continue;
}
}
}
//unrecongnizable
throw new ArgumentException( "unrecognizable term " + term + " at before " + pos );
}
//we will be tolerant to closing parenthesis, i.e. the left parenthesis left will be ignored
foreach ( var f in tmpStack )
if ( f.SpecialKind != SpecialOperandKind.LeftParenthesis )
e.Append( f.Func );
else
throw new ArgumentException( "unmatching parenthesis" );
return e;
}