namespace re2c
{
-static void closure_one(closure_t &clos, Tagpool &tagpool, tagtree_t &tagtree,
- clos_t &c0, nfa_state_t *n, const std::vector<Tag> &tags, closure_t *shadow, std::valarray<Rule> &rules);
-static bool better(const clos_t &c1, const clos_t &c2, Tagpool &tagpool, tagtree_t &tagtree, const std::vector<Tag> &tags);
+static void closure_one(closure_t &clos, Tagpool &tagpool, clos_t &c0,
+ nfa_state_t *n, const std::vector<Tag> &tags, closure_t *shadow, std::valarray<Rule> &rules);
+static bool better(const clos_t &c1, const clos_t &c2, Tagpool &tagpool, const std::vector<Tag> &tags);
static void lower_lookahead_to_transition(closure_t &clos);
-static tcmd_t *generate_versions(closure_t &clos, const std::vector<Tag> &tags, Tagpool &tagpool, tcpool_t &tcpool, tagver_t &maxver, newvers_t &newvers);
-static void orders(closure_t &clos, Tagpool &tagpool, tagtree_t &tagtree, const std::vector<Tag> &tags);
+static tcmd_t *generate_versions(closure_t &clos, const std::vector<Tag> &tags,
+ Tagpool &tagpool, tcpool_t &tcpool, tagver_t &maxver, newvers_t &newvers);
+static void orders(closure_t &clos, Tagpool &tagpool, const std::vector<Tag> &tags);
static bool cmpby_rule_state(const clos_t &x, const clos_t &y);
tcmd_t *closure(closure_t &clos1, closure_t &clos2, Tagpool &tagpool,
- tcpool_t &tcpool, tagtree_t &tagtree, std::valarray<Rule> &rules,
- tagver_t &maxver, newvers_t &newvers, bool lookahead, closure_t *shadow,
+ tcpool_t &tcpool, std::valarray<Rule> &rules, tagver_t &maxver,
+ newvers_t &newvers, bool lookahead, closure_t *shadow,
const std::vector<Tag> &tags)
{
// build tagged epsilon-closure of the given set of NFA states
clos2.clear();
if (shadow) shadow->clear();
- tagtree.init();
+ tagpool.history.init();
for (clositer_t c = clos1.begin(); c != clos1.end(); ++c) {
- closure_one(clos2, tagpool, tagtree, *c, c->state, tags, shadow, rules);
+ closure_one(clos2, tagpool, *c, c->state, tags, shadow, rules);
}
- orders(clos2, tagpool, tagtree, tags);
+ orders(clos2, tagpool, tags);
std::sort(clos2.begin(), clos2.end(), cmpby_rule_state);
* to leftmost strategy; orbit tags are compared by order and by tagged
* epsilon-paths so that earlier iterations are maximized).
*/
-void closure_one(closure_t &clos, Tagpool &tagpool, tagtree_t &tagtree, clos_t &c0,
+void closure_one(closure_t &clos, Tagpool &tagpool, clos_t &c0,
nfa_state_t *n, const std::vector<Tag> &tags, closure_t *shadow,
std::valarray<Rule> &rules)
{
if (n->loop) return;
local_increment_t<uint8_t> _(n->loop);
+ tagtree_t &tagtree = tagpool.history;
clositer_t c = clos.begin(), e = clos.end();
switch (n->type) {
case nfa_state_t::NIL:
- closure_one(clos, tagpool, tagtree, c0, n->nil.out, tags, shadow, rules);
+ closure_one(clos, tagpool, c0, n->nil.out, tags, shadow, rules);
return;
case nfa_state_t::ALT:
- closure_one(clos, tagpool, tagtree, c0, n->alt.out1, tags, shadow, rules);
- closure_one(clos, tagpool, tagtree, c0, n->alt.out2, tags, shadow, rules);
+ closure_one(clos, tagpool, c0, n->alt.out1, tags, shadow, rules);
+ closure_one(clos, tagpool, c0, n->alt.out2, tags, shadow, rules);
return;
case nfa_state_t::TAG:
tagtree.push(n->tag.info, n->tag.bottom ? TAGVER_BOTTOM : TAGVER_CURSOR);
- closure_one(clos, tagpool, tagtree, c0, n->tag.out, tags, shadow, rules);
+ closure_one(clos, tagpool, c0, n->tag.out, tags, shadow, rules);
tagtree.pop(n->tag.info);
return;
case nfa_state_t::RAN:
clos.push_back(c2);
} else {
clos_t &c1 = *c;
- if (better(c1, c2, tagpool, tagtree, tags)) std::swap(c1, c2);
+ if (better(c1, c2, tagpool, tags)) std::swap(c1, c2);
if (shadow) shadow->push_back(c2);
}
}
*/
bool better(const clos_t &c1, const clos_t &c2,
- Tagpool &tagpool, tagtree_t &tagtree, const std::vector<Tag> &tags)
+ Tagpool &tagpool, const std::vector<Tag> &tags)
{
if (c1.ttran == c2.ttran
&& c1.tvers == c2.tvers
*v1 = tagpool[c1.tvers], *v2 = tagpool[c2.tvers],
*o1 = tagpool[c1.order], *o2 = tagpool[c2.order];
tagver_t x, y;
+ tagtree_t &tagtree = tagpool.history;
for (size_t t = 0; t < tagpool.ntags; ++t) {
const Tag &tag = tags[t];
if (x > y) return false;
if (x < y) return true;
- x = t1[t]; y = t2[t];
+ x = tagtree.elem(t1[t]);
+ y = tagtree.elem(t2[t]);
if (x < 0 || y < 0) goto leftmost;
if (x > y) return false;
if (x < y) return true;
tcmd_t *cmd = NULL, *p;
const size_t ntag = tagpool.ntags;
tagver_t *vers = tagpool.buffer;
+ tagtree_t &tagtree = tagpool.history;
clositer_t b = clos.begin(), e = clos.end(), c;
// for each tag, if there is at least one tagged transition,
*vs = tagpool[c->tvers];
for (size_t t = 0; t < ntag; ++t) {
const Tag &tag = tags[t];
- const tagver_t u = us[t];
+ const tagver_t
+ u = tagtree.elem(us[t]),
+ l = tagtree.elem(ls[t]);
if (u == TAGVER_ZERO) continue;
const tagver_t h = history(tag) ? vs[t] : TAGVER_ZERO;
if (n == m) ++maxver;
// add action unless already have an identical one
- if (fixed(tag) || (ls[t] && !history(tag))) continue;
+ if (fixed(tag) || (l && !history(tag))) continue;
for (p = cmd; p; p = p->next) {
if (p->lhs == abs(m) && p->rhs == u && p->pred == abs(h)) break;
}
*us = tagpool[c->ttran],
*vs = tagpool[c->tvers];
for (size_t t = 0; t < ntag; ++t) {
- const tagver_t u = us[t], v = vs[t],
+ const tagver_t v = vs[t],
+ u = tagtree.elem(us[t]),
h = history(tags[t]) ? v : TAGVER_ZERO;
if (u == TAGVER_ZERO) {
vers[t] = v;
}
};
-void orders(closure_t &clos, Tagpool &tagpool,
- tagtree_t &tagtree, const std::vector<Tag> &tags)
+void orders(closure_t &clos, Tagpool &tagpool, const std::vector<Tag> &tags)
{
+ tagtree_t &tagtree = tagpool.history;
clositer_t b = clos.begin(), e = clos.end(), c;
const size_t
ntag = tagpool.ntags,
for (c = b; c != e; ++c, o += ntag) {
c->order = tagpool.insert(o);
}
-
- // flatten lookahead tags (take the last on each path)
- tagver_t *look = tagpool.buffer;
- for (clositer_t c = clos.begin(); c != clos.end(); ++c) {
- if (c->tlook == ZERO_TAGS) continue;
- const tagver_t *oldl = tagpool[c->tlook];
- for (size_t t = 0; t < ntag; ++t) {
- look[t] = tagtree.elem(oldl[t]);
- }
- c->tlook = tagpool.insert(look);
- }
}
} // namespace re2c
const bool lookahead = opts->lookahead;
const size_t ntag = tags.size();
Tagpool tagpool(ntag);
- tagtree_t tagtree(ntag);
kernels_t kernels(tagpool, tcpool, tags);
closure_t clos1, clos2;
newvers_t newvers;
clos_t c0 = {NULL, nfa.root, INITIAL_TAGS, ZERO_TAGS, ZERO_TAGS, ZERO_TAGS, 0};
clos1.push_back(c0);
- acts = closure(clos1, clos2, tagpool, tcpool, tagtree, rules, maxtagver, newvers, lookahead, dump.shadow, tags);
+ acts = closure(clos1, clos2, tagpool, tcpool, rules, maxtagver, newvers, lookahead, dump.shadow, tags);
find_state(*this, dfa_t::NIL, 0/* any */, kernels, clos2, acts, dump);
for (size_t i = 0; i < kernels.size(); ++i) {
newvers.clear();
for (size_t c = 0; c < nchars; ++c) {
reach(kernels[i], clos1, charset[c]);
- acts = closure(clos1, clos2, tagpool, tcpool, tagtree, rules, maxtagver, newvers, lookahead, dump.shadow, tags);
+ acts = closure(clos1, clos2, tagpool, tcpool, rules, maxtagver, newvers, lookahead, dump.shadow, tags);
find_state(*this, i, c, kernels, clos2, acts, dump);
}
}
delete[] order;
}
+static bool equal_lookahead_tags(const kernel_t *x, const kernel_t *y,
+ const Tagpool &tagpool)
+{
+ if (memcmp(x->tlook, y->tlook, x->size * sizeof(size_t)) == 0) {
+ return true;
+ }
+ for (size_t i = 0; i < x->size; ++i) {
+ const tagver_t
+ *xls = tagpool[x->tlook[i]],
+ *yls = tagpool[y->tlook[i]];
+ for (size_t t = 0; t < tagpool.ntags; ++t) {
+ // compare only the last tags
+ const tagver_t
+ xl = tagpool.history.elem(xls[t]),
+ yl = tagpool.history.elem(yls[t]);
+ if (xl != yl) return false;
+ }
+ }
+ return true;
+}
+
struct kernel_eq_t
{
+ Tagpool &tagpool;
bool operator()(const kernel_t *x, const kernel_t *y) const
{
return x->size == y->size
&& memcmp(x->state, y->state, x->size * sizeof(void*)) == 0
&& memcmp(x->tvers, y->tvers, x->size * sizeof(size_t)) == 0
- && memcmp(x->tlook, y->tlook, x->size * sizeof(size_t)) == 0;
- // no need to compare orders: if versions and lookahead coincide, so do orders
+ && equal_lookahead_tags(x, y, tagpool);
+ // if versions and lookahead coincide, so do orders
}
};
// check that kernel sizes, NFA states and orders coincide
const bool compatible = k1->size == k2->size
&& memcmp(k1->state, k2->state, k1->size * sizeof(void*)) == 0
- && memcmp(k1->tlook, k2->tlook, k1->size * sizeof(size_t)) == 0
- && memcmp(k1->order, k2->order, k1->size * sizeof(size_t)) == 0;
+ && memcmp(k1->order, k2->order, k1->size * sizeof(size_t)) == 0
+ && equal_lookahead_tags(k1, k2, tagpool);
if (!compatible) return false;
// map tag versions of one kernel to that of another
const tagver_t
*xv = tagpool[k1->tvers[i]],
*yv = tagpool[k2->tvers[i]],
- *xl = tagpool[k2->tlook[i]];
+ *xl = tagpool[k1->tlook[i]];
for (size_t t = 0; t < ntag; ++t) {
// see note [mapping ignores items with lookahead tags]
- if (xl[t] != TAGVER_ZERO && !history(tags[t])) continue;
+ if (tagpool.history.elem(xl[t]) != TAGVER_ZERO
+ && !history(tags[t])) continue;
const tagver_t x = xv[t], y = yv[t];
tagver_t &x0 = y2x[y], &y0 = x2y[x];
// get kernel hash
uint32_t hash = static_cast<uint32_t>(nkern); // seed
hash = hash32(hash, buffer->state, nkern * sizeof(void*));
- hash = hash32(hash, buffer->tlook, nkern * sizeof(size_t));
hash = hash32(hash, buffer->order, nkern * sizeof(size_t));
// try to find identical kernel
- kernel_eq_t eq;
+ kernel_eq_t eq = {tagpool};
x = lookup.find_with(hash, buffer, eq);
if (x != index_t::NIL) return result_t(x, acts, false);
tcmd_t *copy = NULL, *save = NULL, **p;
for (size_t t = rule.ltag; t < rule.htag; ++t) {
- const tagver_t l = look[t], v = abs(vers[t]),
+ const tagver_t v = abs(vers[t]),
+ l = tagpool.history.elem(look[t]),
h = history(tags[t]) ? v : TAGVER_ZERO;
tagver_t &f = dfa.finvers[t];