Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <bits/stdc++.h>
- using namespace std;
- class Parser{
- static vector < string > get_parameters(string &expression){
- /// Функція, яка повертатиме список параметрів, які були передані в операцію.
- size_t i = 0;
- while (expression[i] != '(') i ++;
- string tmp = "";
- vector < string > res;
- int scope = 0;
- for (size_t j=i+1; j<expression.length()-1; j++){
- if (expression[j] == ',' && scope == 0){
- res.push_back(tmp);
- tmp = "";
- }else{
- tmp += expression[j];
- if (expression[j] == '(') scope ++;
- else if (expression[j] == ')') scope --;
- }
- }
- res.push_back(tmp);
- return res;
- }
- public:
- static string parse(string &expression){
- /// Для початку, видалимо всі пробіли, щоб не заважали.
- string tmp = "";
- for (char &c: expression){
- if (c != ' '){
- tmp += c;
- }
- }
- expression = tmp;
- stack < pair < string, size_t > > operations;
- stack < pair< bool, size_t > > values;
- /// Стек "values" буде зберігати всі значення, які повинні в подальшому опинитися серед параметрів стеку "operations".
- /// Також, кожне значення буде "пам'ятати", до якої операції воно повинно "впасти" як параметр
- vector < bool > values_tmp; /// Вектор, який міститиме всі параметри, передані в операцію, яка зараз розглядається
- bool can_be_processed; /// =true, якщо операція була опрацьована, маючи дані зі стеку "values".
- operations.push({expression, (size_t)0});
- while(!operations.empty()){
- string v = operations.top().first;
- size_t return_pos = operations.top().second; /// Позиція, де має бути вставлений результат цієї операції.
- size_t cur_pos = operations.size(); /// Позиція цієї операції.
- can_be_processed = true; /// Припускаємо, що змогли опрацювати операцію.
- for (string param: get_parameters(v)){ /// йдемо по списку параметрів
- /// Якщо параметр - це не вираз, який має бути опрацьований, а значення, то просто кидаємо його у вектор
- if (param == "false"){
- values_tmp.push_back(false);
- }else{
- if (param == "true"){
- values_tmp.push_back(true);
- }else{
- /// Інакше, пробуємо підставити результат зі стеку значень в цю операцію.
- if (values.size() == 0 || values.top().second != cur_pos){
- /// Якщо нема підходящого значення, то додаємо операцію на опрацювання і кажемо, що операція, яка зараз розглядається, не була завершена
- operations.push({param, cur_pos});
- can_be_processed = false;
- }else{
- /// Якщо є підходяще значення, то витягаємо його зі стеку, кидаємо у вектор
- values_tmp.push_back(values.top().first);
- values.pop();
- }
- }
- }
- }
- if (can_be_processed){
- /// Якщо операцію було опрацьовано успішно, то обчислюємо її значення, використовуючи вектор значень її параметрів.
- if (v[0] == 'n'){
- values.push({!values_tmp[0], return_pos});
- }else{
- if (v[0] == 'a'){
- bool res = true;
- for (bool p: values_tmp){
- res = (res && p);
- }
- values.push({res, return_pos});
- }else{
- bool res = false;
- for (bool p: values_tmp){
- res = (res || p);
- }
- values.push({res, return_pos});
- }
- }
- operations.pop(); /// Видаляємо операцію зі стеку невиконаних.
- }
- values_tmp.clear(); /// Очищаємо вектор параметрів цієї операції, щоб перейти до наступної.
- }
- if (values.top().first) return "true";
- else return "false";
- }
- static void run(){ /// Функція для перевірки роботи класу. Відкриває файл input.txt, бере звідти логічний вираз і обраховує його.
- FILE *f = freopen("input.txt", "r", stdin);
- string s;
- getline(cin, s);
- cout << s+" -> ";
- cout << parse(s) << '\n';
- }
- };
- class Polish{
- static void place_brackets(string &s){
- /// Функція, яка видаляє пробіли з виразу і розставляє дужки навколо всіх операцій множення (Бо це найпріорітетніша операція і дужки значно спрощують роботу)
- string t = "";
- for (char c: s){
- if (c != ' ') t += c;
- }
- s = t;
- size_t i = 0;
- /// Цей цикл знаходить множення, йде вліво, поки треба і ставить відкриваючу дужку, потім аналогічно вправо і ставить закриваючу дужку.
- while(i < s.length()){
- if (s[i] == '*'){
- if (s[i-1] == ')'){
- int scope = 0;
- for (int j=i-1; j>-1; j--){
- if (s[j] == ')') scope ++;
- else{
- if (s[j] == '(') scope --;
- }
- if (scope == 0){
- s = s.substr(0, j) + "(" + s.substr(j, s.length()-j);
- break;
- }
- }
- }else{
- bool was = false;
- for (int j=i-1; j>-1; j--){
- if (s[j] > '9' || s[j] < '0'){
- was = true;
- s = s.substr(0, j+1) + "(" + s.substr(j+1, s.length()-j-1);
- break;
- }
- }
- if (was == false){
- s = "(" + s;
- }
- }
- i ++;
- if (s[i+1] == '('){
- int scope = 0;
- i ++;
- while(i < s.length()){
- if (s[i] == '(') scope ++;
- else if (s[i] == ')') scope --;
- if (scope == 0) break;
- i ++;
- }
- s = s.substr(0, i+1) + ")" + s.substr(i+1, max((size_t)0, s.length() - (i+1)));
- }else{
- while(i+1 < s.length() && s[i+1] <= '9' && s[i+1] >= '0'){
- i ++;
- }
- s = s.substr(0, i+1) + ")" + s.substr(i+1, max((size_t)0, s.length() - (i+1)));
- }
- i ++;
- }
- i ++;
- }
- }
- public:
- static long long solve(string &expression){
- /// Функція, яка рахує значення виразу у польському записі.
- /// Суть проста: записуємо в стек всі числа. Коли зустрічаємо операцію, то беремо зі стеку два останніх числа, виконуємо операцію над ними, і кидаємо результат виконання у стек.
- stack < long long > values;
- long long tmp = -1;
- for (char c: expression){
- if (c == ' '){
- if (tmp > -1) values.push(tmp);
- tmp = -1;
- }else{
- if (c <= '9' && c >= '0'){
- if (tmp == -1) tmp = 0;
- tmp = tmp * 10 + ((long long)(c) - (long long)('0'));
- }else{
- long long a = values.top();
- values.pop();
- long long b = values.top();
- values.pop();
- if (c == '+'){
- values.push(a+b);
- }else{
- if (c == '-'){
- values.push(b-a);
- }else{
- values.push(a*b);
- }
- }
- }
- }
- }
- return values.top(); /// В кінці, відповідь буде єдиним числом, яке залишиться в стекові.
- }
- static string convert(string &s){
- /// Функція, яка конвертує звичайний запис в польський і повертає новий рядок.
- place_brackets(s); /// Спершу ставимо дужки навколо всіх операцій множення.
- stack < pair < string, size_t > > operations, values;
- vector < string > values_tmp;
- vector < char > operations_tmp;
- bool can_be_processed;
- operations.push({s, 0});
- /**
- Далі тут все відбувається схоже до того, як воно було в задачі про логічні операції:
- Є два стеки. В одному зберігаються дужки, які треба перетворити, в іншому - перетворені дужки для подальшого використання.
- Якщо в дужках, які зараз розглядаємо, є ще дужки, то вираз в глибших дужках кидаємо у стек невиконаних операцій, або дістаємо заміну зі стеку значень,
- якщо там є підходящі.
- **/
- while(!operations.empty()){
- string v = operations.top().first;
- size_t return_pos = operations.top().second;
- size_t cur_pos = operations.size();
- size_t i = 0;
- string tmp = "";
- can_be_processed = true;
- while(i < v.length()){
- if (v[i] <= '9' && v[i] >= '0'){
- tmp += v[i];
- }else{
- if (tmp != ""){
- values_tmp.push_back(tmp);
- }
- tmp = "";
- if (v[i] == '('){
- int scope = 1;
- i ++;
- while(i < v.length()){
- if (v[i] == '(') scope ++;
- else if (v[i] == ')') scope --;
- if (scope == 0) break;
- tmp += v[i];
- i ++;
- }
- if (values.size() == 0 || values.top().second != cur_pos){
- operations.push({tmp, cur_pos});
- can_be_processed = false;
- }else{
- values_tmp.push_back(values.top().first);
- values.pop();
- }
- tmp = "";
- }else{
- operations_tmp.push_back(v[i]);
- }
- }
- i ++;
- }
- if (tmp != "") values_tmp.push_back(tmp);
- if (can_be_processed){
- for (size_t i=0; i<operations_tmp.size(); i++){
- values_tmp[i+1] = values_tmp[i] + " " + values_tmp[i+1] + " " + operations_tmp[i];
- }
- operations.pop();
- values.push({values_tmp.back(), return_pos});
- }
- values_tmp.clear();
- operations_tmp.clear();
- }
- return values.top().first;
- }
- static void run(){ /// Функція для перевірки роботи класу. Приймає вираз у звичайному записі, перетворює в польський і обраховує його.
- string s;
- getline(cin, s);
- s = Polish::convert(s);
- cout << Polish::solve(s) << '\n';
- }
- };
- int main(){
- Polish::run();
- Parser::run();
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement