2

I want to parse a floating point number in a text file and insert it in a symbol table; the parser and the symbol table are provided by spirit::qi.

Here is my code:

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>

#include <stdint.h>
#include <iostream>
#include <string>
template<typename VTYPE>
struct VTable : boost::spirit::qi::symbols<char, VTYPE> {
    VTable() {} // empty
};

int main() {
using boost::spirit::qi::_1;
using boost::spirit::qi::eps;
using boost::spirit::qi::rule;
using boost::spirit::qi::ascii::space;
using boost::spirit::qi::space_type;
using boost::spirit::qi::real_parser;
using boost::spirit::qi::int_parser;
using boost::spirit::qi::strict_real_policies;
    VTable<double> floatDecs;
    floatDecs.add("hallo", 15.26)("duDa", 18.5);

const std::string some = "some";
    rule<std::string::iterator, double> value = real_parser<double, strict_real_policies<double>>() [ boost::phoenix::bind(&VTable<double>::add, floatDecs, boost::phoenix::cref(some), _1) ];

    std::cout << boost::spirit::qi::phrase_parse(test.begin(), test.end(), value, space);
    return 0;
}

The problem in here lies in boost::phoenix::bind, but I do not know, how to fix that (I am fairly new to this library).

sehe
  • 374,641
  • 47
  • 450
  • 633
user1861174
  • 507
  • 1
  • 5
  • 14
  • possible duplicate of [How to add qi::symbols in grammar?](http://stackoverflow.com/questions/8780604/how-to-add-qisymbols-in-grammariterator-double) – sehe Jan 14 '13 at 08:38
  • 1
    @sehe the bind expression in that answer is a lot less frightening than mine :p. –  Jan 14 '13 at 10:54
  • Do you really mean some[] to be an array? That doesn't look to me as if it will compile – FatalFlaw Jan 18 '13 at 14:42
  • I have quickly changed from const char[] to std::string, to see if that works better with boost. I simply was not careful enough – user1861174 Jan 18 '13 at 16:44

1 Answers1

3

Here's a working version. After, I'll list what was wrong with yours.

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>

#include <stdint.h>
#include <iostream>
#include <string>
template<typename VTYPE>
struct VTable : boost::spirit::qi::symbols<char, VTYPE> {
    VTable() {} // empty
};

int main() {
using boost::spirit::qi::_1;
using boost::spirit::qi::eps;
using boost::spirit::qi::rule;
using boost::spirit::qi::ascii::space;
using boost::spirit::qi::space_type;
using boost::spirit::qi::real_parser;
using boost::spirit::qi::int_parser;
using boost::spirit::qi::strict_real_policies;

    VTable<double> floatDecs;
    floatDecs.add("hallo", 15.26)("duDa", 18.5);

    const char some[] = "some";

    rule<std::string::iterator, double()> value =
            real_parser<double, strict_real_policies<double> >()
            [ boost::phoenix::bind(floatDecs.add, boost::phoenix::val(some), _1) ];

    std::string test("10.6");

    std::string::iterator b(test.begin()), e(test.end());

    std::cout << boost::spirit::qi::phrase_parse(b, e, value, space);

    return 0;
}

First, the variable you want to use as an argument to add() needs to be fixed.

const char some[] = "some";

Next, you need to fix the syntax in your rule template parameters:

rule<std::string::iterator, double()>

Note the brackets, to make the double a functor declaration rather than a vanilla double, for lazy evaluation.

Next, you need to use the syntax above for your semantic action.

[ boost::phoenix::bind(floatDecs.add, boost::phoenix::val(some), _1) ];

Honestly I am not sure why this works as I am not a phoenix expert, but the link in 'sehe's' comment above provided the answer. Also, you were barking up the wrong tree with cref, there's no indication from add()'s declaration that a reference is what's required. val is what you need to turn the some variable into a phoenix-happy lazy argument.

Finally, you just need to supply some reasonable test data.

The code above should work for you now.

FatalFlaw
  • 1,077
  • 11
  • 19