mirror of
https://github.com/yhirose/cpp-peglib.git
synced 2024-12-22 20:05:31 +00:00
Fix #211
This commit is contained in:
parent
159d5e097c
commit
93d0489098
68
peglib.h
68
peglib.h
@ -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) {
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user