[英]Simple expression with boost::spirit
I need to parse simple_expression ::= limit int_number (days | hours | minutes)
. 我需要解析
simple_expression ::= limit int_number (days | hours | minutes)
。 I wrote code for grammar 我编写了语法代码
struct Parser: grammar<std::string::const_iterator, boost::spirit::ascii::space_type>
{
public:
Parser(ConditionTree& a_lTree):
Parser::base_type(limit_expression),
m_lTree(a_lTree)
{
using boost::spirit::qi::uint_;
using boost::spirit::qi::_1;
using boost::spirit::qi::_2;
limit_expression = limit_days_operator | limit_hours_operator | limit_minutes_operator ;
limit_days_operator = ( string("limit") > uint_ > string("days") )[ phoenix::bind( &ConditionTree::AddDaysLimitOperator, m_lTree, _2) ] ;
limit_hours_operator = ( string("limit") > uint_ > string("hours") )[ phoenix::bind( &ConditionTree::AddHoursLimitOperator, m_lTree, _2) ] ;
limit_minutes_operator = ( string("limit") > uint_ > string("minutes") )[ phoenix::bind( &ConditionTree::AddMinutesLimitOperator, m_lTree, _2) ] ;
BOOST_SPIRIT_DEBUG_NODE(limit_expression);
BOOST_SPIRIT_DEBUG_NODE(limit_days_operator);
BOOST_SPIRIT_DEBUG_NODE(limit_hours_operator);
BOOST_SPIRIT_DEBUG_NODE(limit_minutes_operator);
}
rule<std::string::const_iterator, boost::spirit::ascii::space_type> limit_expression;
rule<std::string::const_iterator, boost::spirit::ascii::space_type> limit_days_operator;
rule<std::string::const_iterator, boost::spirit::ascii::space_type> limit_hours_operator;
rule<std::string::const_iterator, boost::spirit::ascii::space_type> limit_minutes_operator;
ConditionTree& m_lTree;
}
void main()
{
ConditionTree oTree;
Parser parser(oTree);
std::string strTest("limit5minutes");
std::string::const_iterator it_begin(strTest.begin());
std::string::const_iterator it_end(strTest.end());
bool result = phrase_parse(it_begin, it_end, parser, space);
}
But it can't compile with following 2 errors: /usr/include/boost/spirit/home/support/argument.hpp:103: ошибка: no matching function for call to 'assertion_failed(mpl_::failed************ (boost::spirit::result_of::get_arg<boost::fusion::vector1<unsigned int&>, 1>::index_is_out_of_bounds::************)())'
但它无法编译以下2个错误:
/usr/include/boost/spirit/home/support/argument.hpp:103: ошибка: no matching function for call to 'assertion_failed(mpl_::failed************ (boost::spirit::result_of::get_arg<boost::fusion::vector1<unsigned int&>, 1>::index_is_out_of_bounds::************)())'
/usr/include/boost/spirit/home/phoenix/bind/detail/member_function_ptr.hpp:103: ошибка: invalid initialization of reference of type 'const unsigned int&' from expression of type 'mpl_::void_'
on line limit_days_operator = ( string("limit") > uint_ > string("days") )[ phoenix::bind( &ConditionTree::AddDaysLimitOperator, m_lTree, _2) ] ;
on line
limit_days_operator = ( string("limit") > uint_ > string("days") )[ phoenix::bind( &ConditionTree::AddDaysLimitOperator, m_lTree, _2) ] ;
I tryed to move semantic action to uint_ : 我试着将语义动作移到uint_:
limit_days_operator = string("limit") > uint_ [ phoenix::bind( &ConditionTree::AddDaysLimitOperator, m_lTree, _1) ] > string("days") ;
limit_hours_operator = string("limit") > uint_ [ phoenix::bind( &ConditionTree::AddHoursLimitOperator, m_lTree, _1) ] > string("hours") ;
Then the parser correctly read limit5days
, but not correctly limit5minutes
, because, as I see, it can't differ limit5days
from limit5hours
. 然后解析器读取正确
limit5days
,但不能正确limit5minutes
,因为,因为我看到,它无法区别limit5days
从limit5hours
。
There's a lot going on here. 这里有很多事情要做。 However, by the time I was done fixing up little things trying to read it and make it complete (SSCCE), it compiled too: Live On Coliru
然而,当我完成一些小东西试图阅读并完成它(SSCCE)时,它也编译了: Live On Coliru
I briefly illuminate some individual points here: 我在这里简要阐述一些个别观点:
m_lTree
by value, this way you can't mutate the member. m_lTree
,这样m_lTree
成员。 phx::ref
was required here phx::ref
lit
unless you actually want to consume the value of the string as an attribute. lit
除非你真的想要将字符串的值作为属性使用。 Better yet, just write "limit" >> uint_ >> "days"
because overload overloading does the rest "limit" >> uint_ >> "days"
因为重载超载会完成其余的工作 As you've noticed there are number of anti-patterns in this grammar, making it complex: 正如您已经注意到这种语法中有许多反模式,使其变得复杂:
m_lTree
leads to Action At A Distance and tight coupling. m_lTree
导致Action At A Distance和紧耦合。 That all said, I'd simplify things by avoiding semantic actions , and separating parsing and evaluation. 总而言之,我通过避免语义动作 ,分离解析和评估来简化事情。 Simply parsing into a
Limit
struct: 只需解析为
Limit
结构:
qi::rule<Iterator, ConditionTree::Limit(), Skipper> limit_expression;
limit_expression = "limit" >> qi::uint_ >> unit_;
Handles the units without separate expression branches: 处理单元而不使用单独的表达式分支:
unit_.add("days", ConditionTree::Limit::days)
("hours", ConditionTree::Limit::hours)
("minutes", ConditionTree::Limit::minutes);
Because, now, the grammar just parses a Limit
object you can do the evaluation atomically after the parse: 因为,现在,语法只是解析一个
Limit
对象,你可以在解析之后以原子方式进行评估:
ConditionTree::Limit limit;
if (phrase_parse(iter, end, parser, ascii::space, limit))
{
AddLimit(oTree, limit);
}
Separating parsing from evaluation enables you to add things like 将解析与评估分开使您可以添加类似的内容
slightly more interestingly, allows you to write ApplyLimit
in a functional style, not mutating an object: 更有趣的是,允许您以函数式编写
ApplyLimit
,而不是改变对象:
ConditionTree ApplyLimit(ConditionTree const& ct, Limit limit) { return ct + limit; // do something here }
but most importantly: it hugely simplifies the grammar and saves you hours of your life that were better spent otherwise 但最重要的是:它极大地简化了语法,节省了你的生活时间,否则会更好
See this Live On Coliru , outputting: 看到这个Live On Coliru ,输出:
void AddLimit(ConditionTree&, ConditionTree::Limit): 5 minutes
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
struct ConditionTree {
struct Limit {
unsigned value;
enum unit_t { days, hours, minutes } unit;
};
friend void AddLimit(ConditionTree& ct, Limit limit) {
std::cout << "AddLimit: " << limit.value;
switch (limit.unit) {
case Limit::days: std::cout << " days\n"; break;
case Limit::hours: std::cout << " hours\n"; break;
case Limit::minutes: std::cout << " minutes\n"; break;
}
}
};
BOOST_FUSION_ADAPT_STRUCT(ConditionTree::Limit, (unsigned,value)(ConditionTree::Limit::unit_t,unit))
template <typename Iterator = std::string::const_iterator, typename Skipper = ascii::space_type>
struct Parser: qi::grammar<Iterator, ConditionTree::Limit(), ascii::space_type>
{
public:
Parser() : Parser::base_type(limit_expression)
{
unit_.add("days", ConditionTree::Limit::days)
("hours", ConditionTree::Limit::hours)
("minutes", ConditionTree::Limit::minutes);
limit_expression = "limit" >> qi::uint_ >> unit_;
}
qi::symbols<char, ConditionTree::Limit::unit_t> unit_;
qi::rule<Iterator, ConditionTree::Limit(), Skipper> limit_expression;
};
int main()
{
ConditionTree oTree;
Parser<> parser;
std::string strTest("limit5minutes");
std::string::const_iterator iter(strTest.begin()), end(strTest.end());
ConditionTree::Limit limit;
if (phrase_parse(iter, end, parser, ascii::space, limit))
{
AddLimit(oTree, limit);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.