mirror of
https://github.com/yhirose/cpp-peglib.git
synced 2024-12-22 20:05:31 +00:00
Removed 'user defined rule' feature
This commit is contained in:
parent
a56ad1cfc2
commit
79a3c75846
33
README.md
33
README.md
@ -380,6 +380,39 @@ The following are available operators:
|
|||||||
| csc | Capture scope |
|
| csc | Capture scope |
|
||||||
| cap | Capture |
|
| cap | Capture |
|
||||||
| bkr | Back reference |
|
| bkr | Back reference |
|
||||||
|
| usr | User defined parser |
|
||||||
|
|
||||||
|
Adjust definitions
|
||||||
|
------------------
|
||||||
|
|
||||||
|
It's possible to add/override definitions.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto syntax = R"(
|
||||||
|
ROOT <- _ 'Hello' _ NAME '!' _
|
||||||
|
)";
|
||||||
|
|
||||||
|
Rules additional_rules = {
|
||||||
|
{
|
||||||
|
"NAME", usr([](const char* s, size_t n, SemanticValues& sv, any& dt) -> size_t {
|
||||||
|
static vector<string> names = { "PEG", "BNF" };
|
||||||
|
for (const auto& name: names) {
|
||||||
|
if (name.size() <= n && !name.compare(0, name.size(), s, name.size())) {
|
||||||
|
return name.size(); // processed length
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1; // parse error
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"~_", zom(cls(" \t\r\n"))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
auto g = parser(syntax, additional_rules);
|
||||||
|
|
||||||
|
assert(g.parse(" Hello BNF! "));
|
||||||
|
```
|
||||||
|
|
||||||
Unicode support
|
Unicode support
|
||||||
---------------
|
---------------
|
||||||
|
76
peglib.h
76
peglib.h
@ -1127,6 +1127,19 @@ public:
|
|||||||
|
|
||||||
typedef std::function<size_t (const char* s, size_t n, SemanticValues& sv, any& dt)> Parser;
|
typedef std::function<size_t (const char* s, size_t n, SemanticValues& sv, any& dt)> Parser;
|
||||||
|
|
||||||
|
class User : public Ope
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
User(Parser fn) : fn_(fn) {}
|
||||||
|
size_t parse(const char* s, size_t n, SemanticValues& sv, Context& c, any& dt) const override {
|
||||||
|
c.trace("User", s, n, sv, dt);
|
||||||
|
assert(fn_);
|
||||||
|
return fn_(s, n, sv, dt);
|
||||||
|
}
|
||||||
|
void accept(Visitor& v) override;
|
||||||
|
std::function<size_t (const char* s, size_t n, SemanticValues& sv, any& dt)> fn_;
|
||||||
|
};
|
||||||
|
|
||||||
class WeakHolder : public Ope
|
class WeakHolder : public Ope
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -1297,6 +1310,10 @@ inline std::shared_ptr<Ope> ign(const std::shared_ptr<Ope>& ope) {
|
|||||||
return std::make_shared<Ignore>(ope);
|
return std::make_shared<Ignore>(ope);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline std::shared_ptr<Ope> usr(std::function<size_t (const char* s, size_t n, SemanticValues& sv, any& dt)> fn) {
|
||||||
|
return std::make_shared<User>(fn);
|
||||||
|
}
|
||||||
|
|
||||||
inline std::shared_ptr<Ope> ref(const Grammar& grammar, const std::string& name, const char* s, bool is_macro, const std::vector<std::shared_ptr<Ope>>& args) {
|
inline std::shared_ptr<Ope> ref(const Grammar& grammar, const std::string& name, const char* s, bool is_macro, const std::vector<std::shared_ptr<Ope>>& args) {
|
||||||
return std::make_shared<Reference>(grammar, name, s, is_macro, args);
|
return std::make_shared<Reference>(grammar, name, s, is_macro, args);
|
||||||
}
|
}
|
||||||
@ -1330,6 +1347,7 @@ struct Ope::Visitor
|
|||||||
virtual void visit(Capture& /*ope*/) {}
|
virtual void visit(Capture& /*ope*/) {}
|
||||||
virtual void visit(TokenBoundary& /*ope*/) {}
|
virtual void visit(TokenBoundary& /*ope*/) {}
|
||||||
virtual void visit(Ignore& /*ope*/) {}
|
virtual void visit(Ignore& /*ope*/) {}
|
||||||
|
virtual void visit(User& /*ope*/) {}
|
||||||
virtual void visit(WeakHolder& /*ope*/) {}
|
virtual void visit(WeakHolder& /*ope*/) {}
|
||||||
virtual void visit(Holder& /*ope*/) {}
|
virtual void visit(Holder& /*ope*/) {}
|
||||||
virtual void visit(Reference& /*ope*/) {}
|
virtual void visit(Reference& /*ope*/) {}
|
||||||
@ -1443,6 +1461,7 @@ struct DetectLeftRecursion : public Ope::Visitor {
|
|||||||
void visit(Capture& ope) override { ope.ope_->accept(*this); }
|
void visit(Capture& ope) override { ope.ope_->accept(*this); }
|
||||||
void visit(TokenBoundary& ope) override { ope.ope_->accept(*this); }
|
void visit(TokenBoundary& ope) override { ope.ope_->accept(*this); }
|
||||||
void visit(Ignore& ope) override { ope.ope_->accept(*this); }
|
void visit(Ignore& ope) override { ope.ope_->accept(*this); }
|
||||||
|
void visit(User& /*ope*/) override { done_ = true; }
|
||||||
void visit(WeakHolder& ope) override { ope.weak_.lock()->accept(*this); }
|
void visit(WeakHolder& ope) override { ope.weak_.lock()->accept(*this); }
|
||||||
void visit(Holder& ope) override { ope.ope_->accept(*this); }
|
void visit(Holder& ope) override { ope.ope_->accept(*this); }
|
||||||
void visit(Reference& ope) override;
|
void visit(Reference& ope) override;
|
||||||
@ -2010,6 +2029,7 @@ inline void CaptureScope::accept(Visitor& v) { v.visit(*this); }
|
|||||||
inline void Capture::accept(Visitor& v) { v.visit(*this); }
|
inline void Capture::accept(Visitor& v) { v.visit(*this); }
|
||||||
inline void TokenBoundary::accept(Visitor& v) { v.visit(*this); }
|
inline void TokenBoundary::accept(Visitor& v) { v.visit(*this); }
|
||||||
inline void Ignore::accept(Visitor& v) { v.visit(*this); }
|
inline void Ignore::accept(Visitor& v) { v.visit(*this); }
|
||||||
|
inline void User::accept(Visitor& v) { v.visit(*this); }
|
||||||
inline void WeakHolder::accept(Visitor& v) { v.visit(*this); }
|
inline void WeakHolder::accept(Visitor& v) { v.visit(*this); }
|
||||||
inline void Holder::accept(Visitor& v) { v.visit(*this); }
|
inline void Holder::accept(Visitor& v) { v.visit(*this); }
|
||||||
inline void Reference::accept(Visitor& v) { v.visit(*this); }
|
inline void Reference::accept(Visitor& v) { v.visit(*this); }
|
||||||
@ -2115,6 +2135,7 @@ inline void FindReference::visit(Reference& ope) {
|
|||||||
* PEG parser generator
|
* PEG parser generator
|
||||||
*---------------------------------------------------------------------------*/
|
*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
typedef std::unordered_map<std::string, std::shared_ptr<Ope>> Rules;
|
||||||
typedef std::function<void (size_t, size_t, const std::string&)> Log;
|
typedef std::function<void (size_t, size_t, const std::string&)> Log;
|
||||||
|
|
||||||
class ParserGenerator
|
class ParserGenerator
|
||||||
@ -2123,10 +2144,21 @@ public:
|
|||||||
static std::shared_ptr<Grammar> parse(
|
static std::shared_ptr<Grammar> parse(
|
||||||
const char* s,
|
const char* s,
|
||||||
size_t n,
|
size_t n,
|
||||||
|
const Rules& rules,
|
||||||
std::string& start,
|
std::string& start,
|
||||||
Log log)
|
Log log)
|
||||||
{
|
{
|
||||||
return get_instance().perform_core(s, n, start, log);
|
return get_instance().perform_core(s, n, rules, start, log);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::shared_ptr<Grammar> parse(
|
||||||
|
const char* s,
|
||||||
|
size_t n,
|
||||||
|
std::string& start,
|
||||||
|
Log log)
|
||||||
|
{
|
||||||
|
Rules dummy;
|
||||||
|
return parse(s, n, dummy, start, log);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For debuging purpose
|
// For debuging purpose
|
||||||
@ -2412,6 +2444,7 @@ private:
|
|||||||
std::shared_ptr<Grammar> perform_core(
|
std::shared_ptr<Grammar> perform_core(
|
||||||
const char* s,
|
const char* s,
|
||||||
size_t n,
|
size_t n,
|
||||||
|
const Rules& rules,
|
||||||
std::string& start,
|
std::string& start,
|
||||||
Log log)
|
Log log)
|
||||||
{
|
{
|
||||||
@ -2434,6 +2467,22 @@ private:
|
|||||||
|
|
||||||
auto& grammar = *data.grammar;
|
auto& grammar = *data.grammar;
|
||||||
|
|
||||||
|
// User provided rules
|
||||||
|
for (const auto& x: rules) {
|
||||||
|
auto name = x.first;
|
||||||
|
bool ignore = false;
|
||||||
|
if (!name.empty() && name[0] == '~') {
|
||||||
|
ignore = true;
|
||||||
|
name.erase(0, 1);
|
||||||
|
}
|
||||||
|
if (!name.empty()) {
|
||||||
|
auto& rule = grammar[name];
|
||||||
|
rule <= x.second;
|
||||||
|
rule.name = name;
|
||||||
|
rule.ignoreSemanticValue = ignore;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check duplicated definitions
|
// Check duplicated definitions
|
||||||
bool ret = data.duplicates.empty();
|
bool ret = data.duplicates.empty();
|
||||||
|
|
||||||
@ -2763,22 +2812,37 @@ class parser
|
|||||||
public:
|
public:
|
||||||
parser() = default;
|
parser() = default;
|
||||||
|
|
||||||
parser(const char* s, size_t n) {
|
parser(const char* s, size_t n, const Rules& rules) {
|
||||||
load_grammar(s, n);
|
load_grammar(s, n, rules);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parser(const char* s, const Rules& rules)
|
||||||
|
: parser(s, strlen(s), rules) {}
|
||||||
|
|
||||||
|
parser(const char* s, size_t n)
|
||||||
|
: parser(s, n, Rules()) {}
|
||||||
|
|
||||||
parser(const char* s)
|
parser(const char* s)
|
||||||
: parser(s, strlen(s)) {}
|
: parser(s, strlen(s), Rules()) {}
|
||||||
|
|
||||||
operator bool() {
|
operator bool() {
|
||||||
return grammar_ != nullptr;
|
return grammar_ != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool load_grammar(const char* s, size_t n) {
|
bool load_grammar(const char* s, size_t n, const Rules& rules) {
|
||||||
grammar_ = ParserGenerator::parse(s, n, start_, log);
|
grammar_ = ParserGenerator::parse(s, n, rules, start_, log);
|
||||||
return grammar_ != nullptr;
|
return grammar_ != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool load_grammar(const char* s, size_t n) {
|
||||||
|
return load_grammar(s, n, Rules());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool load_grammar(const char* s, const Rules& rules) {
|
||||||
|
auto n = strlen(s);
|
||||||
|
return load_grammar(s, n, rules);
|
||||||
|
}
|
||||||
|
|
||||||
bool load_grammar(const char* s) {
|
bool load_grammar(const char* s) {
|
||||||
auto n = strlen(s);
|
auto n = strlen(s);
|
||||||
return load_grammar(s, n);
|
return load_grammar(s, n);
|
||||||
|
25
test/test.cc
25
test/test.cc
@ -964,6 +964,31 @@ TEST_CASE("Left recursive with empty string test", "[left recursive]")
|
|||||||
REQUIRE(!parser);
|
REQUIRE(!parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("User defined rule test", "[user rule]")
|
||||||
|
{
|
||||||
|
auto g = parser(R"(
|
||||||
|
ROOT <- _ 'Hello' _ NAME '!' _
|
||||||
|
)",
|
||||||
|
{
|
||||||
|
{
|
||||||
|
"NAME", usr([](const char* s, size_t n, SemanticValues& /*sv*/, any& /*dt*/) -> size_t {
|
||||||
|
static vector<string> names = { "PEG", "BNF" };
|
||||||
|
for (const auto& name: names) {
|
||||||
|
if (name.size() <= n && !name.compare(0, name.size(), s, name.size())) {
|
||||||
|
return name.size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return static_cast<size_t>(-1);
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"~_", zom(cls(" \t\r\n"))
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
REQUIRE(g.parse(" Hello BNF! ") == true);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE("Semantic predicate test", "[predicate]")
|
TEST_CASE("Semantic predicate test", "[predicate]")
|
||||||
{
|
{
|
||||||
parser parser("NUMBER <- [0-9]+");
|
parser parser("NUMBER <- [0-9]+");
|
||||||
|
Loading…
Reference in New Issue
Block a user