正在分析BoostSpirit中固定列表中的选择

Parsing selections from a fixed list in Boost.Spirit

本文关键字:列表 选择 BoostSpirit      更新时间:2023-10-16

从员工开始-解析成结构示例:

template <typename Iterator>
struct employee_parser : qi::grammar<Iterator, employee(), ascii::space_type>
{
employee_parser() : employee_parser::base_type(start)
{
using qi::int_;
using qi::lit;
using qi::double_;
using qi::lexeme;
using ascii::char_;
quoted_string %= lexeme['"' >> +(char_ - '"') >> '"'];
start %=
lit("employee")
>> '{'
>>  int_ >> ','
>>  quoted_string >> ','
>>  quoted_string >> ','
>>  double_
>>  '}'
;
}
qi::rule<Iterator, std::string(), ascii::space_type> quoted_string;
qi::rule<Iterator, employee(), ascii::space_type> start;
};

假设我想用一个匹配存储在给定容器中的任何字符串的规则来替换quoted_string

例如,如果我有一个容器,例如:

std::array<std::string, 4> match_list =
{ "string0", "string1", "string2", "string3" };

我希望解析器只将输入与数组中的一个值匹配(容器不必是数组(。

我相信这很简单,但Spirit帮助页面似乎并没有解决这个问题。

它很简单:https://www.boost.org/doc/libs/1_67_0/libs/spirit/doc/html/spirit/qi/reference/string/symbols.html

在Coliru上直播

#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
struct employee {
int id;
std::string sym;
std::string name;
double value;
};
BOOST_FUSION_ADAPT_STRUCT(employee, id, sym, name, value) 
template <typename Iterator, typename Skipper = qi::space_type>
struct employee_parser : qi::grammar<Iterator, employee(), Skipper>
{
employee_parser() : employee_parser::base_type(start)
{
using namespace qi;
quoted_string = lexeme['"' >> +(char_ - '"') >> '"'];
symbol_.add
("string0")
("string1")
("string2")
("string3")
;
start =
lit("employee")
>> '{'
>>  int_ >> ','
>>  symbol_ >> ','
>>  quoted_string >> ','
>>  double_
>>  '}'
;
}
qi::rule<Iterator, std::string(), Skipper> quoted_string;
qi::rule<Iterator, employee(), Skipper> start;
qi::symbols<char, std::string> symbol_;
};
int main() {
std::string const input = "employee { 42, string3, "more names or stuff", 6.7 }";
using It = std::string::const_iterator;
It f = input.begin(), l = input.end();
employee_parser<It> p;
employee e;
if (phrase_parse(f, l, p, qi::space, e)) {
using boost::fusion::operator<<;
std::cout << boost::fusion::tuple_delimiter(';');
std::cout << "Parsed: " << e << "n";
} else {
std::cout << "Parse failedn";
}
if (f!=l)
std::cout << "Remaining input: '" << std::string(f,l) << "'n";
}

打印

Parsed: (42;;more names or stuff;6.7)

实际包含值:

symbol_.add
("string0", "STRING0")
("string1", "STRING1")
("string2", "STRING2")
("string3", "STRING3")
;

打印在Coliru上直播

Parsed: (42;STRING3;more names or stuff;6.7)

或者你可以完全使用另一种类型:

symbol_.add
("string0", 0)
("string1", 1)
("string2", 2)
("string3", 3)
;

symbol_.add
("string0", 0)
("string1", 1)
("string2", 2)
("string3", 3)
;

打印Coliru

Parsed: (42;3;more names or stuff;6.7)

最后,您可以使用raw[]来"转换"输入序列,例如与qi::no_space[]:LiveOnColiru组合

>>  raw[no_case[symbol_]] >> ','

打印

Parsed: (42;sTrInG3;more names or stuff;6.7)

赛斯在评论中鼓励我也发布我的答案后,它就在这里了。正如预期的那样,它非常相似,只是我从传递给语法的std::array中动态构建符号。

#include <iostream>
#include <string>
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/include/qi.hpp>
struct employee {
int age;
std::string surname;
std::string forename;
double salary;
};
BOOST_FUSION_ADAPT_STRUCT(employee, age, surname, forename, salary)
namespace ascii = boost::spirit::ascii;
namespace qi = boost::spirit::qi;
template <typename Iterator, std::size_t N>
struct employee_parser : qi::grammar<Iterator, employee(), ascii::space_type> {
employee_parser(std::array<std::string, N> const &match_list)
: employee_parser::base_type(start) {
using namespace qi;
for (auto match : match_list) {
employees.add(match, match);
}
quoted_string %= lexeme['"' >> +(char_ - '"') >> '"'];
start %=
lit("employee")
>> '{'
>>  int_ >> ','
>>  quoted_string >> ','
>>  employees >> ','
>>  double_
>>  '}'
;
}
qi::rule<Iterator, std::string(), ascii::space_type> quoted_string;
qi::rule<Iterator, employee(), ascii::space_type> start;
qi::symbols<typename std::iterator_traits<Iterator>::value_type,
std::string> employees;
};
template <typename Iterator, std::size_t N>
employee parse(Iterator first, Iterator last,
std::array<std::string, N> const &match_list) {
employee_parser<Iterator, N> const grammar(match_list);
employee e;
bool r = qi::phrase_parse(first, last, grammar, ascii::space, e);
if (!r || first != last) {
std::cerr << "Parsing failed at " + std::string(first, last) + "n";
}
return e;
}
int main() {
employee e;
std::array<std::string, 4> match_list = {"Homer", "Marge", "Lisa", "Bart"};
std::string homer = "employee { 38, "Simpson", Homer, 3.0 }";
e = parse(homer.begin(), homer.end(), match_list);
std::cout << "employee { " << e.age << ", " << e.surname << ", "
<< e.forename << ", " << e.salary << " }n";
// Fails parsing because Hans Mole is not in the list
std::string mole = "employee { 100, "Mole", Hans, 0.0 }";
e = parse(mole.begin(), mole.end(), match_list);
std::cout << "employee { " << e.age << ", " << e.surname << ", "
<< e.forename << ", " << e.salary << " }n";
}
$ clang++ -Wall -Wextra -Wpedantic -std=c++11 test.cpp
$ ./a.out 
employee { 38, Simpson, Homer, 3 }
Parsing failed at employee { 100, "Mole", Hans, 0.0 }
employee { 100, Mole, , 0 }

以下也是霍默工资3.0的参考:https://www.youtube.com/watch?v=HIEWgwRrY9s