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>
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 std::set<const NodeType*> get_reachable_states() const {
34 std::set<const NodeType*> reachableStates;
35 std::vector<const NodeType*> workList;
36 workList.push_back(get_start());
37 while (!workList.empty()) {
38 auto state = workList.back();
39 workList.pop_back();
40 reachableStates.insert(state);
41 state->for_transitions([&](auto, auto to) {
42 if (!reachableStates.contains(to)) workList.push_back(to);
43 });
44 }
45 return reachableStates;
46 }
47
48 friend std::ostream& operator<<(std::ostream& os, const AutomatonBase& automaton) {
49 if constexpr (std::is_same_v<NodeType, DFANode>)
50 os << "digraph dfa {\n";
51 else if constexpr (std::is_same_v<NodeType, NFANode>)
52 os << "digraph nfa {\n";
53 else
54 os << "digraph automaton {\n";
55 os << " start -> \"" << automaton.start_ << "\";\n";
56
57 for (auto& node : automaton.nodes_)
58 os << node;
59 os << "}\n";
60 return os;
61 }
62
63private:
64 std::list<NodeType> nodes_;
65 const NodeType* start_ = nullptr;
66 int id_ = 0;
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.try_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:29
NodeType * add_state()
Definition automaton.h:24
const NodeType * get_start() const
Definition automaton.h:31
std::set< const NodeType * > get_reachable_states() const
Definition automaton.h:33
friend std::ostream & operator<<(std::ostream &os, const AutomatonBase &automaton)
Definition automaton.h:48
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:70
std::optional< Range > merge_ranges(Range a, Range b) noexcept