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
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
| #include <iostream>
#include <conio.h>
#include <string>
#include <stack>
#include <queue>
using namespace std;
int end() { cout << "\nEND\n"; _getch(); return 0; }
queue<char> to_revpol(const string& in)
{
stack<char> stk;//создаем стак для хранения временных операция
queue<char> gen;//создаем очередь, куда все будем пихать
for(auto i : in)//идем по строке
{
if(i == '.')//если это просто точка, т.е. пользователь ввел число по типу 0.2,
gen.push(i);//то тупо пихаем её внутрь
else if((i >= '0' && i <= '9') ||//если это число или переменная, то тоже просто запихиваем
(i >= 'a' && i <= 'z') ||
(i >= 'A' && i <= 'Z'))
{
if(gen.empty() != true &&
(gen.back() >= '0' && gen.back() <= '9') &&
!(i >= '0' && i <= '9'))
{ stk.push('*'); gen.push(';'); }//эта хрень нужна чтобы можно было не ставить знак умножения перед переменной при вводе 5x, например
gen.push(i);
}
else if
(i == '+' || i == '-' ||//если же это операция
i == '*' || i == '/')
{
if(stk.empty() != true && (stk.top() == '*' || stk.top() == '/'))//если у нас что-то есть и последняя оперцаия была * или /, то...
{
if(i == '*' || i == '/')//если сейчас умножаем или делим
{
gen.push(stk.top());//то можно выгрузить предыдущую операцию
stk.top() = i;//и заменить её
}
else if(i == '+' || i == '-')//если же это была оперция меньшего приоритета, т.е. + или -
{
while(stk.empty() != true && stk.top() != '(')//следует выгрузить все до открывающейся скобки, либо пока стек не опустеет
{//зачем? А переведите на ОПН такое: a * b + c. Тут роль скобочки играет главное тело.
gen.push(stk.top());
stk.pop();
}
stk.push(i);
}
}
else//если же стек пуст или последняя операция была не * или /, то...
{
if(gen.empty() != true && (
(gen.back() >= '0' && gen.back() <= '9') ||
(gen.back() >= 'a' && gen.back() <= 'z') ||
(gen.back() >= 'A' && gen.back() <= 'Z')))//если последнее, что было в gen - переменная или цифра,
gen.push(';');//то следует поставить ограничивающий знак
else if(((stk.empty() != true && stk.top() == '(') || gen.empty() == true) && i == '-')//иначе,
gen.push('_');//если стек не пуст и последнее, что в него запили была открывающая скобка, либо у нас вообще пока ничего нет, а i == -, то я вставляю знак _
//зачем? Ну, для того чтобы все не ломалось при таком вводе: -5 + 3 или 4 * (-2 + 1)
if(gen.back() != '_')//если последнее в gen не _, которые мы могли только что записать => это какая-то операция
stk.push(i);
}
}
else if(i == '(')//если же у нас не цифра, не переменная и не операция, а откр. скобка, то...
{
if(gen.empty() != true && (
(gen.back() >= '0' && gen.back() <= '9') ||
(gen.back() >= 'a' && gen.back() <= 'z') ||
(gen.back() >= 'A' && gen.back() <= 'Z')))//если последнее что было в gen - переменная или цифра,
{
gen.push(';');//ставим ограничивающий знак, а в стек записываем *
stk.push('*');//Опять же, зачем? А затем, чтобы не ставить его самим при записи типа: 23(13 + 1), например
}
stk.push(i);//запихиваем ( в стэк
}
else if(i == ')')//если же у нас закрылась скобка, следует выгрущить все операции из stk в gen
{
while(stk.empty() != true && stk.top() != '(')//пока стек не пустой (если он опустел значит пользователь ввел неправильное выражение) и до, конечно, открывающийся скобки
{
gen.push(stk.top());
stk.pop();
}
if(stk.empty() != true)
stk.pop();
else
throw "WRONG INPUT! Missing (";//кидаем исключение, если пользователь был не очень внимателен
}
}
while(stk.empty() != true)//по окончанию работы со строкой в стеке может что-то остаться, потому
{//выносим все что осталось.
gen.push(stk.top());
stk.pop();
}
return gen;//и возвращаем результат
}
double calc(queue<char> in)
{
stack<double> res;//временное хранилище значений
bool minus = false, op = false;//флаги на минус, либо на оперцию
size_t fl = 0;//переменная для правильного ввода значений с плавающей точкой
double temp;//и просто временная переменная
res.push(0.0);//добавляем одно значение
while(in.empty() != true)//пока очередь не опустеет
{
if(in.front() == '_')//если встретился знак _, значит был ввод типа: -3 + 2 или 5 * (-4 + 3) и т.д.
{
minus = true;//поднимаем флаг минуса
in.pop();//убираем эл.
}
else if(in.front() >= '0' && in.front() <= '9')//если получили цифру
{
if(op == true) { res.push(0.0); op = false; }//если была какая-то операция и сейчас нам нужно записать новое значение, то добавляем память и опускаем флаг
while(in.empty() != true && in.front() >= '0' && in.front() <= '9')//пока в очереди что-то есть и пока это цифры
{
if((in.front() == '0' && res.top() == 0.0) == false)//чтобы не умножать 0 на 10 и не прибавлять (48 - 48)
{
if(fl == 0)//если не встречалось ., т.е. пока у нас обычное, целое число
{
res.top() = res.top() * 10 + in.front() - 48;
}
else//иначе
{
temp = in.front() - 48;//переводим символьное число в обычное
for(size_t i = 0; i < fl; i++)//и по счетчику разряда делим на 10
temp /= 10;
res.top() += temp;//и просто добавляем к текущему
fl++;//увеличиваем разряд
}
}
in.pop();//убираем эл.
if(in.empty() != true && in.front() == '.')//если встретилась точка и очередь не пуста, то
{
fl = 1;//счетчик разряда ставим в 1
in.pop();//и удаляем .
}
}
fl = 0;//после считывания числа, обнуляем счетчик разрядов
}
else if((in.front() >= 'a' && in.front() <= 'z') || (in.front() >= 'A' && in.front() <= 'Z'))//если же нам встретилась переменная
{
cout << "Please enter the variable \'";//просим пользователя её ввести
do
{//выводим название переменной. А выводим в цикле за тем, чтобы можно было писать переменные не в одну букву
cout << in.front();
in.pop();
}while(in.empty() != true && (in.front() >= 'a' && in.front() <= 'z') || (in.front() >= 'A' && in.front() <= 'Z'));
cout << "\': ";
if(op == true) { res.push(0.0); op = false;}//если до этого была операция, а теперь нам нужно ввести новое значение, то выделяем память
cin >> res.top();//вводим значение переменной с клавиатуры
}
else if(in.front() == ';' ||
in.front() == '+' || in.front() == '-' ||
in.front() == '*' || in.front() == '/')//если же нам наконец попалась операция
{
if(minus == true)//если флаг минуса поднят
{
minus = false;//опускаем флаг
res.top() = -res.top();//умножаем текущее значение на -1
}
if(in.front() == ';')//если это знак разделитель, значит надо добавить памяти
{
res.push(0.0);//добавляем
in.pop();//убираем знак
}
else if(res.size() > 1)//иначе, если у нас уже что-то есть в стеке
{
temp = res.top();//пихаем в temp последнее значение
res.pop();//убираем его из стека
switch(in.front())//смотрим что это и делаем необходимые операции
{
case '+':
res.top() += temp;
break;
case '-':
res.top() -= temp;
break;
case '*':
res.top() *= temp;
break;
case '/':
res.top() /= temp;
break;
}
op = true;//ставим флаг операции
in.pop();//убираем символ операции из очереди
}
}
}
if(res.size() > 1)//если вдруг в стеке осталось что-то кроме результата, выводим сообщение об ошибке и все, что осталось в стеке
{
cout << "something went wrong!";
while(res.empty() != true)
{
cout << res.top() << ' ';
res.pop();
}
return 0.0;
}
return res.top();//если же все хорошо, возвращаем результат
}
template <class T>
ostream& operator<<(ostream& out, queue<T> cs)
{
while(cs.empty() != true)
{
out << cs.front();
cs.pop();
}
return out;
}
int main()
{
string in;
queue<char> gen;
cout << "Enter an expression:\n";
getline(cin, in);
gen = to_revpol(in);
cout << "Result of the function to_revpol: " << gen << endl;
cout << "Final result: " << calc(gen);
return end();
} |