此代码按预期编译和工作;输入如" {a; b}"被解析并存储在自定义类
中#include <vector>
#include <string>
#include <iostream>
#include <boost/spirit/include/qi.hpp>
namespace t {
using std::vector;
using std::string;
namespace qi = boost::spirit::qi;
struct Block {
Block() = default;
Block(vector<string> const& s) : value(s) {}
vector<string> value;
};
template <typename Iterator, typename Skipper=qi::space_type>
struct G1 : qi::grammar<Iterator, Block(), Skipper> {
template <typename T>
using rule = qi::rule<Iterator, T, Skipper>;
rule<Block()> start;
G1() : G1::base_type(start, "G1") {
start = qi::as<vector<string>>()[
qi::lit('{')
>> *(+(qi::char_ - ';') >> ';')
>> '}'
];
}
};
Block parse(string const input) {
G1<string::const_iterator> g;
Block result;
phrase_parse(begin(input), end(input), g, qi::standard::space, result);
return result;
}
};
int main() {
using namespace std;
auto r = t::parse("{a;b;}");
for (auto& s : r.value) {
cout << s << endl;
}
}
我不明白为什么as&lt;&gt;指令是必要的;从我可以从文档中推断出,原始解析器的合成属性应该已经是字符串的向量。
我已阅读this article有关属性传播和属性兼容性的内容,但我错过了大局;当(不)使用as指令时会发生什么?
答案 0 :(得分:2)
否则
*(+(qi::char_ - ';') >> ';')
只会暴露std::vector<char>
(每个kleene- +会附加到同一属性中)。根据经验,kleene-operators总是直接推回到引用的属性,这也意味着它期望该属性是容器类型(boost::spirit::traits::container_value<>
特征用于检测重复的解析器表达式的属性应转换为)。
在这种情况下,您可能会发现融合适应qi::as_string
更优雅: Live On Coliru
struct Block {
vector<string> value;
};
BOOST_FUSION_ADAPT_STRUCT(t::Block,(std::vector<std::string>,value))
// ...
start =
qi::lit('{')
>> *qi::as_string [ +(qi::char_ - ';') >> ';' ]
>> '}'
;
有了这个,请注意