void warn_nondeterministic_tags(const ctx_t &ctx)
{
    if (ctx.dc_opts->posix_syntax
        || ctx.dc_opts->stadfa) return;

    Warn &warn = ctx.dc_msg.warn;
    const kernels_t &kernels = ctx.dc_kernels;
    const std::vector<Tag> &tags = ctx.dfa.tags;
    const std::valarray<Rule> &rules = ctx.dfa.rules;

    const size_t
        ntag = tags.size(),
        nkrn = kernels.size(),
        nrule = rules.size();
    std::vector<size_t> maxv(ntag, 0);
    std::set<tagver_t> uniq;

    for (uint32_t i = 0; i < nkrn; ++i) {
        const kernel_t *k = kernels[i];
        nfa_state_t **s = k->state;
        const size_t n = k->size;
        const uint32_t *v = k->tvers;

        for (size_t u = 0; u < n;) {
            const size_t r = s[u]->rule;
            const Rule &rule = rules[r];

            const size_t l = u;
            for (; ++u < n && s[u]->rule == r;);
            for (size_t t = rule.ltag; t < rule.htag; ++t) {
                uniq.clear();
                for (size_t m = l; m < u; ++m) {
                    uniq.insert(ctx.dc_tagvertbl[v[m]][t]);
                }
                maxv[t] = std::max(maxv[t], uniq.size());
            }
        }
    }

    for (uint32_t r = 0; r < nrule; ++r) {
        const Rule &rule = rules[r];
        for (size_t t = rule.ltag; t < rule.htag; ++t) {
            const size_t m = maxv[t];
            if (m > 1) {
                warn.nondeterministic_tags(rule.semact->loc, ctx.dc_condname,
                    tags[t].name, m);
            }
        }
    }
}
void warn_nondeterministic_tags(const ctx_t &ctx)
{
    if (ctx.dc_opts->posix_syntax
        || ctx.dc_opts->stadfa) return;

    Warn &warn = ctx.dc_msg.warn;
    const kernels_t &kernels = ctx.dc_kernels;
    const std::vector<Tag> &tags = ctx.dfa.tags;
    const std::valarray<Rule> &rules = ctx.dfa.rules;

    const size_t
        ntag = tags.size(),
        nkrn = kernels.size(),
        nrule = rules.size();
    std::vector<size_t> maxv(ntag, 0);
    std::set<tagver_t> uniq;

    for (uint32_t i = 0; i < nkrn; ++i) {
        const kernel_t *k = kernels[i];
        nfa_state_t **s = k->state;
        const size_t n = k->size;
        const uint32_t *v = k->tvers;

        for (size_t u = 0; u < n;) {
            const size_t r = s[u]->rule;
            const Rule &rule = rules[r];

            const size_t l = u;
            for (; ++u < n && s[u]->rule == r;);
            for (size_t t = rule.ltag; t < rule.htag; ++t) {
                uniq.clear();
                for (size_t m = l; m < u; ++m) {
                    uniq.insert(ctx.dc_tagvertbl[v[m]][t]);
                }
                maxv[t] = std::max(maxv[t], uniq.size());
            }
        }
    }

    for (uint32_t r = 0; r < nrule; ++r) {
        const Rule &rule = rules[r];
        for (size_t t = rule.ltag; t < rule.htag; ++t) {
            const size_t m = maxv[t];
            if (m > 1) {
                warn.nondeterministic_tags(rule.semact->loc, ctx.dc_condname,
                    tags[t].name, m);
            }
        }
    }
}