Add converter regular to NFA
This commit is contained in:
parent
82822d316f
commit
45527d2c06
|
@ -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
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <memory>
|
||||
|
||||
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<char, std::vector<std::weak_ptr<Vertex>>> transitions;
|
||||
std::multimap<char, size_t> 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<Vertex>);
|
||||
void RemoveFinalVertex(std::shared_ptr<Vertex>);
|
||||
void RemoveStartVertex(std::shared_ptr<Vertex>);
|
||||
NFATree() = default;
|
||||
NFATree(const NFATree&) = delete;
|
||||
NFATree(NFATree&&) = default;
|
||||
|
||||
void Composition(NFATree&&, std::vector<std::shared_ptr<Vertex>>
|
||||
start_vertexes, std::vector<std::shared_ptr<Vertex>>
|
||||
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<size_t> start_vertexes,
|
||||
std::vector<size_t> final_vertexes);
|
||||
|
||||
std::shared_ptr<Vertex> GetVertex(size_t number);
|
||||
size_t GetCountVertexes() const;
|
||||
const std::vector<size_t>& GetFinalVertexes() const;
|
||||
const std::vector<size_t>& GetStartVertexes() const;
|
||||
|
||||
void Print() const;
|
||||
private:
|
||||
std::vector<std::shared_ptr<Vertex>> vertexes_;
|
||||
std::vector<std::weak_ptr<Vertex>> final_vertexes_;
|
||||
std::vector<std::weak_ptr<Vertex>> start_vertexes_;
|
||||
size_t count_vertexes_ = 0;
|
||||
std::map<size_t, std::shared_ptr<Vertex>> vertexes_;
|
||||
std::vector<size_t> final_vertexes_;
|
||||
std::vector<size_t> start_vertexes_;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,23 +1,38 @@
|
|||
#include "NFA/NFATree.hpp"
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
namespace NFA {
|
||||
void NFATree::RemoveVertex(std::shared_ptr<Vertex> 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<Vertex>();
|
||||
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> 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> vertex) {
|
|||
}
|
||||
}
|
||||
|
||||
void NFATree::RemoveStartVertex(std::shared_ptr<Vertex> 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> vertex) {
|
|||
}
|
||||
|
||||
void NFATree::Composition(NFATree&& tree,
|
||||
std::vector<std::shared_ptr<Vertex>> start_vertexes,
|
||||
std::vector<std::shared_ptr<Vertex>> final_vertexes) {
|
||||
std::vector<size_t> start_vertexes,
|
||||
std::vector<size_t> 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::Vertex> 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<size_t>& NFATree::GetFinalVertexes() const {
|
||||
return final_vertexes_;
|
||||
}
|
||||
|
||||
const std::vector<size_t>& 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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_;
|
||||
}
|
||||
|
||||
|
|
50
src/converters/RegularToNFA.cpp
Normal file
50
src/converters/RegularToNFA.cpp
Normal file
|
@ -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<typename T>
|
||||
void operator()(T*) const {}
|
||||
};
|
||||
|
||||
template<typename deleter>
|
||||
NFATree RegularToNFA(std::unique_ptr<Node, deleter> 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<Node,
|
||||
do_nothing_deleter>(&const_cast<Node&>(tree.GetNode())));
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
#include <iostream>
|
||||
#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();
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in a new issue