diff --git a/README.md b/README.md
index 8f72417..b0c62b9 100644
--- a/README.md
+++ b/README.md
@@ -20,6 +20,7 @@ The PEG syntax is well described on page 2 in the [document](http://www.brynosau
* `$name(` ... `)` (Capture scope operator)
* `$name<` ... `>` (Named capture operator)
* `$name` (Backreference operator)
+ * `MACRO_NAME(` ... `)` (Parameterized rule or Macro)
This library also supports the linear-time parsing known as the [*Packrat*](http://pdos.csail.mit.edu/~baford/packrat/thesis/thesis.pdf) parsing.
@@ -285,6 +286,28 @@ parser.parse("This is a test text."); // NG
parser.parse("This is a test text."); // NG
```
+Parameterized Rule or Macro
+---------------------------
+
+```peg
+# Syntax
+Start ← _ Expr
+Expr ← Sum
+Sum ← List(Product, SumOpe)
+Product ← List(Value, ProOpe)
+Value ← Number / T('(') Expr T(')')
+
+# Token
+SumOpe ← T('+' / '-')
+ProOpe ← T('*' / '/')
+Number ← T([0-9]+)
+~_ ← [ \t\r\n]*
+
+# Macro
+List(I, D) ← I (D I)*
+T(x) ← < x > _
+```
+
AST generation
--------------
diff --git a/peglib.h b/peglib.h
index 19c3bdb..770fcc5 100644
--- a/peglib.h
+++ b/peglib.h
@@ -497,6 +497,7 @@ public:
std::vector> value_stack;
size_t value_stack_size;
+ std::vector>> args_stack;
size_t nest_level;
@@ -544,6 +545,7 @@ public:
, cache_success(enablePackratParsing ? def_count * (l + 1) : 0)
, tracer(a_tracer)
{
+ args_stack.resize(1);
capture_scope_stack.resize(1);
}
@@ -599,12 +601,24 @@ public:
value_stack_size--;
}
+ void push_args(const std::vector>& args) {
+ args_stack.push_back(args);
+ }
+
+ void pop_args() {
+ args_stack.pop_back();
+ }
+
+ const std::vector>& top_args() const {
+ return args_stack[args_stack.size() - 1];
+ }
+
void push_capture_scope() {
capture_scope_stack.resize(capture_scope_stack.size() + 1);
}
void pop_capture_scope() {
- capture_scope_stack.resize(capture_scope_stack.size() - 1);
+ capture_scope_stack.pop_back();
}
void shift_capture_values() {
@@ -943,6 +957,7 @@ public:
};
class LiteralString : public Ope
+ , public std::enable_shared_from_this
{
public:
LiteralString(const std::string& s)
@@ -961,6 +976,7 @@ public:
};
class CharacterClass : public Ope
+ , public std::enable_shared_from_this
{
public:
CharacterClass(const std::string& chars) : chars_(chars) {}
@@ -997,6 +1013,7 @@ public:
};
class Character : public Ope
+ , public std::enable_shared_from_this
{
public:
Character(char ch) : ch_(ch) {}
@@ -1017,6 +1034,7 @@ public:
};
class AnyCharacter : public Ope
+ , public std::enable_shared_from_this
{
public:
size_t parse(const char* s, size_t n, SemanticValues& sv, Context& c, any& dt) const override {
@@ -1073,9 +1091,7 @@ public:
void accept(Visitor& v) override;
std::shared_ptr ope_;
-
-private:
- MatchAction match_action_;
+ MatchAction match_action_;
};
class TokenBoundary : public Ope
@@ -1146,28 +1162,42 @@ public:
friend class Definition;
};
-class DefinitionReference : public Ope
+typedef std::unordered_map Grammar;
+
+class Reference : public Ope
+ , public std::enable_shared_from_this
{
public:
- DefinitionReference(
- const std::unordered_map& grammar, const std::string& name, const char* s)
+ Reference(
+ const Grammar& grammar,
+ const std::string& name,
+ const char* s,
+ bool is_macro,
+ const std::vector>& args)
: grammar_(grammar)
, name_(name)
- , s_(s) {}
+ , s_(s)
+ , is_macro_(is_macro)
+ , args_(args)
+ , rule_(nullptr)
+ , iarg_(0)
+ {}
size_t parse(const char* s, size_t n, SemanticValues& sv, Context& c, any& dt) const override;
void accept(Visitor& v) override;
- std::shared_ptr get_rule() const;
+ std::shared_ptr get_core_operator() const;
- const std::unordered_map& grammar_;
- const std::string name_;
- const char* s_;
+ const Grammar& grammar_;
+ const std::string name_;
+ const char* s_;
-private:
- mutable std::once_flag init_;
- mutable std::shared_ptr rule_;
+ const bool is_macro_;
+ const std::vector> args_;
+
+ Definition* rule_;
+ size_t iarg_;
};
class Whitespace : public Ope
@@ -1202,6 +1232,83 @@ public:
std::string name_;
};
+/*
+ * Factories
+ */
+template
+std::shared_ptr seq(Args&& ...args) {
+ return std::make_shared(static_cast>(args)...);
+}
+
+template
+std::shared_ptr cho(Args&& ...args) {
+ return std::make_shared(static_cast>(args)...);
+}
+
+inline std::shared_ptr zom(const std::shared_ptr& ope) {
+ return std::make_shared(ope);
+}
+
+inline std::shared_ptr oom(const std::shared_ptr& ope) {
+ return std::make_shared(ope);
+}
+
+inline std::shared_ptr opt(const std::shared_ptr& ope) {
+ return std::make_shared