diff --git a/README.md b/README.md index 26e24b4..320b40e 100644 --- a/README.md +++ b/README.md @@ -609,6 +609,7 @@ usage: grammar_file_path [source_file_path] --opt-only: optimize only AST nodes selected with `no_ast_opt` instruction --trace: show concise trace messages --trace-verbose: show verbose trace messages + --profile: show profile report ``` ### Grammar check diff --git a/lint/README.md b/lint/README.md index 8793068..c93f69b 100644 --- a/lint/README.md +++ b/lint/README.md @@ -14,6 +14,7 @@ usage: grammar_file_path [source_file_path] --source: source text --trace: show concise trace messages --trace-verbose: show verbose trace messages + --profile: show profile report ``` ### Build peglint diff --git a/lint/peglint.cc b/lint/peglint.cc index 7669767..c638bae 100644 --- a/lint/peglint.cc +++ b/lint/peglint.cc @@ -41,7 +41,8 @@ int main(int argc, const char **argv) { auto opt_source = false; vector source; auto opt_trace = false; - auto opt_verbose = false; + auto opt_trace_verbose = false; + auto opt_profile = false; vector path_list; auto argi = 1; @@ -68,8 +69,9 @@ int main(int argc, const char **argv) { } else if (string("--trace") == arg) { opt_trace = true; } else if (string("--trace-verbose") == arg) { - opt_trace = true; - opt_verbose = true; + opt_trace_verbose = true; + } else if (string("--profile") == arg) { + opt_profile = true; } else { path_list.push_back(arg); } @@ -86,6 +88,7 @@ int main(int argc, const char **argv) { --opt-only: optimize only AST nodes selected with `no_ast_opt` instruction --trace: show concise trace messages --trace-verbose: show verbose trace messages + --profile: show profile report )"; return 1; @@ -126,12 +129,10 @@ int main(int argc, const char **argv) { if (opt_packrat) { parser.enable_packrat_parsing(); } - if (opt_trace) { + if (opt_trace || opt_trace_verbose) { size_t prev_pos = 0; parser.enable_trace( - [&](const peg::Ope &ope, const char *s, size_t /*n*/, - const peg::SemanticValues & /*sv*/, const peg::Context &c, - const std::any & /*dt*/) { + [&](auto &ope, auto s, auto, auto &, auto &c, auto &) { auto pos = static_cast(s - c.s); auto backtrack = (pos < prev_pos ? "*" : ""); string indent; @@ -150,9 +151,7 @@ int main(int argc, const char **argv) { << " #" << c.trace_ids.back() << std::endl; prev_pos = static_cast(pos); }, - [&](const peg::Ope &ope, const char *s, size_t /*n*/, - const peg::SemanticValues &sv, const peg::Context &c, - const std::any & /*dt*/, size_t len) { + [&](auto &ope, auto s, auto, auto &sv, auto &c, auto &, auto len) { auto pos = static_cast(s - c.s); if (len != static_cast(-1)) { pos += len; } string indent; @@ -181,7 +180,58 @@ int main(int argc, const char **argv) { << c.trace_ids.back() << choice.str() << token << matched << std::endl; }, - opt_verbose); + opt_trace_verbose); + } + + struct StatsItem { + std::string name; + size_t success; + size_t fail; + }; + std::vector stats; + std::map stats_index; + size_t stats_item_total = false; + + if (opt_profile) { + parser.enable_trace( + [&](auto &ope, auto, auto, auto &, auto &, auto &) { + if (peg::IsOpeType::check(ope)) { + auto &name = dynamic_cast(ope).name(); + if (stats_index.find(name) == stats_index.end()) { + stats_index[name] = stats_index.size(); + stats.push_back({name, 0, 0}); + } + stats_item_total++; + } + }, + [&](auto &ope, auto, auto, auto &, auto &, auto &, auto len) { + if (peg::IsOpeType::check(ope)) { + auto &name = dynamic_cast(ope).name(); + auto index = stats_index[name]; + auto &stat = stats[index]; + if (len != static_cast(-1)) { + stat.success++; + } else { + stat.fail++; + } + if (index == 0) { + size_t id = 0; + std::cout << " id total % success fail " + "definition" + << std::endl; + for (auto &[name, success, fail] : stats) { + char buff[BUFSIZ]; + auto total = success + fail; + auto ratio = total * 100.0 / stats_item_total; + sprintf(buff, "%4zu %10lu %5.2f %10lu %10lu %s", id, total, + ratio, success, fail, name.c_str()); + std::cout << buff << std::endl; + id++; + } + } + } + }, + true); } if (opt_ast) { diff --git a/peglib.h b/peglib.h index c57a738..ba6f740 100644 --- a/peglib.h +++ b/peglib.h @@ -1467,7 +1467,8 @@ public: std::any reduce(SemanticValues &vs, std::any &dt) const; - const char *trace_name() const; + const std::string &name() const; + const std::string &trace_name() const; std::shared_ptr ope_; Definition *outer_; @@ -1825,7 +1826,7 @@ struct TraceOpeName : public Ope::Visitor { void visit(Ignore &) override { name_ = "Ignore"; } void visit(User &) override { name_ = "User"; } void visit(WeakHolder &) override { name_ = "WeakHolder"; } - void visit(Holder &ope) override { name_ = ope.trace_name(); } + void visit(Holder &ope) override { name_ = ope.trace_name().data(); } void visit(Reference &) override { name_ = "Reference"; } void visit(Whitespace &) override { name_ = "Whitespace"; } void visit(BackReference &) override { name_ = "BackReference"; } @@ -1929,7 +1930,7 @@ private: }; struct FindLiteralToken : public Ope::Visitor { - void visit(LiteralString &ope) override { token_ = ope.lit_.c_str(); } + void visit(LiteralString &ope) override { token_ = ope.lit_.data(); } void visit(TokenBoundary &ope) override { ope.ope_->accept(*this); } void visit(Ignore &ope) override { ope.ope_->accept(*this); } void visit(Reference &ope) override; @@ -2491,7 +2492,7 @@ inline size_t parse_literal(const char *s, size_t n, SemanticValues &vs, for (; i < lit.size(); i++) { if (i >= n || (ignore_case ? (std::tolower(s[i]) != std::tolower(lit[i])) : (s[i] != lit[i]))) { - c.set_error_pos(s, lit.c_str()); + c.set_error_pos(s, lit.data()); return static_cast(-1); } } @@ -2574,7 +2575,7 @@ inline void Context::set_error_pos(const char *a_s, const char *literal) { token && token[0] != '\0') { error_info.add(token, true); } else { - error_info.add(rule->name.c_str(), false); + error_info.add(rule->name.data(), false); } } } @@ -2735,9 +2736,13 @@ inline std::any Holder::reduce(SemanticValues &vs, std::any &dt) const { } } -inline const char *Holder::trace_name() const { +inline const std::string &Holder::name() const { + return outer_->name; +} + +inline const std::string &Holder::trace_name() const { if (trace_name_.empty()) { trace_name_ = "[" + outer_->name + "]"; } - return trace_name_.data(); + return trace_name_; } inline size_t Reference::parse_core(const char *s, size_t n, SemanticValues &vs,