依赖于参数的解析器规则
Parser rule dependent on parameter
我试图定义一个规则未完全预定义的解析器,即它们包含可变部分。这对灵气来说没有问题,但由于 X3 的静态特性,我无法实现它。我尝试了 with 指令 ,不幸的是它没有记录,但到目前为止运气不好。到目前为止我发现的唯一例子是在 lambda 表达式中。
我构建了一个简单示例来演示该问题:解析整数,其中分隔符作为参数给出。
#include <boost/spirit/home/x3.hpp>
#include <iostream>
namespace x3 = boost::spirit::x3;
namespace parsing {
x3::rule<struct parser> parser {"parser"};
//struct separator {};
char separator(',');
//auto parser_def = x3::int_ % x3::lit(x3::get<separator>(/* context */)); // candidate function template not viable: requires single argument 'context'
auto parser_def = x3::int_ % x3::lit(separator);
BOOST_SPIRIT_DEFINE(parser)
}
void parse(const std::string &data, const char separator) {
using namespace std;
//auto parser = x3::with<parsing::separator>(ref(separator)) [parsing::parser] >> x3::eoi;
auto parser = parsing::parser >> x3::eoi;
if (x3::parse(data.begin(), data.end(), parser))
cout << "Parse succeeded\n";
else
cout << "Parse failed\n";
}
int main() {
parse("1 2 3", ' ');
parse("1,2,3", ',');
parse("1;2;3", ';');
}
我注释掉了我尝试使用 with 指令的部分。
X3 目前可以吗?有人做过吗?
又看了一些X3的帖子,sehe的这个回答让我大开眼界:
了解 x3::_pass 让我找到了这个解决方案:
#include <boost/spirit/home/x3.hpp>
#include <iostream>
namespace x3 = boost::spirit::x3;
namespace parsing {
x3::rule<struct parser> parser {"parser"};
struct separator {};
// only the separator which is currently in the context is allowed (passes)
auto isSeparator = [](auto& ctx){ x3::_pass(ctx) = x3::_attr(ctx) == x3::get<separator>(ctx); };
// at first match any char and then check whether it is the separator
auto parser_def = x3::int_ % x3::char_[isSeparator];
BOOST_SPIRIT_DEFINE(parser)
}
void parse(const std::string &data, const char separator) {
using namespace std;
auto parser = x3::with<parsing::separator>(ref(separator)) [parsing::parser] >> x3::eoi;
if (x3::parse(data.begin(), data.end(), parser))
cout << "Parse succeeded\n";
else
cout << "Parse failed\n";
}
int main() {
// succeed
parse("1 2 3", ' ');
parse("1,2,3", ',');
parse("1;2;3", ';');
// fail
parse("1,2,3", ' ');
parse("1;2;3", ',');
}
下一步需要测试的是设置多个参数的可能性(可能通过级联 x3::with<>)。
编辑:
是的,通过级联 x3::with<> 设置多个参数似乎可行。
例如:
auto parser = x3::with<parsing::separator>(ref(separator))[x3::with<parsing::separator2>(ref(separator2))[parsing::parser]] >> x3::eoi;
一个更简单的解决方案,您可以有一个获取字符的函数和 returns 类型 x3::rule<struct parser>
.
的解析器值
auto getParser(char sep)
{
return x3::int_ % x3::lit(sep);
}
完整代码(神栓:https://godbolt.org/z/ENxCTF)
#include <boost/spirit/home/x3.hpp>
#include <iostream>
namespace x3 = boost::spirit::x3;
namespace parsing {
x3::rule<struct parser> parser {"parser"};
//struct separator {};
char separator(',');
//auto parser_def = x3::int_ % x3::lit(x3::get<separator>(/* context */)); // candidate function template not viable: requires single argument 'context'
auto parser_def = x3::int_ % x3::lit(separator);
BOOST_SPIRIT_DEFINE(parser)
auto getParser(char sep)
{
return x3::int_ % x3::lit(sep);
}
}
void parse(const std::string &data, const char separator) {
using namespace std;
//auto parser = x3::with<parsing::separator>(ref(separator)) [parsing::parser] >> x3::eoi;
auto parser = parsing::getParser(separator) >> x3::eoi;
if (x3::parse(data.begin(), data.end(), parser))
cout << "Parse succeeded\n";
else
cout << "Parse failed\n";
}
int main() {
parse("1 2 3", ' ');
parse("1,2,3", ',');
parse("1;2;3", ';');
}
我试图定义一个规则未完全预定义的解析器,即它们包含可变部分。这对灵气来说没有问题,但由于 X3 的静态特性,我无法实现它。我尝试了 with 指令 ,不幸的是它没有记录,但到目前为止运气不好。到目前为止我发现的唯一例子是在 lambda 表达式中。
我构建了一个简单示例来演示该问题:解析整数,其中分隔符作为参数给出。
#include <boost/spirit/home/x3.hpp>
#include <iostream>
namespace x3 = boost::spirit::x3;
namespace parsing {
x3::rule<struct parser> parser {"parser"};
//struct separator {};
char separator(',');
//auto parser_def = x3::int_ % x3::lit(x3::get<separator>(/* context */)); // candidate function template not viable: requires single argument 'context'
auto parser_def = x3::int_ % x3::lit(separator);
BOOST_SPIRIT_DEFINE(parser)
}
void parse(const std::string &data, const char separator) {
using namespace std;
//auto parser = x3::with<parsing::separator>(ref(separator)) [parsing::parser] >> x3::eoi;
auto parser = parsing::parser >> x3::eoi;
if (x3::parse(data.begin(), data.end(), parser))
cout << "Parse succeeded\n";
else
cout << "Parse failed\n";
}
int main() {
parse("1 2 3", ' ');
parse("1,2,3", ',');
parse("1;2;3", ';');
}
我注释掉了我尝试使用 with 指令的部分。
X3 目前可以吗?有人做过吗?
又看了一些X3的帖子,sehe的这个回答让我大开眼界:
了解 x3::_pass 让我找到了这个解决方案:
#include <boost/spirit/home/x3.hpp>
#include <iostream>
namespace x3 = boost::spirit::x3;
namespace parsing {
x3::rule<struct parser> parser {"parser"};
struct separator {};
// only the separator which is currently in the context is allowed (passes)
auto isSeparator = [](auto& ctx){ x3::_pass(ctx) = x3::_attr(ctx) == x3::get<separator>(ctx); };
// at first match any char and then check whether it is the separator
auto parser_def = x3::int_ % x3::char_[isSeparator];
BOOST_SPIRIT_DEFINE(parser)
}
void parse(const std::string &data, const char separator) {
using namespace std;
auto parser = x3::with<parsing::separator>(ref(separator)) [parsing::parser] >> x3::eoi;
if (x3::parse(data.begin(), data.end(), parser))
cout << "Parse succeeded\n";
else
cout << "Parse failed\n";
}
int main() {
// succeed
parse("1 2 3", ' ');
parse("1,2,3", ',');
parse("1;2;3", ';');
// fail
parse("1,2,3", ' ');
parse("1;2;3", ',');
}
下一步需要测试的是设置多个参数的可能性(可能通过级联 x3::with<>)。
编辑:
是的,通过级联 x3::with<> 设置多个参数似乎可行。 例如:
auto parser = x3::with<parsing::separator>(ref(separator))[x3::with<parsing::separator2>(ref(separator2))[parsing::parser]] >> x3::eoi;
一个更简单的解决方案,您可以有一个获取字符的函数和 returns 类型 x3::rule<struct parser>
.
auto getParser(char sep)
{
return x3::int_ % x3::lit(sep);
}
完整代码(神栓:https://godbolt.org/z/ENxCTF)
#include <boost/spirit/home/x3.hpp>
#include <iostream>
namespace x3 = boost::spirit::x3;
namespace parsing {
x3::rule<struct parser> parser {"parser"};
//struct separator {};
char separator(',');
//auto parser_def = x3::int_ % x3::lit(x3::get<separator>(/* context */)); // candidate function template not viable: requires single argument 'context'
auto parser_def = x3::int_ % x3::lit(separator);
BOOST_SPIRIT_DEFINE(parser)
auto getParser(char sep)
{
return x3::int_ % x3::lit(sep);
}
}
void parse(const std::string &data, const char separator) {
using namespace std;
//auto parser = x3::with<parsing::separator>(ref(separator)) [parsing::parser] >> x3::eoi;
auto parser = parsing::getParser(separator) >> x3::eoi;
if (x3::parse(data.begin(), data.end(), parser))
cout << "Parse succeeded\n";
else
cout << "Parse failed\n";
}
int main() {
parse("1 2 3", ' ');
parse("1,2,3", ',');
parse("1;2;3", ';');
}