以下程序是一个人为的例子(从我正在工作的较大语法中减少)表现出一种奇怪的行为。
程序的输出按原样运行“hello”并且不正确。
如果我从quoted_string
规则中删除(在此示例中无用)语义操作,则输出是预期的“foo = hello”。
#define BOOST_RESULT_OF_USE_DECLTYPE
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <vector>
#include <string>
#include <iostream>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include "utils.hpp"
namespace t {
using std::vector;
using std::string;
namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;
template <typename Iterator, typename Skipper=qi::space_type>
struct G1 : qi::grammar<Iterator, string(), Skipper> {
template <typename T>
using rule = qi::rule<Iterator, T, Skipper>;
qi::rule<Iterator, string(), qi::locals<char>> quoted_string;
rule<string()> start;
G1() : G1::base_type(start, "G1") {
{
using qi::_1;
using qi::_a;
using attr_signature = vector<char>;
auto handler = [](attr_signature const& elements) -> string {
string output;
for(auto& e : elements) {
output += e;
}
return output;
};
quoted_string = (qi::omit[qi::char_("'\"")[_a = _1]]
>> +(qi::char_ - qi::char_(_a))
>> qi::lit(_a))[qi::_val = phx::bind(handler, _1)];
}
start = qi::string("foo") >> -(qi::string("=") >> quoted_string);
}
};
string parse(string const input) {
G1<string::const_iterator> g;
string result;
phrase_parse(begin(input), end(input), g, qi::standard::space, result);
return result;
}
};
int main() {
using namespace std;
auto r = t::parse("foo='hello'");
cout << r << endl;
}
我绝对可以找到解决方法,但我会弄清楚我缺少什么
答案 0 :(得分:2)
与@cv_and_he解释一样,您将使用handler(_1)
的结果覆盖该属性。由于属性是通过引用传递的,因此会丢失原始值。
自动属性传播规则知道如何连接&#34;字符串&#34;容器值,那么为什么不使用默认实现?
quoted_string %= qi::omit[qi::char_("'\"")[_a = _1]]
>> +(qi::char_ - qi::char_(_a))
>> qi::lit(_a);
(请注意 %=
;即使存在语义操作,也会启用自动传播。
或者,您可以从SA内部推回:
>> +(qi::char_ - qi::char_(_a)) [ phx::push_back(qi::_val, _1) ]
并且,如果您确实需要在handler
中完成某些处理,请通过引用使其成为字符串:
auto handler = [](attr_signature const& elements, std::string& attr) {
for(auto& e : elements) {
attr += e;
}
};
quoted_string = (qi::omit[qi::char_("'\"")[_a = _1]]
>> +(qi::char_ - qi::char_(_a))
>> qi::lit(_a)) [ phx::bind(handler, _1, qi::_val) ];
所有这些方法都有效。
对于非常重要的东西,我过去使用自定义字符串类型和boost :: spirit :: traits自定义点来进行转换: