Attempting to parse SQL like statement with Boost-Spirit

前端 未结 1 1452
隐瞒了意图╮
隐瞒了意图╮ 2021-01-22 22:53

I\'m a newbie in boost::spirit. I wrote the program to parse a SQL statement, like \"select * from table where conditions\". It compile failed. A large of template errors repor

相关标签:
1条回答
  • 2021-01-22 23:38

    Edit Finally behind a computer, revised answer:

    There were three things to note

    1. Syntax errors

    The parser expression contained errors (<< instead of >> as intended). This accounts for a lot of compile errors. Note the appearance of ******* in the compiler error:

    /.../qi/nonterminal/rule.hpp|176 col 13| error: no matching function for call to ‘assertion_failed(mpl_::failed************ 
    

    which is designed to lead you to the corresponding comment in the source code:

    // Report invalid expression error as early as possible.
    // If you got an error_invalid_expression error message here,
    // then the expression (expr) is not a valid spirit qi expression.
    BOOST_SPIRIT_ASSERT_MATCH(qi::domain, Expr);
    

    Easily fixed. One down, two to go!

    2. Adapting the struct

    In order to assign to your datatype as an rule attribute, you need to make it fusion compatible. The most convenient way:

     BOOST_FUSION_ADAPT_STRUCT(db_select,
        (std::string,field)(std::string,table)(std::string,condition));
    

    Now the code compiles. But the parsing fails. One more to go:

    3. Lexemes

    Further more you will need to take measures to avoid 'eating' your query keywords with the +qi::char_ expressions.

    As a basis, consider writing it something like

       lexeme [  (!lit("where")  >> +qi::graph) % +qi::space ]
    
    • lexeme inhibits the skipper for the enclosed expression
    • ! Asserts that the specified keyword must not match

    Lastly, look at the docs for qi::no_case to do case-insensitive matching.

    FULL CODE

    #include <iostream>
    #include <string>
    #include <boost/fusion/adapted.hpp>
    #include <boost/spirit/include/qi.hpp>
    
    namespace qi = boost::spirit::qi;
    
    struct db_select {
        void exec() {}
    
        std::string field;
        std::string table;
        std::string condition;
    };
    
    BOOST_FUSION_ADAPT_STRUCT(db_select,(std::string,field)(std::string,table)(std::string,condition));
    
    std::ostream& operator<<(std::ostream& os, const db_select& se) {
        return os << "field: " << se.field << " table: " << se.table << " condition: " << se.condition;
    }
    
    template <class Iterator>
    struct selecter : qi::grammar<Iterator, db_select (), qi::space_type> {
        selecter() : selecter::base_type(se) {
            using namespace qi;
            se %= "select"
                >> lexeme [ (!lit("from")  >> +graph) % +space ] >> "from"
                >> lexeme [ (!lit("where") >> +graph) % +space ] >> "where" 
                >> +qi::char_;
        } 
    
        qi::rule<Iterator, db_select (), qi::space_type> se;
    };
    
    int main(int argc, char* argv[]) {
        if (argc < 2)
                return -1;
    
        std::string str(argv[1]);
        const char* first = str.c_str();
        const char* last = &str[str.size()];
        selecter<const char*> se;
        db_select rst;
    
        bool r = qi::phrase_parse(first, last, se, qi::space, rst);
        if (!r || first != last) {
                std::cout << "parse failed, at: " << std::string(first, last) << std::endl;
                return -1;
        } else
                std::cout << "success, " << rst << std::endl;
    
        return 0;
    }
    

    Test:

    g++ test.cpp -o test
    ./test "select aap, noot, mies from table where field = 'value'"
    

    Output:

    success, field: aap,noot,mies table: table condition: field='value'
    
    0 讨论(0)
提交回复
热议问题