Improving performance...

pull/3/head
yhirose 9 years ago
parent 90fbf9b541
commit b19d37f052
  1. 2
      example/calc2.cc
  2. 8
      example/example.sln
  3. 543
      peglib.h
  4. 35
      test/test.cc
  5. 12
      test/test.sln

@ -56,7 +56,7 @@ int main(int argc, const char** argv)
NUMBER <= oom(cls("0-9")), [](const char* s, size_t l) { return atol(s); };
long val = 0;
if (EXPRESSION.parse(s, val).ret) {
if (EXPRESSION.parse_with_value(s, val).ret) {
cout << s << " = " << val << endl;
return 0;
}

@ -5,7 +5,9 @@ VisualStudioVersion = 12.0.31101.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "calc", "calc.vcxproj", "{F85B641A-7538-4809-8175-C528FF632CF6}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "calc", "calc2.vcxproj", "{1D09607B-E1C0-4D62-8AB4-9E2D2C2DC6E4}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "calc2", "calc2.vcxproj", "{1D09607B-E1C0-4D62-8AB4-9E2D2C2DC6E4}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "calc3", "calc3.vcxproj", "{E6146F73-3B4C-4D4C-BC55-148930954434}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -21,6 +23,10 @@ Global
{1D09607B-E1C0-4D62-8AB4-9E2D2C2DC6E4}.Debug|Win32.Build.0 = Debug|Win32
{1D09607B-E1C0-4D62-8AB4-9E2D2C2DC6E4}.Release|Win32.ActiveCfg = Release|Win32
{1D09607B-E1C0-4D62-8AB4-9E2D2C2DC6E4}.Release|Win32.Build.0 = Release|Win32
{E6146F73-3B4C-4D4C-BC55-148930954434}.Debug|Win32.ActiveCfg = Debug|Win32
{E6146F73-3B4C-4D4C-BC55-148930954434}.Debug|Win32.Build.0 = Debug|Win32
{E6146F73-3B4C-4D4C-BC55-148930954434}.Release|Win32.ActiveCfg = Release|Win32
{E6146F73-3B4C-4D4C-BC55-148930954434}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

@ -12,8 +12,9 @@
#include <string>
#include <limits>
#include <memory>
#include <mutex>
#include <vector>
#include <map>
#include <unordered_map>
#include <cassert>
#include <cstring>
#include <initializer_list>
@ -153,8 +154,11 @@ private:
* Semantic values
*/
struct SemanticValue {
SemanticValue(any&& _val, const char* _name, const char* _s, size_t _l)
: val(_val), name(_name), s(_s), l(_l) {}
any val;
std::string name;
const char* name;
const char* s;
size_t l;
};
@ -187,6 +191,8 @@ struct SemanticValues : protected std::vector<SemanticValue>
using std::vector<T>::erase;
using std::vector<T>::clear;
using std::vector<T>::swap;
using std::vector<T>::emplace;
using std::vector<T>::emplace_back;
template <typename T, typename U, typename V>
static U reduce(T i, T end, U val, V f){
@ -390,29 +396,61 @@ typedef std::function<void (const char* s, size_t l, size_t i)> MatchAction;
*/
struct Result
{
bool ret;
size_t len;
size_t choice;
const char* ptr;
const std::string err; // TODO: should be `int`.
bool ret;
size_t len;
size_t choice;
const char* ptr;
const char* err; // TODO: should be `int`.
};
Result success(size_t len, size_t choice = 0) {
return Result{ true, len, choice, nullptr, std::string() };
return Result{ true, len, choice, nullptr, nullptr };
}
Result fail(const char* ptr, std::string err = std::string(), std::string name = std::string()) {
Result fail(const char* ptr, const char* err = nullptr) {
return Result{ false, 0, (size_t)-1, ptr, err };
}
/*
* Context
*/
struct Context
{
std::vector<void*> defs;
std::unordered_map<void*, size_t> ids;
std::vector<std::shared_ptr<SemanticValues>> stack;
size_t stack_size;
Context() : stack_size(0){}
SemanticValues& push() {
assert(stack_size <= stack.size());
if (stack_size == stack.size()) {
stack.push_back(std::make_shared<SemanticValues>());
}
auto& sv = *stack[stack_size++];
sv.clear();
sv.s = nullptr;
sv.l = 0;
return sv;
}
void pop() {
stack_size--;
}
};
/*
* Parser operators
*/
class Ope
{
public:
struct Visitor;
virtual ~Ope() {};
virtual Result parse(const char* s, size_t l, SemanticValues& sv, any& dt) const = 0;
virtual Result parse(const char* s, size_t l, SemanticValues& sv, Context& c, any& dt) const = 0;
virtual void accept(Visitor& v) = 0;
};
class Sequence : public Ope
@ -439,14 +477,14 @@ public:
Sequence(const std::vector<std::shared_ptr<Ope>>& opes) : opes_(opes) {}
Sequence(std::vector<std::shared_ptr<Ope>>&& opes) : opes_(std::move(opes)) {}
Result parse(const char* s, size_t l, SemanticValues& sv, any& dt) const {
Result parse(const char* s, size_t l, SemanticValues& sv, Context& c, any& dt) const override {
size_t i = 0;
for (const auto& ope : opes_) {
const auto& rule = *ope;
auto r = rule.parse(s + i, l - i, sv, dt);
auto r = rule.parse(s + i, l - i, sv, c, dt);
if (!r.ret) {
auto err = r.err;
if (err.empty()) {
if (!err) {
err = "missing an element in the 'sequence'";
}
return fail(r.ptr, err);
@ -456,7 +494,9 @@ public:
return success(i);
}
private:
void accept(Visitor& v) override;
//private:
std::vector<std::shared_ptr<Ope>> opes_;
};
@ -482,28 +522,33 @@ public:
PrioritizedChoice(const std::vector<std::shared_ptr<Ope>>& opes) : opes_(opes) {}
PrioritizedChoice(std::vector<std::shared_ptr<Ope>>&& opes) : opes_(std::move(opes)) {}
Result parse(const char* s, size_t l, SemanticValues& sv, any& dt) const {
Result parse(const char* s, size_t l, SemanticValues& sv, Context& c, any& dt) const override {
size_t id = 0;
for (const auto& ope : opes_) {
const auto& rule = *ope;
SemanticValues chldsv;
auto r = rule.parse(s, l, chldsv, dt);
//SemanticValues chldsv;
auto& chldsv = c.push();
auto r = rule.parse(s, l, chldsv, c, dt);
if (r.ret) {
if (!chldsv.empty()) {
sv.insert(sv.end(), chldsv.begin(), chldsv.end());
}
sv.s = chldsv.s;
sv.l = chldsv.l;
c.pop();
return success(r.len, id);
}
id++;
c.pop();
}
return fail(s, "nothing was matched in the 'prioritized choice'");
}
void accept(Visitor& v) override;
size_t size() const { return opes_.size(); }
private:
//private:
std::vector<std::shared_ptr<Ope>> opes_;
};
@ -512,11 +557,11 @@ class ZeroOrMore : public Ope
public:
ZeroOrMore(const std::shared_ptr<Ope>& ope) : ope_(ope) {}
Result parse(const char* s, size_t l, SemanticValues& sv, any& dt) const {
Result parse(const char* s, size_t l, SemanticValues& sv, Context& c, any& dt) const override {
auto i = 0;
while (l - i > 0) {
const auto& rule = *ope_;
auto r = rule.parse(s + i, l - i, sv, dt);
auto r = rule.parse(s + i, l - i, sv, c, dt);
if (!r.ret) {
break;
}
@ -525,7 +570,9 @@ public:
return success(i);
}
private:
void accept(Visitor& v) override;
//private:
std::shared_ptr<Ope> ope_;
};
@ -534,12 +581,12 @@ class OneOrMore : public Ope
public:
OneOrMore(const std::shared_ptr<Ope>& ope) : ope_(ope) {}
Result parse(const char* s, size_t l, SemanticValues& sv, any& dt) const {
Result parse(const char* s, size_t l, SemanticValues& sv, Context& c, any& dt) const override {
const auto& rule = *ope_;
auto r = rule.parse(s, l, sv, dt);
auto r = rule.parse(s, l, sv, c, dt);
if (!r.ret) {
auto err = r.err;
if (err.empty()) {
if (!err) {
err = "nothing occurred in the 'one-or-more'";
}
return fail(r.ptr, r.err);
@ -547,7 +594,7 @@ public:
auto i = r.len;
while (l - i > 0) {
const auto& rule = *ope_;
auto r = rule.parse(s + i, l - i, sv, dt);
auto r = rule.parse(s + i, l - i, sv, c, dt);
if (!r.ret) {
break;
}
@ -556,7 +603,9 @@ public:
return success(i);
}
private:
void accept(Visitor& v) override;
//private:
std::shared_ptr<Ope> ope_;
};
@ -565,13 +614,15 @@ class Option : public Ope
public:
Option(const std::shared_ptr<Ope>& ope) : ope_(ope) {}
Result parse(const char* s, size_t l, SemanticValues& sv, any& dt) const {
Result parse(const char* s, size_t l, SemanticValues& sv, Context& c, any& dt) const override {
const auto& rule = *ope_;
auto r = rule.parse(s, l, sv, dt);
auto r = rule.parse(s, l, sv, c, dt);
return success(r.ret ? r.len : 0);
}
private:
void accept(Visitor& v) override;
//private:
std::shared_ptr<Ope> ope_;
};
@ -580,9 +631,9 @@ class AndPredicate : public Ope
public:
AndPredicate(const std::shared_ptr<Ope>& ope) : ope_(ope) {}
Result parse(const char* s, size_t l, SemanticValues& sv, any& dt) const {
Result parse(const char* s, size_t l, SemanticValues& sv, Context& c, any& dt) const override {
const auto& rule = *ope_;
auto r = rule.parse(s, l, sv, dt);
auto r = rule.parse(s, l, sv, c, dt);
if (r.ret) {
return success(0);
} else {
@ -590,7 +641,9 @@ public:
}
}
private:
void accept(Visitor& v) override;
//private:
std::shared_ptr<Ope> ope_;
};
@ -599,9 +652,9 @@ class NotPredicate : public Ope
public:
NotPredicate(const std::shared_ptr<Ope>& ope) : ope_(ope) {}
Result parse(const char* s, size_t l, SemanticValues& sv, any& dt) const {
Result parse(const char* s, size_t l, SemanticValues& sv, Context& c, any& dt) const override {
const auto& rule = *ope_;
auto r = rule.parse(s, l, sv, dt);
auto r = rule.parse(s, l, sv, c, dt);
if (r.ret) {
return fail(s);
} else {
@ -609,7 +662,9 @@ public:
}
}
private:
void accept(Visitor& v) override;
//private:
std::shared_ptr<Ope> ope_;
};
@ -618,7 +673,7 @@ class LiteralString : public Ope
public:
LiteralString(const std::string& s) : lit_(s) {}
Result parse(const char* s, size_t l, SemanticValues& sv, any& dt) const {
Result parse(const char* s, size_t l, SemanticValues& sv, Context& c, any& dt) const override {
auto i = 0u;
for (; i < lit_.size(); i++) {
if (i >= l || s[i] != lit_[i]) {
@ -628,7 +683,9 @@ public:
return success(i);
}
private:
void accept(Visitor& v) override;
//private:
std::string lit_;
};
@ -637,7 +694,7 @@ class CharacterClass : public Ope
public:
CharacterClass(const std::string& chars) : chars_(chars) {}
Result parse(const char* s, size_t l, SemanticValues& sv, any& dt) const {
Result parse(const char* s, size_t l, SemanticValues& sv, Context& c, any& dt) const override {
// TODO: UTF8 support
if (l < 1) {
return fail(s);
@ -660,7 +717,9 @@ public:
return fail(s);
}
private:
void accept(Visitor& v) override;
//private:
std::string chars_;
};
@ -669,7 +728,7 @@ class Character : public Ope
public:
Character(char ch) : ch_(ch) {}
Result parse(const char* s, size_t l, SemanticValues& sv, any& dt) const {
Result parse(const char* s, size_t l, SemanticValues& sv, Context& c, any& dt) const override {
// TODO: UTF8 support
if (l < 1 || s[0] != ch_) {
return fail(s);
@ -677,14 +736,16 @@ public:
return success(1);
}
private:
void accept(Visitor& v) override;
//private:
char ch_;
};
class AnyCharacter : public Ope
{
public:
Result parse(const char* s, size_t l, SemanticValues& sv, any& dt) const {
Result parse(const char* s, size_t l, SemanticValues& sv, Context& c, any& dt) const override {
// TODO: UTF8 support
if (l < 1) {
return fail(s);
@ -692,6 +753,7 @@ public:
return success(1);
}
void accept(Visitor& v) override;
};
class Capture : public Ope
@ -700,17 +762,19 @@ public:
Capture(const std::shared_ptr<Ope>& ope, MatchAction ma, size_t ci)
: ope_(ope), match_action_(ma), capture_id(ci) {}
Result parse(const char* s, size_t l, SemanticValues& sv, any& dt) const {
Result parse(const char* s, size_t l, SemanticValues& sv, Context& c, any& dt) const override {
assert(ope_);
const auto& rule = *ope_;
auto r = rule.parse(s, l, sv, dt);
auto r = rule.parse(s, l, sv, c, dt);
if (r.ret && match_action_) {
match_action_(s, r.len, capture_id);
}
return r;
}
private:
void accept(Visitor& v) override;
//private:
std::shared_ptr<Ope> ope_;
MatchAction match_action_;
size_t capture_id;
@ -721,10 +785,10 @@ class Anchor : public Ope
public:
Anchor(const std::shared_ptr<Ope>& ope) : ope_(ope) {}
Result parse(const char* s, size_t l, SemanticValues& sv, any& dt) const {
Result parse(const char* s, size_t l, SemanticValues& sv, Context& c, any& dt) const override {
assert(ope_);
const auto& rule = *ope_;
auto r = rule.parse(s, l, sv, dt);
auto r = rule.parse(s, l, sv, c, dt);
if (r.ret) {
sv.s = s;
sv.l = r.len;
@ -732,7 +796,9 @@ public:
return r;
}
private:
void accept(Visitor& v) override;
//private:
std::shared_ptr<Ope> ope_;
};
@ -743,12 +809,14 @@ class User : public Ope
public:
User(Parser fn) : fn_(fn) {}
Result parse(const char* s, size_t l, SemanticValues& sv, any& dt) const {
Result parse(const char* s, size_t l, SemanticValues& sv, Context& c, any& dt) const override {
assert(fn_);
return fn_(s, l, sv, dt);
}
private:
void accept(Visitor& v) override;
//private:
std::function<Result (const char* s, size_t l, SemanticValues& sv, any& dt)> fn_;
};
@ -757,17 +825,163 @@ class WeakHolder : public Ope
public:
WeakHolder(const std::shared_ptr<Ope>& ope) : weak_(ope) {}
Result parse(const char* s, size_t l, SemanticValues& sv, any& dt) const {
Result parse(const char* s, size_t l, SemanticValues& sv, Context& c, any& dt) const override {
auto ope = weak_.lock();
assert(ope);
const auto& rule = *ope;
return rule.parse(s, l, sv, dt);
return rule.parse(s, l, sv, c, dt);
}
private:
void accept(Visitor& v) override;
//private:
std::weak_ptr<Ope> weak_;
};
class Definition;
class Holder : public Ope
{
public:
Holder(Definition* outer)
: outer_(outer) {}
Result parse(const char* s, size_t l, SemanticValues& sv, Context& c, any& dt) const override;
void accept(Visitor& v) override;
//private:
friend class Definition;
any reduce(const SemanticValues& sv, any& dt, const Action& action) const {
if (action) {
return action(sv, dt);
} else if (sv.empty()) {
return any();
} else {
return sv.front().val;
}
}
std::shared_ptr<Ope> ope_;
Definition* outer_;
};
class DefinitionReference : public Ope
{
public:
DefinitionReference(
const std::unordered_map<std::string, Definition>& grammar, const std::string& name)
: grammar_(grammar)
, name_(name) {}
Result parse(const char* s, size_t l, SemanticValues& sv, Context& c, any& dt) const override;
void accept(Visitor& v) override;
std::shared_ptr<Ope> get_rule() const;
private:
const std::unordered_map<std::string, Definition>& grammar_;
const std::string name_;
mutable std::once_flag init_;
mutable std::shared_ptr<Ope> rule_;
};
/*
* Visitor
*/
struct Ope::Visitor
{
virtual void visit(const Sequence& ope) = 0;
virtual void visit(const PrioritizedChoice& ope) = 0;
virtual void visit(const ZeroOrMore& ope) = 0;
virtual void visit(const OneOrMore& ope) = 0;
virtual void visit(const Option& ope) = 0;
virtual void visit(const AndPredicate& ope) = 0;
virtual void visit(const NotPredicate& ope) = 0;
virtual void visit(const LiteralString& ope) = 0;
virtual void visit(const CharacterClass& ope) = 0;
virtual void visit(const Character& ope) = 0;
virtual void visit(const AnyCharacter& ope) = 0;
virtual void visit(const Capture& ope) = 0;
virtual void visit(const Anchor& ope) = 0;
virtual void visit(const User& ope) = 0;
virtual void visit(const WeakHolder& ope) = 0;
virtual void visit(const Holder& ope) = 0;
virtual void visit(const DefinitionReference& ope) = 0;
};
struct DefinitionIDs : public Ope::Visitor
{
DefinitionIDs(
std::vector<void*>& defs,
std::unordered_map<void*, size_t>& ids)
: defs_(defs), ids_(ids) {}
void visit(const Sequence& ope) override {
for (auto ope: ope.opes_) {
ope->accept(*this);
}
}
void visit(const PrioritizedChoice& ope) override {
for (auto ope: ope.opes_) {
ope->accept(*this);
}
}
void visit(const ZeroOrMore& ope) override {
ope.ope_->accept(*this);
}
void visit(const OneOrMore& ope) override {
ope.ope_->accept(*this);
}
void visit(const Option& ope) override {
ope.ope_->accept(*this);
}
void visit(const AndPredicate& ope) override {
ope.ope_->accept(*this);
}
void visit(const NotPredicate& ope) override {
ope.ope_->accept(*this);
}
void visit(const LiteralString& ope) override {
}
void visit(const CharacterClass& ope) override {
}
void visit(const Character& ope) override {
}
void visit(const AnyCharacter& ope) override {
}
void visit(const Capture& ope) override {
ope.ope_->accept(*this);
}
void visit(const Anchor& ope) override {
ope.ope_->accept(*this);
}
void visit(const User& ope) override {
}
void visit(const WeakHolder& ope) override {
ope.weak_.lock()->accept(*this);
}
void visit(const Holder& ope) override {
auto p = (void*)&ope.outer_;
if (ids_.find(p) != ids_.end()) {
return;
}
auto id = defs_.size();
defs_.push_back(p);
ids_[p] = id;
ope.ope_->accept(*this);
}
void visit(const DefinitionReference& ope) override {
ope.get_rule()->accept(*this);
}
private:
std::vector<void*>& defs_;
std::unordered_map<void*, size_t>& ids_;
};
/*
* Definition
*/
@ -814,15 +1028,33 @@ public:
return *this;
}
Result parse_core(const char* s, size_t l, SemanticValues& sv, any& dt) const {
Context c;
DefinitionIDs defIds(c.defs, c.ids);
holder_->accept(defIds);
return holder_->parse(s, l, sv, c, dt);
}
Result parse(const char* s, size_t l, SemanticValues& sv, any& dt) const {
return holder_->parse(s, l, sv, dt);
return parse_core(s, l, sv, dt);
}
Result parse(const char* s, size_t l) const {
SemanticValues sv;
any dt;
return parse_core(s, l, sv, dt);
}
Result parse(const char* s) const {
auto l = strlen(s);
return parse(s, l);
}
template <typename T>
Result parse(const char* s, size_t l, T& val) const {
Result parse_with_value(const char* s, size_t l, T& val) const {
SemanticValues sv;
any dt;
auto r = holder_->parse(s, l, sv, dt);
auto r = parse_core(s, l, sv, dt);
if (r.ret && !sv.empty() && !sv.front().val.is_undefined()) {
val = sv[0].val.get<T>();
}
@ -830,16 +1062,9 @@ public:
}
template <typename T>
Result parse(const char* s, T& val) const {
auto l = strlen(s);
return parse(s, l, val);
}
Result parse(const char* s) const {
Result parse_with_value(const char* s, T& val) const {
auto l = strlen(s);
SemanticValues sv;
any dt;
return holder_->parse(s, l, sv, dt);
return parse_with_value(s, l, val);
}
Definition& operator=(Action ac) {
@ -864,6 +1089,10 @@ public:
return *this;
}
void accept(Ope::Visitor& v) {
holder_->accept(v);
}
std::string name;
std::vector<Action> actions;
bool ignore;
@ -871,81 +1100,81 @@ public:
private:
friend class DefinitionReference;
class Holder : public Ope
{
public:
Holder(Definition* outer)
: outer_(outer) {}
Definition& operator=(const Definition& rhs);
Definition& operator=(Definition&& rhs);
Result parse(const char* s, size_t l, SemanticValues& sv, any& dt) const {
if (!ope_) {
throw std::logic_error("Uninitialized definition ope was used...");
}
std::shared_ptr<Holder> holder_;
};
const auto& rule = *ope_;
SemanticValues chldsv;
auto r = rule.parse(s, l, chldsv, dt);
if (r.ret && !outer_->ignore) {
assert(!outer_->actions.empty());
auto id = r.choice + 1;
const auto& action = (id < outer_->actions.size() && outer_->actions[id])
? outer_->actions[id]
: outer_->actions[0];
if (!chldsv.s) {
chldsv.s = s;
chldsv.l = r.len;
}
auto val = reduce(chldsv, dt, action);
typedef Definition rule;
sv.push_back(SemanticValue{ val, outer_->name, nullptr, 0 });
}
return r;
}
/*
* Implementations
*/
private:
friend class Definition;
inline Result Holder::parse(const char* s, size_t l, SemanticValues& sv, Context& c, any& dt) const {
if (!ope_) {
throw std::logic_error("Uninitialized definition ope was used...");
}
any reduce(const SemanticValues& sv, any& dt, const Action& action) const {
if (action) {
return action(sv, dt);
} else if (sv.empty()) {
return any();
} else {
return sv.front().val;
}
}
const auto& rule = *ope_;
auto& chldsv = c.push();
auto r = rule.parse(s, l, chldsv, c, dt);
if (r.ret && !outer_->ignore) {
assert(!outer_->actions.empty());
std::shared_ptr<Ope> ope_;
Definition* outer_;
};
auto id = r.choice + 1;
const auto& action = (id < outer_->actions.size() && outer_->actions[id])
? outer_->actions[id]
: outer_->actions[0];
Definition& operator=(const Definition& rhs);
Definition& operator=(Definition&& rhs);
if (!chldsv.s) {
chldsv.s = s;
chldsv.l = r.len;
}
std::shared_ptr<Holder> holder_;
};
sv.emplace_back(
reduce(chldsv, dt, action),
outer_->name.c_str(),
nullptr,
0);
}
c.pop();
return r;
}
class DefinitionReference : public Ope
{
public:
DefinitionReference(
const std::map<std::string, Definition>& grammar, const std::string& name)
: grammar_(grammar)
, name_(name) {}
Result DefinitionReference::parse(const char* s, size_t l, SemanticValues& sv, Context& c, any& dt) const {
const auto& rule = *get_rule();
return rule.parse(s, l, sv, c, dt);
}
Result parse(const char* s, size_t l, SemanticValues& sv, any& dt) const {
const auto& rule = *grammar_.at(name_).holder_;
return rule.parse(s, l, sv, dt);
std::shared_ptr<Ope> DefinitionReference::get_rule() const {
if (!rule_) {
std::call_once(init_, [this]() {
rule_ = grammar_.at(name_).holder_;
});
}
private:
const std::map<std::string, Definition>& grammar_;
const std::string name_;
assert(rule_);
return rule_;
};
typedef Definition rule;
inline void Sequence::accept(Visitor& v) { v.visit(*this); }
inline void PrioritizedChoice::accept(Visitor& v) { v.visit(*this); }
inline void ZeroOrMore::accept(Visitor& v) { v.visit(*this); }
inline void OneOrMore::accept(Visitor& v) { v.visit(*this); }
inline void Option::accept(Visitor& v) { v.visit(*this); }
inline void AndPredicate::accept(Visitor& v) { v.visit(*this); }
inline void NotPredicate::accept(Visitor& v) { v.visit(*this); }
inline void LiteralString::accept(Visitor& v) { v.visit(*this); }
inline void CharacterClass::accept(Visitor& v) { v.visit(*this); }
inline void Character::accept(Visitor& v) { v.visit(*this); }
inline void AnyCharacter::accept(Visitor& v) { v.visit(*this); }
inline void Capture::accept(Visitor& v) { v.visit(*this); }
inline void Anchor::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 Holder::accept(Visitor& v) { v.visit(*this); }
inline void DefinitionReference::accept(Visitor& v) { v.visit(*this); }
/*
* Factories
@ -1012,7 +1241,7 @@ inline std::shared_ptr<Ope> usr(std::function<Result (const char* s, size_t l, S
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::unordered_map<std::string, Definition>& grammar, const std::string& name) {
return std::make_shared<DefinitionReference>(grammar, name);
}
@ -1038,10 +1267,10 @@ inline std::pair<size_t, size_t> line_info(const char* s, const char* ptr) {
return std::make_pair(no, col);
}
typedef std::map<std::string, Definition> Grammar;
typedef std::unordered_map<std::string, Definition> Grammar;
typedef std::function<void (size_t, size_t, const std::string&)> Log;
typedef std::map<std::string, std::shared_ptr<Ope>> Rules;
typedef std::unordered_map<std::string, std::shared_ptr<Ope>> Rules;
class PEGParser
{
@ -1085,14 +1314,14 @@ private:
setup_actions();
}
struct Context {
std::shared_ptr<Grammar> grammar;
std::string start;
MatchAction match_action;
std::map<std::string, const char*> references;
size_t capture_count;
struct Data {
std::shared_ptr<Grammar> grammar;
std::string start;
MatchAction match_action;
std::unordered_map<std::string, const char*> references;
size_t capture_count;
Context() : grammar(std::make_shared<Grammar>()), capture_count(0) {}
Data() : grammar(std::make_shared<Grammar>()), capture_count(0) {}
};
void make_grammar() {
@ -1152,8 +1381,6 @@ private:
g["IGNORE"] <= chr('~');
g["Action"] <= seq(chr('{'), anc(zom(npd(chr('}')))), chr('}'), g["Spacing"]);
// Set definition names
for (auto& x: g) {
x.second.name = x.first;
@ -1162,7 +1389,7 @@ private:
void setup_actions() {
g["Definition"] = [&](const SemanticValues& sv, any& dt) {
Context& cxt = *dt.get<Context*>();
Data& data = *dt.get<Data*>();
auto ignore = (sv.size() == 4);
auto baseId = ignore ? 1 : 0;
@ -1170,13 +1397,13 @@ private:
const auto& name = sv[baseId].val.get<std::string>();
auto ope = sv[baseId + 2].val.get<std::shared_ptr<Ope>>();
auto& def = (*cxt.grammar)[name];
auto& def = (*data.grammar)[name];
def <= ope;
def.name = name;
def.ignore = ignore;
if (cxt.start.empty()) {
cxt.start = name;
if (data.start.empty()) {
data.start = name;
}
};
@ -1245,10 +1472,10 @@ private:
return sv[0];
},
[&](const SemanticValues& sv, any& dt) {
Context& cxt = *dt.get<Context*>();
Data& data = *dt.get<Data*>();
const auto& ident = sv[0].val.get<std::string>();
cxt.references[ident] = sv.s; // for error handling
return ref(*cxt.grammar, ident);
data.references[ident] = sv.s; // for error handling
return ref(*data.grammar, ident);
},
[&](const SemanticValues& sv) {
return sv[1];
@ -1260,9 +1487,9 @@ private:
},
// Capture
[&](const SemanticValues& sv, any& dt) {
Context& cxt = *dt.get<Context*>();
Data& data = *dt.get<Data*>();
auto ope = sv[1].val.get<std::shared_ptr<Ope>>();
return cap(ope, cxt.match_action, ++cxt.capture_count);
return cap(ope, data.match_action, ++data.capture_count);
}
};
@ -1293,22 +1520,22 @@ private:
MatchAction ma,
Log log)
{
Context cxt;
cxt.match_action = ma;
Data data;
data.match_action = ma;
SemanticValues sv;
any dt = &cxt;
any dt = &data;
auto r = g["Grammar"].parse(s, l, sv, dt);
if (!r.ret) {
if (log) {
auto line = line_info(s, r.ptr);
log(line.first, line.second, r.err.empty() ? "syntax error" : r.err);
log(line.first, line.second, r.err ? "syntax error" : r.err);
}
return nullptr;
}
auto& grammar = *cxt.grammar;
auto& grammar = *data.grammar;
// User provided rules
for (const auto& x: rules) {
@ -1329,7 +1556,7 @@ private:
}
// Check missing definitions
for (const auto& x : cxt.references) {
for (const auto& x : data.references) {
const auto& name = x.first;
auto ptr = x.second;
if (grammar.find(name) == grammar.end()) {
@ -1341,9 +1568,9 @@ private:
}
}
start = cxt.start;
start = data.start;
return cxt.grammar;
return data.grammar;
}
bool is_hex(char c, int& v) {
@ -1471,7 +1698,7 @@ public:
bool parse(const char* s, size_t l, T& out, bool exact = true) const {
if (grammar_ != nullptr) {
const auto& rule = (*grammar_)[start_];
auto r = rule.parse(s, l, out);
auto r = rule.parse_with_value(s, l, out);
return r.ret && (!exact || r.len == l);
}
return false;
@ -1530,7 +1757,7 @@ public:
if (!r.ret) {
if (log) {
auto line = line_info(s, r.ptr);
log(line.first, line.second, r.err.empty() ? "syntax error" : r.err);
log(line.first, line.second, r.err ? "syntax error" : r.err);
}
} else if (exact && r.len != l) {
auto line = line_info(s, s + r.len);

@ -5,6 +5,17 @@
#include <peglib.h>
#include <iostream>
TEST_CASE("Simple syntax test", "[general]")
{
peglib::peg parser(
" ROOT <- _ "
" _ <- ' ' "
);
bool ret = parser;
REQUIRE(ret == true);
}
TEST_CASE("Empty syntax test", "[general]")
{
peglib::peg parser("");
@ -131,6 +142,24 @@ TEST_CASE("Cyclic grammer test", "[general]")
CHILD <= seq(PARENT);
}
TEST_CASE("Visit test", "[general]")
{
rule ROOT, TAG, TAG_NAME, WS;
ROOT <= seq(WS, zom(TAG));
TAG <= seq(chr('['), TAG_NAME, chr(']'), WS);
TAG_NAME <= oom(seq(npd(chr(']')), dot()));
WS <= zom(cls(" \t"));
std::vector<void*> defs;
std::unordered_map<void*, size_t> ids;
DefinitionIDs defIds(defs, ids);
ROOT.accept(defIds);
REQUIRE(defs.size() == 4);
}
TEST_CASE("Lambda action test", "[general]")
{
peg parser(
@ -180,7 +209,7 @@ TEST_CASE("Backtracking test", "[general]")
bool ret = parser.parse("Hello Two");
REQUIRE(ret == true);
REQUIRE(count == 2);
REQUIRE(count == 1); // Skip second time
}
TEST_CASE("Octal/Hex value test", "[general]")
@ -274,7 +303,7 @@ TEST_CASE("Calculator test", "[general]")
// Parse
long val;
auto m = EXPRESSION.parse("1+2*3*(4-5+6)/7-8", val);
auto m = EXPRESSION.parse_with_value("1+2*3*(4-5+6)/7-8", val);
REQUIRE(m.ret == true);
REQUIRE(val == -3);
@ -320,7 +349,7 @@ TEST_CASE("Calculator test2", "[general]")
// Parse
long val;
auto m = g[start].parse("1+2*3*(4-5+6)/7-8", val);
auto m = g[start].parse_with_value("1+2*3*(4-5+6)/7-8", val);
REQUIRE(m.ret == true);
REQUIRE(val == -3);

@ -1,10 +1,15 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Express 2013 for Windows Desktop
VisualStudioVersion = 12.0.20617.1 PREVIEW
# Visual Studio 2013
VisualStudioVersion = 12.0.31101.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "test.vcxproj", "{6B3E6769-052D-4BC0-9D2C-E9127C3DBB26}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{9F9B51BE-29B3-4CDE-BA49-5751CBC34350}"
ProjectSection(SolutionItems) = preProject
Performance1.psess = Performance1.psess
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
@ -25,4 +30,7 @@ Global
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(Performance) = preSolution
HasPerformanceSessions = true
EndGlobalSection
EndGlobal

Loading…
Cancel
Save