Unsolved Simple DSL Parser with Qt
-
I m trying to parse a simple sql like statement using Qt only. Bison, Yacc or boost::spirit are really cumbersome for my simple task.
My parser should be able to parse the following things :SELECT chr, pos FROM variants SELECT chr, pos FROM variants WHERE chr=3 SELECT chr, pos FROM variants WHERE chr=3 REGION exonic SELECT chr, pos FROM variants REGION exonic
What I want :
VqlParser parser; parser.parse("SELECT chr FROM variant WHERE chr>3 AND chr<5 REGION exonic")
parser.fields() // QStringList("chr") parser.table() // QString("variant") parser.condition() // QString("chr > 3 AND chr < 5") parser.region() // QString("exonic")
Any idea ? With regexp or something else ?
-
Hi,
If it's only for these 4 possible strings then QRegularExpression is likely enough to solve this.
-
@SGaist Do I have to create 4 regular expressions ?
I didn't success to create one regexp which capture each group. -
No you don't.
What expression are you using ?
-
@SGaist This one : https://regex101.com/r/Lpupin/2
SELECT(.+)FROM (\w)+ WHERE (.+) REGION (\w+)
As you can see, I can parse the full query but not the other.
-
You are missing the handling of optional elements and some white spaces:
SELECT(.+)\s+FROM\s+(\w+)(\s+WHERE\s+(.+))?(\s+REGION\s+(\w+))?
-
Unfortunally, the query cannot make difference between the "where clause" and the "region clause" as you see in purple.
-
A simple adjustment should do:
https://regex101.com/r/emTTdh/1 -
Thanks !
I put my own code if you want to check#include <boost/spirit.hpp> #include <string> #include <typeinfo> namespace VQL { template <typename Iterator> auto parse(Iterator begin, Iterator end, bool &success) { using namespace boost::spirit::x3; using x3::lexeme; using x3::alpha; using x3::phrase_parse; using x3::ascii::space; using x3::_attr; vector<std::string> select; std::string from; std::string where; std::string region; auto toSelect = [&](auto & ctx) {select = _attr(ctx);}; auto toFrom = [&](auto & ctx) {from = _attr(ctx);}; auto toWhere = [&](auto & ctx) {where = _attr(ctx);}; auto toRegion = [&](auto & ctx) {region = _attr(ctx);}; auto keywords = x3::lit("SELECT") | x3::lit("FROM") | x3::lit("WHERE") | x3::lit("REGION"); auto word = *(x3::alnum - keywords); auto cond = *(x3::char_ - keywords); success = phrase_parse(begin, end, "SELECT" >> (word % ",")[toSelect] >> ("FROM" >> word[toFrom]) >> -("WHERE" >> x3::lexeme[cond][toWhere]) >> -("REGION" >> word[toRegion]) , space ); return std::make_tuple(select,from,where,region); } } int main(int argc, char **argv) { std::string query = "SELECT chr, pos,chrom FROM variants WHERE chr=3 AND chr=4 REGION exonic"; bool success = false; auto results = VQL::parse(query.begin(), query.end(), success); if (success) { for (auto& field : std::get<0>(results)) std::cout<<"fields "<<field<<"\n"; std::cout<<"from "<< std::get<1>(results)<<std::endl; std::cout<<"where "<< std::get<2>(results)<<std::endl; std::cout<<"region "<< std::get<3>(results)<<std::endl; std::cout<<std::flush; } }
-
I don't touch that. I'd rather spend half a day writing my own LL(1) parser by hand than mess with Spirit ...