我尝试使用Boost :: Spirit解析带有转义序列的带引号的字符串。不幸的是,似乎在语法定义中包含引号会导致大量(非常无用的)编译时错误(正如人们对Boost所期望的那样)。省略引号可以让程序编译,但显然它不会像它应该的那样表现出来。这是代码(实际上是更大图片的一部分,但它证明了这个问题):
#include "boost/spirit/include/qi.hpp"
#include "boost/proto/deep_copy.hpp"
#include "boost/optional.hpp"
#include <string>
using boost::spirit::qi::char_;
using boost::spirit::qi::lexeme;
using boost::proto::deep_copy;
auto string_literal = deep_copy(
lexeme[
// char_('"')
/* >> */ *((char_ - '"' - '\\') | (char_('\\') >> char_))
// >> char_('"')
]);
template <class Iterator, class Grammar>
boost::optional<std::string> parse_string(Iterator first, Iterator last, Grammar&& gr)
{
using boost::spirit::qi::space;
using boost::spirit::qi::phrase_parse;
std::string temp;
bool success = phrase_parse(
first,
last,
gr,
space,
temp
);
if (first == last && success)
return temp;
else return boost::none;
}
int main()
{
std::string str;
std::cout << "string_literal: ";
getline(std::cin, str);
auto presult = parse_string(str.begin(), str.end(), string_literal);
if (presult) {
std::cout << "parsed: " << *presult;
} else
std::cout << "failure\n";
return 0;
}
取消注释string_literal
定义的注释部分会导致错误。在其当前状态(带注释)中,代码编译。我已经尝试了一些事情,例如将引号移动到parse_string
,以及使用不太具体的定义(上面的那个是我能提出的最不具体的,仍然有用,正确的语法是在OCaml language manual,但我想我可以单独验证转义序列),但没有任何效果。
My Boost版本是1.56.0,我的编译器是MinGW-w64 g ++ 4.9.1。任何帮助都是最受欢迎的。
答案 0 :(得分:1)
我花了一点时间才看到它。
问题是 - 最终 - 事实是 [1]
(qi::char_('\\') >> qi::char_) | (qi::char_ - '"')
合成
boost::variant<
boost::fusion::vector2<char, char>,
char>
而不是,正如您可能期望char
或std::vector<char>
。 Spirit的属性兼容性规则接近 magic ,它们让你逃脱它(这非常漂亮),但它也隐藏了你的意识中的问题。
当你进一步复杂化规则时,只会抱怨它。
现在我可以看到两条可能的路径:要么返回 de-escaped 字符串值(不带引号),要将其更改为: [2] < /强>
qi::lexeme [
'"' >>
*(('\\' >> qi::char_) | (qi::char_ - '"'))
>> '"'
]
或 您想要使用引号捕获原始字符串,而您根本不关心公开的属性:
qi::raw [
'"' >>
*(('\\' >> qi::char_) | (qi::char_ - '"'))
>> '"'
]
后者使用从源 - 迭代器对(qi::raw[]
)到std::string
的隐式属性转换(绑定属性)。
查看完整的内容:
<强> Live On Coliru 强>
#include <boost/spirit/include/qi.hpp>
#include <boost/proto/deep_copy.hpp>
#include <boost/optional.hpp>
#include <string>
namespace qi = boost::spirit::qi;
namespace {
auto string_literal = boost::proto::deep_copy(
#if 1
qi::lexeme [
'"' >>
*(('\\' >> qi::char_) | (qi::char_ - '"'))
>> '"'
]
#else
qi::raw [
'"' >>
*(('\\' >> qi::char_) | (qi::char_ - '"'))
>> '"'
]
#endif
);
}
template <class Iterator, class Grammar>
boost::optional<std::string> parse_string(Iterator first, Iterator last, Grammar&& gr)
{
std::string temp;
bool success = qi::phrase_parse(
first,
last,
std::forward<Grammar>(gr),
qi::space,
temp
);
if (success && first == last)
return temp;
else return boost::none;
}
int main()
{
std::string str;
std::cout << "string_literal: ";
getline(std::cin, str);
auto presult = parse_string(str.begin(), str.end(), string_literal);
if (presult) {
std::cout << "parsed: '" << *presult << "'\n";
} else
std::cout << "failure\n";
return 0;
}
[1]
[2] (请注意'\\'
等同于qi::lit('\\')
表达式模板操作数的隐式转换)