2

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 reported. So, would somebody help me?

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

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

struct db_select {
    void exec() {}

    std::string filed;
    std::string table;
    std::string condition;
};

std::ostream& operator<<(std::ostream& os, const db_select& se) {
    return os << "filed: " << se.filed << " table: " << se.table << " condition: " << se.condition;
}

template <class Iterator>
struct selecter : qi::grammar<Iterator, db_select (), ascii::space_type> {
    selecter() : selecter::base_type(se) {
            se %= "select" >> +qi::char_ << "from" << +qi::char_ << "where" << +qi::char_;
    } 

    qi::rule<Iterator, db_select (), ascii::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, ascii::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;
}
superK
  • 3,932
  • 6
  • 30
  • 54
  • I fixed my answer. I missed a syntax error (my brain is not the best C++ compiler). So now, in three steps my answer leads to a working full sample. – sehe Apr 26 '12 at 22:21

1 Answers1

5

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'
sehe
  • 374,641
  • 47
  • 450
  • 633