Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

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 ?


  • Lifetime Qt Champion

    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.


  • Lifetime Qt Champion

    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.


  • Lifetime Qt Champion

    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.

    0_1523397360762_8aec107f-7865-44cf-8d91-78dfff38490c-image.png


  • Qt Champions 2017

    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;
    
        }
    }
    

  • Qt Champions 2017

    I don't touch that. I'd rather spend half a day writing my own LL(1) parser by hand than mess with Spirit ...


Log in to reply