Added 'usr' operator.

This commit is contained in:
yhirose 2015-02-19 22:27:47 -05:00
parent 59153dfdbd
commit 681c754302
2 changed files with 127 additions and 30 deletions

View File

@ -224,21 +224,54 @@ auto ret = ROOT.parse(" [tag1] [tag:2] [tag-3] ");
The following are available operators: The following are available operators:
| Operator | Description | | Operator | Description |
|:---------|:-------------------| | :------- | :------------------ |
| seq | Sequence | | seq | Sequence |
| cho | Prioritized Choice | | cho | Prioritized Choice |
| zom | Zero or More | | zom | Zero or More |
| oom | One or More | | oom | One or More |
| opt | Optional | | opt | Optional |
| apd | And predicate | | apd | And predicate |
| npd | Not predicate | | npd | Not predicate |
| lit | Literal string | | lit | Literal string |
| cls | Character class | | cls | Character class |
| chr | Character | | chr | Character |
| dot | Any character | | dot | Any character |
| anc | Anchor character | | anc | Anchor character |
| cap | Capture character | | cap | Capture character |
| usr | User defiend parser |
Hybrid Parser
-------------
It's even possible to mix parser grammar with parser operaters.
```c++
auto syntax = R"(
ROOT <- _ 'Hello' _ NAME '!' _
)";
Rules rules = {
{
"NAME", usr([](const char* s, size_t l, SemanticValues& v, any& c) {
static vector<string> names = { "PEG", "BNF" };
for (const auto& n: names) {
if (n.size() <= l && !n.compare(0, n.size(), s, n.size())) {
return success(n.size());
}
}
return fail(s);
})
},
{
"~_", zom(cls(" \t\r\n"))
}
};
peg g = peg(syntax, rules);
assert(g.parse(" Hello BNF! "));
```
Sample codes Sample codes
------------ ------------

View File

@ -781,6 +781,22 @@ private:
std::shared_ptr<Ope> ope_; std::shared_ptr<Ope> ope_;
}; };
typedef std::function<Result (const char* s, size_t l, SemanticValues& v, any& c)> Parser;
class User : public Ope
{
public:
User(Parser fn) : fn_(fn) {}
Result parse(const char* s, size_t l, SemanticValues& v, any& c) const {
assert(fn_);
return fn_(s, l, v, c);
}
private:
std::function<Result (const char* s, size_t l, SemanticValues& v, any& c)> fn_;
};
class WeakHolder : public Ope class WeakHolder : public Ope
{ {
public: public:
@ -1038,6 +1054,10 @@ inline std::shared_ptr<Ope> anc(const std::shared_ptr<Ope>& ope) {
return std::make_shared<Anchor>(ope); return std::make_shared<Anchor>(ope);
} }
inline std::shared_ptr<Ope> usr(std::function<Result (const char* s, size_t l, SemanticValues& v, any& c)> fn) {
return std::make_shared<User>(fn);
}
inline std::shared_ptr<Ope> ref(const std::map<std::string, Definition>& grammar, const std::string& name) { inline std::shared_ptr<Ope> ref(const std::map<std::string, Definition>& grammar, const std::string& name) {
return std::make_shared<DefinitionReference>(grammar, name); return std::make_shared<DefinitionReference>(grammar, name);
} }
@ -1067,12 +1087,32 @@ inline std::pair<size_t, size_t> line_info(const char* s, const char* ptr) {
typedef std::map<std::string, Definition> Grammar; typedef std::map<std::string, Definition> Grammar;
typedef std::function<void (size_t, size_t, const std::string&)> Log; typedef std::function<void (size_t, size_t, const std::string&)> Log;
typedef std::map<std::string, std::shared_ptr<Ope>> Rules;
class PEGParser class PEGParser
{ {
public: public:
static std::shared_ptr<Grammar> parse(const char* s, size_t l, std::string& start, MatchAction ma, Log log) { static std::shared_ptr<Grammar> parse(
const char* s,
size_t l,
const Rules& rules,
std::string& start,
MatchAction ma,
Log log)
{
static PEGParser instance; static PEGParser instance;
return get().perform_core(s, l, start, ma, log); return get().perform_core(s, l, rules, start, ma, log);
}
static std::shared_ptr<Grammar> parse(
const char* s,
size_t l,
std::string& start,
MatchAction ma,
Log log)
{
Rules dummy;
return parse(s, l, dummy, start, ma, log);
} }
// For debuging purpose // For debuging purpose
@ -1290,7 +1330,14 @@ private:
g["DOT"] = []() { return dot(); }; g["DOT"] = []() { return dot(); };
} }
std::shared_ptr<Grammar> perform_core(const char* s, size_t l, std::string& start, MatchAction ma, Log log) { std::shared_ptr<Grammar> perform_core(
const char* s,
size_t l,
const Rules& rules,
std::string& start,
MatchAction ma,
Log log)
{
Context cxt; Context cxt;
cxt.match_action = ma; cxt.match_action = ma;
@ -1308,6 +1355,25 @@ private:
auto& grammar = *cxt.grammar; auto& grammar = *cxt.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& def = grammar[name];
def <= x.second;
def.name = name;
def.ignore = ignore;
}
}
// Check missing definitions
for (const auto& x : cxt.references) { for (const auto& x : cxt.references) {
const auto& name = x.first; const auto& name = x.first;
auto ptr = x.second; auto ptr = x.second;
@ -1367,9 +1433,9 @@ class peg
public: public:
peg() = default; peg() = default;
peg(const char* s, size_t l, Log log = nullptr) { peg(const char* s, size_t l, const Rules& rules, Log log = nullptr) {
grammar_ = PEGParser::parse( grammar_ = PEGParser::parse(
s, l, s, l, rules,
start_, start_,
[&](const char* s, size_t l, size_t i) { [&](const char* s, size_t l, size_t i) {
if (match_action) match_action(s, l, i); if (match_action) match_action(s, l, i);
@ -1377,16 +1443,14 @@ public:
log); log);
} }
peg(const char* s, Log log = nullptr) { peg(const char* s, const Rules& rules, Log log = nullptr)
auto l = strlen(s); : peg(s, strlen(s), rules, log) {}
grammar_ = PEGParser::parse(
s, l, peg(const char* s, size_t l, Log log = nullptr)
start_, : peg(s, l, Rules(), log) {}
[&](const char* s, size_t l, size_t i) {
if (match_action) match_action(s, l, i); peg(const char* s, Log log = nullptr)
}, : peg(s, strlen(s), Rules(), log) {}
log);
}
operator bool() { operator bool() {
return grammar_ != nullptr; return grammar_ != nullptr;