Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.19.31.73] |
|
Сообщ.
#1
,
|
|
|
Здравствуйте, подскажите, написал программу для высчитывания логических выражений в консоли, но не могу реализовать проверку ввода, такие как два логических символа подряд или после скобки сразу логический оператор, чтоб при проверке выражения он написал что, ввели неправильно выражение... Как это реализовать, не могу придумать никак? спасибо
#include "stdafx.h" #include <iostream> #include <conio.h> using namespace std; int test(char x); bool number() { bool res = 0; for (;;) { char c = cin.get(); test(c); if (c >= '0' && c <= '1') res = res * 10 + c - '0'; else { cin.putback(c); return res; } } } bool expr(); bool skobki() { char c = cin.get(); test(c); if (c == '(') { int x = expr(); cin.get(); return x; } else { cin.putback(c); return number(); } } bool otric() { int x = skobki(); for (;;) { char c = cin.get(); test(c); switch (c) { case '!': x = !skobki(); break; default: cin.putback(c); return x; } } } bool vtor() { int x = otric(); for (;;) { char c = cin.get(); test(c); switch (c) { case '&': x = x & skobki(); break; default: cin.putback(c); return x; } } } bool expr() { int x = vtor(); for (;;) { char c = cin.get(); test(c); switch (c) { case '^': x = x ^ vtor(); break; case '|': x = x | vtor(); break; default: cin.putback(c); return x; } } } int test(char x) { if (x == '1' || x == '0' || x == '(' || x == ')' || x == '&' || x == '^' || x == '|' || x == '!' || x=='2' || x == '\n') { return 0; } else { cout << endl << "Некорректный ввод!" << endl; system("pause"); exit(1); } } int main() { setlocale(LC_ALL, "rus"); char select; do { cout << "=========================================\n"; cout << " 1 - Ввести выражение"; cout << " 2 - Выход из программы.\n"; cout << "=========================================\n"; cin.clear(); select = cin.get(); cin.get(); switch (select) { case '1': { cout << " Введите выражение:" << endl; int res = expr(); cout << "Результат: " << res << endl; cout << "Нажмите любую клавишу, чтобы вернуться к меню . . .\n"; cout << endl; system("pause"); cin.get(); } break; case '2': return 0; break; // exit default: cout << "Введены неверные данные!\n"; break; } } while (select != '2'); return 0; } |
Сообщ.
#2
,
|
|
|
Сообщ.
#3
,
|
|
|
Это я читал, я не знаю как в мой код реализовать проверку на ввод, у меня все таки сделано не обратной польской записью
|
Сообщ.
#4
,
|
|
|
Цитата ArtemJkee @ Это я читал, я не знаю как в мой код реализовать проверку на ввод, Попробуй сделать автомат состояний. На каждом этапе ввода очередного символа всегда можно определить, какая совокупность символов является допустимой. Надо рассмотреть, сколько таких состояний получится. Для каждого состояния определить совокупность допустимых символов и условия перехода в другие состояния. |
Сообщ.
#5
,
|
|
|
Цитата ArtemJkee @ я не знаю как в мой код реализовать проверку на ввод, у меня все таки сделано не обратной польской записью Проверку ввода можно делать прямо "по ходу" алгоритма. Со скобками - проверять стек (более подробно есть в любом описании алгоритма). Все стальные можно проверить простыми условиями. Цитата ЫукпШ @ Попробуй сделать автомат состояний. Конечный автомат не распознает КС-грамматики. |
Сообщ.
#6
,
|
|
|
Цитата shm @ Все стальные можно проверить простыми условиями. Цитата ЫукпШ @ Попробуй сделать автомат состояний. Конечный автомат не распознает КС-грамматики. "Простыми" это какими ? ..Можно ли при вводе числа с плавающей точкой ввести точку ? или знак ? Это зависит от того, была ли уже введена точка. Или знак. итп итд. Значит, автомат. В более сложных случаях - совокупность автоматов. |
Сообщ.
#7
,
|
|
|
Цитата ЫукпШ @ "Простыми" это какими ? Я рекомендую дождаться от ТС реализации алгоритма, после этого все проверки должны стать очевидны. Да, конечный автомат тут можно использовать, но только для разбиения строки на токены, если это кажется более удобным. Добавлено Цитата ArtemJkee @ у меня все таки сделано не обратной польской записью У тебя есть конкретные требования к алгоритму? Чтобы вычислять скобочные выражения тебе в любом случае нужен стек. |
Сообщ.
#8
,
|
|
|
Я как то от балды недавно делал что то подобное от скуки, но с польской нотацией. Может пригодится.
Вот что получилось: Скрытый текст Operator.h //! Operator.h #pragma once #include <memory> namespace core { enum EPriority { E_LOW, E_MIDLE, E_HIGH }; class COperator { public: virtual int Calculate(int op1, int op2) = 0; virtual EPriority GetPriority() const = 0; virtual char Name() const = 0; virtual int CountArguments() const = 0; virtual ~COperator() {} }; typedef std::shared_ptr<COperator> TOperator; class CPlus : public COperator { public: int Calculate(int op1, int op2) override { return op1 + op2; } EPriority GetPriority() const override { return core::E_MIDLE; } virtual char Name() const override { return '+'; } int CountArguments() const override { return 2; } }; class CMinus : public COperator { public: int Calculate(int op1, int op2) override { return op1 - op2; } EPriority GetPriority() const override { return core::E_MIDLE; } virtual char Name() const override { return '-'; } int CountArguments() const override { return 2; } }; class CMultiple : public COperator { public: int Calculate(int op1, int op2) override { return op1 * op2; } EPriority GetPriority() const override { return core::E_HIGH; } virtual char Name() const override { return '*'; } int CountArguments() const override { return 2; } }; class CDivide : public COperator { public: int Calculate(int op1, int op2) override { return op1 / op2; } EPriority GetPriority() const override { return core::E_HIGH; } virtual char Name() const override { return '/'; } int CountArguments() const override { return 2; } }; class CBra : public COperator { public: int Calculate(int op1, int op2) override { return 0; } EPriority GetPriority() const override { return core::E_LOW; } virtual char Name() const override { return Bra; } int CountArguments() const override { return 0; } public: static const char Bra; }; const char CBra::Bra = '('; class CSket : public COperator { public: int Calculate(int op1, int op2) override { return 0; } EPriority GetPriority() const override { return core::E_LOW; } virtual char Name() const override { return Sket; } int CountArguments() const override { return 0; } public: static const char Sket; }; const char CSket::Sket = ')'; struct Token { enum EOPType { E_UNDEF, E_OPERAND, E_OPERATOR } Type; COperator * m_operator; int m_operand; Token() : Type(Token::E_UNDEF), m_operator(NULL), m_operand(0) { } Token(EOPType type, COperator * op, int operand) : Type(type), m_operator(op), m_operand(operand) { } Token& operator=(const Token& r) { Type = r.Type; m_operator = r.m_operator; m_operand = r.m_operand; return *this; } }; } main.cpp //! main.cpp #include <iostream> #include <string.h> #include <vector> #include <stack> #include <map> #include <string> #include <algorithm> #include "Operator.h" //! (5 * ((13 + 7) * (5-2))) / 10 = 30 using namespace core; class ExpressionParser { private: std::stack<Token> m_operators; std::vector<Token> m_output; std::stack<int> m_result; std::map<char, TOperator> m_operatorMaps; public: ExpressionParser() { m_operatorMaps['+'].reset(new CPlus); m_operatorMaps['-'].reset(new CMinus); m_operatorMaps['*'].reset(new CMultiple); m_operatorMaps['/'].reset(new CDivide); m_operatorMaps['('].reset(new CBra); m_operatorMaps[')'].reset(new CSket); } void ClearStack() { for (;m_operators.size() > 0; m_operators.pop()) ; m_output.clear(); for (;m_result.size() > 0; m_result.pop()) ; } void PrintOutput() { for (auto it = m_output.begin(); it != m_output.end(); ++it) { if (it->Type == Token::E_OPERAND) std::cout << it->m_operand << " "; if (it->Type == Token::E_OPERATOR) std::cout << it->m_operator->Name() << " "; } } int CalculateExpression() { for (auto it = m_output.begin(); it != m_output.end(); ++it) { if (it->Type == Token::E_OPERAND) { m_result.push(it->m_operand); } if (it->Type == Token::E_OPERATOR && it->m_operator != nullptr) { int op1 = m_result.top(); m_result.pop(); int op2 = m_result.top(); m_result.pop(); m_result.push(it->m_operator->Calculate(op2, op1)); } } return m_result.top(); } void ParseExpression(const std::string& expression) { for (std::string::const_iterator it = expression.begin(); it != expression.end(); ++it) { std::string data; for (; it != expression.end() && isdigit(*it); ++it) { data.push_back(*it); } if (!data.empty()) { Token tok; tok.Type = Token::E_OPERAND; m_output.push_back(Token(Token::E_OPERAND, nullptr, atoi(data.c_str()))); --it; } else if (it != expression.end() && m_operatorMaps.find(*it) != m_operatorMaps.end()) { if (*it == core::CSket::Sket) { bool isFoundBra = false; for (; m_operators.size() > 0;) { if (m_operators.top().m_operator->Name() == core::CBra::Bra) { isFoundBra = true; m_operators.pop(); break; } m_output.push_back(m_operators.top()); m_operators.pop(); } if (!isFoundBra) std::cout << "Error: expression is invalid. Symbol ( not found" << std::endl; } else if (m_operators.size() > 0 && m_operators.top().Type == Token::E_OPERATOR && m_operators.top().m_operator != NULL && *it != core::CBra::Bra && m_operators.top().m_operator->GetPriority() >= m_operatorMaps[*it]->GetPriority()) { if (m_operators.top().m_operator->Name() != core::CBra::Bra) { m_output.push_back(m_operators.top()); m_operators.pop(); } m_operators.push(Token(Token::E_OPERATOR, m_operatorMaps[*it].get(), 0)); } else m_operators.push(Token(Token::E_OPERATOR, m_operatorMaps[*it].get(), 0)); } } for (; m_operators.size() > 0;) { m_output.push_back(m_operators.top()); m_operators.pop(); } } }; int main() { ExpressionParser parser; std::string line; while (!std::cin.eof()) { std::getline(std::cin, line); if (line.length() > 0) { try { parser.ClearStack(); parser.ParseExpression(line); parser.PrintOutput(); std::cout << std::endl << "Result: " << parser.CalculateExpression() << std::endl; } catch (std::exception &e) { std::cout << "error: " << e.what() << std::endl; } } } COperator* op1 = new CPlus(); COperator* op2 = new CMinus(); op1 = op2; std::cout << op1->Calculate(10, 5); std::cin.get(); return 0; } |
Сообщ.
#9
,
|
|
|
Цитата shm @ Да, конечный автомат тут можно использовать, но только для разбиения строки на токены, если это кажется более удобным. В этом мире всё является автоматами и их совокупностью. И в потустороннем мире - тоже (если он существует). Даже Всевышний может связно излагать свои мысли, а значит, он тоже автомат состояний. Мыслительный аппарат человека - это работа совокупности автоматов. Ты же не сомневаешься, что можешь решить эту проблему самомтоятельно? --- Любая программа это тоже совокупность автоматов. Описанных либо прямым образом, либо косвенно. "Косвенно" - это когда автомат реализован самой последовательностью операций, флажками, ключами итд итп встречающимися по ходу алгоритма. В случае примитивного алгоритма нет необходимости описывать автомат прямым образом, а в сложном это самый надёжный путь к успеху. Особенно с единственной точкой входа в процедуру, которая должна менять алгоритм в соответствии с условиями.. Это по-определению - автомат. |
Сообщ.
#10
,
|
|
|
КС-грамматика разбирается конечным автоматом с памятью стекового типа.
|
Сообщ.
#11
,
|
|
|
Цитата KILLER @ спасибо, но у тебя через объекты сделано, мне нужно без них Добавлено Цитата ЫукпШ @ а можно пример хотя бы для 1 комбинации? |