private static void ParseConstOrFunc(CalcEnvironment env, int sign) { bool isFunc = false; List <string> args = null; string str = ""; char c; do { c = env.Char; if (char.IsLetter(c) || c == '_') { str += c; } else if (c == '(') { isFunc = true; args = ParseFuncArgs(env); break; } else { break; } env.NextChar(); } while (env.Length != 0); if (isFunc) { env.nodes.AddLast(new FuncNode(str, args.ToArray(), sign)); } else { env.nodes.AddLast(new ConstNode(str, sign)); } }
private void FindFuncValues(CalcEnvironment env) { FuncNode funcNode; string fName; Func <double[], double> func; foreach (Node node in env.nodes) { if (node is FuncNode) { funcNode = node as FuncNode; fName = funcNode.name; for (int i = 0; i < funcNode.args.Length; ++i) { funcNode.args_vals[i] = Calculate(funcNode.args[i]); } if (Functions.Contains(fName, IgnoreCase)) { func = Functions.Get(fName, IgnoreCase); funcNode.number = func(funcNode.args_vals) * funcNode.sign; } else { throw new MissingFunctionException(funcNode.name); } } } }
private static void ParseOpenBrackets(CalcEnvironment env, ref bool firstValue) { char c; wasOpenBrc = false; sign = 1; do { c = env.Char; if (c == '(') { wasOpenBrc = true; ++env.brc; } else if (c == '-') { if (wasOpenBrc || firstValue) { sign *= -1; wasOpenBrc = false; firstValue = false; } else { throw new ParseException(env.i, "Bad minus"); } } else { break; } env.NextChar(); } while (env.Length != 0); }
private static void Calc_Parse(CalcEnvironment env) { var parseStage = 0; var firstValue = true; while (env.Length != 0) { switch (parseStage) { case 0: ParseOpenBrackets(env, ref firstValue); break; case 1: ParseValue(env); break; case 2: ParseCloseBrackets(env); break; case 3: ParseOperation(env); break; } if (++parseStage == 4) { parseStage = 0; } } if (env.brc != 0) { throw new ParseException(env.i, "Missing closing bracket"); } }
private static List <string> ParseFuncArgs(CalcEnvironment env) { List <string> args = new List <string>(); int brc = 0; string arg = ""; char c; while (env.Length != 0) { env.NextChar(); c = env.Char; if (c == ')') { --brc; if (brc == -1) { env.NextChar(); break; } } else if (c == '(') { ++brc; } else if (c == ',') { if (arg != "") { args.Add(arg); arg = ""; } else { throw new ParseException(env.i, "Empty argument"); } } if (c != ',') { arg += c; } } if (brc != -1) { throw new ParseException(env.i, env.Char, "Missing function closing bracket"); } if (arg != "") { args.Add(arg); } else if (args.Count > 0) { throw new ParseException(env.i, "Empty argument"); } return(args); }
private static void ParseValue(CalcEnvironment env) { if (char.IsDigit(env.Char)) { ParseNumber(env, sign); } else if (char.IsLetter(env.Char) || env.Char == '_') { ParseConstOrFunc(env, sign); } }
private static void ParseOperation(CalcEnvironment env) { LinkedListNode <Node> op; if ("^%*/+-".Contains(env.Char)) { op = env.nodes.AddLast(new OperationNode(env.Char, env.brc)); env.AddOpInQueue(op); } else { throw new ParseException(env.i, env.Char, "Operation expected"); } env.NextChar(); }
private static void ParseCloseBrackets(CalcEnvironment env) { char c; while (env.Length != 0) { c = env.Char; if (c == ')') { --env.brc; env.NextChar(); } else { break; } } }
private static void PrintInfo(CalcEnvironment env) { LinkedListNode <Node> node = env.nodes.First; while (node != null) { Console.WriteLine(node.Value); node = node.Next; } Console.WriteLine("Count:" + env.nodes.Count); Console.WriteLine("====================="); Console.WriteLine("Operation Queue"); for (int i = 0; i < env.opQueue.Count; ++i) { Console.WriteLine($"{i + 1}\t{env.opQueue[i].Value}"); } Console.WriteLine("Count: " + env.opQueue.Count); }
private double Calc_Process(CalcEnvironment env) { OperationNode operation; LinkedListNode <Node> a, b; NumberNode aNumb, bNumb; for (int i = 0; i < env.opQueue.Count; ++i) { operation = env.opQueue[i].Value as OperationNode; a = env.opQueue[i].Previous; b = env.opQueue[i].Next; aNumb = a.Value as NumberNode; bNumb = b.Value as NumberNode; switch (operation.operation) { case '^': aNumb.number = Math.Pow(aNumb.number, bNumb.number); break; case '%': aNumb.number %= bNumb.number; break; case '*': aNumb.number *= bNumb.number; break; case '/': if (bNumb.number != 0 || AllowDivisionByZero) { aNumb.number /= bNumb.number; } else { throw new DivideByZeroException(); } break; case '+': aNumb.number += bNumb.number; break; case '-': aNumb.number -= bNumb.number; break; } env.nodes.Remove(b); env.nodes.Remove(env.opQueue[i]); } return(((NumberNode)env.nodes.First.Value).number); }
private static void ParseNumber(CalcEnvironment env, int sign) { var wasDigit = false; var wasDot = false; string str = ""; double numb = 0.0; char c; do { c = env.Char; if (c == '.') { if (wasDigit && !wasDot) { str += '.'; wasDot = true; } else { throw new ParseException(env.i, "Bad dot"); } } else if (char.IsDigit(c)) { str += c; wasDigit = true; } else { break; } env.NextChar(); } while (env.Length != 0); if (!double.TryParse(str, numberStyles, provider, out numb)) { throw new ParseException(env.i, $"Bad number '{str}'"); } env.nodes.AddLast(new NumberNode(numb * sign)); }
public double Calculate(string expr) { CalcEnvironment env = new CalcEnvironment(expr.Length); for (int i = expr.Length - 1; i >= 0; --i) { if (char.IsLetterOrDigit(expr[i]) || ".,+-*/^%()".IndexOf(expr[i]) != -1) { env.exprStack.Push(expr[i]); } } Calc_Parse(env); if (env.nodes.Count == 0) { throw new CalculatorException("Not a valid string"); } FindConstValues(env); FindFuncValues(env); //PrintInfo(env); return(Calc_Process(env)); }
private void FindConstValues(CalcEnvironment env) { ConstNode constNode; string cName; foreach (Node node in env.nodes) { if (node is ConstNode) { constNode = node as ConstNode; cName = constNode.constName; if (Consts.Contains(cName, IgnoreCase)) { constNode.number = Consts.Get(cName, IgnoreCase) * constNode.sign; } else { throw new MissingConstantException(constNode.constName); } } } }