Implement star construction

This commit is contained in:
2024-10-27 13:24:29 +00:00
parent d54080032c
commit bbecd12c91
2 changed files with 85 additions and 1 deletions

View File

@@ -17,6 +17,53 @@ static void construct_literal(char literal, fsa_t *out)
out->initial = id;
}
static void star_fsa(fsa_t *fsa)
{
// If the initial state is already the final state then nothing
// needs to be done.
if (0 == fsa->initial)
return;
// Copy inital state's rules to final state.
fsa_state_t *final = &fsa->states[0];
const fsa_state_t *initial = &fsa->states[fsa->initial];
if (final->capacity < final->count + initial->count) {
do
final->capacity *= 2;
while (final->capacity < final->count + initial->count);
final->rules
= realloc(final->rules, final->capacity * sizeof(fsa_rule_t));
assert(final->rules);
}
const int copy_size = initial->count * sizeof(fsa_rule_t);
memcpy(&final->rules[final->count], initial->rules, copy_size);
final->count += initial->count;
// Move states that come after initial state if there are any.
if (fsa->count - 1 > fsa->initial) {
const int count = fsa->count - fsa->initial - 1;
fsa_state_t *start = &fsa->states[fsa->initial];
memmove(start, start + 1, count * sizeof(fsa_state_t));
}
// Retarget all states' rules.
for (int i = 0; i < fsa->count - 1; ++i) {
for (int j = 0; j < fsa->states[i].count; ++j) {
if (fsa->states[i].rules[j].next == fsa->initial)
fsa->states[i].rules[j].next = 0;
else if (fsa->states[i].rules[j].next > fsa->initial)
// All states after the initial state have been moved
// down by one position.
--fsa->states[i].rules[j].next;
}
}
--fsa->count;
fsa->initial = 0;
free(initial->rules);
}
static void construct_term(const regex_term_t *term, fsa_t *out)
{
switch (term->type) {
@@ -28,10 +75,22 @@ static void construct_term(const regex_term_t *term, fsa_t *out)
break;
case REGEX_TERM_SUBEXPR:
return;
case REGEX_TERM_WILDCARD:
case REGEX_TERM_CLASS:
assert(false);
break;
}
switch (term->quantifier) {
case REGEX_QUANTIFIER_NONE:
break;
case REGEX_QUANTIFIER_STAR:
star_fsa(out);
break;
case REGEX_QUANTIFIER_PLUS:
case REGEX_QUANTIFIER_QMARK:
assert(false);
break;
}
assert(out->states[0].final);