mirror of
https://github.com/yhirose/cpp-peglib.git
synced 2024-12-22 20:05:31 +00:00
Changed namespace/class names.
This commit is contained in:
parent
23737a716b
commit
b9c9216788
46
README.md
46
README.md
@ -7,7 +7,7 @@ C++11 header-only [PEG](http://en.wikipedia.org/wiki/Parsing_expression_grammar)
|
|||||||
|
|
||||||
The PEG syntax is well described on page 2 in the [document](http://pdos.csail.mit.edu/papers/parsing:popl04.pdf). *cpp-peglib* also supports the following additional syntax for now:
|
The PEG syntax is well described on page 2 in the [document](http://pdos.csail.mit.edu/papers/parsing:popl04.pdf). *cpp-peglib* also supports the following additional syntax for now:
|
||||||
|
|
||||||
* `<` ... `>` (Anchor operator)
|
* `<` ... `>` (Token boundary operator)
|
||||||
* `$<` ... `>` (Capture operator)
|
* `$<` ... `>` (Capture operator)
|
||||||
* `$name<` ... `>` (Named capture operator)
|
* `$name<` ... `>` (Named capture operator)
|
||||||
* `~` (Ignore operator)
|
* `~` (Ignore operator)
|
||||||
@ -25,7 +25,7 @@ This is a simple calculator sample. It shows how to define grammar, associate sa
|
|||||||
#include <peglib.h>
|
#include <peglib.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
using namespace peglib;
|
using namespace peg;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
@ -38,7 +38,7 @@ int main(void) {
|
|||||||
Number <- [0-9]+
|
Number <- [0-9]+
|
||||||
)";
|
)";
|
||||||
|
|
||||||
peg parser(syntax);
|
parser parser(syntax);
|
||||||
|
|
||||||
// (3) Setup an action
|
// (3) Setup an action
|
||||||
parser["Additive"] = [](const SemanticValues& sv) {
|
parser["Additive"] = [](const SemanticValues& sv) {
|
||||||
@ -111,13 +111,13 @@ struct SemanticValues : protected std::vector<SemanticValue>
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
`peglib::any` class is very similar to [boost::any](http://www.boost.org/doc/libs/1_57_0/doc/html/any.html). You can obtain a value by castning it to the actual type. In order to determine the actual type, you have to check the return value type of the child action for the semantic value.
|
`peg::any` class is very similar to [boost::any](http://www.boost.org/doc/libs/1_57_0/doc/html/any.html). You can obtain a value by castning it to the actual type. In order to determine the actual type, you have to check the return value type of the child action for the semantic value.
|
||||||
|
|
||||||
`const char* s, size_t n` gives a pointer and length of the matched string. This is same as `sv.s` and `sv.n`.
|
`const char* s, size_t n` gives a pointer and length of the matched string. This is same as `sv.s` and `sv.n`.
|
||||||
|
|
||||||
`any& dt` is a data object which can be used by the user for whatever purposes.
|
`any& dt` is a data object which can be used by the user for whatever purposes.
|
||||||
|
|
||||||
The following example uses `<` ... ` >` operators. They are the *anchor* operators. Each anchor operator creates a semantic value that contains `const char*` of the position. It could be useful to eliminate unnecessary characters.
|
The following example uses `<` ... ` >` operators. They are the *token boundary* operators. Each token boundary operator creates a semantic value that contains `const char*` of the position. It could be useful to eliminate unnecessary characters.
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
auto syntax = R"(
|
auto syntax = R"(
|
||||||
@ -139,7 +139,7 @@ auto ret = pg.parse(" token1, token2 ");
|
|||||||
We can ignore unnecessary semantic values from the list by using `~` operator.
|
We can ignore unnecessary semantic values from the list by using `~` operator.
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
peglib::peg parser(
|
peg::pegparser parser(
|
||||||
" ROOT <- _ ITEM (',' _ ITEM _)* "
|
" ROOT <- _ ITEM (',' _ ITEM _)* "
|
||||||
" ITEM <- ([a-z])+ "
|
" ITEM <- ([a-z])+ "
|
||||||
" ~_ <- [ \t]* "
|
" ~_ <- [ \t]* "
|
||||||
@ -155,22 +155,22 @@ auto ret = parser.parse(" item1, item2 ");
|
|||||||
The following grammar is same as the above.
|
The following grammar is same as the above.
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
peglib::peg parser(
|
peg::parser parser(
|
||||||
" ROOT <- ~_ ITEM (',' ~_ ITEM ~_)* "
|
" ROOT <- ~_ ITEM (',' ~_ ITEM ~_)* "
|
||||||
" ITEM <- ([a-z])+ "
|
" ITEM <- ([a-z])+ "
|
||||||
" _ <- [ \t]* "
|
" _ <- [ \t]* "
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
*Semantic predicate* support is available. We can do it by throwing a `peglib::parse_error` exception in a semantic action.
|
*Semantic predicate* support is available. We can do it by throwing a `peg::parse_error` exception in a semantic action.
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
peglib::peg parser("NUMBER <- [0-9]+");
|
peg::parser parser("NUMBER <- [0-9]+");
|
||||||
|
|
||||||
parser["NUMBER"] = [](const SemanticValues& sv) {
|
parser["NUMBER"] = [](const SemanticValues& sv) {
|
||||||
auto val = stol(sv.str(), nullptr, 10);
|
auto val = stol(sv.str(), nullptr, 10);
|
||||||
if (val != 100) {
|
if (val != 100) {
|
||||||
throw peglib::parse_error("value error!!");
|
throw peg::parse_error("value error!!");
|
||||||
}
|
}
|
||||||
return val;
|
return val;
|
||||||
};
|
};
|
||||||
@ -189,12 +189,12 @@ Simple interface
|
|||||||
|
|
||||||
*cpp-peglib* provides std::regex-like simple interface for trivial tasks.
|
*cpp-peglib* provides std::regex-like simple interface for trivial tasks.
|
||||||
|
|
||||||
`peglib::peg_match` tries to capture strings in the `$< ... >` operator and store them into `peglib::match` object.
|
`peg::peg_match` tries to capture strings in the `$< ... >` operator and store them into `peg::match` object.
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
peglib::match m;
|
peg::match m;
|
||||||
|
|
||||||
auto ret = peglib::peg_match(
|
auto ret = peg::peg_match(
|
||||||
R"(
|
R"(
|
||||||
ROOT <- _ ('[' $< TAG_NAME > ']' _)*
|
ROOT <- _ ('[' $< TAG_NAME > ']' _)*
|
||||||
TAG_NAME <- (!']' .)+
|
TAG_NAME <- (!']' .)+
|
||||||
@ -213,9 +213,9 @@ assert(m.str(3) == "tag-3");
|
|||||||
It also supports named capture with the `$name<` ... `>` operator.
|
It also supports named capture with the `$name<` ... `>` operator.
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
peglib::match m;
|
peg::match m;
|
||||||
|
|
||||||
auto ret = peglib::peg_match(
|
auto ret = peg::peg_match(
|
||||||
R"(
|
R"(
|
||||||
ROOT <- _ ('[' $test< TAG_NAME > ']' _)*
|
ROOT <- _ ('[' $test< TAG_NAME > ']' _)*
|
||||||
TAG_NAME <- (!']' .)+
|
TAG_NAME <- (!']' .)+
|
||||||
@ -235,7 +235,7 @@ REQUIRE(m.str(cap[2]) == "tag-3");
|
|||||||
There are some ways to *search* a peg pattern in a document.
|
There are some ways to *search* a peg pattern in a document.
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
using namespace peglib;
|
using namespace peg;
|
||||||
|
|
||||||
auto syntax = R"(
|
auto syntax = R"(
|
||||||
ROOT <- '[' $< [a-z0-9]+ > ']'
|
ROOT <- '[' $< [a-z0-9]+ > ']'
|
||||||
@ -243,8 +243,8 @@ auto syntax = R"(
|
|||||||
|
|
||||||
auto s = " [tag1] [tag2] [tag3] ";
|
auto s = " [tag1] [tag2] [tag3] ";
|
||||||
|
|
||||||
// peglib::peg_search
|
// peg::peg_search
|
||||||
peg pg(syntax);
|
parser pg(syntax);
|
||||||
size_t pos = 0;
|
size_t pos = 0;
|
||||||
auto n = strlen(s);
|
auto n = strlen(s);
|
||||||
match m;
|
match m;
|
||||||
@ -254,7 +254,7 @@ while (peg_search(pg, s + pos, n - pos, m)) {
|
|||||||
pos += m.length();
|
pos += m.length();
|
||||||
}
|
}
|
||||||
|
|
||||||
// peglib::peg_token_iterator
|
// peg::peg_token_iterator
|
||||||
peg_token_iterator it(syntax, s);
|
peg_token_iterator it(syntax, s);
|
||||||
while (it != peg_token_iterator()) {
|
while (it != peg_token_iterator()) {
|
||||||
cout << it->str() << endl; // entire match
|
cout << it->str() << endl; // entire match
|
||||||
@ -262,7 +262,7 @@ while (it != peg_token_iterator()) {
|
|||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
|
|
||||||
// peglib::peg_token_range
|
// peg::peg_token_range
|
||||||
for (auto& m: peg_token_range(syntax, s)) {
|
for (auto& m: peg_token_range(syntax, s)) {
|
||||||
cout << m.str() << endl; // entire match
|
cout << m.str() << endl; // entire match
|
||||||
cout << m.str(1) << endl; // submatch #1
|
cout << m.str(1) << endl; // submatch #1
|
||||||
@ -275,7 +275,7 @@ Make a parser with parser operators
|
|||||||
Instead of makeing a parser by parsing PEG syntax text, we can also construct a parser by hand with *parser operators*. Here is an example:
|
Instead of makeing a parser by parsing PEG syntax text, we can also construct a parser by hand with *parser operators*. Here is an example:
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
using namespace peglib;
|
using namespace peg;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
vector<string> tags;
|
vector<string> tags;
|
||||||
@ -305,7 +305,7 @@ The following are available operators:
|
|||||||
| cls | Character class |
|
| cls | Character class |
|
||||||
| chr | Character |
|
| chr | Character |
|
||||||
| dot | Any character |
|
| dot | Any character |
|
||||||
| anc | Anchor character |
|
| tok | Token boundary |
|
||||||
| ign | Ignore semantic value |
|
| ign | Ignore semantic value |
|
||||||
| cap | Capture character |
|
| cap | Capture character |
|
||||||
| usr | User defiend parser |
|
| usr | User defiend parser |
|
||||||
@ -337,7 +337,7 @@ Rules additional_rules = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
peg g = peg(syntax, additional_rules);
|
auto g = parser(syntax, additional_rules);
|
||||||
|
|
||||||
assert(g.parse(" Hello BNF! "));
|
assert(g.parse(" Hello BNF! "));
|
||||||
```
|
```
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
using namespace peglib;
|
using namespace peg;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
int main(int argc, const char** argv)
|
int main(int argc, const char** argv)
|
||||||
@ -34,7 +34,7 @@ int main(int argc, const char** argv)
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
peg parser(R"(
|
parser parser(R"(
|
||||||
EXPRESSION <- _ TERM (TERM_OPERATOR TERM)*
|
EXPRESSION <- _ TERM (TERM_OPERATOR TERM)*
|
||||||
TERM <- FACTOR (FACTOR_OPERATOR FACTOR)*
|
TERM <- FACTOR (FACTOR_OPERATOR FACTOR)*
|
||||||
FACTOR <- NUMBER / '(' _ EXPRESSION ')' _
|
FACTOR <- NUMBER / '(' _ EXPRESSION ')' _
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
using namespace peglib;
|
using namespace peg;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
using namespace peglib;
|
using namespace peg;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
int main(int argc, const char** argv)
|
int main(int argc, const char** argv)
|
||||||
@ -39,7 +39,7 @@ int main(int argc, const char** argv)
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
peg parser(R"(
|
parser parser(R"(
|
||||||
EXPRESSION <- _ TERM (TERM_OPERATOR TERM)*
|
EXPRESSION <- _ TERM (TERM_OPERATOR TERM)*
|
||||||
TERM <- FACTOR (FACTOR_OPERATOR FACTOR)*
|
TERM <- FACTOR (FACTOR_OPERATOR FACTOR)*
|
||||||
FACTOR <- NUMBER / '(' _ EXPRESSION ')' _
|
FACTOR <- NUMBER / '(' _ EXPRESSION ')' _
|
||||||
|
@ -86,9 +86,9 @@ const auto grammar_ = R"(
|
|||||||
|
|
||||||
)";
|
)";
|
||||||
|
|
||||||
inline peglib::peg& get_parser()
|
inline peg::parser& get_parser()
|
||||||
{
|
{
|
||||||
static peglib::peg parser;
|
static peg::parser parser;
|
||||||
static bool initialized = false;
|
static bool initialized = false;
|
||||||
|
|
||||||
if (!initialized) {
|
if (!initialized) {
|
||||||
@ -337,7 +337,7 @@ struct Value
|
|||||||
}
|
}
|
||||||
|
|
||||||
Type type;
|
Type type;
|
||||||
peglib::any v;
|
peg::any v;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Symbol {
|
struct Symbol {
|
||||||
@ -408,7 +408,7 @@ struct Environment
|
|||||||
std::map<std::string, Symbol> dictionary;
|
std::map<std::string, Symbol> dictionary;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::function<void (const peglib::Ast& ast, Environment& env, bool force_to_break)> Debugger;
|
typedef std::function<void (const peg::Ast& ast, Environment& env, bool force_to_break)> Debugger;
|
||||||
|
|
||||||
inline bool ObjectValue::has(const std::string& name) const {
|
inline bool ObjectValue::has(const std::string& name) const {
|
||||||
if (properties->find(name) == properties->end()) {
|
if (properties->find(name) == properties->end()) {
|
||||||
@ -544,7 +544,7 @@ struct Interpreter
|
|||||||
: debugger_(debugger) {
|
: debugger_(debugger) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Value exec(const peglib::Ast& ast, std::shared_ptr<Environment> env) {
|
Value exec(const peg::Ast& ast, std::shared_ptr<Environment> env) {
|
||||||
try {
|
try {
|
||||||
return eval(ast, env);
|
return eval(ast, env);
|
||||||
} catch (const Value& val) {
|
} catch (const Value& val) {
|
||||||
@ -553,8 +553,8 @@ struct Interpreter
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Value eval(const peglib::Ast& ast, std::shared_ptr<Environment> env) {
|
Value eval(const peg::Ast& ast, std::shared_ptr<Environment> env) {
|
||||||
using peglib::operator"" _;
|
using peg::operator"" _;
|
||||||
|
|
||||||
if (debugger_) {
|
if (debugger_) {
|
||||||
if (ast.original_tag == "STATEMENT"_) {
|
if (ast.original_tag == "STATEMENT"_) {
|
||||||
@ -598,7 +598,7 @@ private:
|
|||||||
throw std::logic_error("invalid Ast type");
|
throw std::logic_error("invalid Ast type");
|
||||||
}
|
}
|
||||||
|
|
||||||
Value eval_statements(const peglib::Ast& ast, std::shared_ptr<Environment> env) {
|
Value eval_statements(const peg::Ast& ast, std::shared_ptr<Environment> env) {
|
||||||
if (ast.is_token) {
|
if (ast.is_token) {
|
||||||
return eval(ast, env);
|
return eval(ast, env);
|
||||||
} else if (ast.nodes.empty()) {
|
} else if (ast.nodes.empty()) {
|
||||||
@ -612,7 +612,7 @@ private:
|
|||||||
return eval(**it, env);
|
return eval(**it, env);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value eval_while(const peglib::Ast& ast, std::shared_ptr<Environment> env) {
|
Value eval_while(const peg::Ast& ast, std::shared_ptr<Environment> env) {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
auto cond = eval(*ast.nodes[0], env);
|
auto cond = eval(*ast.nodes[0], env);
|
||||||
if (!cond.to_bool()) {
|
if (!cond.to_bool()) {
|
||||||
@ -623,7 +623,7 @@ private:
|
|||||||
return Value();
|
return Value();
|
||||||
}
|
}
|
||||||
|
|
||||||
Value eval_if(const peglib::Ast& ast, std::shared_ptr<Environment> env) {
|
Value eval_if(const peg::Ast& ast, std::shared_ptr<Environment> env) {
|
||||||
const auto& nodes = ast.nodes;
|
const auto& nodes = ast.nodes;
|
||||||
|
|
||||||
for (auto i = 0u; i < nodes.size(); i += 2) {
|
for (auto i = 0u; i < nodes.size(); i += 2) {
|
||||||
@ -640,7 +640,7 @@ private:
|
|||||||
return Value();
|
return Value();
|
||||||
}
|
}
|
||||||
|
|
||||||
Value eval_function(const peglib::Ast& ast, std::shared_ptr<Environment> env) {
|
Value eval_function(const peg::Ast& ast, std::shared_ptr<Environment> env) {
|
||||||
std::vector<FunctionValue::Parameter> params;
|
std::vector<FunctionValue::Parameter> params;
|
||||||
for (auto node: ast.nodes[0]->nodes) {
|
for (auto node: ast.nodes[0]->nodes) {
|
||||||
auto mut = node->nodes[0]->token == "mut";
|
auto mut = node->nodes[0]->token == "mut";
|
||||||
@ -659,7 +659,7 @@ private:
|
|||||||
));
|
));
|
||||||
};
|
};
|
||||||
|
|
||||||
Value eval_function_call(const peglib::Ast& ast, std::shared_ptr<Environment> env, const Value& val) {
|
Value eval_function_call(const peg::Ast& ast, std::shared_ptr<Environment> env, const Value& val) {
|
||||||
const auto& f = val.to_function();
|
const auto& f = val.to_function();
|
||||||
const auto& params = *f.params;
|
const auto& params = *f.params;
|
||||||
const auto& args = ast.nodes;
|
const auto& args = ast.nodes;
|
||||||
@ -686,7 +686,7 @@ private:
|
|||||||
throw std::runtime_error(msg);
|
throw std::runtime_error(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value eval_array_reference(const peglib::Ast& ast, std::shared_ptr<Environment> env, const Value& val) {
|
Value eval_array_reference(const peg::Ast& ast, std::shared_ptr<Environment> env, const Value& val) {
|
||||||
const auto& arr = val.to_array();
|
const auto& arr = val.to_array();
|
||||||
auto idx = eval(ast, env).to_long();
|
auto idx = eval(ast, env).to_long();
|
||||||
if (0 <= idx && idx < static_cast<long>(arr.values->size())) {
|
if (0 <= idx && idx < static_cast<long>(arr.values->size())) {
|
||||||
@ -697,7 +697,7 @@ private:
|
|||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value eval_property(const peglib::Ast& ast, std::shared_ptr<Environment> env, const Value& val) {
|
Value eval_property(const peg::Ast& ast, std::shared_ptr<Environment> env, const Value& val) {
|
||||||
const auto& obj = val.to_object();
|
const auto& obj = val.to_object();
|
||||||
auto name = ast.token;
|
auto name = ast.token;
|
||||||
if (!obj.has(name)) {
|
if (!obj.has(name)) {
|
||||||
@ -717,8 +717,8 @@ private:
|
|||||||
return prop;
|
return prop;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value eval_call(const peglib::Ast& ast, std::shared_ptr<Environment> env) {
|
Value eval_call(const peg::Ast& ast, std::shared_ptr<Environment> env) {
|
||||||
using peglib::operator"" _;
|
using peg::operator"" _;
|
||||||
|
|
||||||
Value val = eval(*ast.nodes[0], env);
|
Value val = eval(*ast.nodes[0], env);
|
||||||
|
|
||||||
@ -736,11 +736,11 @@ private:
|
|||||||
return std::move(val);
|
return std::move(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value eval_block(const peglib::Ast& ast, std::shared_ptr<Environment> env) {
|
Value eval_block(const peg::Ast& ast, std::shared_ptr<Environment> env) {
|
||||||
return Value();
|
return Value();
|
||||||
}
|
}
|
||||||
|
|
||||||
Value eval_logical_or(const peglib::Ast& ast, std::shared_ptr<Environment> env) {
|
Value eval_logical_or(const peg::Ast& ast, std::shared_ptr<Environment> env) {
|
||||||
assert(ast.nodes.size() > 1); // if the size is 1, thes node will be hoisted.
|
assert(ast.nodes.size() > 1); // if the size is 1, thes node will be hoisted.
|
||||||
Value val;
|
Value val;
|
||||||
for (auto node: ast.nodes) {
|
for (auto node: ast.nodes) {
|
||||||
@ -752,7 +752,7 @@ private:
|
|||||||
return std::move(val);
|
return std::move(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value eval_logical_and(const peglib::Ast& ast, std::shared_ptr<Environment> env) {
|
Value eval_logical_and(const peg::Ast& ast, std::shared_ptr<Environment> env) {
|
||||||
Value val;
|
Value val;
|
||||||
for (auto node: ast.nodes) {
|
for (auto node: ast.nodes) {
|
||||||
val = eval(*node, env);
|
val = eval(*node, env);
|
||||||
@ -763,7 +763,7 @@ private:
|
|||||||
return std::move(val);
|
return std::move(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value eval_condition(const peglib::Ast& ast, std::shared_ptr<Environment> env) {
|
Value eval_condition(const peg::Ast& ast, std::shared_ptr<Environment> env) {
|
||||||
assert(ast.nodes.size() == 3); // if the size is 1, thes node will be hoisted.
|
assert(ast.nodes.size() == 3); // if the size is 1, thes node will be hoisted.
|
||||||
|
|
||||||
auto lhs = eval(*ast.nodes[0], env);
|
auto lhs = eval(*ast.nodes[0], env);
|
||||||
@ -779,22 +779,22 @@ private:
|
|||||||
else { throw std::logic_error("invalid internal condition."); }
|
else { throw std::logic_error("invalid internal condition."); }
|
||||||
}
|
}
|
||||||
|
|
||||||
Value eval_unary_plus(const peglib::Ast& ast, std::shared_ptr<Environment> env) {
|
Value eval_unary_plus(const peg::Ast& ast, std::shared_ptr<Environment> env) {
|
||||||
assert(ast.nodes.size() == 2); // if the size is 1, thes node will be hoisted.
|
assert(ast.nodes.size() == 2); // if the size is 1, thes node will be hoisted.
|
||||||
return eval(*ast.nodes[1], env);
|
return eval(*ast.nodes[1], env);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value eval_unary_minus(const peglib::Ast& ast, std::shared_ptr<Environment> env) {
|
Value eval_unary_minus(const peg::Ast& ast, std::shared_ptr<Environment> env) {
|
||||||
assert(ast.nodes.size() == 2); // if the size is 1, thes node will be hoisted.
|
assert(ast.nodes.size() == 2); // if the size is 1, thes node will be hoisted.
|
||||||
return Value(eval(*ast.nodes[1], env).to_long() * -1);
|
return Value(eval(*ast.nodes[1], env).to_long() * -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value eval_unary_not(const peglib::Ast& ast, std::shared_ptr<Environment> env) {
|
Value eval_unary_not(const peg::Ast& ast, std::shared_ptr<Environment> env) {
|
||||||
assert(ast.nodes.size() == 2); // if the size is 1, thes node will be hoisted.
|
assert(ast.nodes.size() == 2); // if the size is 1, thes node will be hoisted.
|
||||||
return Value(!eval(*ast.nodes[1], env).to_bool());
|
return Value(!eval(*ast.nodes[1], env).to_bool());
|
||||||
}
|
}
|
||||||
|
|
||||||
Value eval_bin_expression(const peglib::Ast& ast, std::shared_ptr<Environment> env) {
|
Value eval_bin_expression(const peg::Ast& ast, std::shared_ptr<Environment> env) {
|
||||||
auto ret = eval(*ast.nodes[0], env).to_long();
|
auto ret = eval(*ast.nodes[0], env).to_long();
|
||||||
for (auto i = 1u; i < ast.nodes.size(); i += 2) {
|
for (auto i = 1u; i < ast.nodes.size(); i += 2) {
|
||||||
auto val = eval(*ast.nodes[i + 1], env).to_long();
|
auto val = eval(*ast.nodes[i + 1], env).to_long();
|
||||||
@ -820,7 +820,7 @@ private:
|
|||||||
return keywords.find(ident) != keywords.end();
|
return keywords.find(ident) != keywords.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
Value eval_assignment(const peglib::Ast& ast, std::shared_ptr<Environment> env) {
|
Value eval_assignment(const peg::Ast& ast, std::shared_ptr<Environment> env) {
|
||||||
auto end = ast.nodes.size() - 1;
|
auto end = ast.nodes.size() - 1;
|
||||||
|
|
||||||
auto mut = ast.nodes[0]->token == "mut";
|
auto mut = ast.nodes[0]->token == "mut";
|
||||||
@ -837,7 +837,7 @@ private:
|
|||||||
}
|
}
|
||||||
return std::move(val);
|
return std::move(val);
|
||||||
} else {
|
} else {
|
||||||
using peglib::operator"" _;
|
using peg::operator"" _;
|
||||||
|
|
||||||
Value lval = eval(*ast.nodes[1], env);
|
Value lval = eval(*ast.nodes[1], env);
|
||||||
|
|
||||||
@ -882,11 +882,11 @@ private:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Value eval_identifier(const peglib::Ast& ast, std::shared_ptr<Environment> env) {
|
Value eval_identifier(const peg::Ast& ast, std::shared_ptr<Environment> env) {
|
||||||
return env->get(ast.token);
|
return env->get(ast.token);
|
||||||
};
|
};
|
||||||
|
|
||||||
Value eval_object(const peglib::Ast& ast, std::shared_ptr<Environment> env) {
|
Value eval_object(const peg::Ast& ast, std::shared_ptr<Environment> env) {
|
||||||
ObjectValue obj;
|
ObjectValue obj;
|
||||||
for (auto i = 0u; i < ast.nodes.size(); i++) {
|
for (auto i = 0u; i < ast.nodes.size(); i++) {
|
||||||
const auto& prop = *ast.nodes[i];
|
const auto& prop = *ast.nodes[i];
|
||||||
@ -898,7 +898,7 @@ private:
|
|||||||
return Value(std::move(obj));
|
return Value(std::move(obj));
|
||||||
}
|
}
|
||||||
|
|
||||||
Value eval_array(const peglib::Ast& ast, std::shared_ptr<Environment> env) {
|
Value eval_array(const peg::Ast& ast, std::shared_ptr<Environment> env) {
|
||||||
ArrayValue arr;
|
ArrayValue arr;
|
||||||
for (auto i = 0u; i < ast.nodes.size(); i++) {
|
for (auto i = 0u; i < ast.nodes.size(); i++) {
|
||||||
auto expr = ast.nodes[i];
|
auto expr = ast.nodes[i];
|
||||||
@ -908,19 +908,19 @@ private:
|
|||||||
return Value(std::move(arr));
|
return Value(std::move(arr));
|
||||||
}
|
}
|
||||||
|
|
||||||
Value eval_undefined(const peglib::Ast& ast, std::shared_ptr<Environment> env) {
|
Value eval_undefined(const peg::Ast& ast, std::shared_ptr<Environment> env) {
|
||||||
return Value();
|
return Value();
|
||||||
};
|
};
|
||||||
|
|
||||||
Value eval_bool(const peglib::Ast& ast, std::shared_ptr<Environment> env) {
|
Value eval_bool(const peg::Ast& ast, std::shared_ptr<Environment> env) {
|
||||||
return Value(ast.token == "true");
|
return Value(ast.token == "true");
|
||||||
};
|
};
|
||||||
|
|
||||||
Value eval_number(const peglib::Ast& ast, std::shared_ptr<Environment> env) {
|
Value eval_number(const peg::Ast& ast, std::shared_ptr<Environment> env) {
|
||||||
return Value(stol(ast.token));
|
return Value(stol(ast.token));
|
||||||
};
|
};
|
||||||
|
|
||||||
Value eval_interpolated_string(const peglib::Ast& ast, std::shared_ptr<Environment> env) {
|
Value eval_interpolated_string(const peg::Ast& ast, std::shared_ptr<Environment> env) {
|
||||||
std::string s;
|
std::string s;
|
||||||
for (auto node: ast.nodes) {
|
for (auto node: ast.nodes) {
|
||||||
const auto& val = eval(*node, env);
|
const auto& val = eval(*node, env);
|
||||||
@ -933,7 +933,7 @@ private:
|
|||||||
return Value(std::move(s));
|
return Value(std::move(s));
|
||||||
};
|
};
|
||||||
|
|
||||||
void eval_return(const peglib::Ast& ast, std::shared_ptr<Environment> env) {
|
void eval_return(const peg::Ast& ast, std::shared_ptr<Environment> env) {
|
||||||
if (ast.nodes.empty()) {
|
if (ast.nodes.empty()) {
|
||||||
throw Value();
|
throw Value();
|
||||||
} else {
|
} else {
|
||||||
@ -951,7 +951,7 @@ inline bool run(
|
|||||||
size_t len,
|
size_t len,
|
||||||
Value& val,
|
Value& val,
|
||||||
std::vector<std::string>& msgs,
|
std::vector<std::string>& msgs,
|
||||||
std::shared_ptr<peglib::Ast>& ast,
|
std::shared_ptr<peg::Ast>& ast,
|
||||||
Debugger debugger = nullptr)
|
Debugger debugger = nullptr)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
@ -964,7 +964,7 @@ inline bool run(
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (parser.parse_n(expr, len, ast, path.c_str())) {
|
if (parser.parse_n(expr, len, ast, path.c_str())) {
|
||||||
ast = peglib::AstOptimizer(true, { "PARAMETERS", "ARGUMENTS", "OBJECT", "ARRAY", "RETURN" }).optimize(ast);
|
ast = peg::AstOptimizer(true, { "PARAMETERS", "ARGUMENTS", "OBJECT", "ARRAY", "RETURN" }).optimize(ast);
|
||||||
val = Interpreter(debugger).exec(*ast, env);
|
val = Interpreter(debugger).exec(*ast, env);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
using namespace culebra;
|
using namespace culebra;
|
||||||
using namespace peglib;
|
using namespace peg;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
bool read_file(const char* path, vector<char>& buff)
|
bool read_file(const char* path, vector<char>& buff)
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
using namespace peglib;
|
using namespace peg;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -331,7 +331,7 @@ private:
|
|||||||
// compare <- expression compare_op expression
|
// compare <- expression compare_op expression
|
||||||
const auto& nodes = ast->nodes;
|
const auto& nodes = ast->nodes;
|
||||||
auto lval = eval_expression(nodes[0], env);
|
auto lval = eval_expression(nodes[0], env);
|
||||||
auto op = peglib::str2tag(nodes[1]->token.c_str());
|
auto op = peg::str2tag(nodes[1]->token.c_str());
|
||||||
auto rval = eval_expression(nodes[2], env);
|
auto rval = eval_expression(nodes[2], env);
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case "="_: return lval == rval;
|
case "="_: return lval == rval;
|
||||||
@ -427,7 +427,7 @@ int main(int argc, const char** argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Setup a PEG parser
|
// Setup a PEG parser
|
||||||
peg parser(grammar);
|
parser parser(grammar);
|
||||||
parser.enable_ast<AstPL0>();
|
parser.enable_ast<AstPL0>();
|
||||||
parser.log = [&](size_t ln, size_t col, const string& msg) {
|
parser.log = [&](size_t ln, size_t col, const string& msg) {
|
||||||
cerr << format_error_message(path, ln, col, msg) << endl;
|
cerr << format_error_message(path, ln, col, msg) << endl;
|
||||||
|
@ -59,13 +59,13 @@ int main(int argc, const char** argv)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
peglib::peg peg;
|
peg::parser parser;
|
||||||
|
|
||||||
peg.log = [&](auto ln, auto col, const auto& msg) {
|
parser.log = [&](auto ln, auto col, const auto& msg) {
|
||||||
cerr << syntax_path << ":" << ln << ":" << col << ": " << msg << endl;
|
cerr << syntax_path << ":" << ln << ":" << col << ": " << msg << endl;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!peg.load_grammar(syntax.data(), syntax.size())) {
|
if (!parser.load_grammar(syntax.data(), syntax.size())) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,22 +84,22 @@ int main(int argc, const char** argv)
|
|||||||
source_path = "[commendline]";
|
source_path = "[commendline]";
|
||||||
}
|
}
|
||||||
|
|
||||||
peg.log = [&](auto ln, auto col, const auto& msg) {
|
parser.log = [&](auto ln, auto col, const auto& msg) {
|
||||||
cerr << source_path << ":" << ln << ":" << col << ": " << msg << endl;
|
cerr << source_path << ":" << ln << ":" << col << ": " << msg << endl;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (opt_ast) {
|
if (opt_ast) {
|
||||||
peg.enable_ast();
|
parser.enable_ast();
|
||||||
|
|
||||||
std::shared_ptr<peglib::Ast> ast;
|
std::shared_ptr<peg::Ast> ast;
|
||||||
if (!peg.parse_n(source.data(), source.size(), ast)) {
|
if (!parser.parse_n(source.data(), source.size(), ast)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ast = peglib::AstOptimizer(opt_optimize_ast_nodes).optimize(ast);
|
ast = peg::AstOptimizer(opt_optimize_ast_nodes).optimize(ast);
|
||||||
peglib::AstPrint::print(ast);
|
peg::AstPrint::print(ast);
|
||||||
} else {
|
} else {
|
||||||
if (!peg.parse_n(source.data(), source.size())) {
|
if (!parser.parse_n(source.data(), source.size())) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
100
peglib.h
100
peglib.h
@ -23,7 +23,7 @@
|
|||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace peglib {
|
namespace peg {
|
||||||
|
|
||||||
extern void* enabler;
|
extern void* enabler;
|
||||||
|
|
||||||
@ -846,10 +846,10 @@ private:
|
|||||||
std::string name_;
|
std::string name_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Anchor : public Ope
|
class TokenBoundary : public Ope
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Anchor(const std::shared_ptr<Ope>& ope) : ope_(ope) {}
|
TokenBoundary(const std::shared_ptr<Ope>& ope) : ope_(ope) {}
|
||||||
|
|
||||||
size_t parse(const char* s, size_t n, SemanticValues& sv, Context& c, any& dt) const override {
|
size_t parse(const char* s, size_t n, SemanticValues& sv, Context& c, any& dt) const override {
|
||||||
const auto& rule = *ope_;
|
const auto& rule = *ope_;
|
||||||
@ -979,7 +979,7 @@ struct Ope::Visitor
|
|||||||
virtual void visit(Character& ope) {}
|
virtual void visit(Character& ope) {}
|
||||||
virtual void visit(AnyCharacter& ope) {}
|
virtual void visit(AnyCharacter& ope) {}
|
||||||
virtual void visit(Capture& ope) {}
|
virtual void visit(Capture& ope) {}
|
||||||
virtual void visit(Anchor& ope) {}
|
virtual void visit(TokenBoundary& ope) {}
|
||||||
virtual void visit(Ignore& ope) {}
|
virtual void visit(Ignore& ope) {}
|
||||||
virtual void visit(User& ope) {}
|
virtual void visit(User& ope) {}
|
||||||
virtual void visit(WeakHolder& ope) {}
|
virtual void visit(WeakHolder& ope) {}
|
||||||
@ -1005,7 +1005,7 @@ struct AssignIDToDefinition : public Ope::Visitor
|
|||||||
void visit(AndPredicate& ope) override { ope.ope_->accept(*this); }
|
void visit(AndPredicate& ope) override { ope.ope_->accept(*this); }
|
||||||
void visit(NotPredicate& ope) override { ope.ope_->accept(*this); }
|
void visit(NotPredicate& ope) override { ope.ope_->accept(*this); }
|
||||||
void visit(Capture& ope) override { ope.ope_->accept(*this); }
|
void visit(Capture& ope) override { ope.ope_->accept(*this); }
|
||||||
void visit(Anchor& 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(WeakHolder& ope) override { ope.weak_.lock()->accept(*this); }
|
void visit(WeakHolder& ope) override { ope.weak_.lock()->accept(*this); }
|
||||||
void visit(Holder& ope) override;
|
void visit(Holder& ope) override;
|
||||||
@ -1016,7 +1016,7 @@ struct AssignIDToDefinition : public Ope::Visitor
|
|||||||
|
|
||||||
struct IsToken : public Ope::Visitor
|
struct IsToken : public Ope::Visitor
|
||||||
{
|
{
|
||||||
IsToken() : has_anchor(false), has_rule(false) {}
|
IsToken() : has_token_boundary(false), has_rule(false) {}
|
||||||
|
|
||||||
void visit(Sequence& ope) override {
|
void visit(Sequence& ope) override {
|
||||||
for (auto op: ope.opes_) {
|
for (auto op: ope.opes_) {
|
||||||
@ -1032,16 +1032,16 @@ struct IsToken : public Ope::Visitor
|
|||||||
void visit(OneOrMore& ope) override { ope.ope_->accept(*this); }
|
void visit(OneOrMore& ope) override { ope.ope_->accept(*this); }
|
||||||
void visit(Option& ope) override { ope.ope_->accept(*this); }
|
void visit(Option& ope) override { ope.ope_->accept(*this); }
|
||||||
void visit(Capture& ope) override { ope.ope_->accept(*this); }
|
void visit(Capture& ope) override { ope.ope_->accept(*this); }
|
||||||
void visit(Anchor& ope) override { has_anchor = true; }
|
void visit(TokenBoundary& ope) override { has_token_boundary = true; }
|
||||||
void visit(Ignore& ope) override { ope.ope_->accept(*this); }
|
void visit(Ignore& ope) override { ope.ope_->accept(*this); }
|
||||||
void visit(WeakHolder& ope) override { ope.weak_.lock()->accept(*this); }
|
void visit(WeakHolder& ope) override { ope.weak_.lock()->accept(*this); }
|
||||||
void visit(DefinitionReference& ope) override { has_rule = true; }
|
void visit(DefinitionReference& ope) override { has_rule = true; }
|
||||||
|
|
||||||
bool is_token() const {
|
bool is_token() const {
|
||||||
return has_anchor || !has_rule;
|
return has_token_boundary || !has_rule;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool has_anchor;
|
bool has_token_boundary;
|
||||||
bool has_rule;
|
bool has_rule;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1219,8 +1219,8 @@ inline size_t Holder::parse(const char* s, size_t n, SemanticValues& sv, Context
|
|||||||
|
|
||||||
size_t len;
|
size_t len;
|
||||||
any val;
|
any val;
|
||||||
const char* anchors = s;
|
const char* token_boundary_s = s;
|
||||||
size_t anchorn = n;
|
size_t token_boundary_n = n;
|
||||||
|
|
||||||
c.packrat(s, outer_->id, len, val, [&](any& val) {
|
c.packrat(s, outer_->id, len, val, [&](any& val) {
|
||||||
auto& chldsv = c.push();
|
auto& chldsv = c.push();
|
||||||
@ -1228,13 +1228,13 @@ inline size_t Holder::parse(const char* s, size_t n, SemanticValues& sv, Context
|
|||||||
const auto& rule = *ope_;
|
const auto& rule = *ope_;
|
||||||
len = rule.parse(s, n, chldsv, c, dt);
|
len = rule.parse(s, n, chldsv, c, dt);
|
||||||
|
|
||||||
anchorn = len;
|
token_boundary_n = len;
|
||||||
|
|
||||||
// Invoke action
|
// Invoke action
|
||||||
if (success(len)) {
|
if (success(len)) {
|
||||||
if (chldsv.s) {
|
if (chldsv.s) {
|
||||||
anchors = chldsv.s;
|
token_boundary_s = chldsv.s;
|
||||||
anchorn = chldsv.n;
|
token_boundary_n = chldsv.n;
|
||||||
} else {
|
} else {
|
||||||
chldsv.s = s;
|
chldsv.s = s;
|
||||||
chldsv.n = len;
|
chldsv.n = len;
|
||||||
@ -1255,7 +1255,7 @@ inline size_t Holder::parse(const char* s, size_t n, SemanticValues& sv, Context
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (success(len) && !outer_->ignoreSemanticValue) {
|
if (success(len) && !outer_->ignoreSemanticValue) {
|
||||||
sv.emplace_back(val, outer_->name.c_str(), anchors, anchorn);
|
sv.emplace_back(val, outer_->name.c_str(), token_boundary_s, token_boundary_n);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fail(len) && outer_->error_message && !c.message_pos) {
|
if (fail(len) && outer_->error_message && !c.message_pos) {
|
||||||
@ -1304,7 +1304,7 @@ inline void CharacterClass::accept(Visitor& v) { v.visit(*this); }
|
|||||||
inline void Character::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 AnyCharacter::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 Anchor::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 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); }
|
||||||
@ -1379,8 +1379,8 @@ inline std::shared_ptr<Ope> cap(const std::shared_ptr<Ope>& ope, MatchAction ma)
|
|||||||
return std::make_shared<Capture>(ope, ma, (size_t)-1, std::string());
|
return std::make_shared<Capture>(ope, ma, (size_t)-1, std::string());
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::shared_ptr<Ope> anc(const std::shared_ptr<Ope>& ope) {
|
inline std::shared_ptr<Ope> tok(const std::shared_ptr<Ope>& ope) {
|
||||||
return std::make_shared<Anchor>(ope);
|
return std::make_shared<TokenBoundary>(ope);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::shared_ptr<Ope> ign(const std::shared_ptr<Ope>& ope) {
|
inline std::shared_ptr<Ope> ign(const std::shared_ptr<Ope>& ope) {
|
||||||
@ -1422,7 +1422,7 @@ typedef std::function<void (size_t, size_t, const std::string&)> Log;
|
|||||||
|
|
||||||
typedef std::unordered_map<std::string, std::shared_ptr<Ope>> Rules;
|
typedef std::unordered_map<std::string, std::shared_ptr<Ope>> Rules;
|
||||||
|
|
||||||
class PEGParser
|
class ParserGenerator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static std::shared_ptr<Grammar> parse(
|
static std::shared_ptr<Grammar> parse(
|
||||||
@ -1453,12 +1453,12 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static PEGParser& get_instance() {
|
static ParserGenerator& get_instance() {
|
||||||
static PEGParser instance;
|
static ParserGenerator instance;
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
PEGParser() {
|
ParserGenerator() {
|
||||||
make_grammar();
|
make_grammar();
|
||||||
setup_actions();
|
setup_actions();
|
||||||
}
|
}
|
||||||
@ -1536,7 +1536,7 @@ private:
|
|||||||
void visit(Capture& ope) override {
|
void visit(Capture& ope) override {
|
||||||
ope.ope_->accept(*this);
|
ope.ope_->accept(*this);
|
||||||
}
|
}
|
||||||
void visit(Anchor& ope) override {
|
void visit(TokenBoundary& ope) override {
|
||||||
ope.ope_->accept(*this);
|
ope.ope_->accept(*this);
|
||||||
}
|
}
|
||||||
void visit(Ignore& ope) override {
|
void visit(Ignore& ope) override {
|
||||||
@ -1591,10 +1591,10 @@ private:
|
|||||||
g["IdentStart"] <= cls("a-zA-Z_\x80-\xff");
|
g["IdentStart"] <= cls("a-zA-Z_\x80-\xff");
|
||||||
g["IdentRest"] <= cho(g["IdentStart"], cls("0-9"));
|
g["IdentRest"] <= cho(g["IdentStart"], cls("0-9"));
|
||||||
|
|
||||||
g["Literal"] <= cho(seq(cls("'"), anc(zom(seq(npd(cls("'")), g["Char"]))), cls("'"), g["Spacing"]),
|
g["Literal"] <= cho(seq(cls("'"), tok(zom(seq(npd(cls("'")), g["Char"]))), cls("'"), g["Spacing"]),
|
||||||
seq(cls("\""), anc(zom(seq(npd(cls("\"")), g["Char"]))), cls("\""), g["Spacing"]));
|
seq(cls("\""), tok(zom(seq(npd(cls("\"")), g["Char"]))), cls("\""), g["Spacing"]));
|
||||||
|
|
||||||
g["Class"] <= seq(chr('['), anc(zom(seq(npd(chr(']')), g["Range"]))), chr(']'), g["Spacing"]);
|
g["Class"] <= seq(chr('['), tok(zom(seq(npd(chr(']')), g["Range"]))), chr(']'), g["Spacing"]);
|
||||||
|
|
||||||
g["Range"] <= cho(seq(g["Char"], chr('-'), g["Char"]), g["Char"]);
|
g["Range"] <= cho(seq(g["Char"], chr('-'), g["Char"]), g["Char"]);
|
||||||
g["Char"] <= cho(seq(chr('\\'), cls("nrt'\"[]\\")),
|
g["Char"] <= cho(seq(chr('\\'), cls("nrt'\"[]\\")),
|
||||||
@ -1623,7 +1623,7 @@ private:
|
|||||||
g["Begin"] <= seq(chr('<'), g["Spacing"]);
|
g["Begin"] <= seq(chr('<'), g["Spacing"]);
|
||||||
g["End"] <= seq(chr('>'), g["Spacing"]);
|
g["End"] <= seq(chr('>'), g["Spacing"]);
|
||||||
|
|
||||||
g["BeginCap"] <= seq(chr('$'), anc(opt(g["Identifier"])), chr('<'), g["Spacing"]);
|
g["BeginCap"] <= seq(chr('$'), tok(opt(g["Identifier"])), chr('<'), g["Spacing"]);
|
||||||
g["EndCap"] <= seq(lit(">"), g["Spacing"]);
|
g["EndCap"] <= seq(lit(">"), g["Spacing"]);
|
||||||
|
|
||||||
g["IGNORE"] <= chr('~');
|
g["IGNORE"] <= chr('~');
|
||||||
@ -1742,8 +1742,8 @@ private:
|
|||||||
case 1: { // (Expression)
|
case 1: { // (Expression)
|
||||||
return sv[1].get<std::shared_ptr<Ope>>();
|
return sv[1].get<std::shared_ptr<Ope>>();
|
||||||
}
|
}
|
||||||
case 2: { // Anchor
|
case 2: { // TokenBoundary
|
||||||
return anc(sv[1].get<std::shared_ptr<Ope>>());
|
return tok(sv[1].get<std::shared_ptr<Ope>>());
|
||||||
}
|
}
|
||||||
case 3: { // Capture
|
case 3: { // Capture
|
||||||
auto name = std::string(sv[0].s, sv[0].n);
|
auto name = std::string(sv[0].s, sv[0].n);
|
||||||
@ -2100,33 +2100,33 @@ struct EmptyType {};
|
|||||||
typedef AstBase<EmptyType> Ast;
|
typedef AstBase<EmptyType> Ast;
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------
|
/*-----------------------------------------------------------------------------
|
||||||
* peg
|
* parser
|
||||||
*---------------------------------------------------------------------------*/
|
*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
class peg
|
class parser
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
peg() = default;
|
parser() = default;
|
||||||
|
|
||||||
peg(const char* s, size_t n, const Rules& rules) {
|
parser(const char* s, size_t n, const Rules& rules) {
|
||||||
load_grammar(s, n, rules);
|
load_grammar(s, n, rules);
|
||||||
}
|
}
|
||||||
|
|
||||||
peg(const char* s, const Rules& rules)
|
parser(const char* s, const Rules& rules)
|
||||||
: peg(s, strlen(s), rules) {}
|
: parser(s, strlen(s), rules) {}
|
||||||
|
|
||||||
peg(const char* s, size_t n)
|
parser(const char* s, size_t n)
|
||||||
: peg(s, n, Rules()) {}
|
: parser(s, n, Rules()) {}
|
||||||
|
|
||||||
peg(const char* s)
|
parser(const char* s)
|
||||||
: peg(s, strlen(s), Rules()) {}
|
: parser(s, strlen(s), Rules()) {}
|
||||||
|
|
||||||
operator bool() {
|
operator bool() {
|
||||||
return grammar_ != nullptr;
|
return grammar_ != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool load_grammar(const char* s, size_t n, const Rules& rules) {
|
bool load_grammar(const char* s, size_t n, const Rules& rules) {
|
||||||
grammar_ = PEGParser::parse(
|
grammar_ = ParserGenerator::parse(
|
||||||
s, n,
|
s, n,
|
||||||
rules,
|
rules,
|
||||||
start_,
|
start_,
|
||||||
@ -2253,7 +2253,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T = Ast>
|
template <typename T = Ast>
|
||||||
peg& enable_ast() {
|
parser& enable_ast() {
|
||||||
for (auto& x: *grammar_) {
|
for (auto& x: *grammar_) {
|
||||||
const auto& name = x.first;
|
const auto& name = x.first;
|
||||||
auto& rule = x.second;
|
auto& rule = x.second;
|
||||||
@ -2396,7 +2396,7 @@ struct match
|
|||||||
inline bool peg_match(const char* syntax, const char* s, match& m) {
|
inline bool peg_match(const char* syntax, const char* s, match& m) {
|
||||||
m.matches.clear();
|
m.matches.clear();
|
||||||
|
|
||||||
peg pg(syntax);
|
parser pg(syntax);
|
||||||
pg.match_action = [&](const char* s, size_t n, size_t id, const std::string& name) {
|
pg.match_action = [&](const char* s, size_t n, size_t id, const std::string& name) {
|
||||||
m.matches.push_back(match::Item{ s, n, id, name });
|
m.matches.push_back(match::Item{ s, n, id, name });
|
||||||
};
|
};
|
||||||
@ -2411,11 +2411,11 @@ inline bool peg_match(const char* syntax, const char* s, match& m) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline bool peg_match(const char* syntax, const char* s) {
|
inline bool peg_match(const char* syntax, const char* s) {
|
||||||
peg pg(syntax);
|
parser parser(syntax);
|
||||||
return pg.parse(s);
|
return parser.parse(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool peg_search(peg& pg, const char* s, size_t n, match& m) {
|
inline bool peg_search(parser& pg, const char* s, size_t n, match& m) {
|
||||||
m.matches.clear();
|
m.matches.clear();
|
||||||
|
|
||||||
pg.match_action = [&](const char* s, size_t n, size_t id, const std::string& name) {
|
pg.match_action = [&](const char* s, size_t n, size_t id, const std::string& name) {
|
||||||
@ -2432,18 +2432,18 @@ inline bool peg_search(peg& pg, const char* s, size_t n, match& m) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool peg_search(peg& pg, const char* s, match& m) {
|
inline bool peg_search(parser& pg, const char* s, match& m) {
|
||||||
auto n = strlen(s);
|
auto n = strlen(s);
|
||||||
return peg_search(pg, s, n, m);
|
return peg_search(pg, s, n, m);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool peg_search(const char* syntax, const char* s, size_t n, match& m) {
|
inline bool peg_search(const char* syntax, const char* s, size_t n, match& m) {
|
||||||
peg pg(syntax);
|
parser pg(syntax);
|
||||||
return peg_search(pg, s, n, m);
|
return peg_search(pg, s, n, m);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool peg_search(const char* syntax, const char* s, match& m) {
|
inline bool peg_search(const char* syntax, const char* s, match& m) {
|
||||||
peg pg(syntax);
|
parser pg(syntax);
|
||||||
auto n = strlen(s);
|
auto n = strlen(s);
|
||||||
return peg_search(pg, s, n, m);
|
return peg_search(pg, s, n, m);
|
||||||
}
|
}
|
||||||
@ -2513,7 +2513,7 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
peg peg_;
|
parser peg_;
|
||||||
const char* s_;
|
const char* s_;
|
||||||
size_t l_;
|
size_t l_;
|
||||||
size_t pos_;
|
size_t pos_;
|
||||||
@ -2549,7 +2549,7 @@ private:
|
|||||||
peg_token_iterator end_iter;
|
peg_token_iterator end_iter;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace peglib
|
} // namespace peg
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
106
test/test.cc
106
test/test.cc
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
TEST_CASE("Simple syntax test", "[general]")
|
TEST_CASE("Simple syntax test", "[general]")
|
||||||
{
|
{
|
||||||
peglib::peg parser(
|
peg::parser parser(
|
||||||
" ROOT <- _ "
|
" ROOT <- _ "
|
||||||
" _ <- ' ' "
|
" _ <- ' ' "
|
||||||
);
|
);
|
||||||
@ -18,14 +18,14 @@ TEST_CASE("Simple syntax test", "[general]")
|
|||||||
|
|
||||||
TEST_CASE("Empty syntax test", "[general]")
|
TEST_CASE("Empty syntax test", "[general]")
|
||||||
{
|
{
|
||||||
peglib::peg parser("");
|
peg::parser parser("");
|
||||||
bool ret = parser;
|
bool ret = parser;
|
||||||
REQUIRE(ret == false);
|
REQUIRE(ret == false);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("String capture test", "[general]")
|
TEST_CASE("String capture test", "[general]")
|
||||||
{
|
{
|
||||||
peglib::peg parser(
|
peg::parser parser(
|
||||||
" ROOT <- _ ('[' TAG_NAME ']' _)* "
|
" ROOT <- _ ('[' TAG_NAME ']' _)* "
|
||||||
" TAG_NAME <- (!']' .)+ "
|
" TAG_NAME <- (!']' .)+ "
|
||||||
" _ <- [ \t]* "
|
" _ <- [ \t]* "
|
||||||
@ -33,7 +33,7 @@ TEST_CASE("String capture test", "[general]")
|
|||||||
|
|
||||||
std::vector<std::string> tags;
|
std::vector<std::string> tags;
|
||||||
|
|
||||||
parser["TAG_NAME"] = [&](const peglib::SemanticValues& sv) {
|
parser["TAG_NAME"] = [&](const peg::SemanticValues& sv) {
|
||||||
tags.push_back(sv.str());
|
tags.push_back(sv.str());
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -48,8 +48,8 @@ TEST_CASE("String capture test", "[general]")
|
|||||||
|
|
||||||
TEST_CASE("String capture test with match", "[general]")
|
TEST_CASE("String capture test with match", "[general]")
|
||||||
{
|
{
|
||||||
peglib::match m;
|
peg::match m;
|
||||||
auto ret = peglib::peg_match(
|
auto ret = peg::peg_match(
|
||||||
" ROOT <- _ ('[' $< TAG_NAME > ']' _)* "
|
" ROOT <- _ ('[' $< TAG_NAME > ']' _)* "
|
||||||
" TAG_NAME <- (!']' .)+ "
|
" TAG_NAME <- (!']' .)+ "
|
||||||
" _ <- [ \t]* ",
|
" _ <- [ \t]* ",
|
||||||
@ -63,7 +63,7 @@ TEST_CASE("String capture test with match", "[general]")
|
|||||||
REQUIRE(m.str(3) == "tag-3");
|
REQUIRE(m.str(3) == "tag-3");
|
||||||
}
|
}
|
||||||
|
|
||||||
using namespace peglib;
|
using namespace peg;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
TEST_CASE("String capture test2", "[general]")
|
TEST_CASE("String capture test2", "[general]")
|
||||||
@ -93,7 +93,7 @@ TEST_CASE("String capture test3", "[general]")
|
|||||||
" _ <- [ \t\r\n]* "
|
" _ <- [ \t\r\n]* "
|
||||||
;
|
;
|
||||||
|
|
||||||
peg pg(syntax);
|
parser pg(syntax);
|
||||||
|
|
||||||
std::vector<std::string> tags;
|
std::vector<std::string> tags;
|
||||||
|
|
||||||
@ -112,9 +112,9 @@ TEST_CASE("String capture test3", "[general]")
|
|||||||
|
|
||||||
TEST_CASE("Named capture test", "[general]")
|
TEST_CASE("Named capture test", "[general]")
|
||||||
{
|
{
|
||||||
peglib::match m;
|
peg::match m;
|
||||||
|
|
||||||
auto ret = peglib::peg_match(
|
auto ret = peg::peg_match(
|
||||||
" ROOT <- _ ('[' $test< TAG_NAME > ']' _)* "
|
" ROOT <- _ ('[' $test< TAG_NAME > ']' _)* "
|
||||||
" TAG_NAME <- (!']' .)+ "
|
" TAG_NAME <- (!']' .)+ "
|
||||||
" _ <- [ \t]* ",
|
" _ <- [ \t]* ",
|
||||||
@ -180,14 +180,14 @@ TEST_CASE("Visit test", "[general]")
|
|||||||
|
|
||||||
TEST_CASE("Token check test", "[general]")
|
TEST_CASE("Token check test", "[general]")
|
||||||
{
|
{
|
||||||
peg parser(
|
parser parser(
|
||||||
" EXPRESSION <- _ TERM (TERM_OPERATOR TERM)* "
|
" EXPRESSION <- _ TERM (TERM_OPERATOR TERM)* "
|
||||||
" TERM <- FACTOR (FACTOR_OPERATOR FACTOR)* "
|
" TERM <- FACTOR (FACTOR_OPERATOR FACTOR)* "
|
||||||
" FACTOR <- NUMBER / '(' _ EXPRESSION ')' _ "
|
" FACTOR <- NUMBER / '(' _ EXPRESSION ')' _ "
|
||||||
" TERM_OPERATOR <- < [-+] > _ "
|
" TERM_OPERATOR <- < [-+] > _ "
|
||||||
" FACTOR_OPERATOR <- < [/*] > _ "
|
" FACTOR_OPERATOR <- < [/*] > _ "
|
||||||
" NUMBER <- < [0-9]+ > _ "
|
" NUMBER <- < [0-9]+ > _ "
|
||||||
" ~_ <- [ \t\r\n]* "
|
" _ <- [ \t\r\n]* "
|
||||||
);
|
);
|
||||||
|
|
||||||
REQUIRE(parser["EXPRESSION"].is_token == false);
|
REQUIRE(parser["EXPRESSION"].is_token == false);
|
||||||
@ -199,7 +199,7 @@ TEST_CASE("Token check test", "[general]")
|
|||||||
|
|
||||||
TEST_CASE("Lambda action test", "[general]")
|
TEST_CASE("Lambda action test", "[general]")
|
||||||
{
|
{
|
||||||
peg parser(
|
parser parser(
|
||||||
" START <- (CHAR)* "
|
" START <- (CHAR)* "
|
||||||
" CHAR <- . ");
|
" CHAR <- . ");
|
||||||
|
|
||||||
@ -215,7 +215,7 @@ TEST_CASE("Lambda action test", "[general]")
|
|||||||
|
|
||||||
TEST_CASE("Skip token test", "[general]")
|
TEST_CASE("Skip token test", "[general]")
|
||||||
{
|
{
|
||||||
peglib::peg parser(
|
peg::parser parser(
|
||||||
" ROOT <- _ ITEM (',' _ ITEM _)* "
|
" ROOT <- _ ITEM (',' _ ITEM _)* "
|
||||||
" ITEM <- ([a-z0-9])+ "
|
" ITEM <- ([a-z0-9])+ "
|
||||||
" ~_ <- [ \t]* "
|
" ~_ <- [ \t]* "
|
||||||
@ -232,7 +232,7 @@ TEST_CASE("Skip token test", "[general]")
|
|||||||
|
|
||||||
TEST_CASE("Backtracking test", "[general]")
|
TEST_CASE("Backtracking test", "[general]")
|
||||||
{
|
{
|
||||||
peg parser(
|
parser parser(
|
||||||
" START <- PAT1 / PAT2 "
|
" START <- PAT1 / PAT2 "
|
||||||
" PAT1 <- HELLO ' One' "
|
" PAT1 <- HELLO ' One' "
|
||||||
" PAT2 <- HELLO ' Two' "
|
" PAT2 <- HELLO ' Two' "
|
||||||
@ -253,7 +253,7 @@ TEST_CASE("Backtracking test", "[general]")
|
|||||||
|
|
||||||
TEST_CASE("Backtracking with AST", "[general]")
|
TEST_CASE("Backtracking with AST", "[general]")
|
||||||
{
|
{
|
||||||
peg parser(R"(
|
parser parser(R"(
|
||||||
S <- A? B (A B)* A
|
S <- A? B (A B)* A
|
||||||
A <- 'a'
|
A <- 'a'
|
||||||
B <- 'b'
|
B <- 'b'
|
||||||
@ -268,7 +268,7 @@ TEST_CASE("Backtracking with AST", "[general]")
|
|||||||
|
|
||||||
TEST_CASE("Octal/Hex value test", "[general]")
|
TEST_CASE("Octal/Hex value test", "[general]")
|
||||||
{
|
{
|
||||||
peglib::peg parser(
|
peg::parser parser(
|
||||||
R"( ROOT <- '\132\x7a' )"
|
R"( ROOT <- '\132\x7a' )"
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -281,7 +281,7 @@ TEST_CASE("mutable lambda test", "[general]")
|
|||||||
{
|
{
|
||||||
vector<string> vec;
|
vector<string> vec;
|
||||||
|
|
||||||
peg pg("ROOT <- 'mutable lambda test'");
|
parser pg("ROOT <- 'mutable lambda test'");
|
||||||
|
|
||||||
// This test makes sure if the following code can be compiled.
|
// This test makes sure if the following code can be compiled.
|
||||||
pg["TOKEN"] = [=](const SemanticValues& sv) mutable {
|
pg["TOKEN"] = [=](const SemanticValues& sv) mutable {
|
||||||
@ -297,7 +297,7 @@ TEST_CASE("Simple calculator test", "[general]")
|
|||||||
" Primary <- '(' Additive ')' / Number "
|
" Primary <- '(' Additive ')' / Number "
|
||||||
" Number <- [0-9]+ ";
|
" Number <- [0-9]+ ";
|
||||||
|
|
||||||
peg parser(syntax);
|
parser parser(syntax);
|
||||||
|
|
||||||
parser["Additive"] = [](const SemanticValues& sv) {
|
parser["Additive"] = [](const SemanticValues& sv) {
|
||||||
switch (sv.choice) {
|
switch (sv.choice) {
|
||||||
@ -382,7 +382,7 @@ TEST_CASE("Calculator test2", "[general]")
|
|||||||
;
|
;
|
||||||
|
|
||||||
string start;
|
string start;
|
||||||
auto grammar = PEGParser::parse(syntax, strlen(syntax), start, nullptr, nullptr);
|
auto grammar = ParserGenerator::parse(syntax, strlen(syntax), start, nullptr, nullptr);
|
||||||
auto& g = *grammar;
|
auto& g = *grammar;
|
||||||
|
|
||||||
// Setup actions
|
// Setup actions
|
||||||
@ -417,7 +417,7 @@ TEST_CASE("Calculator test2", "[general]")
|
|||||||
TEST_CASE("Calculator test3", "[general]")
|
TEST_CASE("Calculator test3", "[general]")
|
||||||
{
|
{
|
||||||
// Parse syntax
|
// Parse syntax
|
||||||
peg parser(
|
parser parser(
|
||||||
" # Grammar for Calculator...\n "
|
" # Grammar for Calculator...\n "
|
||||||
" EXPRESSION <- TERM (TERM_OPERATOR TERM)* "
|
" EXPRESSION <- TERM (TERM_OPERATOR TERM)* "
|
||||||
" TERM <- FACTOR (FACTOR_OPERATOR FACTOR)* "
|
" TERM <- FACTOR (FACTOR_OPERATOR FACTOR)* "
|
||||||
@ -458,7 +458,7 @@ TEST_CASE("Calculator test3", "[general]")
|
|||||||
|
|
||||||
TEST_CASE("Calculator test with AST", "[general]")
|
TEST_CASE("Calculator test with AST", "[general]")
|
||||||
{
|
{
|
||||||
peg parser(
|
parser parser(
|
||||||
" EXPRESSION <- _ TERM (TERM_OPERATOR TERM)* "
|
" EXPRESSION <- _ TERM (TERM_OPERATOR TERM)* "
|
||||||
" TERM <- FACTOR (FACTOR_OPERATOR FACTOR)* "
|
" TERM <- FACTOR (FACTOR_OPERATOR FACTOR)* "
|
||||||
" FACTOR <- NUMBER / '(' _ EXPRESSION ')' _ "
|
" FACTOR <- NUMBER / '(' _ EXPRESSION ')' _ "
|
||||||
@ -492,7 +492,7 @@ TEST_CASE("Calculator test with AST", "[general]")
|
|||||||
|
|
||||||
shared_ptr<Ast> ast;
|
shared_ptr<Ast> ast;
|
||||||
auto ret = parser.parse("1+2*3*(4-5+6)/7-8", ast);
|
auto ret = parser.parse("1+2*3*(4-5+6)/7-8", ast);
|
||||||
ast = peglib::AstOptimizer(true).optimize(ast);
|
ast = peg::AstOptimizer(true).optimize(ast);
|
||||||
auto val = eval(*ast);
|
auto val = eval(*ast);
|
||||||
|
|
||||||
REQUIRE(ret == true);
|
REQUIRE(ret == true);
|
||||||
@ -501,7 +501,7 @@ TEST_CASE("Calculator test with AST", "[general]")
|
|||||||
|
|
||||||
TEST_CASE("Ignore semantic value test", "[general]")
|
TEST_CASE("Ignore semantic value test", "[general]")
|
||||||
{
|
{
|
||||||
peg parser(
|
parser parser(
|
||||||
" START <- ~HELLO WORLD "
|
" START <- ~HELLO WORLD "
|
||||||
" HELLO <- 'Hello' _ "
|
" HELLO <- 'Hello' _ "
|
||||||
" WORLD <- 'World' _ "
|
" WORLD <- 'World' _ "
|
||||||
@ -520,7 +520,7 @@ TEST_CASE("Ignore semantic value test", "[general]")
|
|||||||
|
|
||||||
TEST_CASE("Ignore semantic value of 'or' predicate test", "[general]")
|
TEST_CASE("Ignore semantic value of 'or' predicate test", "[general]")
|
||||||
{
|
{
|
||||||
peg parser(
|
parser parser(
|
||||||
" START <- _ !DUMMY HELLO_WORLD '.' "
|
" START <- _ !DUMMY HELLO_WORLD '.' "
|
||||||
" HELLO_WORLD <- HELLO 'World' _ "
|
" HELLO_WORLD <- HELLO 'World' _ "
|
||||||
" HELLO <- 'Hello' _ "
|
" HELLO <- 'Hello' _ "
|
||||||
@ -540,7 +540,7 @@ TEST_CASE("Ignore semantic value of 'or' predicate test", "[general]")
|
|||||||
|
|
||||||
TEST_CASE("Ignore semantic value of 'and' predicate test", "[general]")
|
TEST_CASE("Ignore semantic value of 'and' predicate test", "[general]")
|
||||||
{
|
{
|
||||||
peg parser(
|
parser parser(
|
||||||
" START <- _ &HELLO HELLO_WORLD '.' "
|
" START <- _ &HELLO HELLO_WORLD '.' "
|
||||||
" HELLO_WORLD <- HELLO 'World' _ "
|
" HELLO_WORLD <- HELLO 'World' _ "
|
||||||
" HELLO <- 'Hello' _ "
|
" HELLO <- 'Hello' _ "
|
||||||
@ -559,7 +559,7 @@ TEST_CASE("Ignore semantic value of 'and' predicate test", "[general]")
|
|||||||
|
|
||||||
TEST_CASE("Definition duplicates test", "[general]")
|
TEST_CASE("Definition duplicates test", "[general]")
|
||||||
{
|
{
|
||||||
peg parser(
|
parser parser(
|
||||||
" A <- ''"
|
" A <- ''"
|
||||||
" A <- ''"
|
" A <- ''"
|
||||||
);
|
);
|
||||||
@ -569,7 +569,7 @@ TEST_CASE("Definition duplicates test", "[general]")
|
|||||||
|
|
||||||
TEST_CASE("Left recursive test", "[left recursive]")
|
TEST_CASE("Left recursive test", "[left recursive]")
|
||||||
{
|
{
|
||||||
peg parser(
|
parser parser(
|
||||||
" A <- A 'a'"
|
" A <- A 'a'"
|
||||||
" B <- A 'a'"
|
" B <- A 'a'"
|
||||||
);
|
);
|
||||||
@ -579,7 +579,7 @@ TEST_CASE("Left recursive test", "[left recursive]")
|
|||||||
|
|
||||||
TEST_CASE("Left recursive with option test", "[left recursive]")
|
TEST_CASE("Left recursive with option test", "[left recursive]")
|
||||||
{
|
{
|
||||||
peg parser(
|
parser parser(
|
||||||
" A <- 'a' / 'b'? B 'c' "
|
" A <- 'a' / 'b'? B 'c' "
|
||||||
" B <- A "
|
" B <- A "
|
||||||
);
|
);
|
||||||
@ -589,7 +589,7 @@ TEST_CASE("Left recursive with option test", "[left recursive]")
|
|||||||
|
|
||||||
TEST_CASE("Left recursive with zom test", "[left recursive]")
|
TEST_CASE("Left recursive with zom test", "[left recursive]")
|
||||||
{
|
{
|
||||||
peg parser(
|
parser parser(
|
||||||
" A <- 'a'* A* "
|
" A <- 'a'* A* "
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -598,7 +598,7 @@ TEST_CASE("Left recursive with zom test", "[left recursive]")
|
|||||||
|
|
||||||
TEST_CASE("Left recursive with empty string test", "[left recursive]")
|
TEST_CASE("Left recursive with empty string test", "[left recursive]")
|
||||||
{
|
{
|
||||||
peg parser(
|
parser parser(
|
||||||
" A <- '' A"
|
" A <- '' A"
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -626,7 +626,7 @@ TEST_CASE("User rule test", "[user rule]")
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
peg g = peg(syntax, rules);
|
auto g = parser(syntax, rules);
|
||||||
|
|
||||||
REQUIRE(g.parse(" Hello BNF! ") == true);
|
REQUIRE(g.parse(" Hello BNF! ") == true);
|
||||||
}
|
}
|
||||||
@ -634,7 +634,7 @@ TEST_CASE("User rule test", "[user rule]")
|
|||||||
|
|
||||||
TEST_CASE("Semantic predicate test", "[predicate]")
|
TEST_CASE("Semantic predicate test", "[predicate]")
|
||||||
{
|
{
|
||||||
peg parser("NUMBER <- [0-9]+");
|
parser parser("NUMBER <- [0-9]+");
|
||||||
|
|
||||||
parser["NUMBER"] = [](const SemanticValues& sv) {
|
parser["NUMBER"] = [](const SemanticValues& sv) {
|
||||||
auto val = stol(sv.str(), nullptr, 10);
|
auto val = stol(sv.str(), nullptr, 10);
|
||||||
@ -655,7 +655,7 @@ TEST_CASE("Semantic predicate test", "[predicate]")
|
|||||||
|
|
||||||
TEST_CASE("Japanese character", "[unicode]")
|
TEST_CASE("Japanese character", "[unicode]")
|
||||||
{
|
{
|
||||||
peglib::peg parser(R"(
|
peg::parser parser(R"(
|
||||||
文 <- 修飾語? 主語 述語 '。'
|
文 <- 修飾語? 主語 述語 '。'
|
||||||
主語 <- 名詞 助詞
|
主語 <- 名詞 助詞
|
||||||
述語 <- 動詞 助詞
|
述語 <- 動詞 助詞
|
||||||
@ -678,18 +678,18 @@ bool exact(Grammar& g, const char* d, const char* s) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Grammar& make_peg_grammar() {
|
Grammar& make_peg_grammar() {
|
||||||
return PEGParser::grammar();
|
return ParserGenerator::grammar();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("PEG Grammar", "[peg]")
|
TEST_CASE("PEG Grammar", "[peg]")
|
||||||
{
|
{
|
||||||
auto g = PEGParser::grammar();
|
auto g = ParserGenerator::grammar();
|
||||||
REQUIRE(exact(g, "Grammar", " Definition <- a / ( b c ) / d \n rule2 <- [a-zA-Z][a-z0-9-]+ ") == true);
|
REQUIRE(exact(g, "Grammar", " Definition <- a / ( b c ) / d \n rule2 <- [a-zA-Z][a-z0-9-]+ ") == true);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("PEG Definition", "[peg]")
|
TEST_CASE("PEG Definition", "[peg]")
|
||||||
{
|
{
|
||||||
auto g = PEGParser::grammar();
|
auto g = ParserGenerator::grammar();
|
||||||
REQUIRE(exact(g, "Definition", "Definition <- a / (b c) / d ") == true);
|
REQUIRE(exact(g, "Definition", "Definition <- a / (b c) / d ") == true);
|
||||||
REQUIRE(exact(g, "Definition", "Definition <- a / b c / d ") == true);
|
REQUIRE(exact(g, "Definition", "Definition <- a / b c / d ") == true);
|
||||||
REQUIRE(exact(g, "Definition", "Definition ") == false);
|
REQUIRE(exact(g, "Definition", "Definition ") == false);
|
||||||
@ -700,7 +700,7 @@ TEST_CASE("PEG Definition", "[peg]")
|
|||||||
|
|
||||||
TEST_CASE("PEG Expression", "[peg]")
|
TEST_CASE("PEG Expression", "[peg]")
|
||||||
{
|
{
|
||||||
auto g = PEGParser::grammar();
|
auto g = ParserGenerator::grammar();
|
||||||
REQUIRE(exact(g, "Expression", "a / (b c) / d ") == true);
|
REQUIRE(exact(g, "Expression", "a / (b c) / d ") == true);
|
||||||
REQUIRE(exact(g, "Expression", "a / b c / d ") == true);
|
REQUIRE(exact(g, "Expression", "a / b c / d ") == true);
|
||||||
REQUIRE(exact(g, "Expression", "a b ") == true);
|
REQUIRE(exact(g, "Expression", "a b ") == true);
|
||||||
@ -711,7 +711,7 @@ TEST_CASE("PEG Expression", "[peg]")
|
|||||||
|
|
||||||
TEST_CASE("PEG Sequence", "[peg]")
|
TEST_CASE("PEG Sequence", "[peg]")
|
||||||
{
|
{
|
||||||
auto g = PEGParser::grammar();
|
auto g = ParserGenerator::grammar();
|
||||||
REQUIRE(exact(g, "Sequence", "a b c d ") == true);
|
REQUIRE(exact(g, "Sequence", "a b c d ") == true);
|
||||||
REQUIRE(exact(g, "Sequence", "") == true);
|
REQUIRE(exact(g, "Sequence", "") == true);
|
||||||
REQUIRE(exact(g, "Sequence", "!") == false);
|
REQUIRE(exact(g, "Sequence", "!") == false);
|
||||||
@ -721,7 +721,7 @@ TEST_CASE("PEG Sequence", "[peg]")
|
|||||||
|
|
||||||
TEST_CASE("PEG Prefix", "[peg]")
|
TEST_CASE("PEG Prefix", "[peg]")
|
||||||
{
|
{
|
||||||
auto g = PEGParser::grammar();
|
auto g = ParserGenerator::grammar();
|
||||||
REQUIRE(exact(g, "Prefix", "&[a]") == true);
|
REQUIRE(exact(g, "Prefix", "&[a]") == true);
|
||||||
REQUIRE(exact(g, "Prefix", "![']") == true);
|
REQUIRE(exact(g, "Prefix", "![']") == true);
|
||||||
REQUIRE(exact(g, "Prefix", "-[']") == false);
|
REQUIRE(exact(g, "Prefix", "-[']") == false);
|
||||||
@ -731,7 +731,7 @@ TEST_CASE("PEG Prefix", "[peg]")
|
|||||||
|
|
||||||
TEST_CASE("PEG Suffix", "[peg]")
|
TEST_CASE("PEG Suffix", "[peg]")
|
||||||
{
|
{
|
||||||
auto g = PEGParser::grammar();
|
auto g = ParserGenerator::grammar();
|
||||||
REQUIRE(exact(g, "Suffix", "aaa ") == true);
|
REQUIRE(exact(g, "Suffix", "aaa ") == true);
|
||||||
REQUIRE(exact(g, "Suffix", "aaa? ") == true);
|
REQUIRE(exact(g, "Suffix", "aaa? ") == true);
|
||||||
REQUIRE(exact(g, "Suffix", "aaa* ") == true);
|
REQUIRE(exact(g, "Suffix", "aaa* ") == true);
|
||||||
@ -744,7 +744,7 @@ TEST_CASE("PEG Suffix", "[peg]")
|
|||||||
|
|
||||||
TEST_CASE("PEG Primary", "[peg]")
|
TEST_CASE("PEG Primary", "[peg]")
|
||||||
{
|
{
|
||||||
auto g = PEGParser::grammar();
|
auto g = ParserGenerator::grammar();
|
||||||
REQUIRE(exact(g, "Primary", "_Identifier0_ ") == true);
|
REQUIRE(exact(g, "Primary", "_Identifier0_ ") == true);
|
||||||
REQUIRE(exact(g, "Primary", "_Identifier0_<-") == false);
|
REQUIRE(exact(g, "Primary", "_Identifier0_<-") == false);
|
||||||
REQUIRE(exact(g, "Primary", "( _Identifier0_ _Identifier1_ )") == true);
|
REQUIRE(exact(g, "Primary", "( _Identifier0_ _Identifier1_ )") == true);
|
||||||
@ -760,7 +760,7 @@ TEST_CASE("PEG Primary", "[peg]")
|
|||||||
|
|
||||||
TEST_CASE("PEG Identifier", "[peg]")
|
TEST_CASE("PEG Identifier", "[peg]")
|
||||||
{
|
{
|
||||||
auto g = PEGParser::grammar();
|
auto g = ParserGenerator::grammar();
|
||||||
REQUIRE(exact(g, "Identifier", "_Identifier0_ ") == true);
|
REQUIRE(exact(g, "Identifier", "_Identifier0_ ") == true);
|
||||||
REQUIRE(exact(g, "Identifier", "0Identifier_ ") == false);
|
REQUIRE(exact(g, "Identifier", "0Identifier_ ") == false);
|
||||||
REQUIRE(exact(g, "Identifier", "Iden|t ") == false);
|
REQUIRE(exact(g, "Identifier", "Iden|t ") == false);
|
||||||
@ -771,7 +771,7 @@ TEST_CASE("PEG Identifier", "[peg]")
|
|||||||
|
|
||||||
TEST_CASE("PEG IdentStart", "[peg]")
|
TEST_CASE("PEG IdentStart", "[peg]")
|
||||||
{
|
{
|
||||||
auto g = PEGParser::grammar();
|
auto g = ParserGenerator::grammar();
|
||||||
REQUIRE(exact(g, "IdentStart", "_") == true);
|
REQUIRE(exact(g, "IdentStart", "_") == true);
|
||||||
REQUIRE(exact(g, "IdentStart", "a") == true);
|
REQUIRE(exact(g, "IdentStart", "a") == true);
|
||||||
REQUIRE(exact(g, "IdentStart", "Z") == true);
|
REQUIRE(exact(g, "IdentStart", "Z") == true);
|
||||||
@ -782,7 +782,7 @@ TEST_CASE("PEG IdentStart", "[peg]")
|
|||||||
|
|
||||||
TEST_CASE("PEG IdentRest", "[peg]")
|
TEST_CASE("PEG IdentRest", "[peg]")
|
||||||
{
|
{
|
||||||
auto g = PEGParser::grammar();
|
auto g = ParserGenerator::grammar();
|
||||||
REQUIRE(exact(g, "IdentRest", "_") == true);
|
REQUIRE(exact(g, "IdentRest", "_") == true);
|
||||||
REQUIRE(exact(g, "IdentRest", "a") == true);
|
REQUIRE(exact(g, "IdentRest", "a") == true);
|
||||||
REQUIRE(exact(g, "IdentRest", "Z") == true);
|
REQUIRE(exact(g, "IdentRest", "Z") == true);
|
||||||
@ -793,7 +793,7 @@ TEST_CASE("PEG IdentRest", "[peg]")
|
|||||||
|
|
||||||
TEST_CASE("PEG Literal", "[peg]")
|
TEST_CASE("PEG Literal", "[peg]")
|
||||||
{
|
{
|
||||||
auto g = PEGParser::grammar();
|
auto g = ParserGenerator::grammar();
|
||||||
REQUIRE(exact(g, "Literal", "'abc' ") == true);
|
REQUIRE(exact(g, "Literal", "'abc' ") == true);
|
||||||
REQUIRE(exact(g, "Literal", "'a\\nb\\tc' ") == true);
|
REQUIRE(exact(g, "Literal", "'a\\nb\\tc' ") == true);
|
||||||
REQUIRE(exact(g, "Literal", "'a\\277\tc' ") == true);
|
REQUIRE(exact(g, "Literal", "'a\\277\tc' ") == true);
|
||||||
@ -812,7 +812,7 @@ TEST_CASE("PEG Literal", "[peg]")
|
|||||||
|
|
||||||
TEST_CASE("PEG Class", "[peg]")
|
TEST_CASE("PEG Class", "[peg]")
|
||||||
{
|
{
|
||||||
auto g = PEGParser::grammar();
|
auto g = ParserGenerator::grammar();
|
||||||
REQUIRE(exact(g, "Class", "[]") == true);
|
REQUIRE(exact(g, "Class", "[]") == true);
|
||||||
REQUIRE(exact(g, "Class", "[a]") == true);
|
REQUIRE(exact(g, "Class", "[a]") == true);
|
||||||
REQUIRE(exact(g, "Class", "[a-z]") == true);
|
REQUIRE(exact(g, "Class", "[a-z]") == true);
|
||||||
@ -832,7 +832,7 @@ TEST_CASE("PEG Class", "[peg]")
|
|||||||
|
|
||||||
TEST_CASE("PEG Range", "[peg]")
|
TEST_CASE("PEG Range", "[peg]")
|
||||||
{
|
{
|
||||||
auto g = PEGParser::grammar();
|
auto g = ParserGenerator::grammar();
|
||||||
REQUIRE(exact(g, "Range", "a") == true);
|
REQUIRE(exact(g, "Range", "a") == true);
|
||||||
REQUIRE(exact(g, "Range", "a-z") == true);
|
REQUIRE(exact(g, "Range", "a-z") == true);
|
||||||
REQUIRE(exact(g, "Range", "az") == false);
|
REQUIRE(exact(g, "Range", "az") == false);
|
||||||
@ -843,7 +843,7 @@ TEST_CASE("PEG Range", "[peg]")
|
|||||||
|
|
||||||
TEST_CASE("PEG Char", "[peg]")
|
TEST_CASE("PEG Char", "[peg]")
|
||||||
{
|
{
|
||||||
auto g = PEGParser::grammar();
|
auto g = ParserGenerator::grammar();
|
||||||
REQUIRE(exact(g, "Char", "\\n") == true);
|
REQUIRE(exact(g, "Char", "\\n") == true);
|
||||||
REQUIRE(exact(g, "Char", "\\r") == true);
|
REQUIRE(exact(g, "Char", "\\r") == true);
|
||||||
REQUIRE(exact(g, "Char", "\\t") == true);
|
REQUIRE(exact(g, "Char", "\\t") == true);
|
||||||
@ -876,7 +876,7 @@ TEST_CASE("PEG Char", "[peg]")
|
|||||||
|
|
||||||
TEST_CASE("PEG Operators", "[peg]")
|
TEST_CASE("PEG Operators", "[peg]")
|
||||||
{
|
{
|
||||||
auto g = PEGParser::grammar();
|
auto g = ParserGenerator::grammar();
|
||||||
REQUIRE(exact(g, "LEFTARROW", "<-") == true);
|
REQUIRE(exact(g, "LEFTARROW", "<-") == true);
|
||||||
REQUIRE(exact(g, "SLASH", "/ ") == true);
|
REQUIRE(exact(g, "SLASH", "/ ") == true);
|
||||||
REQUIRE(exact(g, "AND", "& ") == true);
|
REQUIRE(exact(g, "AND", "& ") == true);
|
||||||
@ -891,7 +891,7 @@ TEST_CASE("PEG Operators", "[peg]")
|
|||||||
|
|
||||||
TEST_CASE("PEG Comment", "[peg]")
|
TEST_CASE("PEG Comment", "[peg]")
|
||||||
{
|
{
|
||||||
auto g = PEGParser::grammar();
|
auto g = ParserGenerator::grammar();
|
||||||
REQUIRE(exact(g, "Comment", "# Comment.\n") == true);
|
REQUIRE(exact(g, "Comment", "# Comment.\n") == true);
|
||||||
REQUIRE(exact(g, "Comment", "# Comment.") == false);
|
REQUIRE(exact(g, "Comment", "# Comment.") == false);
|
||||||
REQUIRE(exact(g, "Comment", " ") == false);
|
REQUIRE(exact(g, "Comment", " ") == false);
|
||||||
@ -900,7 +900,7 @@ TEST_CASE("PEG Comment", "[peg]")
|
|||||||
|
|
||||||
TEST_CASE("PEG Space", "[peg]")
|
TEST_CASE("PEG Space", "[peg]")
|
||||||
{
|
{
|
||||||
auto g = PEGParser::grammar();
|
auto g = ParserGenerator::grammar();
|
||||||
REQUIRE(exact(g, "Space", " ") == true);
|
REQUIRE(exact(g, "Space", " ") == true);
|
||||||
REQUIRE(exact(g, "Space", "\t") == true);
|
REQUIRE(exact(g, "Space", "\t") == true);
|
||||||
REQUIRE(exact(g, "Space", "\n") == true);
|
REQUIRE(exact(g, "Space", "\n") == true);
|
||||||
@ -910,7 +910,7 @@ TEST_CASE("PEG Space", "[peg]")
|
|||||||
|
|
||||||
TEST_CASE("PEG EndOfLine", "[peg]")
|
TEST_CASE("PEG EndOfLine", "[peg]")
|
||||||
{
|
{
|
||||||
auto g = PEGParser::grammar();
|
auto g = ParserGenerator::grammar();
|
||||||
REQUIRE(exact(g, "EndOfLine", "\r\n") == true);
|
REQUIRE(exact(g, "EndOfLine", "\r\n") == true);
|
||||||
REQUIRE(exact(g, "EndOfLine", "\n") == true);
|
REQUIRE(exact(g, "EndOfLine", "\n") == true);
|
||||||
REQUIRE(exact(g, "EndOfLine", "\r") == true);
|
REQUIRE(exact(g, "EndOfLine", "\r") == true);
|
||||||
|
Loading…
Reference in New Issue
Block a user