Парсер выводит пустую строку, как только встречает тригонометрию на входе
Имеется парсер, который должен различать в введённом в строку тексте математическое выражение и правильно его обрабатывать. Однако, если во вводимой строке появляется тригонометрическая функция (sin
, cos
и т.д.) то в качестве вывода программа возвращает пустую строку. Никак не получается понять, почему так происходит, подскажите пожалуйста, как исправить.
#include <iostream>
#include <cmath>
#include <map>
#include <stack>
#include <sstream>
#include <string>
#include <vector>
using namespace std;
const double PI = 3.14159265358979323846;
struct Operation {
int precedence;
double (*func)(double, double);
};
map<string, Operation> MATH = {
{"+", {1, [](double x, double y) { return x + y; }}},
{"-", {1, [](double x, double y) { return x - y; }}},
{"*", {2, [](double x, double y) { return x * y; }}},
{"/", {2, [](double x, double y) { return x / y; }}},
{"^", {3, [](double x, double y) { return pow(x, y); }}},
};
map<string, double(*)(double)> TRIGONOMETRY = {
{"sin", sin},
{"cos", cos},
{"tan", tan},
{"cot", [](double x) { return 1.0 / tan(x); }},
};
vector<string> parse(const string& formula) {
vector<string> tokens;
string number, trigonometry;
for (size_t i = 0; i < formula.size(); ++i) {
char s = formula[i];
if (isalpha(s)) {
trigonometry += s; // собираем тригонометрические функции
// Проверяем, если у нас уже есть функция
if (TRIGONOMETRY.count(trigonometry) || (i+1 == formula.size() || !isalnum(formula[i+1]))) {
tokens.push_back(trigonometry);
trigonometry = "";
}
} else if (isdigit(s) || s == '.') {
number += s;
} else {
if (!number.empty()) {
tokens.push_back(number);
number = "";
}
if (s == '(' || s == ')') {
tokens.push_back(string(1, s));
} else if (MATH.count(string(1, s))) {
tokens.push_back(string(1, s));
}
}
}
if (!number.empty()) {
tokens.push_back(number);
}
return tokens;
}
vector<string> sortfunc(const vector<string>& parsingObject) {
stack<string> stack;
vector<string> output;
for (const auto& token : parsingObject) {
if (MATH.count(token)) {
while (!stack.empty() && stack.top() != "(" &&
MATH[token].precedence <= MATH[stack.top()].precedence) {
output.push_back(stack.top());
stack.pop();
}
stack.push(token);
} else if (token == ")") {
while (!stack.empty()) {
string x = stack.top();
stack.pop();
if (x == "(") break;
output.push_back(x);
}
} else if (token == "(") {
stack.push(token);
} else {
output.push_back(token);
}
}
while (!stack.empty()) {
output.push_back(stack.top());
stack.pop();
}
return output;
}
double calculate(const vector<string>& pol) {
stack<double> stack;
for (const auto& token : pol) {
if (TRIGONOMETRY.count(token)) {
double x = stack.top();
stack.pop();
stack.push(TRIGONOMETRY[token](x));
} else if (MATH.count(token)) {
double y = stack.top();
stack.pop();
double x = stack.top();
stack.pop();
stack.push(MATH[token].func(x, y));
} else if (token == "pi") {
stack.push(PI);
} else {
stack.push(stod(token)); // Преобразование строки в число
}
}
return stack.top();
}
double evaluate(const string& formula) {
vector<string> parsed = parse(formula);
vector<string> sorted = sortfunc(parsed);
return calculate(sorted);
}
int main() {
cout << evaluate("cos(pi) + 1 * 2 ^ 2") << endl;
return 0;
}
Ответы (1 шт):
Автор решения: rost
→ Ссылка
Заменил соответствующую часть в функции parse
:
// Проверяем, если у нас уже есть функция
if (TRIGONOMETRY.count(trigonometry) || (i+1 == formula.size() || !isalnum(formula[i+1]))) {
на:
// Проверяем, если у нас уже есть функция
if (TRIGONOMETRY.count(trigonometry) || (i+1 == formula.size() || !isalnum(formula[i+1]))) {
Если всё функционирует корректно и не было изменений, то в функции double calculate(const vector<string>& pol)
строка:
double x = stack.top();
должна оставаться как есть, и любые операции с TRIGONOMETRY
должны обрабатываться.