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