From 475556a43032be22c82a3fa5d6f6bec8f49b2c21 Mon Sep 17 00:00:00 2001 From: cheeseandmacaroni Date: Tue, 16 Nov 2021 11:15:14 +0300 Subject: [PATCH 1/4] first --- src/Source.cpp | 324 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 324 insertions(+) create mode 100644 src/Source.cpp diff --git a/src/Source.cpp b/src/Source.cpp new file mode 100644 index 0000000..bea2d4b --- /dev/null +++ b/src/Source.cpp @@ -0,0 +1,324 @@ +#include +#include +#include +using namespace std; + +// Document, standart +// компилятор +// gcc +// mvsc, gcc, clang, icc + +// Арифмитические выражения +// Калькулятор +// input data: +// std::string, арифмитическое выражение вида: 7+3-2-(-5)*4+3^2 +// output data: +// 1. проверка корректности выражения: ++)2(-3532-5+3)(25235++2352(35---235 +// 2. вычислить выражение +// список поддерживаемых операций (+,-,*,/,^, un -) и фич (поддержка переменных x, y, z; +// поддержка функций sin, cos, ...; поддержка десятичных дробей 3.14) + +// арифмитические знаки ~ оператор +// бинарный оператор f // (a1, a2) +// унарный оператор f // (a1) +// тернарный оператор f // (a1, a2, a3) +// ... +// число, переменная или выражение ~ операнд +// 123, x, (sin(7)*2+3) + +// Текущее состояние ~ текущая, обрабатываемая лексема. + + +// первый в выражении: +// унарный оператор или операнд или ( + +// унарный оператор, что может идти за ним? +// (, операнд + +// операнд (число, переменная), что может идти за ним? +// бинарный оператор, ), конец выражения + + +// бинарный оператор (+, -, /, *, ^), что может идти за ним? +// операнд, ( + +// "(" что может идти за ней? +// опернад, унарный оператор + +enum class TypeLexeme +{ + number, + variable, + un_op, + bin_op, + left_bracket, + right_bracket, + sin, + cos, + error +}; + +enum class Priority +{ + number, + bracket, + low, + mid, + high +}; + +struct Lexeme +{ + TypeLexeme type; + std::string value; + Priority priority; +}; + +enum class LexemeState +{ + start, + number, + variable, + un_op, + bin_op, + left_bracket, + right_bracket, + end, + sincos, + error +}; + +Lexeme convertToLexeme(const std::string &expression, size_t &index, LexemeState state) +{ + std::string value; + if (expression[index] >= '0' && expression[index] <= '9') + { + if (expression[index + 1] == '0') + { + value.push_back('0'); + ++index; + return Lexeme({ TypeLexeme::number, value, Priority::number }); + } + while (expression[index] >= '0' && expression[index] <= '9') + { + value.push_back(expression[index]); + ++index; + } + return Lexeme({ TypeLexeme::number, value, Priority::number }); + } + else if (expression[index] == '*' || expression[index] == '/') + { + value.push_back(expression[index]); + index++; + return Lexeme({ TypeLexeme::bin_op, value, Priority::mid }); + } + else if (expression[index] == '^') + { + value.push_back(expression[index]); + index++; + return Lexeme({ TypeLexeme::bin_op, value, Priority::high }); + } + else if (expression[index] == '+' || (expression[index] == '-' && (state == LexemeState::variable || state == LexemeState::number || state == LexemeState::right_bracket))) + { + value.push_back(expression[index]); + index++; + return Lexeme({ TypeLexeme::bin_op, value, Priority::low }); + } + else if (expression[index] == '-' && (state == LexemeState::left_bracket || state == LexemeState::start)) + { + value.push_back(expression[index]); + index++; + return Lexeme({ TypeLexeme::un_op, value, Priority::high }); + } + else if (expression[index] == '(' && (state == LexemeState::sincos || state == LexemeState::bin_op || state == LexemeState::start || state == LexemeState::un_op)) + { + value.push_back(expression[index]); + index++; + return Lexeme({ TypeLexeme::left_bracket, value, Priority::bracket }); + } + else if (expression[index] == ')' && (state == LexemeState::variable || state == LexemeState::number)) + { + value.push_back(expression[index]); + index++; + return Lexeme({ TypeLexeme::right_bracket, value, Priority::bracket }); + } + else if ((expression.substr(index, 3) == "sin" || expression.substr(index, 3) == "cos") && (state == LexemeState::un_op || state == LexemeState::left_bracket || state == LexemeState::bin_op || state == LexemeState::start)) + { + if (expression.substr(index, 3) == "sin") + { + value = "sin"; + index += 3; + return Lexeme({ TypeLexeme::sin, value, Priority::high }); + } + else if (expression.substr(index, 3) == "cos") + { + value = "cos"; + index += 3; + return Lexeme({ TypeLexeme::cos, value, Priority::high }); + } + } + else if (expression[index] >= 'a' && expression[index] <= 'z') + { + value.push_back(expression[index]); + index++; + return Lexeme({ TypeLexeme::variable, value, Priority::low }); + } + return Lexeme({ TypeLexeme::error, value, Priority::low }); +} + +// все лексемы состоят из одного символа, то есть число 12345 недопустимо +// нужно проконтролировать корректность скобок +// счетчик скобок scopeCounter +// if (scope == '(') scopeCounter++; +// if (scope == ')') scopeCounter--; +// в каждый момент scopeCounter >= 0 +// (()))( +std::vector convertStrToLexemes(const std::string& expression) +{ + int scopeCounter = 0; + std::vector res; + LexemeState state = LexemeState::start; + size_t index = 0; + while (index < expression.size()) + { + const Lexeme lexeme = convertToLexeme(expression, index, state); + if (state == LexemeState::start) + { + if (lexeme.type == TypeLexeme::un_op) + { + state = LexemeState::un_op; + } + else if (lexeme.type == TypeLexeme::variable || lexeme.type == TypeLexeme::number) + { + state = LexemeState::variable; + } + else if (lexeme.type == TypeLexeme::left_bracket) + { + state = LexemeState::left_bracket; + scopeCounter++; + } + else if (lexeme.type == TypeLexeme::sin || lexeme.type == TypeLexeme::cos) + { + state = LexemeState::sincos; + } + else throw "Error: invalid expression format (start lexeme is incorrect)"; + } + else if (state == LexemeState::un_op) + { + if (lexeme.type == TypeLexeme::variable || lexeme.type == TypeLexeme::number) + { + state = LexemeState::variable; + } + else if (lexeme.type == TypeLexeme::sin || lexeme.type == TypeLexeme::cos) + { + state = LexemeState::sincos; + } + else if (lexeme.type == TypeLexeme::left_bracket) + { + state = LexemeState::left_bracket; + scopeCounter++; + } + else throw "Error: invalid expression after unary operator"; + } + else if (state == LexemeState::variable) + { + if (lexeme.type == TypeLexeme::bin_op) + { + state = LexemeState::bin_op; + } + else if (lexeme.type == TypeLexeme::right_bracket) + { + state = LexemeState::right_bracket; + scopeCounter--; + } + else throw "Error: invalid expression after a variable"; + } + else if (state == LexemeState::bin_op) + { + if (lexeme.type == TypeLexeme::variable || lexeme.type == TypeLexeme::number) + { + state = LexemeState::variable; + } + else if (lexeme.type == TypeLexeme::left_bracket) + { + state = LexemeState::left_bracket; + scopeCounter++; + } + else if (lexeme.type == TypeLexeme::sin || lexeme.type == TypeLexeme::cos) + { + state = LexemeState::sincos; + } + else throw "Error: invalid expression after a binary operator"; + } + else if (state == LexemeState::left_bracket) + { + if (lexeme.type == TypeLexeme::left_bracket) + { + state = LexemeState::left_bracket; + scopeCounter++; + } + else if (lexeme.type == TypeLexeme::un_op) + { + state = LexemeState::un_op; + } + else if (lexeme.type == TypeLexeme::variable || lexeme.type == TypeLexeme::number) + { + state = LexemeState::variable; + } + else if (lexeme.type == TypeLexeme::sin || lexeme.type == TypeLexeme::cos) + { + state = LexemeState::sincos; + } + else throw "Error: invalid expression after a left bracket"; + } + else if (state == LexemeState::right_bracket) + { + if (lexeme.type == TypeLexeme::right_bracket) + { + state = LexemeState::right_bracket; + scopeCounter--; + } + else if (lexeme.type == TypeLexeme::bin_op) + { + state = LexemeState::bin_op; + } + else throw "Error: invalid expression after a right bracket"; + } + else if (state == LexemeState::sincos) + { + if (lexeme.type == TypeLexeme::variable) + { + state = LexemeState::variable; + } + else if (lexeme.type == TypeLexeme::left_bracket) + { + state = LexemeState::left_bracket; + scopeCounter++; + } + else throw "Error: invalid sin/cos argument"; + } + else if (scopeCounter < 0) throw "Error: brackets are out of order"; + else throw "error"; + res.push_back(lexeme); + } + return res; +} + +// 2^3/4 + +int main() +{ + std::vector test = convertStrToLexemes("-3+19*sin(x)+(-3)+18*cos(2398)"); + for (int i = 0; i < test.size(); i++) + { + std::cout << test[i].value << '\t' << static_cast(test[i].type) << std::endl; + } + getchar(); + return 0; +} + +// API +bool check_arithmetic_expression(const std::string& s) +{ + return false; +} From 04be14f721df9216a7e9bfe86e2eb8e79f7844ad Mon Sep 17 00:00:00 2001 From: cheeseandmacaroni Date: Mon, 29 Nov 2021 13:29:54 +0300 Subject: [PATCH 2/4] first version --- src/Source.cpp | 225 +++++++++++++++++++++++++++++++------------------ 1 file changed, 142 insertions(+), 83 deletions(-) diff --git a/src/Source.cpp b/src/Source.cpp index bea2d4b..cd9044a 100644 --- a/src/Source.cpp +++ b/src/Source.cpp @@ -1,50 +1,12 @@ #include #include #include +#include +#include using namespace std; -// Document, standart -// компилятор -// gcc -// mvsc, gcc, clang, icc - -// Арифмитические выражения -// Калькулятор -// input data: -// std::string, арифмитическое выражение вида: 7+3-2-(-5)*4+3^2 -// output data: -// 1. проверка корректности выражения: ++)2(-3532-5+3)(25235++2352(35---235 -// 2. вычислить выражение -// список поддерживаемых операций (+,-,*,/,^, un -) и фич (поддержка переменных x, y, z; -// поддержка функций sin, cos, ...; поддержка десятичных дробей 3.14) - -// арифмитические знаки ~ оператор -// бинарный оператор f // (a1, a2) -// унарный оператор f // (a1) -// тернарный оператор f // (a1, a2, a3) -// ... -// число, переменная или выражение ~ операнд -// 123, x, (sin(7)*2+3) - -// Текущее состояние ~ текущая, обрабатываемая лексема. - - -// первый в выражении: -// унарный оператор или операнд или ( - -// унарный оператор, что может идти за ним? -// (, операнд - -// операнд (число, переменная), что может идти за ним? -// бинарный оператор, ), конец выражения - - -// бинарный оператор (+, -, /, *, ^), что может идти за ним? -// операнд, ( - -// "(" что может идти за ней? -// опернад, унарный оператор - +//оператор ^ не работает корректно не учтена правая ассоциативность +//для корректной работы используйте скобки: 2^(3^2) вместо 2^3^2 enum class TypeLexeme { number, @@ -53,8 +15,6 @@ enum class TypeLexeme bin_op, left_bracket, right_bracket, - sin, - cos, error }; @@ -84,10 +44,9 @@ enum class LexemeState left_bracket, right_bracket, end, - sincos, error }; - +bool check_arithmetic_expression(const std::string& s); Lexeme convertToLexeme(const std::string &expression, size_t &index, LexemeState state) { std::string value; @@ -130,13 +89,13 @@ Lexeme convertToLexeme(const std::string &expression, size_t &index, LexemeState index++; return Lexeme({ TypeLexeme::un_op, value, Priority::high }); } - else if (expression[index] == '(' && (state == LexemeState::sincos || state == LexemeState::bin_op || state == LexemeState::start || state == LexemeState::un_op)) + else if (expression[index] == '(' && (state == LexemeState::bin_op || state == LexemeState::start || state == LexemeState::un_op)) { value.push_back(expression[index]); index++; return Lexeme({ TypeLexeme::left_bracket, value, Priority::bracket }); } - else if (expression[index] == ')' && (state == LexemeState::variable || state == LexemeState::number)) + else if (expression[index] == ')' && (state == LexemeState::variable || state == LexemeState::number || state == LexemeState::right_bracket)) { value.push_back(expression[index]); index++; @@ -148,13 +107,13 @@ Lexeme convertToLexeme(const std::string &expression, size_t &index, LexemeState { value = "sin"; index += 3; - return Lexeme({ TypeLexeme::sin, value, Priority::high }); + return Lexeme({ TypeLexeme::un_op, value, Priority::high }); } else if (expression.substr(index, 3) == "cos") { value = "cos"; index += 3; - return Lexeme({ TypeLexeme::cos, value, Priority::high }); + return Lexeme({ TypeLexeme::un_op, value, Priority::high }); } } else if (expression[index] >= 'a' && expression[index] <= 'z') @@ -166,13 +125,6 @@ Lexeme convertToLexeme(const std::string &expression, size_t &index, LexemeState return Lexeme({ TypeLexeme::error, value, Priority::low }); } -// все лексемы состоят из одного символа, то есть число 12345 недопустимо -// нужно проконтролировать корректность скобок -// счетчик скобок scopeCounter -// if (scope == '(') scopeCounter++; -// if (scope == ')') scopeCounter--; -// в каждый момент scopeCounter >= 0 -// (()))( std::vector convertStrToLexemes(const std::string& expression) { int scopeCounter = 0; @@ -197,10 +149,6 @@ std::vector convertStrToLexemes(const std::string& expression) state = LexemeState::left_bracket; scopeCounter++; } - else if (lexeme.type == TypeLexeme::sin || lexeme.type == TypeLexeme::cos) - { - state = LexemeState::sincos; - } else throw "Error: invalid expression format (start lexeme is incorrect)"; } else if (state == LexemeState::un_op) @@ -209,9 +157,9 @@ std::vector convertStrToLexemes(const std::string& expression) { state = LexemeState::variable; } - else if (lexeme.type == TypeLexeme::sin || lexeme.type == TypeLexeme::cos) + else if (lexeme.type == TypeLexeme::un_op) { - state = LexemeState::sincos; + state = LexemeState::un_op; } else if (lexeme.type == TypeLexeme::left_bracket) { @@ -244,9 +192,9 @@ std::vector convertStrToLexemes(const std::string& expression) state = LexemeState::left_bracket; scopeCounter++; } - else if (lexeme.type == TypeLexeme::sin || lexeme.type == TypeLexeme::cos) + else if (lexeme.type == TypeLexeme::un_op) { - state = LexemeState::sincos; + state = LexemeState::un_op; } else throw "Error: invalid expression after a binary operator"; } @@ -265,9 +213,9 @@ std::vector convertStrToLexemes(const std::string& expression) { state = LexemeState::variable; } - else if (lexeme.type == TypeLexeme::sin || lexeme.type == TypeLexeme::cos) + else if (lexeme.type == TypeLexeme::un_op) { - state = LexemeState::sincos; + state = LexemeState::un_op; } else throw "Error: invalid expression after a left bracket"; } @@ -284,36 +232,147 @@ std::vector convertStrToLexemes(const std::string& expression) } else throw "Error: invalid expression after a right bracket"; } - else if (state == LexemeState::sincos) + else if (scopeCounter < 0) throw "Error: brackets are out of order"; + else throw "error"; + res.push_back(lexeme); + } + return res; +} + +std::vector reverse_Polish_notation(const std::vector &src) +{ + std::vector out; + std::stack op_stack; + for (const Lexeme &lex : src) + { + if (lex.type == TypeLexeme::variable || lex.type == TypeLexeme::number) + { + out.push_back(lex); + } + else if (lex.type == TypeLexeme::left_bracket || lex.type == TypeLexeme::un_op) + { + op_stack.push(lex); + } + else if (lex.type == TypeLexeme::right_bracket) { - if (lexeme.type == TypeLexeme::variable) + while (!op_stack.empty() && (op_stack.top().type != TypeLexeme::left_bracket)) { - state = LexemeState::variable; + out.push_back(op_stack.top()); + op_stack.pop(); } - else if (lexeme.type == TypeLexeme::left_bracket) + op_stack.pop(); + } + else if (lex.type == TypeLexeme::bin_op) + { + while (!op_stack.empty() && (op_stack.top().type == TypeLexeme::un_op || op_stack.top().priority >= lex.priority)) { - state = LexemeState::left_bracket; - scopeCounter++; + out.push_back(op_stack.top()); + op_stack.pop(); } - else throw "Error: invalid sin/cos argument"; + op_stack.push(lex); } - else if (scopeCounter < 0) throw "Error: brackets are out of order"; - else throw "error"; - res.push_back(lexeme); } - return res; + while (!op_stack.empty()) + { + out.push_back(op_stack.top()); + op_stack.pop(); + } + return out; } -// 2^3/4 +double calc_rpn(std::vector &src_rpn) +{ + std::stack tmp_stack; + for (size_t i = 0; i < src_rpn.size(); ++i) + { + if (src_rpn[i].type == TypeLexeme::un_op) + { + if (src_rpn[i].value == "-") + { + double operand = tmp_stack.top(); + tmp_stack.pop(); + tmp_stack.push(-operand); + } + else if (src_rpn[i].value == "sin") + { + double operand = tmp_stack.top(); + tmp_stack.pop(); + tmp_stack.push(sin(operand)); + } + else if (src_rpn[i].value == "cos") + { + double operand = tmp_stack.top(); + tmp_stack.pop(); + tmp_stack.push(cos(operand)); + } + } + else if (src_rpn[i].type == TypeLexeme::number || src_rpn[i].type == TypeLexeme::variable) + { + tmp_stack.push(stoi(src_rpn[i].value)); + } + else if (src_rpn[i].type == TypeLexeme::bin_op) + { + double second_operand = tmp_stack.top(); + tmp_stack.pop(); + double first_operand = tmp_stack.top(); + tmp_stack.pop(); + if (src_rpn[i].value == "+") + { + tmp_stack.push(first_operand + second_operand); + } + else if (src_rpn[i].value == "-") + { + tmp_stack.push(first_operand - second_operand); + } + else if (src_rpn[i].value == "*") + { + tmp_stack.push(first_operand * second_operand); + } + else if (src_rpn[i].value == "^") + { + tmp_stack.push(std::pow(first_operand, second_operand)); + } + else if (src_rpn[i].value == "/") + { + if (second_operand == 0) throw "Division by zero"; + tmp_stack.push(first_operand / second_operand); + } + } + } + return tmp_stack.top(); +} int main() { - std::vector test = convertStrToLexemes("-3+19*sin(x)+(-3)+18*cos(2398)"); - for (int i = 0; i < test.size(); i++) + std::string expression("-3+19^5*(-sin(x))-(-3)+18*cos(y)"); + std::vector lexems = convertStrToLexemes(expression); + std::set variables; + for (size_t i = 0; i < lexems.size(); ++i) + { + if (lexems[i].type == TypeLexeme::variable) + { + variables.insert(lexems[i].value[0]); + } + } + std::set::iterator it = variables.begin(); + while (it != variables.end()) { - std::cout << test[i].value << '\t' << static_cast(test[i].type) << std::endl; + double variable_value; + std::cout << "Enter the value of " << *it << ": " << std::endl; + std::cin >> variable_value; + for (size_t j = 0; j < lexems.size(); ++j) + { + if (lexems[j].value[0] == *it) + { + lexems[j].value = std::to_string(variable_value); + lexems[j].type = TypeLexeme::number; + } + } + it++; } - getchar(); + std::vector RPN = reverse_Polish_notation(lexems); + std::cout << calc_rpn(RPN); + system("pause"); return 0; } From 39e138b5ac148cfbbd35ddeb4cb6139d1500fe1d Mon Sep 17 00:00:00 2001 From: cheeseandmacaroni Date: Tue, 14 Dec 2021 22:32:48 +0300 Subject: [PATCH 3/4] simplified conditions --- src/Source.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Source.cpp b/src/Source.cpp index cd9044a..c919c16 100644 --- a/src/Source.cpp +++ b/src/Source.cpp @@ -47,7 +47,7 @@ enum class LexemeState error }; bool check_arithmetic_expression(const std::string& s); -Lexeme convertToLexeme(const std::string &expression, size_t &index, LexemeState state) +Lexeme convertToLexeme(const std::string &expression, size_t &index) { std::string value; if (expression[index] >= '0' && expression[index] <= '9') @@ -77,31 +77,31 @@ Lexeme convertToLexeme(const std::string &expression, size_t &index, LexemeState index++; return Lexeme({ TypeLexeme::bin_op, value, Priority::high }); } - else if (expression[index] == '+' || (expression[index] == '-' && (state == LexemeState::variable || state == LexemeState::number || state == LexemeState::right_bracket))) + else if (expression[index] == '+' || expression[index] == '-' ) { value.push_back(expression[index]); index++; return Lexeme({ TypeLexeme::bin_op, value, Priority::low }); } - else if (expression[index] == '-' && (state == LexemeState::left_bracket || state == LexemeState::start)) + else if (expression[index] == '-') { value.push_back(expression[index]); index++; return Lexeme({ TypeLexeme::un_op, value, Priority::high }); } - else if (expression[index] == '(' && (state == LexemeState::bin_op || state == LexemeState::start || state == LexemeState::un_op)) + else if (expression[index] == '(') { value.push_back(expression[index]); index++; return Lexeme({ TypeLexeme::left_bracket, value, Priority::bracket }); } - else if (expression[index] == ')' && (state == LexemeState::variable || state == LexemeState::number || state == LexemeState::right_bracket)) + else if (expression[index] == ')') { value.push_back(expression[index]); index++; return Lexeme({ TypeLexeme::right_bracket, value, Priority::bracket }); } - else if ((expression.substr(index, 3) == "sin" || expression.substr(index, 3) == "cos") && (state == LexemeState::un_op || state == LexemeState::left_bracket || state == LexemeState::bin_op || state == LexemeState::start)) + else if (expression.substr(index, 3) == "sin" || expression.substr(index, 3) == "cos") { if (expression.substr(index, 3) == "sin") { From 03d079bb8fa902a1d085ce75bd6354d50141e3e0 Mon Sep 17 00:00:00 2001 From: cheeseandmacaroni Date: Tue, 14 Dec 2021 22:35:34 +0300 Subject: [PATCH 4/4] simplified conditions --- src/Source.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Source.cpp b/src/Source.cpp index c919c16..ca779dc 100644 --- a/src/Source.cpp +++ b/src/Source.cpp @@ -47,7 +47,7 @@ enum class LexemeState error }; bool check_arithmetic_expression(const std::string& s); -Lexeme convertToLexeme(const std::string &expression, size_t &index) +Lexeme convertToLexeme(const std::string &expression, size_t &index, LexemeState state) { std::string value; if (expression[index] >= '0' && expression[index] <= '9') @@ -77,13 +77,13 @@ Lexeme convertToLexeme(const std::string &expression, size_t &index) index++; return Lexeme({ TypeLexeme::bin_op, value, Priority::high }); } - else if (expression[index] == '+' || expression[index] == '-' ) + else if (expression[index] == '+' || (expression[index] == '-' && (state == LexemeState::variable || state == LexemeState::number || state == LexemeState::right_bracket))) { value.push_back(expression[index]); index++; return Lexeme({ TypeLexeme::bin_op, value, Priority::low }); } - else if (expression[index] == '-') + else if (expression[index] == '-' && (state == LexemeState::left_bracket || state == LexemeState::start)) { value.push_back(expression[index]); index++;