This commit is contained in:
yhirose 2022-06-07 19:45:34 -04:00
parent 159d5e097c
commit 93d0489098
2 changed files with 58 additions and 20 deletions

View File

@ -1953,23 +1953,7 @@ struct HasEmptyElement : public Ope::Visitor {
HasEmptyElement(std::vector<std::pair<const char *, std::string>> &refs) HasEmptyElement(std::vector<std::pair<const char *, std::string>> &refs)
: refs_(refs) {} : refs_(refs) {}
void visit(Sequence &ope) override { 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(PrioritizedChoice &ope) override { void visit(PrioritizedChoice &ope) override {
for (auto op : ope.opes_) { for (auto op : ope.opes_) {
op->accept(*this); op->accept(*this);
@ -2012,10 +1996,15 @@ private:
}; };
struct DetectInfiniteLoop : public Ope::Visitor { struct DetectInfiniteLoop : public Ope::Visitor {
DetectInfiniteLoop(const char *s, const std::string &name) { DetectInfiniteLoop(const char *s, const std::string &name,
std::vector<std::pair<const char *, std::string>> &refs)
: refs_(refs) {
refs_.emplace_back(s, name); refs_.emplace_back(s, name);
} }
DetectInfiniteLoop(std::vector<std::pair<const char *, std::string>> &refs)
: refs_(refs) {}
void visit(Sequence &ope) override { void visit(Sequence &ope) override {
for (auto op : ope.opes_) { for (auto op : ope.opes_) {
op->accept(*this); op->accept(*this);
@ -2059,7 +2048,7 @@ struct DetectInfiniteLoop : public Ope::Visitor {
std::string error_name; std::string error_name;
private: private:
std::vector<std::pair<const char *, std::string>> refs_; std::vector<std::pair<const char *, std::string>> &refs_;
std::unordered_map<std::string, bool> has_error_cache_; std::unordered_map<std::string, bool> has_error_cache_;
}; };
@ -2974,6 +2963,44 @@ inline void DetectLeftRecursion::visit(Reference &ope) {
done_ = true; 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) { inline void HasEmptyElement::visit(Reference &ope) {
auto it = std::find_if(refs_.begin(), refs_.end(), auto it = std::find_if(refs_.begin(), refs_.end(),
[&](const std::pair<const char *, std::string> &ref) { [&](const std::pair<const char *, std::string> &ref) {
@ -3956,7 +3983,8 @@ private:
bool detect_infiniteLoop(const Data &data, Definition &rule, const Log &log, bool detect_infiniteLoop(const Data &data, Definition &rule, const Log &log,
const char *s) const { const char *s) const {
DetectInfiniteLoop vis(data.start_pos, rule.name); std::vector<std::pair<const char *, std::string>> refs;
DetectInfiniteLoop vis(data.start_pos, rule.name, refs);
rule.accept(vis); rule.accept(vis);
if (vis.has_error) { if (vis.has_error) {
if (log) { if (log) {

View File

@ -223,6 +223,16 @@ TEST(InfiniteLoopTest, word) {
EXPECT_FALSE(pg); EXPECT_FALSE(pg);
} }
TEST(InfiniteLoopTest, in_sequence) {
parser pg(R"(
S <- A*
A <- 'a' B
B <- 'a' ''*
)");
EXPECT_FALSE(pg);
}
TEST(PrecedenceTest, Precedence_climbing) { TEST(PrecedenceTest, Precedence_climbing) {
parser parser(R"( parser parser(R"(
START <- _ EXPRESSION START <- _ EXPRESSION