Пример #1
0
static
void setReportId(ReportManager &rm, NGWrapper &g, NFAVertex v, s32 adj) {
    // Don't try and set the report ID of a special vertex.
    assert(!is_special(v, g));

    // There should be no reports set already.
    assert(g[v].reports.empty());

    Report r = rm.getBasicInternalReport(g, adj);

    g[v].reports.insert(rm.getInternalId(r));
    DEBUG_PRINTF("set report id for vertex %u, adj %d\n",
                 g[v].index, adj);
}
Пример #2
0
/** \brief Replace the graph's reports with new reports that specify bounds. */
static
void updateReportBounds(ReportManager &rm, NGWrapper &g, NFAVertex accept,
                        set<NFAVertex> &done) {
    for (auto v : inv_adjacent_vertices_range(accept, g)) {
        // Don't operate on g.accept itself.
        if (v == g.accept) {
            assert(accept == g.acceptEod);
            continue;
        }

        // Don't operate on a vertex we've already done.
        if (contains(done, v)) {
            continue;
        }
        done.insert(v);

        flat_set<ReportID> new_reports;
        auto &reports = g[v].reports;

        for (auto id : reports) {
            Report ir = rm.getReport(id); // make a copy
            assert(!ir.hasBounds());

            // Note that we need to cope with offset adjustment here.

            ir.minOffset = g.min_offset - ir.offsetAdjust;
            if (g.max_offset == MAX_OFFSET) {
                ir.maxOffset = MAX_OFFSET;
            } else {
                ir.maxOffset = g.max_offset - ir.offsetAdjust;
            }
            assert(ir.maxOffset >= ir.minOffset);

            ir.minLength = g.min_length;
            if (g.min_length && !g.som) {
                ir.quashSom = true;
            }

            DEBUG_PRINTF("id %u -> min_offset=%llu, max_offset=%llu, "
                         "min_length=%llu\n",
                         id, ir.minOffset, ir.maxOffset, ir.minLength);
            new_reports.insert(rm.getInternalId(ir));
        }

        DEBUG_PRINTF("swapping reports on vertex %u\n",
                     g[v].index);
        reports.swap(new_reports);
    }
}
Пример #3
0
static
void getHighlanderReporters(const NGHolder &g, const NFAVertex accept,
                            const ReportManager &rm,
                            set<NFAVertex> &verts) {
    for (auto v : inv_adjacent_vertices_range(accept, g)) {
        if (v == g.accept) {
            continue;
        }

        const auto &reports = g[v].reports;
        if (reports.empty()) {
            assert(0);
            continue;
        }

        // Must be _all_ highlander callback reports.
        for (auto report : reports) {
            const Report &ir = rm.getReport(report);
            if (ir.ekey == INVALID_EKEY || ir.type != EXTERNAL_CALLBACK) {
                goto next_vertex;
            }

            // If there's any bounds, these are handled outside the NFA and
            // probably shouldn't be pre-empted.
            if (ir.hasBounds()) {
                goto next_vertex;
            }
        }

        verts.insert(v);
    next_vertex:
        continue;
    }
}
Пример #4
0
SourceManager::SourceManager(StringPool &strings, ReportManager &reports)
 : strings_(strings),
   rr_(reports),
   next_source_id_(1),
   last_lookup_(0)
{
  reports.setSourceManager(this);
}
Пример #5
0
static
bool hasOffsetAdjustments(const ReportManager &rm, const NGHolder &g) {
    for (auto report : all_reports(g)) {
        const Report &ir = rm.getReport(report);
        if (ir.offsetAdjust) {
            return true;
        }
    }
    return false;
}
Пример #6
0
int main(int argc, char **argv)
{
  args::Parser parser("Documentation generator.");

  args::StringOption filename(parser,
    "filename",
    "SourcePawn file to scan for documentation.");

  StringPool strings;
  ReportManager reports;
  SourceManager source(strings, reports);

  if (!parser.parse(argc, argv)) {
    parser.usage(stderr, argc, argv);
    return 1;
  }

  PoolAllocator pool;
  {
    PoolScope scope(pool);

    CompileContext cc(pool, strings, reports, source);

    cc.SkipResolution();

    const char* file = filename.value().chars();
    JsonObject *obj = Run(cc, file);
    if (!obj) {
      reports.PrintMessages();
      return 1;
    }

    JsonRenderer renderer(stdout);
    renderer.Render(obj);

    if (reports.HasMessages())
      reports.PrintMessages();
  }

  return 0;
}
Пример #7
0
static
bool hasOffsetAdjust(const ReportManager &rm, NGWrapper &g,
                     int *adjust) {
    const auto &reports = all_reports(g);
    if (reports.empty()) {
        assert(0);
        return false;
    }

    int offsetAdjust = rm.getReport(*reports.begin()).offsetAdjust;
    for (auto report : reports) {
        const Report &ir = rm.getReport(report);
        if (ir.offsetAdjust != offsetAdjust) {
            DEBUG_PRINTF("different adjusts!\n");
            return false;
        }
    }

    *adjust = offsetAdjust;
    return true;
}
Пример #8
0
void dumpReportManager(const ReportManager &rm, const Grey &grey) {
    if (!grey.dumpFlags) {
        return;
    }

    stringstream ss;
    ss << grey.dumpPath << "internal_reports.txt";
    FILE *f = fopen(ss.str().c_str(), "w");
    const vector<Report> &reports = rm.reports();
    for (u32 i = 0; i < reports.size(); i++) {
        const Report &ir = reports[i];
        fprintf(f, "int %u: %s onmatch: %u", i, irTypeToString(ir.type),
                ir.onmatch);

        u32 dkey = rm.getDkey(ir);
        if (dkey != MO_INVALID_IDX) {
            fprintf(f, " dkey %u", dkey);
        }
        if (ir.ekey != MO_INVALID_IDX) {
            fprintf(f, " ekey %u", ir.ekey);
        }
        if (ir.hasBounds()) {
            fprintf(f, " hasBounds (minOffset=%llu, maxOffset=%llu, "
                       "minLength=%llu)",
                    ir.minOffset, ir.maxOffset, ir.minLength);
        }
        if (ir.offsetAdjust != 0) {
            fprintf(f, " offsetAdjust: %d", ir.offsetAdjust);
        }
        if (isReverseNfaReport(ir)) {
            fprintf(f, " reverse nfa: %u", ir.revNfaIndex);
        }
        if (isSomRelSetReport(ir)) {
            fprintf(f, " set, adjust: %lld", ir.somDistance);
        }
        fprintf(f, "\n");
    }
    fclose(f);
}
Пример #9
0
/** \brief Find the (min, max) offset adjustment for the reports on a given
 * vertex. */
static
pair<s32,s32> getMinMaxOffsetAdjust(const ReportManager &rm,
                                    const NGHolder &g, NFAVertex v) {
    s32 minAdj = 0, maxAdj = 0;
    const auto &reports = g[v].reports;
    for (auto ri = reports.begin(), re = reports.end(); ri != re; ++ri) {
        const Report &ir = rm.getReport(*ri);
        if (ri == reports.begin()) {
            minAdj = ir.offsetAdjust;
            maxAdj = ir.offsetAdjust;
        } else {
            minAdj = min(minAdj, ir.offsetAdjust);
            maxAdj = max(maxAdj, ir.offsetAdjust);
        }
    }

    return make_pair(minAdj, maxAdj);
}
Пример #10
0
set<u32> reportsToEkeys(const set<ReportID> &reports, const ReportManager &rm) {
    assert(!reports.empty());

    set<u32> ekeys;

    for (auto it = reports.begin(), ite = reports.end(); it != ite; ++it) {
        u32 e = rm.getReport(*it).ekey;
        if (it == reports.begin()) {
            if (e != INVALID_EKEY) {
                ekeys.insert(e);
            }
        } else {
            ekeysUnion(&ekeys, e);
        }
    }

    return ekeys;
}
Пример #11
0
/**
 * True if the vertex has (a) a self-loop, (b) only out-edges to accept and
 * itself and (c) only simple exhaustible reports.
 */
static
bool hasOnlySelfLoopAndExhaustibleAccepts(const NGHolder &g,
                                          const ReportManager &rm,
                                          NFAVertex v) {
    if (!edge(v, v, g).second) {
        return false;
    }

    for (auto w : adjacent_vertices_range(v, g)) {
        if (w != v && w != g.accept) {
            return false;
        }
    }

    for (const auto &report_id : g[v].reports) {
        if (!isSimpleExhaustible(rm.getReport(report_id))) {
            return false;
        }
    }

    return true;
}
Пример #12
0
/** Remove any edges from vertices that generate accepts (for Highlander
 * graphs). */
void pruneHighlanderAccepts(NGHolder &g, const ReportManager &rm) {
    // Safety check: all reports must be simple exhaustible reports, or this is
    // not safe. This optimisation should be called early enough that no
    // internal reports have been added.
    for (auto report_id : all_reports(g)) {
        const Report &ir = rm.getReport(report_id);

        if (ir.ekey == INVALID_EKEY || ir.hasBounds() ||
            !isExternalReport(ir)) {
            DEBUG_PRINTF("report %u is not external highlander with "
                         "no bounds\n", report_id);
            return;
        }
    }

    vector<NFAEdge> dead;
    for (auto u : inv_adjacent_vertices_range(g.accept, g)) {
        if (is_special(u, g)) {
            continue;
        }

        // We can prune any out-edges that aren't accepts
        for (const auto &e : out_edges_range(u, g)) {
            if (!is_any_accept(target(e, g), g)) {
                dead.push_back(e);
            }
        }
    }

    if (dead.empty()) {
        return;
    }

    DEBUG_PRINTF("found %zu removable edges due to single match\n", dead.size());
    remove_edges(dead, g);
    pruneUseless(g);
}
Пример #13
0
void pruneHighlanderDominated(NGHolder &g, const ReportManager &rm) {
    vector<NFAVertex> reporters;
    for (auto v : inv_adjacent_vertices_range(g.accept, g)) {
        for (const auto &report_id : g[v].reports) {
            const Report &r = rm.getReport(report_id);
            if (isSimpleExhaustible(r)) {
                reporters.push_back(v);
                break;
            }
        }
    }
    for (auto v : inv_adjacent_vertices_range(g.acceptEod, g)) {
        for (const auto &report_id : g[v].reports) {
            const Report &r = rm.getReport(report_id);
            if (isSimpleExhaustible(r)) {
                reporters.push_back(v);
                break;
            }
        }
    }

    if (reporters.empty()) {
        return;
    }


    sort(begin(reporters), end(reporters), make_index_ordering(g));
    reporters.erase(unique(begin(reporters), end(reporters)), end(reporters));

    DEBUG_PRINTF("%zu vertices have simple exhaustible reports\n",
                 reporters.size());

    const auto &dom = findDominators(g);
    bool modified = false;

    // If a reporter vertex is dominated by another with the same report, we
    // can remove that report; if all reports are removed, we can remove the
    // vertex entirely.
    for (const auto v : reporters) {
        const auto reports = g[v].reports; // copy, as we're going to mutate
        for (const auto &report_id : reports) {
            if (!isSimpleExhaustible(rm.getReport(report_id))) {
                continue;
            }
            if (isDominatedByReporter(g, dom, v, report_id)) {
                DEBUG_PRINTF("removed dominated report %u from vertex %u\n",
                             report_id, g[v].index);
                g[v].reports.erase(report_id);
            }
        }

        if (g[v].reports.empty()) {
            DEBUG_PRINTF("removed edges to accepts from %u, no reports left\n",
                          g[v].index);
            remove_edge(v, g.accept, g);
            remove_edge(v, g.acceptEod, g);
            modified = true;
        }
    }

    // If a reporter vertex has a self-loop, but otherwise only leads to accept
    // (note: NOT acceptEod) and has simple exhaustible reports, we can delete
    // the self-loop.
    for (const auto v : reporters) {
        if (hasOnlySelfLoopAndExhaustibleAccepts(g, rm, v)) {
            remove_edge(v, v, g);
            modified = true;
            DEBUG_PRINTF("removed self-loop on %u\n", g[v].index);
        }
    }

    if (!modified) {
        return;
    }

    pruneUseless(g);

    // We may have only removed self-loops, in which case pruneUseless wouldn't
    // renumber, so we do edge renumbering explicitly here.
    g.renumberEdges();
}