vkdoom_m/tools/re2c/src/ir/dfa/minimization.cc
2016-02-06 20:58:35 -06:00

252 lines
5 KiB
C++

#include <string.h>
#include <utility>
#include <vector>
#include "src/conf/opt.h"
#include "src/ir/dfa/dfa.h"
#include "src/globals.h"
namespace re2c
{
class RuleOp;
/*
* note [DFA minimization: table filling algorithm]
*
* This algorithm is simple and slow; it's a reference implementation.
*
* The algorithm constructs (strictly lower triangular) boolean matrix
* indexed by DFA states. Each matrix cell (S1,S2) indicates if states
* S1 and S2 are distinguishable. Initialy states are distinguished
* according to their rule and context. One step of the algorithm
* updates the matrix as follows: each pair of states S1 and S2 is
* marked as distinguishable iff exist transitions from S1 and S2 on
* the same symbol that go to distinguishable states. The algorithm
* loops until the matrix stops changing.
*/
static void minimization_table(
size_t *part,
const std::vector<dfa_state_t*> &states,
size_t nchars)
{
const size_t count = states.size();
bool **tbl = new bool*[count];
tbl[0] = new bool[count * (count - 1) / 2];
for (size_t i = 0; i < count - 1; ++i)
{
tbl[i + 1] = tbl[i] + i;
}
for (size_t i = 0; i < count; ++i)
{
dfa_state_t *s1 = states[i];
for (size_t j = 0; j < i; ++j)
{
dfa_state_t *s2 = states[j];
tbl[i][j] = s1->ctx != s2->ctx
|| s1->rule != s2->rule;
}
}
for (bool loop = true; loop;)
{
loop = false;
for (size_t i = 0; i < count; ++i)
{
for (size_t j = 0; j < i; ++j)
{
if (!tbl[i][j])
{
for (size_t k = 0; k < nchars; ++k)
{
size_t oi = states[i]->arcs[k];
size_t oj = states[j]->arcs[k];
if (oi < oj)
{
std::swap(oi, oj);
}
if (oi != oj &&
(oi == dfa_t::NIL ||
oj == dfa_t::NIL ||
tbl[oi][oj]))
{
tbl[i][j] = true;
loop = true;
break;
}
}
}
}
}
}
for (size_t i = 0; i < count; ++i)
{
part[i] = i;
for (size_t j = 0; j < i; ++j)
{
if (!tbl[i][j])
{
part[i] = j;
break;
}
}
}
delete[] tbl[0];
delete[] tbl;
}
/*
* note [DFA minimization: Moore algorithm]
*
* The algorithm maintains partition of DFA states.
* Initial partition is coarse: states are distinguished according
* to their rule and context. Partition is gradually refined: each
* set of states is split into minimal number of subsets such that
* for all states in a subset transitions on the same symbol go to
* the same set of states.
* The algorithm loops until partition stops changing.
*/
static void minimization_moore(
size_t *part,
const std::vector<dfa_state_t*> &states,
size_t nchars)
{
const size_t count = states.size();
size_t *next = new size_t[count];
std::map<std::pair<RuleOp*, bool>, size_t> init;
for (size_t i = 0; i < count; ++i)
{
dfa_state_t *s = states[i];
std::pair<RuleOp*, bool> key(s->rule, s->ctx);
if (init.insert(std::make_pair(key, i)).second)
{
part[i] = i;
next[i] = dfa_t::NIL;
}
else
{
const size_t j = init[key];
part[i] = j;
next[i] = next[j];
next[j] = i;
}
}
size_t *out = new size_t[nchars * count];
size_t *diff = new size_t[count];
for (bool loop = true; loop;)
{
loop = false;
for (size_t i = 0; i < count; ++i)
{
if (i != part[i] || next[i] == dfa_t::NIL)
{
continue;
}
for (size_t j = i; j != dfa_t::NIL; j = next[j])
{
size_t *o = &out[j * nchars];
size_t *a = states[j]->arcs;
for (size_t c = 0; c < nchars; ++c)
{
o[c] = a[c] == dfa_t::NIL
? dfa_t::NIL
: part[a[c]];
}
}
size_t diff_count = 0;
for (size_t j = i; j != dfa_t::NIL;)
{
const size_t j_next = next[j];
size_t n = 0;
for (; n < diff_count; ++n)
{
size_t k = diff[n];
if (memcmp(&out[j * nchars],
&out[k * nchars],
nchars * sizeof(size_t)) == 0)
{
part[j] = k;
next[j] = next[k];
next[k] = j;
break;
}
}
if (n == diff_count)
{
diff[diff_count++] = j;
part[j] = j;
next[j] = dfa_t::NIL;
}
j = j_next;
}
loop |= diff_count > 1;
}
}
delete[] out;
delete[] diff;
delete[] next;
}
void minimization(dfa_t &dfa)
{
const size_t count = dfa.states.size();
size_t *part = new size_t[count];
switch (opts->dfa_minimization)
{
case DFA_MINIMIZATION_TABLE:
minimization_table(part, dfa.states, dfa.nchars);
break;
case DFA_MINIMIZATION_MOORE:
minimization_moore(part, dfa.states, dfa.nchars);
break;
}
size_t *compact = new size_t[count];
for (size_t i = 0, j = 0; i < count; ++i)
{
if (i == part[i])
{
compact[i] = j++;
}
}
size_t new_count = 0;
for (size_t i = 0; i < count; ++i)
{
dfa_state_t *s = dfa.states[i];
if (i == part[i])
{
size_t *arcs = s->arcs;
for (size_t c = 0; c < dfa.nchars; ++c)
{
if (arcs[c] != dfa_t::NIL)
{
arcs[c] = compact[part[arcs[c]]];
}
}
dfa.states[new_count++] = s;
}
else
{
delete s;
}
}
dfa.states.resize(new_count);
delete[] compact;
delete[] part;
}
} // namespace re2c