From 45527d2c06d0a12c0e5a126a80be14b007845ccf Mon Sep 17 00:00:00 2001 From: MaxanRus Date: Sun, 3 Oct 2021 16:42:51 +0300 Subject: [PATCH] Add converter regular to NFA --- CMakeLists.txt | 1 + include/NFA/NFATree.hpp | 49 ++++++++++---- src/NFA/NFATree.cpp | 109 +++++++++++++++++++++++++------- src/NFA/NFATreeVertex.cpp | 8 +-- src/converters/RegularToNFA.cpp | 50 +++++++++++++++ src/main.cpp | 9 +++ src/regular/RegularTreeNode.cpp | 3 +- 7 files changed, 187 insertions(+), 42 deletions(-) create mode 100644 src/converters/RegularToNFA.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 3e62eeb..3edb7f2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,6 +20,7 @@ set(SOURCE_FILES src/regular/RegularTreeNode.cpp src/NFA/NFATree.cpp src/NFA/NFATreeVertex.cpp + src/converters/RegularToNFA.cpp ) set(TEST_FILES diff --git a/include/NFA/NFATree.hpp b/include/NFA/NFATree.hpp index 4358931..d67a199 100644 --- a/include/NFA/NFATree.hpp +++ b/include/NFA/NFATree.hpp @@ -2,6 +2,7 @@ #include #include +#include #include namespace NFA { @@ -10,29 +11,51 @@ class NFATree { class Vertex { public: Vertex(); - Vertex(bool is_finale, bool is_start); bool IsFinal() const; bool IsStart() const; - void SetFinal(bool value); - void SetStart(bool value); + size_t GetNumber() const; - std::map>> transitions; + std::multimap transitions; private: + Vertex(bool is_final, bool is_start); + + size_t number_; bool is_final_ = false; bool is_start_ = false; + + friend class NFATree; }; - void RemoveVertex(std::shared_ptr); - void RemoveFinalVertex(std::shared_ptr); - void RemoveStartVertex(std::shared_ptr); + NFATree() = default; + NFATree(const NFATree&) = delete; + NFATree(NFATree&&) = default; - void Composition(NFATree&&, std::vector> - start_vertexes, std::vector> - final_vertexes); + NFATree& operator=(const NFATree&) = delete; + NFATree& operator=(NFATree&&) = default; + + size_t AddNewVertex(); + void AddFinalVertex(size_t number); + void AddStartVertex(size_t number); + + void RemoveVertex(size_t number); + void RemoveFinalVertex(size_t number); + void RemoveStartVertex(size_t number); + + void Composition(NFATree&&, + std::vector start_vertexes, + std::vector final_vertexes); + + std::shared_ptr GetVertex(size_t number); + size_t GetCountVertexes() const; + const std::vector& GetFinalVertexes() const; + const std::vector& GetStartVertexes() const; + + void Print() const; private: - std::vector> vertexes_; - std::vector> final_vertexes_; - std::vector> start_vertexes_; + size_t count_vertexes_ = 0; + std::map> vertexes_; + std::vector final_vertexes_; + std::vector start_vertexes_; }; } diff --git a/src/NFA/NFATree.cpp b/src/NFA/NFATree.cpp index 73bfb65..cf2f8f8 100644 --- a/src/NFA/NFATree.cpp +++ b/src/NFA/NFATree.cpp @@ -1,23 +1,38 @@ #include "NFA/NFATree.hpp" #include +#include namespace NFA { -void NFATree::RemoveVertex(std::shared_ptr vertex) { - RemoveFinalVertex(vertex); - RemoveStartVertex(vertex); - for (size_t i = 0; i < vertexes_.size(); ++i) { - if (vertexes_[i] == vertex) { - std::swap(vertexes_[i], vertexes_.back()); - vertexes_.pop_back(); - break; - } +size_t NFATree::AddNewVertex() { + vertexes_[count_vertexes_] = std::make_shared(); + vertexes_[count_vertexes_]->number_ = count_vertexes_; + return count_vertexes_++; +} + +void NFATree::AddFinalVertex(size_t number) { + if (!vertexes_[number]->is_final_) { + vertexes_[number]->is_final_ = true; + final_vertexes_.push_back(number); } } -void NFATree::RemoveFinalVertex(std::shared_ptr vertex) { +void NFATree::AddStartVertex(size_t number) { + if (!vertexes_[number]->is_start_) { + vertexes_[number]->is_start_ = true; + start_vertexes_.push_back(number); + } +} + +void NFATree::RemoveVertex(size_t number) { + RemoveFinalVertex(number); + RemoveStartVertex(number); + vertexes_.erase(number); +} + +void NFATree::RemoveFinalVertex(size_t number) { for (size_t i = 0; i < final_vertexes_.size(); ++i) { - if (final_vertexes_[i].lock() == vertex) { - final_vertexes_[i].lock()->SetFinal(false); + if (final_vertexes_[i] == number) { + vertexes_[number]->is_final_ = false; std::swap(final_vertexes_[i], final_vertexes_.back()); final_vertexes_.pop_back(); break; @@ -25,10 +40,10 @@ void NFATree::RemoveFinalVertex(std::shared_ptr vertex) { } } -void NFATree::RemoveStartVertex(std::shared_ptr vertex) { +void NFATree::RemoveStartVertex(size_t number) { for (size_t i = 0; i < start_vertexes_.size(); ++i) { - if (start_vertexes_[i].lock() == vertex) { - start_vertexes_[i].lock()->SetStart(false); + if (start_vertexes_[i] == number) { + vertexes_[number]->is_start_ = false; std::swap(start_vertexes_[i], start_vertexes_.back()); start_vertexes_.pop_back(); break; @@ -37,29 +52,79 @@ void NFATree::RemoveStartVertex(std::shared_ptr vertex) { } void NFATree::Composition(NFATree&& tree, - std::vector> start_vertexes, - std::vector> final_vertexes) { + std::vector start_vertexes, + std::vector final_vertexes) { auto add_final_vertexes = tree.final_vertexes_; auto add_start_vertexes = tree.start_vertexes_; - vertexes_.insert(vertexes_.begin(), tree.vertexes_.begin(), tree.vertexes_.end()); + size_t new_count_vertexes = count_vertexes_; + + for (auto& i: tree.vertexes_) { + new_count_vertexes = std::max(new_count_vertexes, i.first + count_vertexes_); + i.second->number_ += count_vertexes_; + for (auto& j: i.second->transitions) { + j.second += count_vertexes_; + } + vertexes_[i.second->number_] = std::move(i.second); + } + + for (auto& i: add_start_vertexes) { + i += count_vertexes_; + } + for (auto& i: add_final_vertexes) { + i += count_vertexes_; + } + + count_vertexes_ = new_count_vertexes; for (auto& i: start_vertexes) { for (auto& j: add_start_vertexes) { - i->transitions[' '].push_back(j); + vertexes_[i]->transitions.emplace(' ', j); } } for (auto& i: add_final_vertexes) { for (auto& j: final_vertexes) { - i.lock()->transitions[' '].push_back(j); + vertexes_[i]->transitions.emplace(' ', j); } } for (auto& i: add_final_vertexes) { - i.lock()->SetFinal(false); + vertexes_[i]->is_final_ = false; } for (auto& i: add_start_vertexes) { - i.lock()->SetStart(false); + vertexes_[i]->is_start_ = false; } } + +std::shared_ptr NFATree::GetVertex(size_t number) { + if (vertexes_.count(number)) + return vertexes_[number]; + return nullptr; +} + +size_t NFATree::GetCountVertexes() const { + return count_vertexes_; +} + +const std::vector& NFATree::GetFinalVertexes() const { + return final_vertexes_; +} + +const std::vector& NFATree::GetStartVertexes() const { + return start_vertexes_; +} + +void NFATree::Print() const { + for (auto i: vertexes_) { + std::cout << i.second->number_ << " " << "f-" << i.second->is_final_ << " s-" << + i.second->is_start_ << std::endl; + } + for (auto& i: vertexes_) { + for (auto& j: i.second->transitions) { + std::cout << i.second->number_ << "->" << j.second << " <" << j.first << ">" << + std::endl; + } + } + std::cout << std::endl; +} } diff --git a/src/NFA/NFATreeVertex.cpp b/src/NFA/NFATreeVertex.cpp index 3f4f4bf..cc9ca82 100644 --- a/src/NFA/NFATreeVertex.cpp +++ b/src/NFA/NFATreeVertex.cpp @@ -15,11 +15,7 @@ bool Vertex::IsStart() const { return is_start_; } -void Vertex::SetFinal(bool value) { - is_final_ = value; -} - -void Vertex::SetStart(bool value) { - is_start_ = value; +size_t Vertex::GetNumber() const { + return number_; } diff --git a/src/converters/RegularToNFA.cpp b/src/converters/RegularToNFA.cpp new file mode 100644 index 0000000..12e3c7c --- /dev/null +++ b/src/converters/RegularToNFA.cpp @@ -0,0 +1,50 @@ +#include "converters/RegularToNFA.hpp" +#include "regular/RegularTree.hpp" +#include "NFA/NFATree.hpp" + +using namespace NFA; +using namespace regular; +using Node = RegularTree::Node; + +struct do_nothing_deleter{ + template + void operator()(T*) const {} +}; + +template +NFATree RegularToNFA(std::unique_ptr node) { + NFATree result; + if (node->type == Node::Type::Word) { + auto last = result.AddNewVertex(); + result.AddStartVertex(last); + for (char i: node->word) { + auto tmp = result.AddNewVertex(); + result.GetVertex(last)->transitions.emplace(i, tmp); + last = tmp; + } + result.AddFinalVertex(last); + } else if (node->type == Node::Type::Concatenation) { + result = RegularToNFA(std::move(node->children[0])); + for (auto it = node->children.begin() + 1; it != node->children.end(); ++it) { + auto tmp = RegularToNFA(std::move(*it)); + auto v = result.AddNewVertex(); + result.Composition(std::move(tmp), result.GetFinalVertexes(), {v}); + while (!result.GetFinalVertexes().empty()) { + result.RemoveFinalVertex(result.GetFinalVertexes()[0]); + } + result.AddFinalVertex(v); + } + + } else if (node->type == Node::Type::Addition) { + // TODO + } + return result; +} + +namespace converters { +NFATree RegularToNFA(RegularTree&& tree) { + const Node& root = tree.GetNode(); + return RegularToNFA(std::unique_ptr(&const_cast(tree.GetNode()))); +} +} diff --git a/src/main.cpp b/src/main.cpp index 080b2cb..3253512 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,5 +1,6 @@ #include #include "regular/RegularTree.hpp" +#include "converters/RegularToNFA.hpp" int main() { using namespace regular; @@ -7,4 +8,12 @@ int main() { std::cin >> str; RegularTree reg_tree(str); reg_tree.Print(); + + auto NFA_tree = converters::RegularToNFA(std::move(reg_tree)); + + std::cout << std::endl; + + NFA_tree.Print(); + + } diff --git a/src/regular/RegularTreeNode.cpp b/src/regular/RegularTreeNode.cpp index 7b4637b..3939d17 100644 --- a/src/regular/RegularTreeNode.cpp +++ b/src/regular/RegularTreeNode.cpp @@ -16,6 +16,7 @@ void Node::Print() const { } void Node::ParseCurrentType(const std::string_view regular) { + std::cout << "# " << regular << std::endl; const size_t n = regular.size(); children.clear(); word.clear(); @@ -87,7 +88,7 @@ void Node::ParseCurrentType(const std::string_view regular) { } else if (regular[i] == ')') { --balance; if (balance == 0) { - AddChild(regular.substr(begin_child + 1, i - begin_child - 1)); + AddChild(regular.substr(begin_child, i - begin_child)); begin_child = i + 1; } } else if (i + 1 == n) {