Thorin 1.9.0
The Higher ORder INtermediate representation
Loading...
Searching...
No Matches
automaton.h
Go to the documentation of this file.
1#pragma once
2
3#include <cstdint>
4
5#include <iostream>
6#include <list>
7#include <set>
8#include <unordered_map>
9#include <vector>
10
11#include <absl/container/flat_hash_map.h>
12
14
15namespace automaton {
16
17class DFANode;
18class NFANode;
19
20template<class NodeType> class AutomatonBase {
21public:
22 AutomatonBase() = default;
23 AutomatonBase(const AutomatonBase&) = delete;
25
26 NodeType* add_state() {
27 nodes_.emplace_back();
28 return &nodes_.back();
29 }
30
31 void set_start(const NodeType* start) { start_ = start; }
32
33 const NodeType* get_start() const { return start_; }
34
35 std::set<const NodeType*> get_reachable_states() const {
36 std::set<const NodeType*> reachableStates;
37 std::vector<const NodeType*> workList;
38 workList.push_back(get_start());
39 while (!workList.empty()) {
40 auto state = workList.back();
41 workList.pop_back();
42 reachableStates.insert(state);
43 state->for_transitions([&](auto, auto to) {
44 if (!reachableStates.contains(to)) workList.push_back(to);
45 });
46 }
47 return reachableStates;
48 }
49
50 friend std::ostream& operator<<(std::ostream& os, const AutomatonBase& automaton) {
51 if constexpr (std::is_same_v<NodeType, DFANode>)
52 os << "digraph dfa {\n";
53 else if constexpr (std::is_same_v<NodeType, NFANode>)
54 os << "digraph nfa {\n";
55 else
56 os << "digraph automaton {\n";
57 os << " start -> \"" << automaton.start_ << "\";\n";
58
59 for (auto& node : automaton.nodes_) os << node;
60 os << "}\n";
61 return os;
62 }
63
64private:
65 std::list<NodeType> nodes_;
66 const NodeType* start_ = nullptr;
67};
68
69template<class NodeType, class PrintCharF>
70std::ostream& print_node(std::ostream& os, const NodeType& node, PrintCharF&& print_char) {
71 if (node.is_accepting()) os << " \"" << &node << "\" [shape=doublecircle];\n";
72 if (node.is_erroring()) os << " \"" << &node << "\" [shape=square];\n";
73
74 absl::flat_hash_map<const NodeType*, std::vector<Range>> node2transitions;
75 node.for_transitions([&](auto c, auto to) {
76 if (!node2transitions.contains(to))
77 node2transitions.emplace(to, std::vector<Range>{
78 Range{c, c}
79 });
80 else
81 node2transitions[to].push_back({c, c});
82 });
83
84 for (auto& [to, ranges] : node2transitions) {
85 std::sort(ranges.begin(), ranges.end(), RangeCompare{});
86 ranges = merge_ranges(ranges);
87 for (auto& [lo, hi] : ranges) {
88 os << " \"" << &node << "\" -> \"" << to << "\" [label=\"" << std::forward<PrintCharF>(print_char)(lo);
89 if (lo != hi) os << "-" << std::forward<PrintCharF>(print_char)(hi);
90 os << " (" << lo;
91 if (lo != hi) os << "-" << hi;
92 os << ")\"];\n";
93 }
94 }
95
96 return os;
97}
98
99} // namespace automaton
void set_start(const NodeType *start)
Definition automaton.h:31
NodeType * add_state()
Definition automaton.h:26
const NodeType * get_start() const
Definition automaton.h:33
std::set< const NodeType * > get_reachable_states() const
Definition automaton.h:35
friend std::ostream & operator<<(std::ostream &os, const AutomatonBase &automaton)
Definition automaton.h:50
AutomatonBase(const AutomatonBase &)=delete
AutomatonBase & operator=(const AutomatonBase &)=delete
std::ostream & print_node(std::ostream &os, const NodeType &node, PrintCharF &&print_char)
Definition automaton.h:70
std::optional< Range > merge_ranges(Range a, Range b) noexcept