【问题标题】:Boost::Spirit::Qi - Splitting rules into separate classesBoost::Spirit::Qi - 将规则拆分为单独的类
【发布时间】:2015-03-24 15:17:32
【问题描述】:

我想将我的规则(制作)分成单独的类。我在 Boost::Spirit::Qi 中找不到任何这样做的例子。

Boost 示例都显示了一个语法类中的规则。

这是我的语法:

<start> ::= @ ( <event_bool_no_param> )
<event_bool_no_param> ::= RAMPING_COMPLETED | STATE_TIMEOUT  

这是我的语法课:

template <typename Iterator, typename Skipper>
struct Event_Grammar
    : boost::spirit::qi::grammar<Iterator, Skipper>
{
    Event_Grammar() : Event_Grammar::base_type(start)
        {
            using boost::spirit::ascii::char_;
            using boost::spirit::qi::eps;

            start = 
                (
                    char_('@') >> char_('(') >> Event_Bool_No_Param<Iterator>() >> char_(')')
                )
                ;

        }
    boost::spirit::qi::rule<Iterator, Skipper> start;
};

这是我的另一个语法课:

template <typename Iterator>
struct Event_Bool_No_Param
    : qi::grammar<Iterator>
{
    Event_Bool_No_Param () 
        : Event_Bool_No_Param::base_type(start)
        {
            using qi::lexeme;
            using qi::lit;

            start =
                lit("STATE_TIMEOUT") | lit("RAMPING_COMPLETED") | lit("PASSIVE_MEAS_COMPLETED")
                ;
        }
    qi::rule<Iterator> start;
};

我收到一个未处理的异常错误,文本为“@ ( STATE_TIMEOUT )”。

这是顶部(最近的)堆栈跟踪:

Event_Grammar.exe!boost::spirit::qi::sequence_base<boost::spirit::qi::sequence<boost::fusion::cons<boost::spirit::qi::literal_char<boost::spirit::char_encoding::ascii,0,0>,boost::fusion::cons<boost::spirit::qi::literal_char<boost::spirit::char_encoding::ascii,0,0>,boost::fusion::cons<boost::spirit::qi::reference<boost::spirit::qi::rule<std::_String_const_iterator<char,std::char_traits<char>,std::allocator<char> >,boost::spirit::unused_type,boost::spirit::unused_type,boost::spirit::unused_type,boost::spirit::unused_type> const >,boost::fusion::cons<boost::spirit::qi::literal_char<boost::spirit::char_encoding::ascii,0,0>,boost::fusion::nil_> > > > >,boost::fusion::cons<boost::spirit::qi::literal_char<boost::spirit::char_encoding::ascii,0,0>,boost::fusion::cons<boost::spirit::qi::literal_char<boost::spirit::char_encoding::ascii,0,0>,boost::fusion::cons<boost::spirit::qi::reference<boost::spirit::qi::rule<std::_String_const_iterator<char,std::char_traits<char>,std::allocator<char> >,boost::spirit::unused_type,boost::spirit::unused_type,boost::spirit::unused_type,boost::spirit::unused_type> const >,boost::fusion::cons<boost::spirit::qi::literal_char<boost::spirit::char_encoding::ascii,0,0>,boost::fusion::nil_> > > > >::parse_impl<std::_String_const_iterator<char,std::char_traits<char>,std::allocator<char> >,boost::spirit::context<boost::fusion::cons<boost::spirit::unused_type &,boost::fusion::nil_>,boost::fusion::vector0<void> >,boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space,boost::spirit::char_encoding::ascii> >,boost::spirit::unused_type>(std::_String_const_iterator<char,std::char_traits<char>,std::allocator<char> > & first, const std::_String_const_iterator<char,std::char_traits<char>,std::allocator<char> > & last, boost::spirit::context<boost::fusion::cons<boost::spirit::unused_type &,boost::fusion::nil_>,boost::fusion::vector0<void> > & context, const boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space,boost::spirit::char_encoding::ascii> > & skipper, boost::spirit::unused_type & attr_, boost::mpl::bool_<0> __formal)  Line 88 + 0x55 bytes C++
    Event_Grammar.exe!boost::spirit::qi::sequence_base<boost::spirit::qi::sequence<boost::fusion::cons<boost::spirit::qi::literal_char<boost::spirit::char_encoding::ascii,0,0>,boost::fusion::cons<boost::spirit::qi::literal_char<boost::spirit::char_encoding::ascii,0,0>,boost::fusion::cons<boost::spirit::qi::reference<boost::spirit::qi::rule<std::_String_const_iterator<char,std::char_traits<char>,std::allocator<char> >,boost::spirit::unused_type,boost::spirit::unused_type,boost::spirit::unused_type,boost::spirit::unused_type> const >,boost::fusion::cons<boost::spirit::qi::literal_char<boost::spirit::char_encoding::ascii,0,0>,boost::fusion::nil_> > > > >,boost::fusion::cons<boost::spirit::qi::literal_char<boost::spirit::char_encoding::ascii,0,0>,boost::fusion::cons<boost::spirit::qi::literal_char<boost::spirit::char_encoding::ascii,0,0>,boost::fusion::cons<boost::spirit::qi::reference<boost::spirit::qi::rule<std::_String_const_iterator<char,std::char_traits<char>,std::allocator<char> >,boost::spirit::unused_type,boost::spirit::unused_type,boost::spirit::unused_type,boost::spirit::unused_type> const >,boost::fusion::cons<boost::spirit::qi::literal_char<boost::spirit::char_encoding::ascii,0,0>,boost::fusion::nil_> > > > >::parse<std::_String_const_iterator<char,std::char_traits<char>,std::allocator<char> >,boost::spirit::context<boost::fusion::cons<boost::spirit::unused_type &,boost::fusion::nil_>,boost::fusion::vector0<void> >,boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space,boost::spirit::char_encoding::ascii> >,boost::spirit::unused_type>(std::_String_const_iterator<char,std::char_traits<char>,std::allocator<char> > & first, const std::_String_const_iterator<char,std::char_traits<char>,std::allocator<char> > & last, boost::spirit::context<boost::fusion::cons<boost::spirit::unused_type &,boost::fusion::nil_>,boost::fusion::vector0<void> > & context, const boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space,boost::spirit::char_encoding::ascii> > & skipper, boost::spirit::unused_type & attr_)  Line 125 C++
    Event_Grammar.exe!boost::spirit::qi::detail::parser_binder<boost::spirit::qi::sequence<boost::fusion::cons<boost::spirit::qi::literal_char<boost::spirit::char_encoding::ascii,0,0>,boost::fusion::cons<boost::spirit::qi::literal_char<boost::spirit::char_encoding::ascii,0,0>,boost::fusion::cons<boost::spirit::qi::reference<boost::spirit::qi::rule<std::_String_const_iterator<char,std::char_traits<char>,std::allocator<char> >,boost::spirit::unused_type,boost::spirit::unused_type,boost::spirit::unused_type,boost::spirit::unused_type> const >,boost::fusion::cons<boost::spirit::qi::literal_char<boost::spirit::char_encoding::ascii,0,0>,boost::fusion::nil_> > > > >,boost::mpl::bool_<0> >::call<std::_String_const_iterator<char,std::char_traits<char>,std::allocator<char> >,boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space,boost::spirit::char_encoding::ascii> >,boost::spirit::context<boost::fusion::cons<boost::spirit::unused_type &,boost::fusion::nil_>,boost::fusion::vector0<void> > >(std::_String_const_iterator<char,std::char_traits<char>,std::allocator<char> > & first, const std::_String_const_iterator<char,std::char_traits<char>,std::allocator<char> > & last, boost::spirit::context<boost::fusion::cons<boost::spirit::unused_type &,boost::fusion::nil_>,boost::fusion::vector0<void> > & context, const boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space,boost::spirit::char_encoding::ascii> > & skipper, boost::mpl::bool_<0> __formal)  Line 44    C++

这是发生异常的代码位置,function_template.hpp#761:

result_type operator()(BOOST_FUNCTION_PARMS) const
{
  if (this->empty())
    boost::throw_exception(bad_function_call());

  return get_vtable()->invoker
           (this->functor BOOST_FUNCTION_COMMA BOOST_FUNCTION_ARGS);
}

所以,我的问题是:

  1. 所有规则都需要在单个语法类中吗?
  2. 如何在规则中引用语法类?
  3. 我在上述课程中的错误在哪里?

我正在使用:

  • 提升 1.57.0
  • Visual Studio 2010
  • Windows 7

【问题讨论】:

  • 完全猜测(我没有使用这个版本的升压精神),也许你的Event_Bool_No_Param&lt;Iterator&gt; 的生命周期需要坚持?看看是否有一个指向该子语法的(智能)指针存储在Event_Grammar 中,看看你的问题是否消失了?
  • @Yakk:谢谢你关于变量的提示。

标签: c++ parsing boost grammar boost-spirit-qi


【解决方案1】:

首先是问题:

  1. 所有规则都需要在单个语法类中吗?

    绝对不是。语法只是一种将规则组合在一起并在需要时提供额外状态的机制。语法只是一个类/结构,因此它是封装语法概念的非常方便的工具。

  2. 如何在规则中引用语法类?

    您需要一个语法实例。暂时的会引起悲伤。

  3. 我在上面的课程中的错误在哪里?

    错误在于您在构建规则时创建了临时对象。您想要一个将组合成其他语法和规则的语法(或规则)实例。

例如:

Live On Coliru

#include <boost/spirit/home/qi.hpp>
namespace qi    = boost::spirit::qi;
namespace ascii = boost::spirit::qi::ascii;

template <typename Iterator>
struct Event_Bool_No_Param : qi::grammar<Iterator>
{
    Event_Bool_No_Param () 
        : Event_Bool_No_Param::base_type(start)
    {
        using qi::lit;

        start =
            lit("STATE_TIMEOUT") | lit("RAMPING_COMPLETED") | lit("PASSIVE_MEAS_COMPLETED")
            ;
    }
    qi::rule<Iterator> start;
};


template <typename Iterator, typename Skipper>
struct Event_Grammar : boost::spirit::qi::grammar<Iterator, Skipper>
{
    Event_Grammar() : Event_Grammar::base_type(start)
    {
        using boost::spirit::ascii::char_;

        start = 
            char_('@') >> char_('(') >> event_no_param >> char_(')')
            ;

    }
    qi::rule<Iterator, Skipper> start;
    Event_Bool_No_Param<Iterator> event_no_param;
};

int main()
{
    using iterator_t = std::string::const_iterator;
    std::string input = "@ ( STATE_TIMEOUT )";
    iterator_t iter = input.begin();
    iterator_t end = input.end();

    Event_Grammar<iterator_t,ascii::space_type> grammar;   

    bool ok = qi::phrase_parse( iter, end
            , grammar
            , ascii::space
            );

    return ok? 0 : 255;
}

哪个或?

至于使用哪个 OR 符号,||| 不是一回事。你很可能想要|

| - 是另一种选择。

A | B | C

  • 解析ABC

|| - 是顺序或运算符 (sequential or)

A || B * 解析A 后跟可选的B 或解析B

    A >> -B | B

【讨论】:

  • “语法只是一种将规则组合在一起并在需要时提供额外状态的机制。”。我一直将grammar 视为对相同类型参数(例如IteratorSkipper)的一组规则进行参数化的一种方式。如果不需要通用性,可以保留“免费”规则变量。
【解决方案2】:

这里有两个问题,对我来说并不明显:

  • 语法变量
  • 使用“||”而不是“|”。

语法实例

规则可以使用其他语法,但需要有其他语法的实例。

Event_Grammar 类现在看起来像:

    #include "event_bool_no_param.hpp"

    template <typename Iterator, typename Skipper>
    struct Event_Grammar
        : boost::spirit::qi::grammar<Iterator, Skipper>
    {
        Event_Grammar() : Event_Grammar::base_type(start)
            {
                using boost::spirit::ascii::char_;
                using boost::spirit::qi::eps;
                using qi::lit;

// Notice the identifier "grammar_bool_no_param"
// which is an instance of the grammer / rule Event_Bool_No_Param.
                start = 
                    (
                        char_('@') >> char_('(') >> grammar_bool_no_param >> char_(')')
                    )
                    ;

            }

        // *** A rule or grammar needs an instance!
        Event_Bool_No_Param<Iterator>               grammar_bool_no_param;
        boost::spirit::qi::rule<Iterator, Skipper>  start;
    };

正确的“或”符号

在规则中,“OR”的符号是"||" 而不是"|"

template <typename Iterator>
struct Event_Bool_No_Param
    : qi::grammar<Iterator>
{
    Event_Bool_No_Param () 
        : Event_Bool_No_Param::base_type(start)
        {
            using qi::lexeme;
            using qi::lit;

            start =
                lit("STATE_TIMEOUT") || lit("RAMPING_COMPLETED") || lit("PASSIVE_MEAS_COMPLETED")
                ;
        }
    qi::rule<Iterator> start;
};

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-04
    相关资源
    最近更新 更多