private double ReadNumber(SimpleParser parser) { var factor = parser.NextIs('-') ? -1 : 1; parser.ConsumeAny('+', '-'); if (!double.TryParse(parser.ConsumeAny("0.123456789".ToCharArray()), NumberStyles.Any, CultureInfo.InvariantCulture, out var result)) { return(double.NaN); } return(factor * result); }
public double Eval() { var op_count = -1; while (parser.HasNext) { if (Operations.Count > op_count) { op_count = Operations.Count; } else { break; } parser.ConsumeAny(' '); if (parser.NextIs('(')) { parser.Skip(1); var exp = new Expression(parser) { MustConsumeClosingBracket = true }; exp.Eval(); var op = new Operation { Operator = "+", Expression = exp }; Operations.Add(op); } else if (parser.NextIs("+-*^/%".ToCharArray())) { var op = new Operation() { Operator = parser.NextChar.ToString() }; parser.Skip(1); parser.ConsumeAny(' '); if (parser.NextIs('(')) { parser.Skip(1); var exp = new Expression(parser); exp.MustConsumeClosingBracket = true; op.Expression = exp; exp.Eval(); } else { op.Expression = new Expression(ReadNumber(parser)); } Operations.Add(op); } else if (parser.NextIs("0.123456789".ToCharArray())) { Operations.Add(new Operation { Operator = "+", Expression = new Expression(ReadNumber(parser)) }); } else if (parser.NextIs(')') && MustConsumeClosingBracket) { parser.Skip(1); break; } } if (!Operations.Any()) { return(double.NaN); } var first_op = Operations.First(); if (string.IsNullOrEmpty(first_op.Operator)) { first_op.Operator = "+"; } else if (first_op.Operator == "-") { first_op.Operator = "+"; first_op.Expression.Value = (first_op.Expression.Value ?? Double.NaN) * (-1); } if (Operations.Count == 1) { var op = Operations[0]; var val = op.Expression.Value; if (val == null) { return(double.NaN); } if (op.Operator == "-") { Value = (-1.0 * (val.Value)); } else { Value = val; } } else if (Operations.Count == 2) { Value = Operations[1].Apply(Operations[0].Apply(0)); } else { if (Precedence(Operations[0].Operator) > 0) { return(double.NaN); // only + and minus may be first operator! } // repeated contraction by precedence while (Operations.Count > 1) { var highest_op = Operations.Select(x => x.Operator).OrderByDescending(x => Precedence(x)).First(); if (Precedence(highest_op) == 0) { double sum = 0; foreach (var op in Operations) { sum = op.Apply(sum); } return(sum); } var ops = new List <Operation>(); int i = 0; foreach (var op in Operations) { if (op.Operator == highest_op) { var last_op = ops[ops.Count - 1]; last_op.Expression.Value = op.Apply(last_op.Expression.Value ?? double.NaN); i++; continue; } ops.Add(op); i++; } Operations = ops; } return(Operations[0].Apply(0)); } return(Value ?? double.NaN); }