-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathKalkulation.cpp
204 lines (170 loc) · 6.5 KB
/
Kalkulation.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
#include <iostream>
#include <string>
#include <cctype>
#include <locale>
#include <stdexcept>
double expression(const char*& expressionToParse);
// Возвращает текущий символ в выражении, не изменяя указатель
char peek(const char* expressionToParse) {
return *expressionToParse;
}
// Возвращает текущий символ и продвигает указатель вперёд
char get(const char*& expressionToParse) {
return *expressionToParse++;
}
// Обрабатывает ошибку, выбрасывая исключение с заданным сообщением
void handleError(const std::string& message) {
throw std::runtime_error("Ошибка: " + message);
}
// Парсит число из выражения и продвигает указатель
double number(const char*& expressionToParse) {
// Используется std::stod для конвертации подстроки в число с плавающей точкой
double result = std::stod(std::string(expressionToParse));
// Продвигаем указатель до тех пор, пока символы являются цифрами или точкой
while (std::isdigit(peek(expressionToParse)) || peek(expressionToParse) == '.') {
get(expressionToParse);
}
return result;
}
// Обрабатывает фактор в выражении (число, унарный минус или выражение в скобках)
double factor(const char*& expressionToParse) throw(std::runtime_error) {
// Если текущий символ - минус, обрабатываем унарный минус
if (peek(expressionToParse) == '-') {
get(expressionToParse);
return -number(expressionToParse);
}
// Если текущий символ - плюс, обрабатываем сообщение "Партия гордится тобой!"
else if (peek(expressionToParse) == '+' && peek(expressionToParse++) == '+') {
handleError("Партия гордится тобой!");
return 0;
}
// Если текущий символ - цифра, обрабатываем число
else if (std::isdigit(peek(expressionToParse))) {
return number(expressionToParse);
}
// Если текущий символ - открывающая скобка, обрабатываем выражение в скобках
else if (peek(expressionToParse) == '(') {
get(expressionToParse);
double result = expression(expressionToParse);
// Проверяем наличие закрывающей скобки
if (peek(expressionToParse) != ')') {
handleError("Отсутствует закрывающая скобка");
return 0;
}
get(expressionToParse); // Продвигаем указатель на символ после закрывающей скобки
return result;
}
throw std::runtime_error("Неверный формат выражения");
}
// Обрабатывает терм в выражении (умножение и деление)
double term(const char*& expressionToParse) {
// Обрабатываем первый фактор
double result = factor(expressionToParse);
// Продолжаем обработку, пока есть умножение или деление
while (peek(expressionToParse) == '*' || peek(expressionToParse) == '/') {
char op = get(expressionToParse);
double nextFactor = factor(expressionToParse);
// Выполняем умножение или деление в зависимости от оператора
if (op == '*') {
result *= nextFactor;
}
else if (nextFactor != 0) {
result /= nextFactor;
}
else {
handleError("Деление на ноль");
return 0;
}
}
return result;
}
// Обрабатывает выражение (сложение и вычитание)
double expression(const char*& expressionToParse) {
// Обрабатываем первый терм
double result = term(expressionToParse);
// Продолжаем обработку, пока есть сложение или вычитание
while (peek(expressionToParse) == '+' || peek(expressionToParse) == '-') {
char op = get(expressionToParse);
double nextTerm = term(expressionToParse);
// Выполняем сложение или вычитание в зависимости от оператора
if (op == '+') {
result += nextTerm;
}
else {
result -= nextTerm;
}
}
return result;
}
// Удаляет пробелы из строки
void removeSpaces(std::string& str) {
std::locale loc("");
// Используем erase и remove_if для удаления пробелов из строки
str.erase(std::remove_if(str.begin(), str.end(), [&loc](unsigned char c) {
return std::isspace(c, loc);
}), str.end());
}
// Проверяет, является ли символ допустимым в выражении
bool isValidSymbol(char c) {
return std::isdigit(c) || c == '+' || c == '-' || c == '*' || c == '/' || c == '(' || c == ')' || c == '.';
}
// Проверяет, содержит ли строка только допустимые символы
bool isValidExpression(const std::string& str) {
// Проверяем каждый символ в строке
for (char c : str) {
if (!isValidSymbol(c)) {
return false;
}
}
return true;
}
// Получает ввод выражения от пользователя
std::string getInputExpression() {
std::cout << ">_ ";
std::string userInput;
// Получаем строку ввода от пользователя с помощью std::getline
std::getline(std::cin, userInput);
return userInput;
}
// Основная функция программы
int main() {
// Устанавливаем кодировку для корректного отображения кириллических символов в консоли
system("chcp 1251");
std::cout << "Введите арифметическое выражение:\n";
// Основной цикл программы
while (true) {
// Получаем ввод выражения от пользователя
std::string userInput = getInputExpression();
// Проверяем, если введена пустая строка, завершаем программу
if (userInput.empty()) {
std::cout << "До встречи!" << std::endl;
break;
}
// Удаляем пробелы из введённой строки
removeSpaces(userInput);
// Проверяем, содержит ли строка только допустимые символы
if (!isValidExpression(userInput)) {
std::cerr << "Ошибка: Введены недопустимые символы. Пожалуйста, введите выражение заново." << std::endl;
continue;
}
// Преобразуем строку в массив символов для обработки
const char* expressionToParse = userInput.c_str();
try {
// Вычисляем результат выражения
double result = expression(expressionToParse);
// Проверяем на переполнение
if (std::isinf(result)) {
std::cout << "Переполнение" << std::endl;
}
else {
std::cout << "Результат: " << result << std::endl;
}
}
// Обрабатываем исключения, возникающие при ошибках в выражении
catch (const std::exception& e) {
std::cerr << e.what() << std::endl;
continue;
}
}
return 0;
}