gpt4 book ai didi

c++ - Boost.Spirit.Qi : How to return attributes with Nabialek trick

转载 作者:IT老高 更新时间:2023-10-28 23:15:10 25 4
gpt4 key购买 nike

按照几个教程(例如 http://boost-spirit.com/home/articles/qi-example/nabialek-trick/ ),我想使用 Nabialek 技巧来拥有一个动态解析器​​。解析已经可以正常工作,但我没有得到传输的属性。解释如 https://stackoverflow.com/a/9109972/2524462建议,属性应该是可能的,但不是参数。

这只是一个将字符串和数字解析为结构的小示例。这只是为了展示我的问题;这种方法应该在以后真正需要动态解析器​​的更大系统中使用。

问题:如何使用 Nabialek 技巧传输属性?

我不是精神专家,所以请多多包涵。我正在使用 gcc 4.8.1 和 boost 1.54。

#define BOOST_SPIRIT_DEBUG
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>

namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;

//------------------------------------------------------------------------------
// Data structure
struct myline {
myline()
: _n(0), _s("") {
}

myline(int n, std::string s)
: _n(n), _s(s) {
}

void set(int n, std::string s) {
_n = n;
_s = s;
}

int _n;
std::string _s;
};

BOOST_FUSION_ADAPT_STRUCT(::myline, (int, _n) (std::string, _s))

//------------------------------------------------------------------------------
// Parser grammar
template<typename It, typename Skipper = qi::space_type>
struct parser: qi::grammar<It, myline(), Skipper> {
parser()
: parser::base_type(start) {
using namespace qi;

start = line;

string %= qi::lexeme["'" >> *~qi::char_("'") >> "'"];

one = (string >> "@" >> qi::int_)[_val = phx::construct<myline>(_2, _1)];
two = (qi::int_ >> "@" >> string);

keyword.add("one", &one)("two", &two);

line = keyword[_a = _1] >> qi::lazy(*_a);

on_error<fail>(
start,
std::cout << phx::val("Error! Expecting ") << _4
<< phx::val(" here: \"") << phx::construct<std::string>(_3, _2)
<< phx::val("\"\n"));

BOOST_SPIRIT_DEBUG_NODES((start)(line)(one)(two))
}

private:
template<typename Attr> using Rule = qi::rule<It, Attr(), Skipper>;

Rule<myline> start, one, two;
qi::rule<It, myline, Skipper, qi::locals<Rule<myline>*> > line;

Rule<std::string> string;

qi::symbols<char, Rule<myline>*> keyword;
};

//------------------------------------------------------------------------------
int main() {
for (const std::string input : std::vector<std::string> { "one 'test'@1",
"two 2@'test'" }) {
auto f(std::begin(input)), l(std::end(input));
const static parser<decltype(f)> p;

myline parsed_script;
bool ok = qi::phrase_parse(f, l, p, qi::space, parsed_script);

if (!ok) {
std::cout << "invalid input\n";
}

std::cout << parsed_script._n << ": " << parsed_script._s << std::endl;

if (f != l) {
std::cout << "unparsed: '" << std::string(f, l) << "'" << std::endl;
}
}
}

解析结果:

<start>
<try>one 'test'@1</try>
<line>
<try>one 'test'@1</try>
<one>
<try> 'test'@1</try>
<success></success>
<attributes>[[1, [t, e, s, t]]]</attributes>
</one>
<success></success>
<attributes>[]</attributes><locals>(0x43b0e0)</locals>
</line>
<success></success>
<attributes>[[0, []]]</attributes>
</start>
<start>
<try>two 2@'test'</try>
<line>
<try>two 2@'test'</try>
<two>
<try> 2@'test'</try>
<success></success>
<attributes>[[2, [t, e, s, t]]]</attributes>
</two>
<success></success>
<attributes>[]</attributes><locals>(0x43b110)</locals>
</line>
<success></success>
<attributes>[[0, []]]</attributes>
</start>

最佳答案

你在精神课上一直很关注:)

有很多问题:

  1. line 的属性声明规则错误:

    qi::rule<It, myline, Skipper, qi::locals<Rule<myline>*> > line;

    需要

    qi::rule<It, myline(), Skipper, qi::locals<Rule<myline>*> > line;
  2. 在存在语义 Action 时禁止自动属性传播。有关更多信息,请参阅最近的答案:Boost.spirit: parsing number char and string .因此,您需要使用 %= 明确参与 Spirit 的自动规则行为。 :

    line = keyword[_a = _1] >> qi::lazy(*_a);

    需要

    // NOTE the %=
    line %= omit [ keyword[_a = _1] ] >> qi::lazy(*_a);

    注意事项:

    • %=可以继续string规则(没有语义 Action 意味着自动属性传播)
    • 我们需要明确 omit[]关键字匹配的结果,因为我们不能真正分配 Rule<>*到我们的myline属性

这是固定版本:

#define BOOST_SPIRIT_DEBUG
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>

namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;

//------------------------------------------------------------------------------
// Data structure
struct myline {
myline()
: _n(0), _s("") {
}

myline(int n, std::string s)
: _n(n), _s(s) {
}

void set(int n, std::string s) {
_n = n;
_s = s;
}

int _n;
std::string _s;
};

BOOST_FUSION_ADAPT_STRUCT(::myline, (int, _n) (std::string, _s))

//------------------------------------------------------------------------------
// Parser grammar
template<typename It, typename Skipper = qi::space_type>
struct parser: qi::grammar<It, myline(), Skipper> {
parser()
: parser::base_type(start) {
using namespace qi;

start = line;

string = qi::lexeme["'" >> *~qi::char_("'") >> "'"];

one = (string >> "@" >> qi::int_) [_val = phx::construct<myline>(_2, _1)];
two = (qi::int_ >> "@" >> string);

keyword.add("one", &one)("two", &two);

// NOTE the %=
line %= omit [ keyword[_a = _1] ] >> qi::lazy(*_a);

on_error<fail>(
start,
std::cout << phx::val("Error! Expecting ") << _4
<< phx::val(" here: \"") << phx::construct<std::string>(_3, _2)
<< phx::val("\"\n"));

BOOST_SPIRIT_DEBUG_NODES((start)(line)(one)(two))
}

private:
template<typename Attr> using Rule = qi::rule<It, Attr(), Skipper>;

Rule<myline> start, one, two;
qi::rule<It, myline(), Skipper, qi::locals<Rule<myline>* > > line;

Rule<std::string> string;

qi::symbols<char, Rule<myline>* > keyword;
};

//------------------------------------------------------------------------------
int main() {
for (const std::string input : std::vector<std::string> { "one 'test1'@1",
"two 2@'test2'" }) {
auto f(std::begin(input)), l(std::end(input));
const static parser<decltype(f)> p;

myline parsed_script;
bool ok = qi::phrase_parse(f, l, p, qi::space, parsed_script);

if (!ok) {
std::cout << "invalid input\n";
}

std::cout << parsed_script._n << ": " << parsed_script._s << std::endl;

if (f != l) {
std::cout << "unparsed: '" << std::string(f, l) << "'" << std::endl;
}
}
}

打印:

<start>
<try>one 'test1'@1</try>
<line>
<try>one 'test1'@1</try>
<one>
<try> 'test1'@1</try>
<success></success>
<attributes>[[1, [t, e, s, t, 1]]]</attributes>
</one>
<success></success>
<attributes>[[1, [t, e, s, t, 1]]]</attributes><locals>(0x6386c0)</locals>
</line>
<success></success>
<attributes>[[1, [t, e, s, t, 1]]]</attributes>
</start>
1: test1
<start>
<try>two 2@'test2'</try>
<line>
<try>two 2@'test2'</try>
<two>
<try> 2@'test2'</try>
<success></success>
<attributes>[[2, [t, e, s, t, 2]]]</attributes>
</two>
<success></success>
<attributes>[[2, [t, e, s, t, 2]]]</attributes><locals>(0x6386f0)</locals>
</line>
<success></success>
<attributes>[[2, [t, e, s, t, 2]]]</attributes>
</start>
2: test2

关于c++ - Boost.Spirit.Qi : How to return attributes with Nabialek trick,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17717590/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com