防止 Boost Spirit Symbol 解析器过早接受关键字

Posted

技术标签:

【中文标题】防止 Boost Spirit Symbol 解析器过早接受关键字【英文标题】:Prevent the Boost Spirit Symbol parser from accepting a keyword too early 【发布时间】:2014-03-24 11:41:00 【问题描述】:

如何防止 Boost Spirit Symbol 解析器在以有效关键字(符号)开头时接受关键字(符号)。我希望该构造无法整体解析“ONEMORE”并且无法成功解析“ONE”,因为这是一个有效的关键字,然后在“MORE”上失败。

下面是代码的实际输出:

Keyword as a number: 1
Keyword as a number: 2
Keyword as a number: 1
Invalid keyword: MORETHREE

这就是我喜欢的样子:

Keyword as a number: 1
Keyword as a number: 2
Invalid keyword: ONEMORE
Keyword as a number: 3

代码只是说明问题的一个示例。

#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <iostream>
#include <string>

using namespace std;
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;

void printNumber( unsigned u )

    cout << "Keyword as a number: " << u << endl;


void printInvalidKeyword( const string &s )

    cout << "Invalid keyword: " << s << endl;


template <typename Iterator>
struct keyword_parser : qi::grammar<Iterator, ascii::space_type>

    struct mySymbols_ : qi::symbols<char, unsigned>
    
        mySymbols_()
        
            add
            ("ONE"   , 1)
            ("TWO"   , 2)
            ("THREE" , 2)
            ;
        

     mySymbols;

    keyword_parser() : keyword_parser::base_type(start)
    
        using qi::_1;
        using qi::raw;
        using ascii::char_;

        start %= *(
                   mySymbols[&printNumber]
                    |
                   invalid[&printInvalidKeyword]
                   );

        invalid = +char_;

    

    qi::rule<Iterator, ascii::space_type> start;
    qi::rule<Iterator, std::string(), ascii::space_type> invalid;
;

int main()

    using boost::spirit::ascii::space;
    typedef std::string::const_iterator iterator_type;
    typedef keyword_parser<iterator_type> keyword_parser;

    std::string s = "ONE TWO ONEMORE THREE";
    iterator_type b = s.begin();
    iterator_type e = s.end();
    phrase_parse(b, e, keyword_parser(), space);

    return 0;

【问题讨论】:

【参考方案1】:

qi::repository::distinct或自己采取一些措施:

start %= *(
           keyword  [cout << val("Keyword as a number: ") << _1 << endl]
         | invalid  [cout << val("Invalid keyword: ")     << _1 << endl]
         );

keyword = mySymbols >> !(char_("a-zA-Z0-9_"));

invalid = +ascii::graph;

被声明为的规则

qi::rule<Iterator, ascii::space_type> start;

// lexemes do not ignore embedded skippables
qi::rule<Iterator, int()> keyword;
qi::rule<Iterator, std::string()> invalid;

Live On Coliru

打印:

Keyword as a number: 1
Keyword as a number: 2
Invalid keyword: ONEMORE
Keyword as a number: 2

完整来源:

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <iostream>
#include <string>

using namespace std;
namespace qi    = boost::spirit::qi;
namespace phx   = boost::phoenix;
namespace ascii = boost::spirit::ascii;

template <typename Iterator>
struct keyword_parser : qi::grammar<Iterator, ascii::space_type>

    struct mySymbols_ : qi::symbols<char, unsigned>
    
        mySymbols_()
        
            add
            ("ONE"   , 1)
            ("TWO"   , 2)
            ("THREE" , 2)
            ;
        

     mySymbols;

    keyword_parser() : keyword_parser::base_type(start)
    
        using qi::_1;
        using ascii::char_;
        using phx::val;

        start %= *(
                   keyword  [cout << val("Keyword as a number: ") << _1 << endl]
                 | invalid  [cout << val("Invalid keyword: ")     << _1 << endl]
                 );

        keyword = mySymbols >> !(char_("a-zA-Z0-9_"));

        invalid = +ascii::graph;

    

    qi::rule<Iterator, ascii::space_type> start;
    // lexemes do not ignore embedded skippables
    qi::rule<Iterator, int()> keyword;
    qi::rule<Iterator, std::string()/*IMPLICIT LEXEME:, ascii::space_type*/> invalid;
;

int main()

    using boost::spirit::ascii::space;
    typedef std::string::const_iterator iterator_type;
    typedef keyword_parser<iterator_type> keyword_parser;

    std::string s = "ONE TWO ONEMORE THREE";
    iterator_type b = s.begin();
    iterator_type e = s.end();
    phrase_parse(b, e, keyword_parser(), space);

    return 0;

【讨论】:

有些事情很简单,除非你看不到它:-) 谢谢。

以上是关于防止 Boost Spirit Symbol 解析器过早接受关键字的主要内容,如果未能解决你的问题,请参考以下文章

使用 boost-spirit 解析 ipv4 地址

使用 boost::spirit::x3 解析成向量<boost::string_view>

boost::spirit 解析器的编译错误

boost::spirit 算术公式解析器无法编译

Boost:spirit 解析成结构并重用部分结构

无法使用 Boost Spirit X3 解析空的 C++ 结构