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/regular/RegularTreeNode.cpp
|
||||||
src/NFA/NFATree.cpp
|
src/NFA/NFATree.cpp
|
||||||
src/NFA/NFATreeVertex.cpp
|
src/NFA/NFATreeVertex.cpp
|
||||||
|
src/converters/RegularToNFA.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set(TEST_FILES
|
set(TEST_FILES
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <set>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace NFA {
|
namespace NFA {
|
||||||
|
@ -10,29 +11,51 @@ class NFATree {
|
||||||
class Vertex {
|
class Vertex {
|
||||||
public:
|
public:
|
||||||
Vertex();
|
Vertex();
|
||||||
Vertex(bool is_finale, bool is_start);
|
|
||||||
|
|
||||||
bool IsFinal() const;
|
bool IsFinal() const;
|
||||||
bool IsStart() const;
|
bool IsStart() const;
|
||||||
void SetFinal(bool value);
|
size_t GetNumber() const;
|
||||||
void SetStart(bool value);
|
|
||||||
|
|
||||||
std::map<char, std::vector<std::weak_ptr<Vertex>>> transitions;
|
std::multimap<char, size_t> transitions;
|
||||||
private:
|
private:
|
||||||
|
Vertex(bool is_final, bool is_start);
|
||||||
|
|
||||||
|
size_t number_;
|
||||||
bool is_final_ = false;
|
bool is_final_ = false;
|
||||||
bool is_start_ = false;
|
bool is_start_ = false;
|
||||||
|
|
||||||
|
friend class NFATree;
|
||||||
};
|
};
|
||||||
|
|
||||||
void RemoveVertex(std::shared_ptr<Vertex>);
|
NFATree() = default;
|
||||||
void RemoveFinalVertex(std::shared_ptr<Vertex>);
|
NFATree(const NFATree&) = delete;
|
||||||
void RemoveStartVertex(std::shared_ptr<Vertex>);
|
NFATree(NFATree&&) = default;
|
||||||
|
|
||||||
void Composition(NFATree&&, std::vector<std::shared_ptr<Vertex>>
|
NFATree& operator=(const NFATree&) = delete;
|
||||||
start_vertexes, std::vector<std::shared_ptr<Vertex>>
|
NFATree& operator=(NFATree&&) = default;
|
||||||
final_vertexes);
|
|
||||||
|
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:
|
private:
|
||||||
std::vector<std::shared_ptr<Vertex>> vertexes_;
|
size_t count_vertexes_ = 0;
|
||||||
std::vector<std::weak_ptr<Vertex>> final_vertexes_;
|
std::map<size_t, std::shared_ptr<Vertex>> vertexes_;
|
||||||
std::vector<std::weak_ptr<Vertex>> start_vertexes_;
|
std::vector<size_t> final_vertexes_;
|
||||||
|
std::vector<size_t> start_vertexes_;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,23 +1,38 @@
|
||||||
#include "NFA/NFATree.hpp"
|
#include "NFA/NFATree.hpp"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
namespace NFA {
|
namespace NFA {
|
||||||
void NFATree::RemoveVertex(std::shared_ptr<Vertex> vertex) {
|
size_t NFATree::AddNewVertex() {
|
||||||
RemoveFinalVertex(vertex);
|
vertexes_[count_vertexes_] = std::make_shared<Vertex>();
|
||||||
RemoveStartVertex(vertex);
|
vertexes_[count_vertexes_]->number_ = count_vertexes_;
|
||||||
for (size_t i = 0; i < vertexes_.size(); ++i) {
|
return count_vertexes_++;
|
||||||
if (vertexes_[i] == vertex) {
|
|
||||||
std::swap(vertexes_[i], vertexes_.back());
|
|
||||||
vertexes_.pop_back();
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
for (size_t i = 0; i < final_vertexes_.size(); ++i) {
|
||||||
if (final_vertexes_[i].lock() == vertex) {
|
if (final_vertexes_[i] == number) {
|
||||||
final_vertexes_[i].lock()->SetFinal(false);
|
vertexes_[number]->is_final_ = false;
|
||||||
std::swap(final_vertexes_[i], final_vertexes_.back());
|
std::swap(final_vertexes_[i], final_vertexes_.back());
|
||||||
final_vertexes_.pop_back();
|
final_vertexes_.pop_back();
|
||||||
break;
|
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) {
|
for (size_t i = 0; i < start_vertexes_.size(); ++i) {
|
||||||
if (start_vertexes_[i].lock() == vertex) {
|
if (start_vertexes_[i] == number) {
|
||||||
start_vertexes_[i].lock()->SetStart(false);
|
vertexes_[number]->is_start_ = false;
|
||||||
std::swap(start_vertexes_[i], start_vertexes_.back());
|
std::swap(start_vertexes_[i], start_vertexes_.back());
|
||||||
start_vertexes_.pop_back();
|
start_vertexes_.pop_back();
|
||||||
break;
|
break;
|
||||||
|
@ -37,29 +52,79 @@ void NFATree::RemoveStartVertex(std::shared_ptr<Vertex> vertex) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void NFATree::Composition(NFATree&& tree,
|
void NFATree::Composition(NFATree&& tree,
|
||||||
std::vector<std::shared_ptr<Vertex>> start_vertexes,
|
std::vector<size_t> start_vertexes,
|
||||||
std::vector<std::shared_ptr<Vertex>> final_vertexes) {
|
std::vector<size_t> final_vertexes) {
|
||||||
auto add_final_vertexes = tree.final_vertexes_;
|
auto add_final_vertexes = tree.final_vertexes_;
|
||||||
auto add_start_vertexes = tree.start_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& i: start_vertexes) {
|
||||||
for (auto& j: add_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& i: add_final_vertexes) {
|
||||||
for (auto& j: final_vertexes) {
|
for (auto& j: final_vertexes) {
|
||||||
i.lock()->transitions[' '].push_back(j);
|
vertexes_[i]->transitions.emplace(' ', j);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (auto& i: add_final_vertexes) {
|
for (auto& i: add_final_vertexes) {
|
||||||
i.lock()->SetFinal(false);
|
vertexes_[i]->is_final_ = false;
|
||||||
}
|
}
|
||||||
for (auto& i: add_start_vertexes) {
|
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_;
|
return is_start_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Vertex::SetFinal(bool value) {
|
size_t Vertex::GetNumber() const {
|
||||||
is_final_ = value;
|
return number_;
|
||||||
}
|
|
||||||
|
|
||||||
void Vertex::SetStart(bool value) {
|
|
||||||
is_start_ = value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
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 <iostream>
|
||||||
#include "regular/RegularTree.hpp"
|
#include "regular/RegularTree.hpp"
|
||||||
|
#include "converters/RegularToNFA.hpp"
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
using namespace regular;
|
using namespace regular;
|
||||||
|
@ -7,4 +8,12 @@ int main() {
|
||||||
std::cin >> str;
|
std::cin >> str;
|
||||||
RegularTree reg_tree(str);
|
RegularTree reg_tree(str);
|
||||||
reg_tree.Print();
|
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) {
|
void Node::ParseCurrentType(const std::string_view regular) {
|
||||||
|
std::cout << "# " << regular << std::endl;
|
||||||
const size_t n = regular.size();
|
const size_t n = regular.size();
|
||||||
children.clear();
|
children.clear();
|
||||||
word.clear();
|
word.clear();
|
||||||
|
@ -87,7 +88,7 @@ void Node::ParseCurrentType(const std::string_view regular) {
|
||||||
} else if (regular[i] == ')') {
|
} else if (regular[i] == ')') {
|
||||||
--balance;
|
--balance;
|
||||||
if (balance == 0) {
|
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;
|
begin_child = i + 1;
|
||||||
}
|
}
|
||||||
} else if (i + 1 == n) {
|
} else if (i + 1 == n) {
|
||||||
|
|
Loading…
Reference in a new issue