mirror of
https://github.com/yhirose/cpp-peglib.git
synced 2024-12-22 11:55:30 +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)
|
||||
: 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<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) {}
|
||||
|
||||
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<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_;
|
||||
};
|
||||
|
||||
@ -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<const char *, std::string> &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<std::pair<const char *, std::string>> refs;
|
||||
DetectInfiniteLoop vis(data.start_pos, rule.name, refs);
|
||||
rule.accept(vis);
|
||||
if (vis.has_error) {
|
||||
if (log) {
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user