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} // namespace
16
17// calculate epsilon closure of a set of states
19 NFASet closure;
20 std::queue<const NFANode*> stateQueue;
21 for (const auto& state : states)
22 stateQueue.push(state);
23 while (!stateQueue.empty()) {
24 auto currentState = stateQueue.front();
25 stateQueue.pop();
26 closure.insert(currentState);
27 currentState->for_transitions([&](auto c, auto to) {
29 if (closure.find(to) == closure.end()) stateQueue.push(to);
30 }
31 });
32 }
33 return closure;
34}
35
36NFASet epsilonClosure(const NFANode* state) { return epsilonClosure(NFASet{state}); }
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 if (nextStates.find(c) == nextStates.end())
56 nextStates.try_emplace(c, NFASet{to});
57 else
58 nextStates[c].insert(to);
59 });
60 }
61 // add new states for unknown next states
62 for (auto& [c, tos] : nextStates) {
63 auto toStateClosure = epsilonClosure(tos);
64 if (dfaStates.find(toStateClosure) == dfaStates.end()) {
65 dfaStates.emplace(toStateClosure, dfa->add_state());
66 stateQueue.push(toStateClosure);
67 }
68 currentDfaState->add_transition(dfaStates[toStateClosure], c);
69 }
70 }
71 dfa->set_start(dfaStates[startState]);
72 for (auto& [state, dfaState] : dfaStates) {
73 for (auto& nfaState : state) {
74 if (nfaState->is_accepting()) dfaState->set_accepting(true);
75 if (nfaState->is_erroring()) {
76 dfaState->set_accepting(false);
77 dfaState->set_erroring(true);
78 break;
79 }
80 }
81 }
82 return dfa;
83}
84
85} // namespace automaton
const NodeType * get_start() const
Definition automaton.h:31
NFASet epsilonClosure(const NFASet &states)
Definition nfa2dfa.cpp:18
std::unique_ptr< DFA > nfa2dfa(const NFA &nfa)
Definition nfa2dfa.cpp:39
std::set< const NFANode *, NFANode::Lt > NFASet
Definition nfa.h:68