From 93d0489098093c2f92f0ec9dae61a5d78e47ddc5 Mon Sep 17 00:00:00 2001 From: yhirose Date: Tue, 7 Jun 2022 19:45:34 -0400 Subject: [PATCH] Fix #211 --- peglib.h | 68 ++++++++++++++++++++++++++++++++++++--------------- test/test2.cc | 10 ++++++++ 2 files changed, 58 insertions(+), 20 deletions(-) diff --git a/peglib.h b/peglib.h index 05aa778..859d3df 100644 --- a/peglib.h +++ b/peglib.h @@ -1953,23 +1953,7 @@ struct HasEmptyElement : public Ope::Visitor { HasEmptyElement(std::vector> &refs) : refs_(refs) {} - void visit(Sequence &ope) override { - auto save_is_empty = false; - const char *save_error_s = nullptr; - std::string save_error_name; - for (auto op : ope.opes_) { - op->accept(*this); - if (!is_empty) { return; } - save_is_empty = is_empty; - save_error_s = error_s; - save_error_name = error_name; - is_empty = false; - error_name.clear(); - } - is_empty = save_is_empty; - error_s = save_error_s; - error_name = save_error_name; - } + void visit(Sequence &ope) override; void visit(PrioritizedChoice &ope) override { for (auto op : ope.opes_) { op->accept(*this); @@ -2012,10 +1996,15 @@ private: }; struct DetectInfiniteLoop : public Ope::Visitor { - DetectInfiniteLoop(const char *s, const std::string &name) { + DetectInfiniteLoop(const char *s, const std::string &name, + std::vector> &refs) + : refs_(refs) { refs_.emplace_back(s, name); } + DetectInfiniteLoop(std::vector> &refs) + : refs_(refs) {} + void visit(Sequence &ope) override { for (auto op : ope.opes_) { op->accept(*this); @@ -2059,7 +2048,7 @@ struct DetectInfiniteLoop : public Ope::Visitor { std::string error_name; private: - std::vector> refs_; + std::vector> &refs_; std::unordered_map has_error_cache_; }; @@ -2974,6 +2963,44 @@ inline void DetectLeftRecursion::visit(Reference &ope) { done_ = true; } +inline void HasEmptyElement::visit(Sequence &ope) { + auto save_is_empty = false; + const char *save_error_s = nullptr; + std::string save_error_name; + + auto it = ope.opes_.begin(); + while (it != ope.opes_.end()) { + (*it)->accept(*this); + if (!is_empty) { + ++it; + while (it != ope.opes_.end()) { + DetectInfiniteLoop vis(refs_); + (*it)->accept(vis); + if (vis.has_error) { + std::cout << "infinite loop!" << std::endl; + is_empty = true; + error_s = vis.error_s; + error_name = vis.error_name; + } + ++it; + } + return; + } + + save_is_empty = is_empty; + save_error_s = error_s; + save_error_name = error_name; + + is_empty = false; + error_name.clear(); + ++it; + } + + is_empty = save_is_empty; + error_s = save_error_s; + error_name = save_error_name; +} + inline void HasEmptyElement::visit(Reference &ope) { auto it = std::find_if(refs_.begin(), refs_.end(), [&](const std::pair &ref) { @@ -3956,7 +3983,8 @@ private: bool detect_infiniteLoop(const Data &data, Definition &rule, const Log &log, const char *s) const { - DetectInfiniteLoop vis(data.start_pos, rule.name); + std::vector> refs; + DetectInfiniteLoop vis(data.start_pos, rule.name, refs); rule.accept(vis); if (vis.has_error) { if (log) { diff --git a/test/test2.cc b/test/test2.cc index fdf8a7c..2f618d0 100644 --- a/test/test2.cc +++ b/test/test2.cc @@ -223,6 +223,16 @@ TEST(InfiniteLoopTest, word) { EXPECT_FALSE(pg); } +TEST(InfiniteLoopTest, in_sequence) { + parser pg(R"( + S <- A* + A <- 'a' B + B <- 'a' ''* + )"); + + EXPECT_FALSE(pg); +} + TEST(PrecedenceTest, Precedence_climbing) { parser parser(R"( START <- _ EXPRESSION