TEST_F(TestDFA, Equivalence) { instance << "q0"; instance << "q1"; instance.addTransition("q0", "q1", 'a'); instance.accept("q1"); DFA copy; ASSERT_NO_THROW(copy = ~~instance); ASSERT_EQ(instance.size(), copy.size()); DFA almostEqual; almostEqual << "q0"; almostEqual << "q1"; almostEqual.addTransition("q0", "q1", 'b'); almostEqual.accept("q1"); bool r; ASSERT_NO_THROW(r = (copy == instance)); EXPECT_TRUE(r); EXPECT_EQ(2, instance.size()); EXPECT_EQ(2, copy.size()); ASSERT_NO_THROW(r = (almostEqual == instance)); EXPECT_FALSE(r); EXPECT_EQ(2, instance.size()); EXPECT_EQ(2, almostEqual.size()); }
TEST_F(TestDFA, Union) { instance << "q0"; instance << "q1"; instance << "q2"; instance.addTransition("q0", "q1", 'a'); instance.addTransition("q1", "q2", 'a'); instance.addTransition("q2", "q0", 'a'); instance.accept("q0"); DFA second; second << "q0"; second << "q1"; second.addTransition("q0", "q1", 'a'); second.addTransition("q1", "q0", 'a'); second.accept("q0"); DFA unionDFA = instance | second; EXPECT_EQ(3, instance.size()); EXPECT_EQ(2, second.size()); EXPECT_EQ(6, unionDFA.size()); EXPECT_TRUE(unionDFA.accepts()); unionDFA.read("a"); EXPECT_FALSE(unionDFA.accepts()); unionDFA.read("a"); EXPECT_TRUE(unionDFA.accepts()); unionDFA.read("a"); EXPECT_TRUE(unionDFA.accepts()); unionDFA.read("a"); EXPECT_TRUE(unionDFA.accepts()); unionDFA.read("a"); EXPECT_FALSE(unionDFA.accepts()); unionDFA.read("a"); EXPECT_TRUE(unionDFA.accepts()); }
TEST_F(TestDFA, DeadStateRemoval) { instance << "q0"; instance << "q1"; instance << "q2"; instance << "q3"; instance.addTransition("q0", "q1", 'a'); instance.addTransition("q1", "q2", 'b'); instance.addTransition("q2", "q2", 'c'); instance.addTransition("q3", "q3", 'd'); EXPECT_EQ(4, instance.size()); DFA other = instance.withoutDeadStates(); EXPECT_EQ(0, other.size()); instance.accept("q1"); other = instance.withoutDeadStates(); EXPECT_EQ(2, other.size()); EXPECT_EQ(other.initialState(), instance.initialState()); instance.accept("q3"); other = instance.withoutDeadStates(); EXPECT_EQ(3, other.size()); EXPECT_EQ(other.initialState(), instance.initialState()); DFA empty; ASSERT_NO_THROW(empty.withoutDeadStates()); EXPECT_EQ(0, empty.withoutDeadStates().size()); }
TEST_F(TestDFA, Intersection) { instance << "q0"; instance << "q1"; instance << "q2"; instance.addTransition("q0", "q1", 'a'); instance.addTransition("q1", "q2", 'a'); instance.addTransition("q2", "q0", 'a'); instance.accept("q0"); DFA second; second << "q0"; second << "q1"; second.addTransition("q0", "q1", 'a'); second.addTransition("q1", "q0", 'a'); second.accept("q0"); DFA intersection = instance & second; EXPECT_EQ(3, instance.size()); EXPECT_EQ(2, second.size()); EXPECT_EQ(6, intersection.size()); EXPECT_TRUE(intersection.accepts()); intersection.read("a"); EXPECT_FALSE(intersection.accepts()); intersection.read("a"); EXPECT_FALSE(intersection.accepts()); intersection.read("a"); EXPECT_FALSE(intersection.accepts()); intersection.read("a"); EXPECT_FALSE(intersection.accepts()); intersection.read("a"); EXPECT_FALSE(intersection.accepts()); intersection.read("a"); EXPECT_TRUE(intersection.accepts()); }
TEST_F(TestDFA, Containment) { instance << "q0"; instance << "q1"; instance << "q2"; instance << "q3"; instance.addTransition("q0", "q1", 'a'); instance.addTransition("q0", "q1", 'b'); instance.addTransition("q1", "q2", 'a'); instance.addTransition("q1", "q2", 'b'); instance.addTransition("q2", "q3", 'a'); instance.addTransition("q2", "q3", 'b'); instance.addTransition("q3", "q0", 'a'); instance.addTransition("q3", "q0", 'b'); instance.accept("q0"); instance.accept("q2"); DFA second; second << "q0"; second << "q1"; second.addTransition("q0", "q1", 'a'); second.addTransition("q1", "q0", 'a'); second.accept("q0"); bool r1, r2; ASSERT_NO_THROW(r1 = instance.contains(second)); ASSERT_NO_THROW(r2 = second.contains(instance)); EXPECT_TRUE(r1); EXPECT_FALSE(r2); EXPECT_EQ(4, instance.size()); EXPECT_EQ(2, second.size()); }
TEST_F(TestDFA, Complement) { instance << "q0"; instance << "q1"; instance << "q2"; instance.addTransition("q0", "q1", 'a'); instance.addTransition("q1", "q2", 'a'); instance.addTransition("q2", "q0", 'a'); instance.accept("q0"); DFA complement; ASSERT_NO_THROW(complement = ~instance); EXPECT_EQ(3, instance.size()); EXPECT_EQ(3, complement.size()); EXPECT_TRUE(instance.accepts()); EXPECT_FALSE(complement.accepts()); instance.read("a"); complement.read("a"); EXPECT_FALSE(instance.accepts()); EXPECT_TRUE(complement.accepts()); instance.read("a"); complement.read("a"); EXPECT_FALSE(instance.accepts()); EXPECT_TRUE(complement.accepts()); instance.read("a"); complement.read("a"); EXPECT_TRUE(instance.accepts()); EXPECT_FALSE(complement.accepts()); }
TEST_F(TestDFA, MinimizationStress) { auto fn = [](unsigned i) -> std::string { return std::to_string(i); }; unsigned limit = 999; instance.reserve(limit); for (unsigned i = 0; i < limit; i++) { instance << ("q" + fn(i)); } instance.accept("q" + fn(limit - 2)); instance.accept("q" + fn(limit - 1)); instance.addTransition("q0", "q1", 'a'); instance.addTransition("q0", "q2", 'b'); for (unsigned i = 1; i < limit - 2; i += 2) { unsigned next = (i + 1) % limit; instance.addTransition("q" + fn(i), "q" + fn(next), 'a'); instance.addTransition("q" + fn(next), "q" + fn(i), 'a'); instance.addTransition("q" + fn(i), "q" + fn((i + 2) % limit), 'b'); instance.addTransition("q" + fn(next), "q" + fn((i + 3) % limit), 'b'); } DFA other; ASSERT_NO_THROW(other = instance.minimized()); EXPECT_EQ((limit + 1)/2, other.size()); }
TEST_F(TestDFA, EquivalentStateRemoval) { instance << "q0"; instance << "q1"; instance << "q2"; instance << "q3"; instance << "q4"; instance << "q5"; instance.addTransition("q0", "q1", 'a'); instance.addTransition("q1", "q2", 'b'); instance.addTransition("q2", "q2", 'c'); instance.addTransition("q3", "q3", 'd'); instance.addTransition("q3", "q4", 'a'); instance.addTransition("q4", "q5", 'a'); instance.addTransition("q5", "q3", 'a'); instance.accept("q2"); EXPECT_EQ(6, instance.size()); instance.read("abc"); EXPECT_TRUE(instance.accepts()); instance.read("d"); EXPECT_FALSE(instance.accepts()); DFA other = instance.withoutDeadStates(); EXPECT_EQ(3, other.size()); EXPECT_EQ(other.initialState(), instance.initialState()); other.read("abc"); EXPECT_TRUE(other.accepts()); other.read("d"); EXPECT_FALSE(other.accepts()); }
bool DFAMerger::add(const DFA& dfa) { if (_start == -1) { _start = new_state(); } assert(_start >= 0); size_t size = dfa.size(); size_t base = _trans.size(); _trans.resize(base + size); for (size_t i = 0; i < size; i++) { const DFATran& tran = dfa[i]; for (DFATran::const_iterator it = tran.begin(); it != tran.end(); ++it) { _trans[base + i][it->first].insert(base + it->second); } const Tag& tag = dfa.tags(i); if (!tag.empty()) { Tag& to = _tags[base + i]; to.insert(tag.begin(), tag.end()); } } _trans[_start][EPSILON].insert(base + dfa.start()); const States& last = dfa.last(); for (States::const_iterator it = last.begin(); it != last.end(); ++it) { _last.insert(base + *it); } return true; }
unsigned long regex_parser::parse_regex_group(FILE *file, int group[]){ unsigned long size = _INFINITY; do { NFA *nfa = group_regex(file, group); nfa->remove_epsilon(); nfa->reduce(); DFA *dfa = nfa->nfa2dfa(); delete nfa; size = dfa->size(); delete dfa; } while (0); return size; }
TEST_F(TestDFA, UselessStateRemoval) { instance << "q0"; instance << "q1"; instance << "q2"; instance << "q3"; instance.accept("q1"); instance.addTransition("q0", "q1", 'a'); instance.addTransition("q1", "q2", 'b'); instance.addTransition("q2", "q2", 'c'); instance.addTransition("q3", "q3", 'd'); EXPECT_EQ(4, instance.size()); DFA other = instance.withoutUselessStates(); EXPECT_EQ(2, other.size()); EXPECT_EQ(other.initialState(), instance.initialState()); }
TEST_F(TestDFA, Minimization) { instance << "q0"; instance << "q1"; instance << "q2"; instance << "q3"; instance << "q4"; instance << "q5"; instance.accept("q3"); instance.addTransition("q0", "q1", 'a'); instance.addTransition("q0", "q2", 'b'); instance.addTransition("q1", "q2", 'b'); instance.addTransition("q2", "q1", 'b'); instance.addTransition("q1", "q3", 'c'); instance.addTransition("q2", "q3", 'c'); instance.addTransition("q3", "q4", 'a'); instance.addTransition("q4", "q4", 'b'); instance.addTransition("q5", "q2", 'a'); DFA minimized; ASSERT_NO_THROW(minimized = instance.minimized()); EXPECT_EQ(3, minimized.size()); EXPECT_EQ(minimized.initialState().getName(), instance.initialState().getName()); }
void print_dfa(const DFA& dfa) { cout << "start : " << dfa.start() << endl; cout << "last : "; const ::mpl::lexer::detail::States& last = dfa.last(); print_set(last); cout << endl; for (size_t i = 0; i < dfa.size(); i++) { const ::mpl::lexer::detail::DFATran& tran = dfa[i]; for (::mpl::lexer::detail::DFATran::const_iterator it = tran.begin(); it != tran.end(); ++it) { cout << i << "("; if (it->first == ::mpl::lexer::detail::EPSILON) { cout << "\\0"; } else if (it->first == ::mpl::lexer::detail::OTHER) { cout << "-1"; } else { //cout << it->first; cout << "0x" << hex << (int)(it->first & 0xFF) << dec; } cout << ")"; cout << "\t->\t"; cout << it->second; cout << endl; } } for (::mpl::lexer::detail::States::const_iterator it = last.begin(); it != last.end(); ++it) { const ::mpl::lexer::detail::Tag& tag = dfa.tags(*it); cout << *it << ": "; print_set(tag); cout << endl; } }