diff --git a/lib/fsa.c b/lib/fsa.c index dc5800d..092819a 100644 --- a/lib/fsa.c +++ b/lib/fsa.c @@ -65,3 +65,24 @@ void fsa_add_rule(fsa_t *fsa, int from, int to, int input) rule->next = to; ++state->count; } + +bool fsa_accepts(const fsa_t *dfa, const char *input, int len) +{ + const char *end = input + len; + int current = dfa->initial; + while (input < end) { + bool found = false; + const fsa_rule_t *rules = dfa->states[current].rules; + for (int i = 0; i < dfa->states[current].count; ++i) { + if (rules[i].input == *input) { + current = rules[i].next; + found = true; + break; + } + } + if (!found) + return false; + ++input; + } + return dfa->states[current].final; +} diff --git a/lib/include/fsa.h b/lib/include/fsa.h index 85ee342..8f0c6e7 100644 --- a/lib/include/fsa.h +++ b/lib/include/fsa.h @@ -35,4 +35,6 @@ void fsa_free(const fsa_t *fsa); int fsa_add_state(fsa_t *fsa); void fsa_add_rule(fsa_t *fsa, int from, int to, int input); +bool fsa_accepts(const fsa_t *dfa, const char *input, int len); + #endif diff --git a/tests/convert_tests.c b/tests/convert_tests.c index 9cf07a2..52386af 100644 --- a/tests/convert_tests.c +++ b/tests/convert_tests.c @@ -6,6 +6,8 @@ #include "convert.h" #include "testing.h" +#define ACCEPTS(dfa, s) fsa_accepts(dfa, s, strlen(s)) + static bool is_deterministic(const fsa_t *fsa) { for (int i = 0; i < fsa->count; ++i) { @@ -23,26 +25,6 @@ static bool is_deterministic(const fsa_t *fsa) return true; } -static bool accepts(const fsa_t *dfa, const char *input) -{ - int current = dfa->initial; - while ('\0' != *input) { - bool found = false; - const fsa_rule_t *rules = dfa->states[current].rules; - for (int i = 0; i < dfa->states[current].count; ++i) { - if (rules[i].input == *input) { - current = rules[i].next; - found = true; - break; - } - } - if (!found) - return false; - ++input; - } - return dfa->states[current].final; -} - static void test_trivial_case(void) { fsa_t nfa; @@ -56,9 +38,9 @@ static void test_trivial_case(void) convert_to_dfa(&nfa, &dfa); ASSERT_TRUE(is_deterministic(&dfa)); - ASSERT_TRUE(accepts(&dfa, "a")); - ASSERT_FALSE(accepts(&dfa, "aa")); - ASSERT_FALSE(accepts(&dfa, "b")); + ASSERT_TRUE(ACCEPTS(&dfa, "a")); + ASSERT_FALSE(ACCEPTS(&dfa, "aa")); + ASSERT_FALSE(ACCEPTS(&dfa, "b")); fsa_free(&nfa); fsa_free(&dfa); @@ -80,13 +62,13 @@ static void test_epsilon_move(void) convert_to_dfa(&nfa, &dfa); ASSERT_TRUE(is_deterministic(&dfa)); - ASSERT_TRUE(accepts(&dfa, "a")); - ASSERT_TRUE(accepts(&dfa, "b")); - ASSERT_FALSE(accepts(&dfa, "aa")); - ASSERT_FALSE(accepts(&dfa, "bb")); - ASSERT_FALSE(accepts(&dfa, "ab")); - ASSERT_FALSE(accepts(&dfa, "ba")); - ASSERT_FALSE(accepts(&dfa, "c")); + ASSERT_TRUE(ACCEPTS(&dfa, "a")); + ASSERT_TRUE(ACCEPTS(&dfa, "b")); + ASSERT_FALSE(ACCEPTS(&dfa, "aa")); + ASSERT_FALSE(ACCEPTS(&dfa, "bb")); + ASSERT_FALSE(ACCEPTS(&dfa, "ab")); + ASSERT_FALSE(ACCEPTS(&dfa, "ba")); + ASSERT_FALSE(ACCEPTS(&dfa, "c")); fsa_free(&nfa); fsa_free(&dfa); @@ -110,13 +92,13 @@ static void test_branch(void) convert_to_dfa(&nfa, &dfa); ASSERT_TRUE(is_deterministic(&dfa)); - ASSERT_TRUE(accepts(&dfa, "aa")); - ASSERT_TRUE(accepts(&dfa, "ab")); - ASSERT_FALSE(accepts(&dfa, "a")); - ASSERT_FALSE(accepts(&dfa, "aaa")); - ASSERT_FALSE(accepts(&dfa, "abb")); - ASSERT_FALSE(accepts(&dfa, "c")); - ASSERT_FALSE(accepts(&dfa, "ac")); + ASSERT_TRUE(ACCEPTS(&dfa, "aa")); + ASSERT_TRUE(ACCEPTS(&dfa, "ab")); + ASSERT_FALSE(ACCEPTS(&dfa, "a")); + ASSERT_FALSE(ACCEPTS(&dfa, "aaa")); + ASSERT_FALSE(ACCEPTS(&dfa, "abb")); + ASSERT_FALSE(ACCEPTS(&dfa, "c")); + ASSERT_FALSE(ACCEPTS(&dfa, "ac")); fsa_free(&nfa); fsa_free(&dfa); @@ -145,19 +127,19 @@ static void test_nfa_a(void) ASSERT_TRUE(is_deterministic(&dfa)); - ASSERT_TRUE(accepts(&dfa, "")); - ASSERT_TRUE(accepts(&dfa, "a")); - ASSERT_TRUE(accepts(&dfa, "b")); - ASSERT_TRUE(accepts(&dfa, "ab")); - ASSERT_TRUE(accepts(&dfa, "ba")); - ASSERT_TRUE(accepts(&dfa, "aaaab")); + ASSERT_TRUE(ACCEPTS(&dfa, "")); + ASSERT_TRUE(ACCEPTS(&dfa, "a")); + ASSERT_TRUE(ACCEPTS(&dfa, "b")); + ASSERT_TRUE(ACCEPTS(&dfa, "ab")); + ASSERT_TRUE(ACCEPTS(&dfa, "ba")); + ASSERT_TRUE(ACCEPTS(&dfa, "aaaab")); - ASSERT_FALSE(accepts(&dfa, "aaab")); - ASSERT_FALSE(accepts(&dfa, "aaaba")); - ASSERT_FALSE(accepts(&dfa, "aaabb")); - ASSERT_FALSE(accepts(&dfa, "aaaaab")); - ASSERT_FALSE(accepts(&dfa, "aaaaaba")); - ASSERT_FALSE(accepts(&dfa, "aaaaabb")); + ASSERT_FALSE(ACCEPTS(&dfa, "aaab")); + ASSERT_FALSE(ACCEPTS(&dfa, "aaaba")); + ASSERT_FALSE(ACCEPTS(&dfa, "aaabb")); + ASSERT_FALSE(ACCEPTS(&dfa, "aaaaab")); + ASSERT_FALSE(ACCEPTS(&dfa, "aaaaaba")); + ASSERT_FALSE(ACCEPTS(&dfa, "aaaaabb")); fsa_free(&nfa); fsa_free(&dfa); @@ -184,21 +166,21 @@ static void test_nfa_b(void) ASSERT_TRUE(is_deterministic(&dfa)); - ASSERT_TRUE(accepts(&dfa, "")); - ASSERT_TRUE(accepts(&dfa, "a")); - ASSERT_TRUE(accepts(&dfa, "aaaaaa")); - ASSERT_TRUE(accepts(&dfa, "b")); - ASSERT_TRUE(accepts(&dfa, "bbbbb")); - ASSERT_TRUE(accepts(&dfa, "aaaaaa")); - ASSERT_TRUE(accepts(&dfa, "aaaaabaa")); - ASSERT_TRUE(accepts(&dfa, "aaaaabaab")); + ASSERT_TRUE(ACCEPTS(&dfa, "")); + ASSERT_TRUE(ACCEPTS(&dfa, "a")); + ASSERT_TRUE(ACCEPTS(&dfa, "aaaaaa")); + ASSERT_TRUE(ACCEPTS(&dfa, "b")); + ASSERT_TRUE(ACCEPTS(&dfa, "bbbbb")); + ASSERT_TRUE(ACCEPTS(&dfa, "aaaaaa")); + ASSERT_TRUE(ACCEPTS(&dfa, "aaaaabaa")); + ASSERT_TRUE(ACCEPTS(&dfa, "aaaaabaab")); - ASSERT_FALSE(accepts(&dfa, "ba")); - ASSERT_FALSE(accepts(&dfa, "aba")); - ASSERT_FALSE(accepts(&dfa, "abab")); - ASSERT_FALSE(accepts(&dfa, "aaaaaba")); - ASSERT_FALSE(accepts(&dfa, "aaaaabaaa")); - ASSERT_FALSE(accepts(&dfa, "aaaaabbaabbaaa")); + ASSERT_FALSE(ACCEPTS(&dfa, "ba")); + ASSERT_FALSE(ACCEPTS(&dfa, "aba")); + ASSERT_FALSE(ACCEPTS(&dfa, "abab")); + ASSERT_FALSE(ACCEPTS(&dfa, "aaaaaba")); + ASSERT_FALSE(ACCEPTS(&dfa, "aaaaabaaa")); + ASSERT_FALSE(ACCEPTS(&dfa, "aaaaabbaabbaaa")); fsa_free(&nfa); fsa_free(&dfa); @@ -230,24 +212,24 @@ static void test_nfa_c(void) ASSERT_TRUE(is_deterministic(&dfa)); - ASSERT_TRUE(accepts(&dfa, "a")); - ASSERT_TRUE(accepts(&dfa, "aba")); - ASSERT_TRUE(accepts(&dfa, "aaba")); - ASSERT_TRUE(accepts(&dfa, "abaaba")); - ASSERT_TRUE(accepts(&dfa, "ba")); - ASSERT_TRUE(accepts(&dfa, "babba")); - ASSERT_TRUE(accepts(&dfa, "baaa")); - ASSERT_TRUE(accepts(&dfa, "baba")); - ASSERT_TRUE(accepts(&dfa, "babaa")); + ASSERT_TRUE(ACCEPTS(&dfa, "a")); + ASSERT_TRUE(ACCEPTS(&dfa, "aba")); + ASSERT_TRUE(ACCEPTS(&dfa, "aaba")); + ASSERT_TRUE(ACCEPTS(&dfa, "abaaba")); + ASSERT_TRUE(ACCEPTS(&dfa, "ba")); + ASSERT_TRUE(ACCEPTS(&dfa, "babba")); + ASSERT_TRUE(ACCEPTS(&dfa, "baaa")); + ASSERT_TRUE(ACCEPTS(&dfa, "baba")); + ASSERT_TRUE(ACCEPTS(&dfa, "babaa")); - ASSERT_FALSE(accepts(&dfa, "")); - ASSERT_FALSE(accepts(&dfa, "ab")); - ASSERT_FALSE(accepts(&dfa, "aab")); - ASSERT_FALSE(accepts(&dfa, "abbab")); - ASSERT_FALSE(accepts(&dfa, "b")); - ASSERT_FALSE(accepts(&dfa, "bb")); - ASSERT_FALSE(accepts(&dfa, "baaabab")); - ASSERT_FALSE(accepts(&dfa, "aabababab")); + ASSERT_FALSE(ACCEPTS(&dfa, "")); + ASSERT_FALSE(ACCEPTS(&dfa, "ab")); + ASSERT_FALSE(ACCEPTS(&dfa, "aab")); + ASSERT_FALSE(ACCEPTS(&dfa, "abbab")); + ASSERT_FALSE(ACCEPTS(&dfa, "b")); + ASSERT_FALSE(ACCEPTS(&dfa, "bb")); + ASSERT_FALSE(ACCEPTS(&dfa, "baaabab")); + ASSERT_FALSE(ACCEPTS(&dfa, "aabababab")); fsa_free(&nfa); fsa_free(&dfa);