0

I am newbie in C++, althouth I need to parser a SQL-like expression: country='USA' AND state='CA' AND price >= 100.0, it is just a fake example, but it's feasible.

So, I tried to solve using spirit QI. Each column has a specific type: float, integer, double, char and string. I wanna create a reusable grammar to support those column types with template or/and trait, but I'm blocked.

I want something like that:

template <typename Iterator, typename ColumnType, typename Skipper>
struct test : qi::grammar<Iterator, ColumnType, Skipper>
{
    test() : test::base_type(expression)
    {
        expression = MyTrait<ColumnType>::type >> "AND" >> MyTrait<ColumnType>::type;
    }

    qi::rule<Iterator, ColumnType, Skipper> expression;
};

I tried to use the Signature template parameter, but didn't work.

MyTrait.h: using namespace boost::spirit::qi;

template< typename T >
struct MyTrait
{
    typedef T type;
};

template<> struct MyTrait< double >
{
    typedef double_type type;
};

template<> struct MyTrait< float >
{
    typedef float_type type;
};

The basic idea in MyTrait is just to convert primitive types (double, float...) to spirit QI types, in order to use them in the grammar. Note that MyTrait<\double>::type results in double_type from QI, but in the grammar must be double_.

main.cpp:

int main() {
    std::string input("99.0 AND 2.0");
    std::string::const_iterator iter = input.begin();
    std::string::const_iterator end = input.end();
    test<std::string::const_iterator, double, qi::space_type> test_parser;
    double result;
    bool r = phrase_parse(iter, end, test_parser, qi::space, result);
    return 0;
 }

Am I on the right track?

Follow compiler error messages as required by Chris Beck:

g++-4.8 -I/usr/include/boost -O0 -g3 -Wall -c -fmessage-length=0 --std=c++11  -fpermissive -MMD -MP -MF"src/main.d" -MT"src/main.o" -o "src/main.o" "../src/main.cpp"
../src/main.cpp: In instantiation of ‘test<Iterator, ColumnType, Skipper>::test() [with Iterator = __gnu_cxx::__normal_iterator<const char*, std::basic_string<char> >; ColumnType = double; Skipper = boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::standard> >, 0l>]’:
../src/main.cpp:91:60:   required from here
../src/main.cpp:76:57: error: dependent-name ‘MyTrait<ColumnType>::type’ is parsed as a non-type, but instantiation yields a type
     expression = MyTrait<ColumnType>::type >> "AND" >> MyTrait<ColumnType>::type;
                                                     ^
../src/main.cpp:76:57: note: say ‘typename MyTrait<ColumnType>::type’ if a type is meant
../src/main.cpp:76:48: error: dependent-name ‘MyTrait<ColumnType>::type’ is parsed as a non-type, but instantiation yields a type
     expression = MyTrait<ColumnType>::type >> "AND" >> MyTrait<ColumnType>::type;
                                            ^
../src/main.cpp:76:48: note: say ‘typename MyTrait<ColumnType>::type’ if a type is meant
Tiago Kepe
  • 13
  • 4
  • It looks like you changed the name `MyTrait` to `BitMapTrait` but only changed it partially... that could cause problems. – Chris Beck Jun 09 '16 at 00:32
  • 1
    In SO when you want someone to help debug a problem, you need to (1) fully post complete error messages (2) fully post complete code that can be compiled / attempted to compile and reproduce the issue. Especially with Spirit, these two things are necessary or its just a waste of time. – Chris Beck Jun 09 '16 at 00:34
  • @ChrisBeck I updated the code and added the compiler error messages as required. Thanks. – Tiago Kepe Jun 09 '16 at 12:18

1 Answers1

0

As far as I understand you want to automatically hardwire a particular parser to a given result_type. Your going to give up much of qi's flexibility in doing so. I recommend reviewing your approach at all.

The code sample below does what I understood so far what you want to achieve.

But (!) the actual result of the parsing will not be float or what but a vector. There are two floats in your input string. One of that gets lost. I did not do anything to prevent that.

And (!) the code below does not address mix and match of different types (columns) you might want to parse. I did not do anything to make that possible.

The code below just plainly adresses the input you gave. It compiles and I hope this helps to climb the next step. ;)

#include <boost/spirit/home/qi.hpp>
#include <boost/utility/enable_if.hpp>

namespace qi = boost::spirit::qi;

template <typename T>
typename boost::enable_if<boost::is_same<T,double>, qi::double_type>::type
my_NOT_A_trait()
{
    return qi::double_type();
};

template <typename T>
typename boost::enable_if<boost::is_same<T, float>, qi::float_type>::type
my_NOT_A_trait()
{
    return qi::float_type();
};

template <typename Iterator, typename ColumnType>
struct test : qi::grammar<Iterator, ColumnType(), qi::space_type>
{
    qi::rule<Iterator, ColumnType(), qi::space_type> expression;

    test() : test::base_type(expression)
    {
        expression = my_NOT_A_trait<ColumnType>() >> qi::lit("AND") >> my_NOT_A_trait<ColumnType>();
    }

};

template<typename Iterator, typename Skipper, typename Result>
bool parse(Iterator first, Iterator const& last, Skipper const& skipper, Result& result)
{
    return qi::phrase_parse(first, last, test<Iterator,Result>(), qi::space, result);
}

int main()
{
    float result;

    std::string input = "99.0 AND 2.0";
    auto b(input.begin()), e(input.end());

    if (parse(b, e, qi::space, result))
        std::cout << "Success." << std::endl;
    else
        std::cout << "Failure." << std::endl;

    return 0;
}
Frank
  • 178
  • 6
  • Thanks @Frank , your suggestion helped me alot, that's what I needed. – Tiago Kepe Jun 22 '16 at 12:17
  • If it helped you, I would appreciate if you marked the answer as accepted so that others do not have to spend time on a question that appears unsolved. – Frank Jul 04 '16 at 14:15