Parsing a SQL INSERT with Boost Spirit Classic
I'm trying to learn Boost Spirit and as an exercise, I've tried to parse a SQL INSERT statement
using Boost Spirit Classic.
This is the string I'm trying to parse:
INSERT INTO example_tab (cola, colb, colc, cold) VALUES (vala, valb, valc, vald);
From this SELECT example I've created this little grammar:
struct microsql_grammar : public grammar<microsql_grammar>
{
template <typename ScannerT>
struct definition
{
definition(microsql_grammar const& self)
{
keywords = "insert", "into", "values";
chlit<> LPAREN('(');
chlit<> RPAREN(')');
chlit<> SEMI(';');
chlit<> COMMA(',');
typedef inhibit_case<strlit<> > token_t;
token_t INSERT = as_lower_d["insert"];
token_t INTO = as_lower_d["into"];
token_t VALUES = as_lower_d["values"];
identifier =
nocase_d
[
开发者_JAVA百科 lexeme_d
[
(alpha_p >> *(alnum_p | '_'))
]
];
string_literal =
lexeme_d
[
ch_p('\'') >> +( anychar_p - ch_p('\'') )
>> ch_p('\'')
];
program = +(query);
query = insert_into_clause >> SEMI;
insert_into_clause = insert_clause >> into_clause;
insert_clause = INSERT >> INTO >> identifier >> LPAREN >> var_list_clause >> RPAREN;
into_clause = VALUES >> LPAREN >> var_list_clause >> RPAREN;
var_list_clause = list_p( identifier, COMMA );
}
rule<ScannerT> const& start() const { return program; }
symbols<> keywords;
rule<ScannerT> identifier, string_literal, program, query, insert_into_clause, insert_clause,
into_clause, var_list_clause;
};
};
Using a minimal to test it:
void test_it(const string& my_example)
{
microsql_grammar g;
if (!parse(example.c_str(), g, space_p).full)
{
// point a - FAIL
throw new exception();
}
// point b - OK
}
Unfortunately it always enters the point A and throws the exception. Since I'm new to this, I have no idea where my error lies. I have two questions:
- What's the proper way to debug parsing errors when using Boost Spirit?
- Why parsing fails in this example?
To get visibility into what is failing to parse, assign the result of parse to a parse_info<>, then log/examine the parse_info<>::stop field, which in this case should be a const char * pointing at the last byte of you input string that matched your grammar.
microsql_grammar g;
parse_info<std::string::const_iterator> result = parse(example.begin(), example.end(), g, space_p)
if (!result.full)
{
std::string parsed(example.begin(), result.stop);
std::cout << parsed << std::endl;
// point a - FAIL
}
// point b - OK
Apologies if this doesn't compile, but should be a starting point.
精彩评论