规则在 1.46 boost::spirit 上工作并停止在 boost spirit 1.55 上工作
rules working on 1.46 boost::spirit and stopped working on boost spirit 1.55
constant_double_quotation_string %= char_( '"' ) >>
*( spirit::qi::string( "\\"" )[ _val += _1 ] |
( char_ - '"' ) ) >> char_( '"' );
constant_single_quotation_string %= char_( '\'' ) >>
*( spirit::qi::string( "\\'" )[ _val += _1 ] |
( char_ - '\'' ) ) >> char_( '\'' );
现在说 char 不是 class 或 gcc 4.7.2 的结构或联合类型?
您甚至没有指定 constant_single_quotation_string
规则的声明类型。
以下是一些观察结果和工作方法:
自从你
- 显然不希望合成的属性值是输入序列未转义你可以简单地使用
qi::raw[]
指令直接镜像输入序列。这样你就可以简化规则本身
您根本不需要%=
(自动规则分配)或语义操作([_val+=_1]
); ¹
相反,如果您不希望 opening/closing 引号作为一部分
的属性,只需将 qi::char_('"')
替换为 qi::lit('"')
(或者实际上,只需 '"'
)
简化版:
qi::rule<It, std::string()>
dq_literal,
sq_literal;
dq_literal = raw [ '"' >> *("\\"" | ~char_('"')) >> '"' ];
sq_literal = raw [ "'" >> *("\'" | ~char_("'")) >> "'" ];
完整演示
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
template <typename It, typename Skipper = qi::space_type>
struct my_grammar : qi::grammar<It, std::string(), Skipper> {
my_grammar() : my_grammar::base_type(start) {
using namespace qi;
start = dq_literal
| sq_literal;
dq_literal = raw [ '"' >> *("\\"" | ~char_('"')) >> '"' ];
sq_literal = raw [ "'" >> *("\'" | ~char_("'")) >> "'" ];
BOOST_SPIRIT_DEBUG_NODES(
(start)(dq_literal)(sq_literal)
)
}
private:
qi::rule<It, std::string(), Skipper> start;
// drop skipper to make these rules implicitly 'lexeme'
// see:
qi::rule<It, std::string()>
dq_literal,
sq_literal;
};
int main() {
using It = std::string::const_iterator;
my_grammar<It> g;
for (std::string const& input : {
"\"hello world\"",
"\"hello \\"world\\"\"",
"'bye world'",
"'bye \"\'world\'\"'",
"bogus" })
{
std::cout << "\n------- Parsing: " << input << '\n';
It f = input.begin(), l = input.end();
std::string result;
bool ok = qi::phrase_parse(f, l, g, qi::space, result);
if (ok)
std::cout << "Parse success: " << result << "\n";
else
std::cout << "Parse failed\n";
if (f!=l)
std::cout << "Remaining unparsed input '" << std::string(f,l) << "'\n";
}
}
正在打印:
------- Parsing: "hello world"
Parse success: "hello world"
------- Parsing: "hello \"world\""
Parse success: "hello \"world\""
------- Parsing: 'bye world'
Parse success: 'bye world'
------- Parsing: 'bye "\'world\'"'
Parse success: 'bye "\'world\'"'
------- Parsing: bogus
Parse failed
Remaining unparsed input 'bogus'
¹ 另见 Boost Spirit: "Semantic actions are evil"?
Elaborating on my
如果您真的想公开 unescaped 值,我建议:
- 不使用
raw
(显然,因为我们不希望在存在转义字符的情况下反映确切的输入序列)
- 仍然不使用语义动作
- 而是巧妙地使用
lit('\')
来 匹配 转义字符而不将其添加到输出序列中。
在这里,我选择对两个 double-/single 引用的文字解析器使用单个规则定义。相反,我将预期的引号字符作为 inherited attribute:
传递
qi::rule<It, std::string(char)>
q_literal;
q_literal = lit(_r1) >> *('\' >> char_ | (char_ - lit(_r1))) >> lit(_r1);
start = q_literal('"') | q_literal('\'');
演示
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
template <typename It, typename Skipper = qi::space_type>
struct my_grammar : qi::grammar<It, std::string(), Skipper> {
my_grammar() : my_grammar::base_type(start) {
using namespace qi;
start = q_literal('"') | q_literal('\'');
q_literal = lit(_r1) >> *('\' >> char_ | (char_ - lit(_r1))) >> lit(_r1);
BOOST_SPIRIT_DEBUG_NODES( (start)(q_literal) )
}
private:
qi::rule<It, std::string(), Skipper> start;
// drop skipper to make these rules implicitly 'lexeme'
// see:
qi::rule<It, std::string(char)> q_literal;
};
int main() {
using It = std::string::const_iterator;
my_grammar<It> g;
for (std::string const& input : {
"\"hello world\"",
"\"hello \\"world\\"\"",
"'bye world'",
"'bye \"\'world\'\"'",
"bogus" })
{
std::cout << "\n------- Parsing: " << input << '\n';
It f = input.begin(), l = input.end();
std::string result;
bool ok = qi::phrase_parse(f, l, g, qi::space, result);
if (ok)
std::cout << "Parse success: " << result << "\n";
else
std::cout << "Parse failed\n";
if (f!=l)
std::cout << "Remaining unparsed input '" << std::string(f,l) << "'\n";
}
}
打印未转义文字:
------- Parsing: "hello world"
Parse success: hello world
------- Parsing: "hello \"world\""
Parse success: hello "world"
------- Parsing: 'bye world'
Parse success: bye world
------- Parsing: 'bye "\'world\'"'
Parse success: bye "'world'"
------- Parsing: bogus
Parse failed
Remaining unparsed input 'bogus'
constant_double_quotation_string %= char_( '"' ) >>
*( spirit::qi::string( "\\"" )[ _val += _1 ] |
( char_ - '"' ) ) >> char_( '"' );
constant_single_quotation_string %= char_( '\'' ) >>
*( spirit::qi::string( "\\'" )[ _val += _1 ] |
( char_ - '\'' ) ) >> char_( '\'' );
现在说 char 不是 class 或 gcc 4.7.2 的结构或联合类型?
您甚至没有指定 constant_single_quotation_string
规则的声明类型。
以下是一些观察结果和工作方法:
自从你
- 显然不希望合成的属性值是输入序列未转义你可以简单地使用
qi::raw[]
指令直接镜像输入序列。这样你就可以简化规则本身 您根本不需要
%=
(自动规则分配)或语义操作([_val+=_1]
); ¹相反,如果您不希望 opening/closing 引号作为一部分 的属性,只需将
qi::char_('"')
替换为qi::lit('"')
(或者实际上,只需'"'
)
简化版:
qi::rule<It, std::string()>
dq_literal,
sq_literal;
dq_literal = raw [ '"' >> *("\\"" | ~char_('"')) >> '"' ];
sq_literal = raw [ "'" >> *("\'" | ~char_("'")) >> "'" ];
完整演示
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
template <typename It, typename Skipper = qi::space_type>
struct my_grammar : qi::grammar<It, std::string(), Skipper> {
my_grammar() : my_grammar::base_type(start) {
using namespace qi;
start = dq_literal
| sq_literal;
dq_literal = raw [ '"' >> *("\\"" | ~char_('"')) >> '"' ];
sq_literal = raw [ "'" >> *("\'" | ~char_("'")) >> "'" ];
BOOST_SPIRIT_DEBUG_NODES(
(start)(dq_literal)(sq_literal)
)
}
private:
qi::rule<It, std::string(), Skipper> start;
// drop skipper to make these rules implicitly 'lexeme'
// see:
qi::rule<It, std::string()>
dq_literal,
sq_literal;
};
int main() {
using It = std::string::const_iterator;
my_grammar<It> g;
for (std::string const& input : {
"\"hello world\"",
"\"hello \\"world\\"\"",
"'bye world'",
"'bye \"\'world\'\"'",
"bogus" })
{
std::cout << "\n------- Parsing: " << input << '\n';
It f = input.begin(), l = input.end();
std::string result;
bool ok = qi::phrase_parse(f, l, g, qi::space, result);
if (ok)
std::cout << "Parse success: " << result << "\n";
else
std::cout << "Parse failed\n";
if (f!=l)
std::cout << "Remaining unparsed input '" << std::string(f,l) << "'\n";
}
}
正在打印:
------- Parsing: "hello world"
Parse success: "hello world"
------- Parsing: "hello \"world\""
Parse success: "hello \"world\""
------- Parsing: 'bye world'
Parse success: 'bye world'
------- Parsing: 'bye "\'world\'"'
Parse success: 'bye "\'world\'"'
------- Parsing: bogus
Parse failed
Remaining unparsed input 'bogus'
¹ 另见 Boost Spirit: "Semantic actions are evil"?
Elaborating on my
如果您真的想公开 unescaped 值,我建议:
- 不使用
raw
(显然,因为我们不希望在存在转义字符的情况下反映确切的输入序列) - 仍然不使用语义动作
- 而是巧妙地使用
lit('\')
来 匹配 转义字符而不将其添加到输出序列中。
在这里,我选择对两个 double-/single 引用的文字解析器使用单个规则定义。相反,我将预期的引号字符作为 inherited attribute:
传递qi::rule<It, std::string(char)>
q_literal;
q_literal = lit(_r1) >> *('\' >> char_ | (char_ - lit(_r1))) >> lit(_r1);
start = q_literal('"') | q_literal('\'');
演示
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
template <typename It, typename Skipper = qi::space_type>
struct my_grammar : qi::grammar<It, std::string(), Skipper> {
my_grammar() : my_grammar::base_type(start) {
using namespace qi;
start = q_literal('"') | q_literal('\'');
q_literal = lit(_r1) >> *('\' >> char_ | (char_ - lit(_r1))) >> lit(_r1);
BOOST_SPIRIT_DEBUG_NODES( (start)(q_literal) )
}
private:
qi::rule<It, std::string(), Skipper> start;
// drop skipper to make these rules implicitly 'lexeme'
// see:
qi::rule<It, std::string(char)> q_literal;
};
int main() {
using It = std::string::const_iterator;
my_grammar<It> g;
for (std::string const& input : {
"\"hello world\"",
"\"hello \\"world\\"\"",
"'bye world'",
"'bye \"\'world\'\"'",
"bogus" })
{
std::cout << "\n------- Parsing: " << input << '\n';
It f = input.begin(), l = input.end();
std::string result;
bool ok = qi::phrase_parse(f, l, g, qi::space, result);
if (ok)
std::cout << "Parse success: " << result << "\n";
else
std::cout << "Parse failed\n";
if (f!=l)
std::cout << "Remaining unparsed input '" << std::string(f,l) << "'\n";
}
}
打印未转义文字:
------- Parsing: "hello world"
Parse success: hello world
------- Parsing: "hello \"world\""
Parse success: hello "world"
------- Parsing: 'bye world'
Parse success: bye world
------- Parsing: 'bye "\'world\'"'
Parse success: bye "'world'"
------- Parsing: bogus
Parse failed
Remaining unparsed input 'bogus'