Attempting to parse SQL like statement with Boost-Spirit

前端 未结 1 1470
隐瞒了意图╮
隐瞒了意图╮ 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 
    #include 
    #include 
    #include 
    
    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 
    struct selecter : qi::grammar {
        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 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 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)
提交回复
热议问题