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