From e3e868f9002246ac398be38e558f19810193e1dd Mon Sep 17 00:00:00 2001 From: Scott Vokes Date: Wed, 9 Oct 2024 16:08:15 -0400 Subject: [PATCH 1/2] Temporary interface: Add fsm_determinise_with_config. This works, but we may want to make some naming changes. I'd prefer to use a struct rather than a single parameter here -- as long as other fields have a sensible default when zeroed, the callers will only need to make the interface change once. --- include/fsm/fsm.h | 15 ++++++++++++++ src/libfsm/determinise.c | 43 +++++++++++++++++++++++++++++++++------- src/libfsm/libfsm.syms | 1 + 3 files changed, 52 insertions(+), 7 deletions(-) diff --git a/include/fsm/fsm.h b/include/fsm/fsm.h index 877d5c1bf..1dd710d0e 100644 --- a/include/fsm/fsm.h +++ b/include/fsm/fsm.h @@ -385,6 +385,21 @@ fsm_remove_epsilons(struct fsm *fsm); int fsm_determinise(struct fsm *fsm); +/* Determinise, with a passed in configuration + * and a distinct return value for reaching + * the state limit. */ +struct fsm_determinise_config { + size_t state_limit; /* 0: no limit */ +}; +enum fsm_determinise_with_config_res { + FSM_DETERMINISE_WITH_CONFIG_OK, + FSM_DETERMINISE_WITH_CONFIG_STATE_LIMIT_REACHED, + FSM_DETERMINISE_WITH_CONFIG_ERRNO, +}; +enum fsm_determinise_with_config_res +fsm_determinise_with_config(struct fsm *fsm, + const struct fsm_determinise_config *config); + /* * Make a DFA complete, as per fsm_iscomplete. */ diff --git a/src/libfsm/determinise.c b/src/libfsm/determinise.c index 42992b6bc..0190e65ad 100644 --- a/src/libfsm/determinise.c +++ b/src/libfsm/determinise.c @@ -17,16 +17,20 @@ dump_labels(FILE *f, const uint64_t labels[4]) } } -int -fsm_determinise(struct fsm *nfa) +enum fsm_determinise_with_config_res +fsm_determinise_with_config(struct fsm *nfa, + const struct fsm_determinise_config *config) { - int res = 0; + enum fsm_determinise_with_config_res res = FSM_DETERMINISE_WITH_CONFIG_ERRNO; struct mappingstack *stack = NULL; struct interned_state_set_pool *issp = NULL; struct map map = { NULL, 0, 0, NULL }; struct mapping *curr = NULL; size_t dfacount = 0; + const size_t state_limit = config == NULL + ? 0 + : config->state_limit; struct analyze_closures_env ac_env = { 0 }; @@ -40,7 +44,7 @@ fsm_determinise(struct fsm *nfa) */ if (fsm_has(nfa, fsm_hasepsilons)) { if (!fsm_remove_epsilons(nfa)) { - return 0; + return FSM_DETERMINISE_WITH_CONFIG_ERRNO; } } @@ -52,7 +56,12 @@ fsm_determinise(struct fsm *nfa) issp = interned_state_set_pool_alloc(nfa->alloc); if (issp == NULL) { - return 0; + return FSM_DETERMINISE_WITH_CONFIG_ERRNO; + } + + if (state_limit != 0 && fsm_countstates(nfa) > state_limit) { + res = FSM_DETERMINISE_WITH_CONFIG_STATE_LIMIT_REACHED; + goto cleanup; } { @@ -74,7 +83,7 @@ fsm_determinise(struct fsm *nfa) */ if (!fsm_getstart(nfa, &start)) { - res = 1; + res = FSM_DETERMINISE_WITH_CONFIG_OK; goto cleanup; } @@ -150,6 +159,11 @@ fsm_determinise(struct fsm *nfa) assert(m->dfastate < dfacount); } else { /* not found -- add a new one and push it to the stack for processing */ + + if (state_limit != 0 && dfacount > state_limit) { + res = FSM_DETERMINISE_WITH_CONFIG_STATE_LIMIT_REACHED; + goto cleanup; + } if (!map_add(&map, dfacount, iss, &m)) { goto cleanup; } @@ -260,7 +274,7 @@ fsm_determinise(struct fsm *nfa) assert(fsm_all(nfa, fsm_isdfa)); #endif - res = 1; + res = FSM_DETERMINISE_WITH_CONFIG_OK; cleanup: map_free(&map); @@ -311,6 +325,21 @@ fsm_determinise(struct fsm *nfa) return res; } +int +fsm_determinise(struct fsm *nfa) +{ + enum fsm_determinise_with_config_res res = fsm_determinise_with_config(nfa, NULL); + switch (res) { + case FSM_DETERMINISE_WITH_CONFIG_OK: + return 1; + case FSM_DETERMINISE_WITH_CONFIG_STATE_LIMIT_REACHED: + /* unreachable */ + return 0; + case FSM_DETERMINISE_WITH_CONFIG_ERRNO: + return 0; + } +} + /* Add DFA_state to the list for NFA_state. */ static int add_reverse_mapping(const struct fsm_alloc *alloc, diff --git a/src/libfsm/libfsm.syms b/src/libfsm/libfsm.syms index 34be09e77..67497d00a 100644 --- a/src/libfsm/libfsm.syms +++ b/src/libfsm/libfsm.syms @@ -101,6 +101,7 @@ fsm_countstates fsm_trim fsm_reverse fsm_determinise +fsm_determinise_with_config fsm_remove_epsilons fsm_complete fsm_minimise From 07e1a0ce6a0c6d4d11b4790435217cac8c371bbf Mon Sep 17 00:00:00 2001 From: Scott Vokes Date: Thu, 10 Oct 2024 11:44:01 -0400 Subject: [PATCH 2/2] Add 'default:' (should be unreachable) for switch case. This is getting rejected by CI. --- src/libfsm/determinise.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libfsm/determinise.c b/src/libfsm/determinise.c index 0190e65ad..559230175 100644 --- a/src/libfsm/determinise.c +++ b/src/libfsm/determinise.c @@ -336,6 +336,7 @@ fsm_determinise(struct fsm *nfa) /* unreachable */ return 0; case FSM_DETERMINISE_WITH_CONFIG_ERRNO: + default: return 0; } }