diff --git a/apps/UnitTestsApp/include/UnitTestsApp/UnitTests.h b/apps/UnitTestsApp/include/UnitTestsApp/UnitTests.h new file mode 100644 index 00000000..1bda687a --- /dev/null +++ b/apps/UnitTestsApp/include/UnitTestsApp/UnitTests.h @@ -0,0 +1,29 @@ +#pragma once + +#include "AutomatonToImage/AutomatonToImage.h" +#include "InputGenerator/RegexGenerator.h" +#include "Interpreter/Interpreter.h" +#include "Objects/AlgExpression.h" +#include "Objects/FiniteAutomaton.h" +#include "Objects/Grammar.h" +#include "Objects/Language.h" +#include "Objects/Regex.h" +#include "Objects/TransformationMonoid.h" +#include "Tester/Tester.h" +#include "gtest/gtest.h" +#include + +class UnitTests +{ +public: + UnitTests(){}; + + static int InitTests(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); + }; + + using Lexeme = AlgExpression::Lexeme; + using LexemeType = AlgExpression::Lexeme::Type; + static std::vector parse_string(std::string str) {return AlgExpression::parse_string(str);}; +}; diff --git a/apps/UnitTestsApp/src/UnitTests.cpp b/apps/UnitTestsApp/src/UnitTests.cpp index a28bdef2..e0d99604 100644 --- a/apps/UnitTestsApp/src/UnitTests.cpp +++ b/apps/UnitTestsApp/src/UnitTests.cpp @@ -1,18 +1,6 @@ -#include "AutomatonToImage/AutomatonToImage.h" -#include "InputGenerator/RegexGenerator.h" -#include "Interpreter/Interpreter.h" -#include "Objects/FiniteAutomaton.h" -#include "Objects/Grammar.h" -#include "Objects/Language.h" -#include "Objects/Regex.h" -#include "Objects/TransformationMonoid.h" -#include "Tester/Tester.h" -#include "gtest/gtest.h" -#include +#include "UnitTestsApp/UnitTests.h" TEST(ParseStringTest, Test_regex_lexer) { - using L = AlgExpression::Lexeme::Type; - struct Test { string regex_str; bool want_err; @@ -30,6 +18,13 @@ TEST(ParseStringTest, Test_regex_lexer) { {"&", true}, {"&1", false, 1}, {"[b[a]:1&1]:2&2", false, 11}, + // тесты на отрицание + {"^a", false, 2}, + {"a^|b", true}, + {"d^*^b", true}, + {"d|^|b", true}, + {"a^", false, 4}, // a . ^ eps + {"a|(c^)", false, 8}, // a | ( c . ^ eps ) }; for (const auto& t : tests) { @@ -37,13 +32,13 @@ TEST(ParseStringTest, Test_regex_lexer) { message << "Case: " << t.regex_str << ", WantErr: " << t.want_err; SCOPED_TRACE(message.str()); - vector l = AlgExpression::parse_string(t.regex_str); + vector l = UnitTests::parse_string(t.regex_str); ASSERT_FALSE(l.empty()); if (t.want_err) { - ASSERT_EQ(L::error, l[0].type); + ASSERT_EQ(UnitTests::LexemeType::error, l[0].type); } else { - ASSERT_NE(L::error, l[0].type); + ASSERT_NE(UnitTests::LexemeType::error, l[0].type); ASSERT_EQ(t.lexemes_len, l.size()); // TODO: добавить проверку содержимого l } @@ -493,4 +488,4 @@ TEST(TestCaseName, Test_GlaisterShallit) { check_classes_number("a(b|c)(a|b)(b|c)", 5); check_classes_number("abc|bca", 6); check_classes_number("abc|bbc", 4); -} \ No newline at end of file +} diff --git a/apps/UnitTestsApp/src/main.cpp b/apps/UnitTestsApp/src/main.cpp index 087e824b..3418bd4e 100644 --- a/apps/UnitTestsApp/src/main.cpp +++ b/apps/UnitTestsApp/src/main.cpp @@ -1,4 +1,5 @@ #include "UnitTestsApp/Example.h" +#include "UnitTestsApp/UnitTests.h" #include "gtest/gtest.h" #include #include @@ -7,6 +8,5 @@ using namespace std; int main(int argc, char** argv) { cout << "Unit Tests\n"; // Тестирование - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); + return UnitTests::InitTests(argc, argv); } diff --git a/libs/Objects/CMakeLists.txt b/libs/Objects/CMakeLists.txt index 1d1ff0f5..d78f0881 100644 --- a/libs/Objects/CMakeLists.txt +++ b/libs/Objects/CMakeLists.txt @@ -1,15 +1,6 @@ # Set the project name project(Objects) -include(FetchContent) -FetchContent_Declare( - googletest - URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip -) - -set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) -FetchContent_MakeAvailable(googletest) - # Create a sources variable with a link to all cpp files to compile set(SOURCES src/TransformationMonoid.cpp @@ -35,5 +26,4 @@ target_include_directories(${PROJECT_NAME} target_link_libraries(${PROJECT_NAME} Fraction AutomatonToImage - gtest ) \ No newline at end of file diff --git a/libs/Objects/include/Objects/AlgExpression.h b/libs/Objects/include/Objects/AlgExpression.h index 6ab887af..8158e846 100644 --- a/libs/Objects/include/Objects/AlgExpression.h +++ b/libs/Objects/include/Objects/AlgExpression.h @@ -2,12 +2,10 @@ #include "BaseObject.h" #include "iLogTemplate.h" -#include "gtest/gtest.h" #include #include class AlgExpression : public BaseObject { - FRIEND_TEST(ParseStringTest, Test_regex_lexer); protected: struct Lexeme { @@ -18,7 +16,7 @@ class AlgExpression : public BaseObject { alt, // | conc, // . star, // * - minus, // ^ + negative, // ^ symb, // alphabet symbol eps, // Epsilon squareBrL, // [ @@ -42,7 +40,7 @@ class AlgExpression : public BaseObject { conc, // Unary: star, - minus, + negative, // Terminal: symb, // [i] @@ -91,7 +89,6 @@ class AlgExpression : public BaseObject { AlgExpression* scan_symb(const vector&, int, int); AlgExpression* scan_eps(const vector&, int, int); AlgExpression* scan_par(const vector&, int, int); - AlgExpression* scan_minus(const vector&, int, int); static void update_balance(const AlgExpression::Lexeme&, int&); // список листьев дерева regex @@ -135,4 +132,5 @@ class AlgExpression : public BaseObject { friend class FiniteAutomaton; friend class Tester; + friend class UnitTests; }; \ No newline at end of file diff --git a/libs/Objects/include/Objects/Regex.h b/libs/Objects/include/Objects/Regex.h index 10e6e609..7d34eff8 100644 --- a/libs/Objects/include/Objects/Regex.h +++ b/libs/Objects/include/Objects/Regex.h @@ -36,6 +36,11 @@ class Regex : public AlgExpression { void normalize_this_regex(const vector>&); // переписывание regex по // пользовательским правилам + // Построение из вектора лексем дерева регулярного выражения + // 2 и 3 аргумент - это начальный и конечный индекс рассматриваемых лексем в векторе + Regex* expr(const vector&, int, int) override; + Regex* scan_minus(const vector&, int, int); + public: Regex() = default; Regex(const string&); diff --git a/libs/Objects/src/AlgExpression.cpp b/libs/Objects/src/AlgExpression.cpp index 698a439f..54df5f7b 100644 --- a/libs/Objects/src/AlgExpression.cpp +++ b/libs/Objects/src/AlgExpression.cpp @@ -111,7 +111,7 @@ string AlgExpression::to_txt() const { // ставим скобки при итерации, если символов > 1 str1 = "(" + str1 + ")"; break; - case Type::minus: + case Type::negative: symb = '^'; return symb + str1; default: @@ -164,7 +164,7 @@ string AlgExpression::type_to_str() const { return "*"; case Type::symb: return "symb"; - case Type::minus: + case Type::negative: return "^"; default: break; @@ -241,7 +241,7 @@ vector AlgExpression::parse_string(string str) { Lexeme lexeme; switch (c) { case '^': - lexeme.type = Lexeme::Type::minus; + lexeme.type = Lexeme::Type::negative; break; case '(': lexeme.type = Lexeme::Type::parL; @@ -284,11 +284,14 @@ vector AlgExpression::parse_string(string str) { brackets_are_empty = false; break; case '|': + if (index != 0 && lexemes.back().type == Lexeme::Type::negative) + return {Lexeme::Type::error}; lexeme.type = Lexeme::Type::alt; break; case '*': if (index == 0 || (index != 0 && (lexemes.back().type == Lexeme::Type::star || - lexemes.back().type == Lexeme::Type::alt))) + lexemes.back().type == Lexeme::Type::alt || + lexemes.back().type == Lexeme::Type::negative))) return {Lexeme::Type::error}; lexeme.type = Lexeme::Type::star; break; @@ -339,7 +342,7 @@ vector AlgExpression::parse_string(string str) { // AlgExpression::Lexeme right lexeme.type == Lexeme::Type::symb || lexeme.type == Lexeme::Type::parL || lexeme.type == Lexeme::Type::squareBrL || lexeme.type == Lexeme::Type::ref || - lexeme.type == Lexeme::Type::minus)) { + lexeme.type == Lexeme::Type::negative)) { // We place . between lexemes.emplace_back(Lexeme::Type::conc); } @@ -348,7 +351,7 @@ vector AlgExpression::parse_string(string str) { ((lexeme.type == Lexeme::Type::alt && (lexemes.back().type == Lexeme::Type::parL || lexemes.back().type == Lexeme::Type::squareBrL)) || - (lexemes.back().type == Lexeme::Type::alt && + ((lexemes.back().type == Lexeme::Type::alt || lexemes.back().type == Lexeme::Type::negative) && (lexeme.type == Lexeme::Type::parR || lexeme.type == Lexeme::Type::squareBrR || lexeme.type == Lexeme::Type::alt)))) { // We place eps between @@ -386,7 +389,7 @@ vector AlgExpression::parse_string(string str) { lexemes.insert(lexemes.begin(), {Lexeme::Type::eps}); } - if (lexemes.back().type == Lexeme::Type::alt) { + if (lexemes.back().type == Lexeme::Type::alt || lexemes.back().type == Lexeme::Type::negative) { lexemes.emplace_back(Lexeme::Type::eps); } @@ -431,9 +434,6 @@ AlgExpression* AlgExpression::expr(const vector& lexemes, if (!p) { p = scan_conc(lexemes, index_start, index_end); } - if (!p) { - p = scan_minus(lexemes, index_start, index_end); - } if (!p) { p = scan_star(lexemes, index_start, index_end); } @@ -453,28 +453,6 @@ void AlgExpression::update_balance(const AlgExpression::Lexeme& l, int& balance) } } -AlgExpression* AlgExpression::scan_minus(const vector& lexemes, - int index_start, int index_end) { - AlgExpression* p = nullptr; - - if (lexemes[index_start].type != Lexeme::Type::minus) { - return nullptr; - } - - AlgExpression* l = expr(lexemes, index_start + 1, index_end); - if (l == nullptr) { - delete l; - return nullptr; - } - p = make(); - p->term_l = l; - p->value = lexemes[index_start]; - p->type = minus; - - p->alphabet = l->alphabet; - return p; -} - AlgExpression* AlgExpression::scan_conc(const vector& lexemes, int index_start, int index_end) { AlgExpression* p = nullptr; diff --git a/libs/Objects/src/Regex.cpp b/libs/Objects/src/Regex.cpp index b59ab520..dbc91a0f 100644 --- a/libs/Objects/src/Regex.cpp +++ b/libs/Objects/src/Regex.cpp @@ -72,6 +72,55 @@ template vector Regex::cast(vector ptrs) { return regexPointers; } +Regex* Regex::expr(const vector& lexemes, int index_start, + int index_end) { + AlgExpression* p; + p = scan_symb(lexemes, index_start, index_end); + if (!p) { + p = scan_eps(lexemes, index_start, index_end); + } + + if (!p) { + p = scan_alt(lexemes, index_start, index_end); + } + if (!p) { + p = scan_conc(lexemes, index_start, index_end); + } + if (!p) { + p = scan_minus(lexemes, index_start, index_end); + } + if (!p) { + p = scan_star(lexemes, index_start, index_end); + } + if (!p) { + p = scan_par(lexemes, index_start, index_end); + } + + return cast(p); +} + +Regex* Regex::scan_minus(const vector& lexemes, + int index_start, int index_end) { + Regex* p = nullptr; + + if (lexemes[index_start].type != Lexeme::Type::negative) { + return nullptr; + } + + Regex* l = expr(lexemes, index_start + 1, index_end); + if (l == nullptr) { + delete l; + return nullptr; + } + p = make(); + p->term_l = l; + p->value = lexemes[index_start]; + p->type = negative; + + p->alphabet = l->alphabet; + return p; +} + // возвращает пару <вектор сотсояний, max_index> pair, int> Regex::get_thompson(int max_index) const { string str; // идентификатор состояния