【问题标题】:unhandled exception using Boost Spirit to parse grammar使用 Boost Spirit 解析语法的未处理异常
【发布时间】:2013-07-30 07:57:58
【问题描述】:

我正在尝试使用 Boost Spirit 来解析以下语法: 句子: 名词动词 连词句

连词: “和”

名词: “鸟类” “猫”

动词: “飞” “喵”

语法只包含名词>>动词规则时解析成功。 当语法被修改为包含句子>>连词>>句子规则并且我提供了一个无效的输入,例如“birds fly”而不是“birdsfly”时,我在程序运行时得到一个未处理的异常。

这是根据 boost doc 上的示例修改的代码

#define BOOST_VARIANT_MINIMIZE_SIZE
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/lex_lexertl.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_statement.hpp>
#include <boost/spirit/include/phoenix_container.hpp>
#include <iostream>
#include <string>

using namespace boost::spirit;
using namespace boost::spirit::ascii;

template <typename Lexer>
struct token_list : lex::lexer<Lexer>
{
    token_list()
    {
        noun = "birds|cats";    
        verb =  "fly|meow";
        conjunction = "and";

        this->self.add
            (noun)         
            (verb) 
            (conjunction)
        ;
    }
    lex::token_def<std::string> noun, verb, conjunction;
};

template <typename Iterator>
struct Grammar : qi::grammar<Iterator>
{
    template <typename TokenDef>
    Grammar(TokenDef const& tok)
      : Grammar::base_type(sentence)
    {
        sentence = (tok.noun>>tok.verb)
        |
        (sentence>>tok.conjunction>>sentence)>>eoi
    ;
    }
    qi::rule<Iterator> sentence;
};

int main()
{
typedef lex::lexertl::token<char const*, boost::mpl::vector<std::string>> token_type;
typedef lex::lexertl::lexer<token_type> lexer_type;
typedef token_list<lexer_type>::iterator_type iterator_type;

     token_list<lexer_type> word_count;         
     Grammar<iterator_type> g (word_count); 

     std::string str = "birdsfly"; 
 //std::string str = "birds fly"; this input caused unhandled exception

     char const* first = str.c_str();
     char const* last = &first[str.size()];

     bool r = lex::tokenize_and_parse(first, last, word_count, g);

     if (r) {
         std::cout << "Parsing passed"<< "\n";
     }
     else {
         std::string rest(first, last);
         std::cerr << "Parsing failed\n" << "stopped at: \"" 
                   << rest << "\"\n";
     }
    system("PAUSE");
    return 0;
}

【问题讨论】:

    标签: c++ boost-spirit boost-spirit-qi boost-spirit-lex


    【解决方案1】:

    您在sentence 规则的第二个分支中有左递归。

    sentence = sentence >> ....
    

    总是会在句子上递归,所以你会看到一个stackoverflow。

    我建议写这样的规则,例如:

    sentence = 
          (tok.noun >> tok.verb) 
      >> *(tok.conjunction >> sentence) 
      >> qi::eoi
      ;
    

    现在结果显示

    g++ -Wall -pedantic -std=c++0x -g -O0 test.cpp -o test
    Parsing failed
    stopped at: " fly"
    

    (当然还有不可避免的“sh: PAUSE: command not found”...)

    PS.请不要using namespace。而是:

    namespace qi  = boost::spirit::qi;
    namespace lex = boost::spirit::lex;
    

    这是一个删除/修复了一些其他内容的清理版本:http://coliru.stacked-crooked.com/view?id=1fb26ca3e8c207979eaaf4592c319316-e223fd4a885a77b520bbfe69dda8fb91

    #define BOOST_VARIANT_MINIMIZE_SIZE
    #include <boost/spirit/include/qi.hpp>
    #include <boost/spirit/include/lex_lexertl.hpp>
    // #include <boost/spirit/include/phoenix.hpp>
    #include <iostream>
    #include <string>
    
    namespace qi  = boost::spirit::qi;
    namespace lex = boost::spirit::lex;
    
    template <typename Lexer>
    struct token_list : lex::lexer<Lexer>
    {
        token_list()
        {
            noun        = "birds|cats";    
            verb        = "fly|meow";
            conjunction = "and";
    
            this->self.add
                (noun)         
                (verb) 
                (conjunction)
            ;
        }
    
        lex::token_def<std::string> noun, verb, conjunction;
    };
    
    template <typename Iterator>
    struct Grammar : qi::grammar<Iterator>
    {
        template <typename TokenDef>
        Grammar(TokenDef const& tok) : Grammar::base_type(sentence)
        {
            sentence = 
                  (tok.noun >> tok.verb) 
              >> *(tok.conjunction >> sentence) 
              >> qi::eoi
              ;
        }
        qi::rule<Iterator> sentence;
    };
    
    int main()
    {
        typedef std::string::const_iterator It;
        typedef lex::lexertl::token<It, boost::mpl::vector<std::string>> token_type;
        typedef lex::lexertl::lexer<token_type> lexer_type;
        typedef token_list<lexer_type>::iterator_type iterator_type;
    
        token_list<lexer_type> word_count;         
        Grammar<iterator_type> g(word_count); 
    
        //std::string str = "birdsfly"; 
        const std::string str = "birds fly";
    
        It first = str.begin();
        It last  = str.end();
    
        bool r = lex::tokenize_and_parse(first, last, word_count, g);
    
        if (r) {
            std::cout << "Parsing passed"<< "\n";
        }
        else {
            std::string rest(first, last);
            std::cerr << "Parsing failed\n" << "stopped at: \"" << rest << "\"\n";
        }
    }
    

    【讨论】:

    • 咳咳,SO.com 精神大师又来了 :)
    • @cv_and_he 我估计他准备好后会回来的。让我们不要推动 OP - 因为如果我们为他填写详细信息,他只会错过细节并且无法理解。 编辑无论如何,感谢您挖掘 a relevant reference,以防他想过去。抱歉,如果我建议您的评论不受欢迎。很受欢迎。
    • 请停止擦除历史记录。
    猜你喜欢
    • 2011-03-05
    • 2022-11-16
    • 1970-01-01
    • 1970-01-01
    • 2017-10-30
    • 2021-10-28
    • 1970-01-01
    • 1970-01-01
    • 2015-01-25
    相关资源
    最近更新 更多