diff --git a/Compiler/Models/Lab5/PolishNotationCalculator.cs b/Compiler/Models/Lab5/PolishNotationCalculator.cs new file mode 100644 index 0000000..68a3778 --- /dev/null +++ b/Compiler/Models/Lab5/PolishNotationCalculator.cs @@ -0,0 +1,151 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Lab5; + +public class PolishNotationCalculator +{ + public string infixExpr { get; private set; } + public string postfixExpr { get; private set; } + + private Dictionary operationPriority = new() { + {'(', 0}, + {'+', 1}, + {'-', 1}, + {'*', 2}, + {'/', 2}, + {'^', 3}, + {'~', 4} + }; + + public PolishNotationCalculator(string expression) + { + infixExpr = expression; + postfixExpr = ToPostfix(infixExpr + "\r"); + } + + private string GetStringNumber(string expr, ref int pos) + { + string strNumber = ""; + + for (; pos < expr.Length; pos++) + { + char num = expr[pos]; + + if (Char.IsDigit(num)) + strNumber += num; + else + { + pos--; + break; + } + } + + return strNumber; + } + + private string ToPostfix(string infixExpr) + { + string postfixExpr = ""; + Stack stack = new(); + + for (int i = 0; i < infixExpr.Length; i++) + { + char c = infixExpr[i]; + + if (Char.IsDigit(c)) + { + postfixExpr += GetStringNumber(infixExpr, ref i) + " "; + } + else if (c == '(') + { + stack.Push(c); + } + else if (c == ')') + { + while (stack.Count > 0 && stack.Peek() != '(') + postfixExpr += stack.Pop() + " "; + stack.Pop(); + } + else if (operationPriority.ContainsKey(c)) + { + char op = c; + if (op == '-' && (i == 0 || (i > 1 && operationPriority.ContainsKey(infixExpr[i - 1])))) + op = '~'; + + while (stack.Count > 0 && (operationPriority[stack.Peek()] >= operationPriority[op])) + postfixExpr += stack.Pop() + " "; + stack.Push(op); + } + else if (c != '\r' && c != '\n') + { + throw new ArgumentException($"Обнаружен недопустимый символ в выражении: \"{c}\""); + } + } + foreach (char op in stack) + postfixExpr += op + " "; + + return postfixExpr; + } + + private double Execute(char op, double first, double second) + { + switch (op) + { + case '+': + return first + second; + case '-': + return first - second; + case '*': + return first * second; + case '/': + if (second == 0) + { + throw new DivideByZeroException("Невозможно выполнить деление на ноль"); + } + return first / second; + case '^': + return Math.Pow(first, second); + default: + throw new ArgumentException("Недопустимая операция: " + op); + } + } + + public double Calc() + { + Stack locals = new(); + int counter = 0; + + for (int i = 0; i < postfixExpr.Length; i++) + { + char c = postfixExpr[i]; + + if (Char.IsDigit(c)) + { + string number = GetStringNumber(postfixExpr, ref i); + locals.Push(Convert.ToDouble(number)); + } + else if (operationPriority.ContainsKey(c)) + { + counter += 1; + if (c == '~') + { + double last = locals.Count > 0 ? locals.Pop() : 0; + + locals.Push(Execute('-', 0, last)); + continue; + } + + double second = locals.Count > 0 ? locals.Pop() : 0, + first = locals.Count > 0 ? locals.Pop() : 0; + + locals.Push(Execute(c, first, second)); + } + } + + return locals.Pop(); + } +} diff --git a/Compiler/ViewModels/MainWindowViewModel.cs b/Compiler/ViewModels/MainWindowViewModel.cs index e7708bd..e3495ff 100644 --- a/Compiler/ViewModels/MainWindowViewModel.cs +++ b/Compiler/ViewModels/MainWindowViewModel.cs @@ -1,7 +1,9 @@ using Microsoft.Win32; using System.Collections.ObjectModel; using System.Windows; +using Lab5; using Lab7; +using System.Linq.Expressions; namespace Compiler; @@ -49,6 +51,7 @@ public class MainWindowViewModel : ViewModelBase private RelayCommand _viewSourceCodeCommand; private RelayCommand _removeErrorsCommand; private RelayCommand _parseWhileCommand; + private RelayCommand _calculateExprCommand; public event EventHandler StringSent; public event EventHandler LexemeSent; @@ -211,6 +214,11 @@ public RelayCommand ParseWhileCommand { get => _parseWhileCommand ??= new RelayCommand(ParseWhile); } + + public RelayCommand CalculateExprCommand + { + get => _calculateExprCommand ??= new RelayCommand(CalculateExpr); + } public RelayCommand OpenFileCommand { @@ -266,6 +274,19 @@ public void ParseWhile(object obj) { VMText = _whileParser.Parse(_whileLexer.Analyze(_fileContent)); } + + public void CalculateExpr(object obj) + { + try + { + PolishNotationCalculator polishNotationCalculator = new(_fileContent.Replace("\n", "").Replace("\r", "").Replace(" ", "")); + VMText = $"Исходное арифметическое выражение:\n{polishNotationCalculator.infixExpr}\n\nВыражение в ПОЛИЗ:\n{string.Join(" ", polishNotationCalculator.postfixExpr)}\n\nОтвет: {polishNotationCalculator.Calc()}."; + } + catch (Exception ex) + { + VMText = ex.Message; + } + } public void RemoveErrors(object obj) { diff --git a/Compiler/Views/MainWindow.xaml b/Compiler/Views/MainWindow.xaml index 08dcd5d..4a51a2e 100644 --- a/Compiler/Views/MainWindow.xaml +++ b/Compiler/Views/MainWindow.xaml @@ -226,32 +226,74 @@ + + + - - + - + + + + + - -