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