MimIR
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
nfa2dfa.cpp
Go to the documentation of this file.
1#include "automaton/nfa2dfa.h"
2
3#include <map>
4#include <queue>
5
6namespace automaton {
7
8namespace {
9/// Compares NFASet%s lexicographically by NFANode::id - never by pointer value.
10struct NFASetLt {
11 bool operator()(const NFASet& a, const NFASet& b) const {
12 return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end(), NFANode::Lt{});
13 }
14};
15
16// calculate epsilon closure of a set of states
17NFASet epsilonClosure(const NFASet& states) {
18 NFASet closure;
19 std::queue<const NFANode*> stateQueue;
20 for (const auto& state : states)
21 stateQueue.push(state);
22 while (!stateQueue.empty()) {
23 auto currentState = stateQueue.front();
24 stateQueue.pop();
25 closure.insert(currentState);
26 currentState->for_transitions([&](auto c, auto to) {
28 if (!closure.contains(to)) stateQueue.push(to);
29 }
30 });
31 }
32 return closure;
33}
34
35NFASet epsilonClosure(const NFANode* state) { return epsilonClosure(NFASet{state}); }
36} // namespace
37
38// nfa2dfa implementation
39std::unique_ptr<DFA> nfa2dfa(const NFA& nfa) {
40 auto dfa = std::make_unique<DFA>();
41 std::map<NFASet, DFANode*, NFASetLt> dfaStates;
42 std::queue<NFASet> stateQueue;
43 NFASet startState = epsilonClosure(nfa.get_start());
44 dfaStates.emplace(startState, dfa->add_state());
45 stateQueue.push(startState);
46 while (!stateQueue.empty()) {
47 auto currentState = stateQueue.front();
48 stateQueue.pop();
49 auto currentDfaState = dfaStates[currentState];
50 std::map<std::uint16_t, NFASet> nextStates;
51 // calculate next states
52 for (auto& nfaState : currentState) {
53 nfaState->for_transitions([&](auto c, auto to) {
54 if (c == NFA::SpecialTransitons::EPSILON) return;
55 nextStates[c].insert(to);
56 });
57 }
58 // add new states for unknown next states
59 for (auto& [c, tos] : nextStates) {
60 auto toStateClosure = epsilonClosure(tos);
61 auto [i, fresh] = dfaStates.try_emplace(toStateClosure);
62 if (fresh) {
63 i->second = dfa->add_state();
64 stateQueue.push(std::move(toStateClosure));
65 }
66 currentDfaState->add_transition(i->second, c);
67 }
68 }
69 dfa->set_start(dfaStates[startState]);
70 for (auto& [state, dfaState] : dfaStates) {
71 for (auto& nfaState : state) {
72 if (nfaState->is_accepting()) dfaState->set_accepting(true);
73 if (nfaState->is_erroring()) {
74 dfaState->set_accepting(false);
75 dfaState->set_erroring(true);
76 break;
77 }
78 }
79 }
80 return dfa;
81}
82
83} // namespace automaton
const NodeType * get_start() const
Definition automaton.h:34
std::unique_ptr< DFA > nfa2dfa(const NFA &nfa)
Definition nfa2dfa.cpp:39
std::set< const NFANode *, NFANode::Lt > NFASet
Definition nfa.h:65