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.Runtime.CompilerServices; using System.Windows.Forms; namespace Engine { public partial class Form1 : Form { private Dictionary Symbols { get; set; } = 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(); PrintSymbolsTable(); button1.Text = "Result: " + HandleAddAndSub(stack); } 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); item.SubItems.Add(token.Type.ToString()); ExpressionBreakdownListView.Items.Add(item); } } double HandleParenthesis(Stack tokens, bool callerHasPriority = false) { var runningValue = 0d; var previousToken = new Token() { Type = TokenType.Unknown }; for(; ;) { if (tokens.Count == 0) break; var currentToken = tokens.Pop(); if(currentToken.Type == TokenType.Constant) { previousToken = currentToken; continue; } else if(currentToken.Type == TokenType.ExpStart) { var tmp = HandleParenthesis(tokens); runningValue = tmp; } else if(currentToken.Type == TokenType.Add || currentToken.Type == TokenType.Subtract) { var lookAHead = tokens.Pop(); if(lookAHead.Type == TokenType.ExpStart) { var tmp = HandleParenthesis(tokens); if (runningValue == 0) runningValue = Operate(Convert.ToDouble(previousToken.Value), tmp, currentToken.Type); else runningValue = Operate(runningValue, tmp, currentToken.Type); continue; } tokens.Push(lookAHead); tokens.Push(currentToken); if (previousToken.Type != TokenType.Unknown) tokens.Push(previousToken); else tokens.Push(new Token { Type = TokenType.Constant, Value = runningValue.ToString() }); runningValue = HandleAddAndSub(tokens); previousToken.Type = TokenType.Unknown; } else if (currentToken.Type == TokenType.Power) { var lookAHead = tokens.Pop(); if(lookAHead.Type == TokenType.ExpStart) { var powerOf = HandleParenthesis(tokens, true); runningValue = Operate(Convert.ToDouble(previousToken.Value), powerOf, currentToken.Type); previousToken.Type = TokenType.Unknown; continue; } var tmp = Operate(Convert.ToDouble(previousToken.Value), Convert.ToDouble(lookAHead.Value), currentToken.Type); previousToken.Type = TokenType.Unknown; runningValue = tmp; } else if (currentToken.Type == TokenType.Multiply || currentToken.Type == TokenType.Divide) { var lookAHead = tokens.Peek(); if (lookAHead.Type == TokenType.ExpStart) { tokens.Pop(); var tmpe = Operate(Convert.ToDouble(previousToken.Value), HandleParenthesis(tokens), currentToken.Type); previousToken.Type = TokenType.Unknown; runningValue = tmpe; continue; } tokens.Push(currentToken); if (previousToken.Type != TokenType.Unknown) tokens.Push(previousToken); else tokens.Push(new Token { Type = TokenType.Constant, Value = runningValue.ToString() }); var tmp = HandleMultAndDiv(tokens); previousToken.Type = TokenType.Unknown; runningValue = tmp; } else if (currentToken.Type == TokenType.ExpEnd) { if(tokens.Count > 0 && tokens.Peek().Type == TokenType.Power) { //Pop the power of token before returning. tokens.Pop(); runningValue = Operate(runningValue, Convert.ToDouble(tokens.Pop().Value), TokenType.Power); } if(!callerHasPriority && tokens.Count > 0 && (tokens.Peek().Type == TokenType.Multiply || tokens.Peek().Type == TokenType.Divide)) { var op = tokens.Pop(); var twoAHead = tokens.Pop(); if(twoAHead.Type == TokenType.ExpStart) { runningValue = Operate(runningValue, HandleParenthesis(tokens, true), op.Type); } else { runningValue = Operate(runningValue, Convert.ToDouble(twoAHead.Value), op.Type); } } break; } } return runningValue; } double HandleMultAndDiv(Stack tokens) { var runningValue = 0d; var previousToken = new Token() { Type = TokenType.Unknown }; for(; ;) { if (tokens.Count == 0) break; //"Current" token. if (tokens.Peek().Type != TokenType.Multiply && tokens.Peek().Type != TokenType.Divide && tokens.Peek().Type != TokenType.Constant && tokens.Peek().Type != TokenType.Variable) { break; } var currentToken = tokens.Pop(); if (currentToken.Type == TokenType.Constant) { previousToken = currentToken; continue; } else if (currentToken.Type == TokenType.Multiply || currentToken.Type == TokenType.Divide) { var lookAHead = tokens.Pop(); if (lookAHead.Type == TokenType.ExpStart) { var tmp = HandleParenthesis(tokens, true); if (runningValue == 0) runningValue = Operate(Convert.ToDouble(previousToken.Value), tmp, currentToken.Type); else runningValue = Operate(runningValue, tmp, currentToken.Type); previousToken.Type = TokenType.Unknown; continue; } if (lookAHead.Type == TokenType.Constant) { if (runningValue == 0) runningValue = Operate(Convert.ToDouble(previousToken.Value), Convert.ToDouble(lookAHead.Value), currentToken.Type); else runningValue = Operate(runningValue, Convert.ToDouble(lookAHead.Value), currentToken.Type); previousToken.Type = TokenType.Unknown; } else if(lookAHead.Type == TokenType.ExpStart) { var tmp = HandleParenthesis(tokens, true); if (runningValue == 0) runningValue = Operate(Convert.ToDouble(previousToken.Value), tmp, currentToken.Type); else runningValue = Operate(runningValue, tmp, currentToken.Type); previousToken.Type = TokenType.Unknown; } } } return runningValue; } double HandleAddAndSub(Stack tokens) { var runningValue = 0d; var previousToken = new Token() { Type = TokenType.Unknown }; for(; ;) { if (tokens.Count == 0) break; var currentToken = tokens.Pop(); if(currentToken.Type == TokenType.Constant) { previousToken = currentToken; continue; } if (currentToken.Type == TokenType.ExpEnd) { tokens.Push(currentToken); break; } if(currentToken.Type == TokenType.ExpStart) { var tmp = HandleParenthesis(tokens); runningValue = tmp; } else if(currentToken.Type == TokenType.Add || currentToken.Type == TokenType.Subtract) { var lookAHead = tokens.Pop(); if (lookAHead.Type == TokenType.ExpStart) { var tmp = HandleParenthesis(tokens); if (runningValue == 0) runningValue = Operate(Convert.ToDouble(previousToken.Value), tmp, currentToken.Type); else runningValue = Operate(runningValue, tmp, currentToken.Type); previousToken.Type = TokenType.Unknown; continue; } if (tokens.Count > 0 && (tokens.Peek().Type == TokenType.Multiply || tokens.Peek().Type == TokenType.Divide)) { tokens.Push(lookAHead); var tmp = HandleMultAndDiv(tokens); if (runningValue == 0) runningValue = Operate(Convert.ToDouble(previousToken.Value), tmp, currentToken.Type); else runningValue = Operate(runningValue, tmp, currentToken.Type); previousToken.Type = TokenType.Unknown; } else { if (runningValue == 0) runningValue = Operate(Convert.ToDouble(previousToken.Value), Convert.ToDouble(lookAHead.Value), currentToken.Type); else runningValue = Operate(runningValue, Convert.ToDouble(lookAHead.Value), currentToken.Type); previousToken.Type = TokenType.Unknown; } } else if (currentToken.Type == TokenType.Multiply || currentToken.Type == TokenType.Divide) { tokens.Push(currentToken); if (previousToken.Type != TokenType.Unknown) tokens.Push(previousToken); else tokens.Push(new Token { Type = TokenType.Constant, Value = runningValue.ToString() }); var tmp = HandleMultAndDiv(tokens); previousToken.Type = TokenType.Unknown; //TODO: this is wrong I'm sure. runningValue = tmp; } } return runningValue; } 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 }); } } if((i + 1) == expression.Length) { tokens.Add(new Token() { Value = $"{tmp}{c}", Type = TokenType.Constant });//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 }); tokens.Add(new Token() { Value = "*", Type = TokenType.Multiply }); } tokens.Add(new Token() { Value = "(", Type = TokenType.ExpStart });//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 }); //new Node(tmp, Node.Token.Constant)); } tokens.Add(new Token() { Value = ")", Type = TokenType.ExpEnd }); //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 }); //new Node(tmp, Node.Token.Constant)); } tokens.Add(new Token() { Value = c.ToString(), Type = op });//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 }); } } if ((i + 1) < expression.Length) { var lookAHead = expression[i + 1]; if(lookAHead == '(') { tokens.Add(new Token() { Value = c.ToString(), Type = TokenType.Variable }); tokens.Add(new Token() { Value = "*", Type = TokenType.Multiply }); tmp = string.Empty; parsingNumber = false; continue; } } if (parsingNumber) { tokens.Add(new Token() { Value = tmp, Type = TokenType.Constant }); tokens.Add(new Token() { Value = "*", Type = TokenType.Multiply }); } tokens.Add(new Token() { Value = c.ToString(), Type = TokenType.Variable }); parsingNumber = false; tmp = string.Empty; } } return tokens; } double Operate(double n1, double n2, TokenType operation, [CallerMemberName] string source = "") { switch(operation) { case TokenType.Add: ActionsListView.Items.Add($"From {source} {GetOperatorVerb(operation)} {n1} and {n2} to get {n1 + n2}"); return n1 + n2; case TokenType.Divide: ActionsListView.Items.Add($"From {source} {GetOperatorVerb(operation)} {n1} and {n2} to get {n1 / n2}"); return n1 / n2; case TokenType.Multiply: ActionsListView.Items.Add($"From {source} {GetOperatorVerb(operation)} {n1} and {n2} to get {n1 * n2}"); return n1 * n2; case TokenType.Power: ActionsListView.Items.Add($"From {source} {GetOperatorVerb(operation)} {n1} to the power of {n2} to get {Math.Pow(n1, n2)}"); return Math.Pow(n1, n2); case TokenType.Subtract: ActionsListView.Items.Add($"From {source} {GetOperatorVerb(operation)} {n1} and {n2} to get {n1 - n2}"); 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 TokenType Type; } enum TokenType { Add, Subtract, Multiply, Divide, Power, Variable, Constant, ExpStart, ExpEnd, SubScript, SuperScript, Unknown } } }