Skip to content

Commit

Permalink
Fix #213
Browse files Browse the repository at this point in the history
  • Loading branch information
yhirose committed Jun 15, 2022
1 parent af43f1f commit 7d05fc1
Showing 1 changed file with 47 additions and 24 deletions.
71 changes: 47 additions & 24 deletions peglib.h
Original file line number Diff line number Diff line change
Expand Up @@ -1950,8 +1950,12 @@ struct DetectLeftRecursion : public Ope::Visitor {
};

struct HasEmptyElement : public Ope::Visitor {
HasEmptyElement(std::vector<std::pair<const char *, std::string>> &refs)
: refs_(refs) {}
HasEmptyElement(std::vector<std::pair<const char *, std::string>>
&detect_infinite_loop_cache,
std::vector<std::pair<const char *, std::string>>
&has_empty_element_cache)
: detect_infinite_loop_cache_(detect_infinite_loop_cache),
has_empty_element_cache_(has_empty_element_cache) {}

void visit(Sequence &ope) override;
void visit(PrioritizedChoice &ope) override {
Expand Down Expand Up @@ -1990,20 +1994,30 @@ struct HasEmptyElement : public Ope::Visitor {
private:
void set_error() {
is_empty = true;
tie(error_s, error_name) = refs_.back();
tie(error_s, error_name) = has_empty_element_cache_.back();
}
std::vector<std::pair<const char *, std::string>> &refs_;
std::vector<std::pair<const char *, std::string>>
&detect_infinite_loop_cache_;
std::vector<std::pair<const char *, std::string>> &has_empty_element_cache_;
};

struct DetectInfiniteLoop : public Ope::Visitor {
DetectInfiniteLoop(const char *s, const std::string &name,
std::vector<std::pair<const char *, std::string>> &refs)
: refs_(refs) {
refs_.emplace_back(s, name);
}

DetectInfiniteLoop(std::vector<std::pair<const char *, std::string>> &refs)
: refs_(refs) {}
std::vector<std::pair<const char *, std::string>>
&detect_infinite_loop_cache,
std::vector<std::pair<const char *, std::string>>
&has_empty_element_cache)
: detect_infinite_loop_cache_(detect_infinite_loop_cache),
has_empty_element_cache_(has_empty_element_cache) {
detect_infinite_loop_cache_.emplace_back(s, name);
}

DetectInfiniteLoop(std::vector<std::pair<const char *, std::string>>
&detect_infinite_loop_cache,
std::vector<std::pair<const char *, std::string>>
&has_empty_element_cache)
: detect_infinite_loop_cache_(detect_infinite_loop_cache),
has_empty_element_cache_(has_empty_element_cache) {}

void visit(Sequence &ope) override {
for (auto op : ope.opes_) {
Expand All @@ -2019,7 +2033,8 @@ struct DetectInfiniteLoop : public Ope::Visitor {
}
void visit(Repetition &ope) override {
if (ope.max_ == std::numeric_limits<size_t>::max()) {
HasEmptyElement vis(refs_);
HasEmptyElement vis(detect_infinite_loop_cache_,
has_empty_element_cache_);
ope.ope_->accept(vis);
if (vis.is_empty) {
has_error = true;
Expand Down Expand Up @@ -2048,7 +2063,9 @@ struct DetectInfiniteLoop : public Ope::Visitor {
std::string error_name;

private:
std::vector<std::pair<const char *, std::string>> &refs_;
std::vector<std::pair<const char *, std::string>>
&detect_infinite_loop_cache_;
std::vector<std::pair<const char *, std::string>> &has_empty_element_cache_;
std::unordered_map<std::string, bool> has_error_cache_;
};

Expand Down Expand Up @@ -3041,7 +3058,8 @@ inline void HasEmptyElement::visit(Sequence &ope) {
if (!is_empty) {
++it;
while (it != ope.opes_.end()) {
DetectInfiniteLoop vis(refs_);
DetectInfiniteLoop vis(detect_infinite_loop_cache_,
has_empty_element_cache_);
(*it)->accept(vis);
if (vis.has_error) {
is_empty = true;
Expand All @@ -3068,34 +3086,36 @@ inline void HasEmptyElement::visit(Sequence &ope) {
}

inline void HasEmptyElement::visit(Reference &ope) {
auto it = std::find_if(refs_.begin(), refs_.end(),
auto &refs = has_empty_element_cache_;
auto it = std::find_if(refs.begin(), refs.end(),
[&](const std::pair<const char *, std::string> &ref) {
return ope.name_ == ref.second;
});
if (it != refs_.end()) { return; }
if (it != refs.end()) { return; }

if (ope.rule_) {
refs_.emplace_back(ope.s_, ope.name_);
refs.emplace_back(ope.s_, ope.name_);
ope.rule_->accept(*this);
refs_.pop_back();
refs.pop_back();
}
}

inline void DetectInfiniteLoop::visit(Reference &ope) {
auto it = std::find_if(refs_.begin(), refs_.end(),
auto &refs = detect_infinite_loop_cache_;
auto it = std::find_if(refs.begin(), refs.end(),
[&](const std::pair<const char *, std::string> &ref) {
return ope.name_ == ref.second;
});
if (it != refs_.end()) { return; }
if (it != refs.end()) { return; }

if (ope.rule_) {
auto it = has_error_cache_.find(ope.name_);
if (it != has_error_cache_.end()) {
has_error = it->second;
} else {
refs_.emplace_back(ope.s_, ope.name_);
refs.emplace_back(ope.s_, ope.name_);
ope.rule_->accept(*this);
refs_.pop_back();
refs.pop_back();
has_error_cache_[ope.name_] = has_error;
}
}
Expand Down Expand Up @@ -4047,8 +4067,11 @@ class ParserGenerator {

bool detect_infiniteLoop(const Data &data, Definition &rule, const Log &log,
const char *s) const {
std::vector<std::pair<const char *, std::string>> refs;
DetectInfiniteLoop vis(data.start_pos, rule.name, refs);
std::vector<std::pair<const char *, std::string>>
detect_infinite_loop_cache;
std::vector<std::pair<const char *, std::string>> has_empty_element_cache;
DetectInfiniteLoop vis(data.start_pos, rule.name,
detect_infinite_loop_cache, has_empty_element_cache);
rule.accept(vis);
if (vis.has_error) {
if (log) {
Expand Down

0 comments on commit 7d05fc1

Please sign in to comment.