Handle initial state being final in merge_fsas()
This commit is contained in:
parent
755f3f6805
commit
280168bb6f
@ -99,35 +99,33 @@ static void retarget_merged_rules(
|
|||||||
if (0 == rules[i].next)
|
if (0 == rules[i].next)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// IDs less than initial have to be offset by one less than
|
// If the state came before the initial state it should be
|
||||||
// base_count because the final state (ID zero) is not copied.
|
// offset by one less than base_count, because the final state
|
||||||
// If they are greater it's two less as the initial state is
|
// (index zero) came before it and was not copied into the
|
||||||
// also not copied. Finally, if the target is the initial
|
// base.
|
||||||
// state then it should be changed to the base's initial
|
const int before_offset = base_count - 1;
|
||||||
// state.
|
|
||||||
|
// If it came after the initial state it must be offset by two
|
||||||
|
// less than base_count because both the final state and the
|
||||||
|
// initial state came before it and were not copied -- unless
|
||||||
|
// the initial state is the same state as the final state, in
|
||||||
|
// which case the offset is still only one less than
|
||||||
|
// base_count.
|
||||||
|
const int after_offset = base_count - (0 != initial ? 2 : 1);
|
||||||
|
|
||||||
if (rules[i].next < initial)
|
if (rules[i].next < initial)
|
||||||
rules[i].next += base_count - 1;
|
rules[i].next += before_offset;
|
||||||
else if (rules[i].next > initial)
|
else if (rules[i].next > initial)
|
||||||
rules[i].next += base_count - 2;
|
rules[i].next += after_offset;
|
||||||
else
|
else if (rules[i].next == initial)
|
||||||
rules[i].next = base_initial;
|
rules[i].next = base_initial;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void merge_fsas(fsa_t *base, const fsa_t *other)
|
static void merge_fsas(fsa_t *base, const fsa_t *other)
|
||||||
{
|
{
|
||||||
const int new_count = base->count + other->count - 2;
|
// Copy rules from the other's initial state into the base's
|
||||||
if (base->capacity < new_count) {
|
// initial state.
|
||||||
do
|
|
||||||
base->capacity *= 2;
|
|
||||||
while (base->capacity < new_count);
|
|
||||||
base->states
|
|
||||||
= realloc(base->states, base->capacity * sizeof(fsa_state_t));
|
|
||||||
assert(base->states);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy rules from the other's initial state into the base's, then
|
|
||||||
// retarget them.
|
|
||||||
fsa_state_t *initial = &base->states[base->initial];
|
fsa_state_t *initial = &base->states[base->initial];
|
||||||
const fsa_state_t *other_initial = &other->states[other->initial];
|
const fsa_state_t *other_initial = &other->states[other->initial];
|
||||||
const int new_rule_count = initial->count + other_initial->count;
|
const int new_rule_count = initial->count + other_initial->count;
|
||||||
@ -142,13 +140,23 @@ static void merge_fsas(fsa_t *base, const fsa_t *other)
|
|||||||
memcpy(
|
memcpy(
|
||||||
&initial->rules[initial->count], other_initial->rules,
|
&initial->rules[initial->count], other_initial->rules,
|
||||||
other_initial->count * sizeof(fsa_rule_t));
|
other_initial->count * sizeof(fsa_rule_t));
|
||||||
|
|
||||||
|
// Retarget the copied rules.
|
||||||
retarget_merged_rules(
|
retarget_merged_rules(
|
||||||
&initial->rules[initial->count], other_initial->count,
|
&initial->rules[initial->count], other_initial->count,
|
||||||
other->initial, base->initial, base->count);
|
other->initial, base->initial, base->count);
|
||||||
initial->count = new_rule_count;
|
|
||||||
|
|
||||||
// Copy other states, skipping the initial state, then retarget
|
// Copy other states, skipping the initial state.
|
||||||
// their rules.
|
const int skipped_states = other->initial != 0 ? 2 : 1;
|
||||||
|
const int new_count = base->count + other->count - skipped_states;
|
||||||
|
if (base->capacity < new_count) {
|
||||||
|
do
|
||||||
|
base->capacity *= 2;
|
||||||
|
while (base->capacity < new_count);
|
||||||
|
base->states
|
||||||
|
= realloc(base->states, base->capacity * sizeof(fsa_state_t));
|
||||||
|
assert(base->states);
|
||||||
|
}
|
||||||
int offset = base->count;
|
int offset = base->count;
|
||||||
if (1 < other->initial) {
|
if (1 < other->initial) {
|
||||||
const int copy_count = other->initial - 1;
|
const int copy_count = other->initial - 1;
|
||||||
@ -163,15 +171,20 @@ static void merge_fsas(fsa_t *base, const fsa_t *other)
|
|||||||
&base->states[offset], &other->states[other->initial],
|
&base->states[offset], &other->states[other->initial],
|
||||||
copy_size);
|
copy_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Retarget the copied states' rules.
|
||||||
for (int i = base->count; i < new_count; ++i) {
|
for (int i = base->count; i < new_count; ++i) {
|
||||||
retarget_merged_rules(
|
retarget_merged_rules(
|
||||||
base->states[i].rules, base->states[i].count, other->initial,
|
base->states[i].rules, base->states[i].count, other->initial,
|
||||||
base->initial, base->count);
|
base->initial, base->count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
initial->count = new_rule_count;
|
||||||
base->count = new_count;
|
base->count = new_count;
|
||||||
|
|
||||||
free(other->states[0].rules);
|
free(other->states[0].rules);
|
||||||
free(other->states[other->initial].rules);
|
if (other->initial != 0)
|
||||||
|
free(other->states[other->initial].rules);
|
||||||
free(other->states);
|
free(other->states);
|
||||||
|
|
||||||
assert(base->states[0].final);
|
assert(base->states[0].final);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user