using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace Engine { public partial class Form1 : Form { //Invert over all expression (i + 7) ^ 2 -> -(i + 7) ^ 2 private Stack Tree = new Stack(); private Dictionary Symbols = new Dictionary(); public Form1() { InitializeComponent(); } private void Button1_Click(object sender, EventArgs e) { var s = textBox1.Text; var f = FlattenInput(s); PrintFlatList(f); f.Reverse(); var stack = new Stack(f); ActionsListView.Items.Clear(); button1.Text = "Result: " + NewCalc(stack); //var f2 = GetSubExpressions(f); //PrintSteps(f2); //PrintSymbolsTable(); //var result = Calc(f2); //button1.Text = $"Result: {result}"; //var result = Calc(FlattenInput(s)); } void PrintSteps(List> expressions) { StepsListView.Items.Clear(); for(var i = 0; i < expressions.Count; i++) { var expression = expressions[i]; var item = new ListViewItem($"Step {i + 1}"); var ex = string.Empty; foreach (var token in expression) { if (!token.IsCoefficent) ex += token.Value + " "; else ex += token.Value; } item.SubItems.Add(ex); StepsListView.Items.Add(item); } } void PrintSymbolsTable() { SymbolsListView.Items.Clear(); foreach(var k in Symbols) { var item = new ListViewItem(k.Key); item.SubItems.Add(k.Value.ToString()); SymbolsListView.Items.Add(item); } } void PrintFlatList(List tokens) { ExpressionBreakdownListView.Items.Clear(); foreach(var token in tokens) { var item = new ListViewItem(token.Value); if(!token.IsCoefficent) item.SubItems.Add(token.Type.ToString()); else item.SubItems.Add(token.Type.ToString() + " (Coefficent)"); ExpressionBreakdownListView.Items.Add(item); } } double NewCalc(Stack tokens, double co = 1) { var previousToken = new Token() { Type = TokenType.Unknown }; var runningValue = 0d; while(tokens.Count > 0) { var token = tokens.Pop(); if (token.Type == TokenType.ExpEnd) { if(tokens.Count > 0 && tokens.Peek().Type == TokenType.Power) { var op = tokens.Pop(); var powerOf = tokens.Pop(); if(powerOf.Type == TokenType.Constant) { ActionsListView.Items.Add($"Taking {runningValue} to the power of {powerOf.Value}."); runningValue = Operate(runningValue, Convert.ToDouble(powerOf.Value), op.Type); } } break; } if(token.Type == TokenType.ExpStart) { runningValue = NewCalc(tokens); continue; } if(token.IsCoefficent) { var lookAHead = tokens.Pop(); if (lookAHead.Type == TokenType.Variable) { ActionsListView.Items.Add($"{token.Value} is a coeffiecent, multiplying it against {Symbols[lookAHead.Value]} (Symbol '{lookAHead.Value}')."); runningValue += Convert.ToDouble(token.Value) * Symbols[lookAHead.Value]; if (previousToken.Type != TokenType.Unknown) throw new Exception("Token shouldn't have a valid value!"); //2a( if(tokens.Count != 0 && tokens.Peek().Type == TokenType.ExpStart) { runningValue += NewCalc(tokens, runningValue); } previousToken = new Token() { Type = TokenType.Constant, Value = runningValue.ToString(), IsCoefficent = false }; continue; } else if (lookAHead.Type == TokenType.ExpStart) { runningValue += NewCalc(tokens, Convert.ToDouble(token.Value)); previousToken = new Token() { Type = TokenType.Constant, Value = runningValue.ToString(), IsCoefficent = false }; continue; } else throw new Exception("Invalid grammar!"); } //If token is an operator if(GetOperator(token.Value[0]) != TokenType.Unknown) { //Operator found var lookAHead = tokens.Pop(); if(lookAHead.Type == TokenType.Constant && !lookAHead.IsCoefficent) { var tmpValue = 0d; while (tokens.Count > 0 && (tokens.Peek().Type == TokenType.Multiply || tokens.Peek().Type == TokenType.Divide || tokens.Peek().Type == TokenType.Power)) { var op = tokens.Pop(); if (op.Type != TokenType.Power) { var next = tokens.Pop(); if (next.Type == TokenType.ExpStart) { var returnValue = NewCalc(tokens); if (tmpValue != 0) { ActionsListView.Items.Add($"{GetOperatorVerb(op.Type)} {tmpValue} (tmp) and {returnValue} (returnValue)."); tmpValue = Operate(tmpValue, returnValue, op.Type); lookAHead.Value = tmpValue.ToString(); } else { ActionsListView.Items.Add($"{GetOperatorVerb(op.Type)} {Convert.ToDouble(lookAHead.Value) * co} (lookAHead) and {returnValue} (returnValue)."); tmpValue = Operate(Convert.ToDouble(lookAHead.Value) * co, returnValue, op.Type); lookAHead.Value = tmpValue.ToString(); } continue; } if (tmpValue != 0) { ActionsListView.Items.Add($"{GetOperatorVerb(op.Type)} {tmpValue} (tmp) and {Convert.ToDouble(next.Value) * co} (next)."); tmpValue = Operate(tmpValue, Convert.ToDouble(next.Value) * co, op.Type); lookAHead.Value = tmpValue.ToString(); } else { ActionsListView.Items.Add($"{GetOperatorVerb(op.Type)} {Convert.ToDouble(lookAHead.Value) *co} (lookAHead) and {next.Value} (next)."); tmpValue = Operate(Convert.ToDouble(lookAHead.Value) *co, Convert.ToDouble(next.Value) *co, op.Type); lookAHead.Value = tmpValue.ToString(); } } else if (op.Type == TokenType.Power) { } } //if(tokens.Count > 0 && (tokens.Peek().Type == TokenType.Divide || tokens.Peek().Type == TokenType.Multiply || tokens.Peek().Type == TokenType.Power)) //{ // var op = tokens.Pop(); // var con = tokens.Pop(); // //TODO: check if "con" is a variable, right now we're assuming its a constant. // ActionsListView.Items.Add($"{GetOperatorVerb(op.Type)} {Convert.ToDouble(lookAHead.Value) * co} and {Convert.ToDouble(con.Value) * co} (Oder of Operations)."); // var tmp = Operate(Convert.ToDouble(lookAHead.Value) * co, Convert.ToDouble(con.Value) * co, op.Type); // ActionsListView.Items.Add($"{GetOperatorVerb(token.Type)} {Convert.ToDouble(previousToken.Value) * co} and {tmp}."); // runningValue += Operate(Convert.ToDouble(previousToken.Value) * co, tmp, token.Type); // previousToken = new Token { Type = TokenType.Unknown }; //} //else //{ if (previousToken.Type != TokenType.Unknown) { ActionsListView.Items.Add($"{GetOperatorVerb(token.Type)} {Convert.ToDouble(previousToken.Value) * co} and {Convert.ToDouble(lookAHead.Value) * co}."); runningValue += Operate(Convert.ToDouble(previousToken.Value) * co, Convert.ToDouble(lookAHead.Value) * co, token.Type); } else { ActionsListView.Items.Add($"{GetOperatorVerb(token.Type)} {runningValue} and {Convert.ToDouble(lookAHead.Value) * co}."); runningValue = Operate(runningValue, Convert.ToDouble(lookAHead.Value) * co, token.Type); } //} } } else if(token.Type == TokenType.Constant) { previousToken = token; } } return runningValue; } List> GetSubExpressions(List tokens) { var expressions = new List>(); var stack = new Stack>(); var tmp = new List(); var skipCount = 0; var nestingLevel = 0; for(var i = 0; i < tokens.Count; i++) { if(skipCount > 0) { skipCount--; continue; } var token = tokens[i]; //if (stack.Count > 0 && nestingLevel == 0) //{ // if (!stack.Peek()[0].IsCoefficent) // { // var offset = 0; // while(stack.Count > 0) // { // expressions.Insert(0, stack.Pop()); // offset++; // } // } //} if (token.IsCoefficent) { //var lookAhead = tokens[i + 1]; //if(lookAhead.Type != Node.Token.ExpStart) //{ if (tmp.Count > 0) expressions.Add(new List(tmp)); expressions.Add(new List() { token }); //} //else //{ // stack.Push(new List(tmp)); //} tmp.Clear(); } else if (token.Type == Node.Token.ExpStart) { nestingLevel++; //if (i - 1 >= 0) //{ // var lookBehind = tokens[i - 1]; // if (lookBehind.IsCoefficent) // { // tmp.Remove(tmp.Last()); // expressions.Add(new List(tmp)); // tmp.Clear(); // stack.Push(new List { lookBehind }); // //tmp.Add(token); // continue; // } //} if (tmp.Count > 0) expressions.Add(new List(tmp)); tmp.Clear(); tmp.Add(token); } else if(token.Type == Node.Token.ExpEnd) { nestingLevel--; if (i + 1 < tokens.Count) { var lookAHead = tokens[i + 1]; if (lookAHead.Type == Node.Token.Power) { var toPowerOf = tokens[i + 2]; tmp.Add(token); tmp.Add(lookAHead); tmp.Add(toPowerOf); expressions.Add(new List(tmp)); tmp.Clear(); skipCount = 2; continue; } } tmp.Add(token); if (tmp.Count > 0) expressions.Add(new List(tmp)); tmp.Clear(); } else { tmp.Add(token); } } if(tmp.Count > 0) { expressions.Add(new List(tmp)); } return expressions; } List FlattenInput(string expression) { //if (expression.Count(x => x == '(') == 1 && expression.Count(x => x == ')') == 1) throw new Exception("Unbalanced params!"); //if(expression.Count(x => x == '(') % 2 != 0 || expression.Count(x => x == ')') % 2 != 0) throw new Exception("Unbalanced params!"); Symbols.Clear(); var tokens = new List(); var tmp = string.Empty; var parsingNumber = false; for(var i = 0; i < expression.Length; i++) { var c = expression[i]; var op = GetOperator(c); if (c == '.' || int.TryParse(c.ToString(), out int _)) { if(tokens.Count > 1) { var lookBehind = tokens[tokens.Count - 1]; if(lookBehind.Type == TokenType.ExpEnd) { tokens.Add(new Token() { Value = "^", Type = TokenType.Power, IsCoefficent = false }); } } if((i + 1) == expression.Length) { tokens.Add(new Token() { Value = $"{tmp}{c}", Type = TokenType.Constant, IsCoefficent = false });//new Node($"{tmp}{c}", Node.Token.Constant)); } parsingNumber = true; tmp += c; continue; } else if(c == '(') { if (parsingNumber) { tokens.Add(new Token() { Value = tmp, Type = TokenType.Constant, IsCoefficent = true });//new Node(tmp, Node.Token.Constant) { IsCoefficent = true }); } tokens.Add(new Token() { Value = "(", Type = TokenType.ExpStart, IsCoefficent = false });//new Node("(", Node.Token.ExpStart)); parsingNumber = false; tmp = string.Empty; continue; } else if(c == ')') { if (parsingNumber) { tokens.Add(new Token() { Value = tmp, Type = TokenType.Constant, IsCoefficent = false }); //new Node(tmp, Node.Token.Constant)); } tokens.Add(new Token() { Value = ")", Type = TokenType.ExpEnd, IsCoefficent = false }); //new Node(c.ToString(), Node.Token.ExpEnd)); parsingNumber = false; tmp = string.Empty; continue; } else if(op != TokenType.Unknown) { if(parsingNumber) { tokens.Add(new Token() { Value = tmp, Type = TokenType.Constant, IsCoefficent = false }); //new Node(tmp, Node.Token.Constant)); } tokens.Add(new Token() { Value = c.ToString(), Type = op, IsCoefficent = false });//new Node(c.ToString(), op)); parsingNumber = false; tmp = string.Empty; continue; } else if(c != ' ') { if (!Symbols.ContainsKey(c.ToString())) { Symbols.Add(c.ToString(), 1); } else { Symbols[c.ToString()]++; } if (tokens.Count > 1) { var lookBehind = tokens[tokens.Count - 1]; if (lookBehind.Type == TokenType.ExpEnd) { tokens.Add(new Token() { Value = "^", Type = TokenType.Power, IsCoefficent = false });//new Node("^", Node.Token.Power)); } } if ((i + 1) < expression.Length) { var lookAHead = expression[i + 1]; if(lookAHead == '(') { tokens.Add(new Token() { Value = c.ToString(), Type = TokenType.Variable, IsCoefficent = true }); tmp = string.Empty; parsingNumber = false; continue; } } if (parsingNumber) { tokens.Add(new Token() {Value = tmp, Type = TokenType.Constant, IsCoefficent = true }); } tokens.Add(new Token() { Value = c.ToString(), Type = TokenType.Variable, IsCoefficent = false }); parsingNumber = false; tmp = string.Empty; } } return tokens; } //double Calc(List> expressions, double co = 1) //{ // //Assumption: an operator is never last in the list. // //double runningTotal = 0; // double lastValue = 0; // var next = true; // Node previousToken = new Node("zzzz", Node.Token.Unknown); // for(var i = 0; i < expressions.Count;) // { // if (!next) break; // var tokens = expressions[i]; // expressions.RemoveAt(i); // for (var j = 0; j < tokens.Count; j++) // { // var token = tokens[j]; // if(token.IsCoefficent) // { // if(tokens.Count == 1) // { // return Calc(expressions, Convert.ToDouble(token.Value)); // } // } // else if(token.Type == Node.Token.Constant) // { // previousToken = token; // } // else if(token.Type == Node.Token.Variable) // { // //TODO: do symbol lookup to get value for this variale. // previousToken = new Node("666", Node.Token.Variable); // } // else if(GetOperator(token.Value[0]) != Node.Token.Unknown) // { // if(tokens.Count > j + 1) // { // j++; // var lookAHead = tokens[j]; // if(lookAHead.Type == Node.Token.Constant) // { // if (previousToken.Type != Node.Token.Unknown) // { // lastValue = Operate(Convert.ToDouble(previousToken.Value) * co, Convert.ToDouble(lookAHead.Value) * co, token.Type); // previousToken = new Node("zzzz", Node.Token.Unknown); // } // else // lastValue = Operate(lastValue * co, Convert.ToDouble(lookAHead.Value) * co, token.Type); // } // } // else // { // lastValue = Operate(Convert.ToDouble(previousToken.Value), Calc(expressions), token.Type); // } // } // else if(token.Type == Node.Token.ExpStart) // { // } // else if(token.Type == Node.Token.ExpEnd) // { // if(tokens.Count > j + 1) // { // var lookAHead = tokens[j + 1]; // if(lookAHead.Type == Node.Token.Power) // { // lookAHead = tokens[j + 2]; // lastValue = Operate(lastValue, Convert.ToDouble(lookAHead.Value), Node.Token.Power); // } // } // next = false; // } // } // } // return lastValue; //} double Operate(double n1, double n2, TokenType operation) { switch(operation) { case TokenType.Add: return n1 + n2; case TokenType.Divide: return n1 / n2; case TokenType.Multiply: return n1 * n2; case TokenType.Power: return Math.Pow(n1, n2); case TokenType.Subtract: return n1 - n2; default: throw new Exception("Token must be an operator!"); } } TokenType GetOperator(char c) { switch (c) { case '+': return TokenType.Add; case '-': return TokenType.Subtract; case '*': return TokenType.Multiply; case '^': return TokenType.Power; case '/': return TokenType.Divide; default: return TokenType.Unknown; } } string GetOperatorVerb(TokenType type) { switch (type) { case TokenType.Add: return "Adding"; case TokenType.Divide: return "Dividing"; case TokenType.Multiply: return "Multiplying"; case TokenType.Power: return "Raising"; case TokenType.Subtract: return "Subtracting"; default: throw new Exception("Token must be an operator!"); } } struct Token { public string Value; public bool IsCoefficent; public TokenType Type; } enum TokenType { Add, Subtract, Multiply, Divide, Power, Variable, Constant, ExpStart, ExpEnd, SubScript, SuperScript, Unknown } } }