Boost logo

Boost :

From: Jarrad Waterloo (jwaterloo_at_[hidden])
Date: 2007-07-12 09:32:01


Question #1 of 3: How do I fix this error? [Note: This is still my original
question.]

1>d:\documents and settings\jwaterloo\my documents\visual studio
2005\projects\json_parser\json_parser\json_parser.cpp(150) : error C2440:
'<function-style-cast>' : cannot convert from 'phoenix::actor<BaseT>' to
'phoenix::stl::push_back'

1> with

1> [

1>
BaseT=phoenix::closure_member<0,phoenix::closure<std::vector<boost::any>,pho
enix::nil_t,phoenix::nil_t,phoenix::nil_t,phoenix::nil_t,phoenix::nil_t>>

1> ]

 

when

 

p_array = '['

>> !(p_value[phoenix::stl::push_back(p_array.values)] % ',')

>> ']';

 

where

 

p_array has a context of the following

 

struct any_s_closure : boost::spirit::closure<any_s_closure, vector<any> >

{

            member1 values;

};

 

and is declared as

 

typedef rule<ScannerT, any_s_closure::context_t> rule_any_s;

rule_any_s p_array;

 

Question #2 of 3: What type should my iterator parameters be on the call
operator when creating a custom semantic action functor?

There are examples similar to this in the documentation but they didn't seem
to work.

 

struct my_functor

{

      my_functor(std::string& str_) : str(str_)

      {}

 

      void operator()(char const* first, char const* last)
const//std::string::const_iterator first, std::string::const_iterator last)
const

      {

            str.assign(first, last);

      }

 

      std::string& str;

};

 

struct nv_map_inserter

{

      nv_map_inserter(nv_map& map, std::string& name, boost::any& value)

            : map(map), name(name), value(value)

      {

            //this->map = map;

            //this->name = name;

            //this->value = value;

      }

 

      void operator()(char const* first, char const* last)
const//std::string::const_iterator first, std::string::const_iterator last)
const

      {

            //str.assign(first, last);

            map.insert(nv_map::value_type(name, value));

      }

 

      nv_map& map;

      std::string& name;

      boost::any& value;

};

 

Question #3 of 3: How do I debug using '#define BOOST_SPIRIT_DEBUG' when
using closures with a member of any?

Any needs stream operators which it doesn't have. I know this may be an
idiot question but I am asking it anyway because I tried the following 2 and
could get neither to work. Any assistance would be appreciated.

 

template<class Ch, class Tr>

basic_ostream<Ch, Tr>& operator<<(basic_ostream<Ch, Tr>& s, const boost::any
z)

{

      if(z.empty())

            s << "null";

      else if(operand.type() == typeid(double))

            s << any_cast<double>(z);

      else if(operand.type() == typeid(bool))

            s << any_cast<bool>(z);

      else if(operand.type() == typeid(std::string))

            s << any_cast<std::string>(z);

      else if(operand.type() == typeid(std::vector<boost::any>))

            s << any_cast<std::vector<boost::any> >(z);

      else if(operand.type() == typeid(std::map<std::string, boost::any>))

            s << any_cast<std::map<std::string, boost::any> >(z);

      return s;

}

 

ostream& operator<<(ostream& s, const boost::any z)

{

      if(z.empty())

            s << "null";

      else if(z.type() == typeid(double))

            s << any_cast<double>(z);

      else if(z.type() == typeid(bool))

            s << any_cast<bool>(z);

      else if(z.type() == typeid(std::string))

            s << any_cast<std::string>(z);

      else if(z.type() == typeid(std::vector<boost::any>))

            s << any_cast<std::vector<boost::any> >(z);

      else if(z.type() == typeid(std::map<std::string, boost::any>))

            s << any_cast<std::map<std::string, boost::any> >(z);

      return s;

}

 

Source Follows:

// json_parser.cpp : Defines the entry point for the console application.

//

//#define BOOST_SPIRIT_DEBUG

 

#include "stdafx.h"

#include "stl_containers.hpp"

#include <iostream>

#include <string>

#include <vector>

#include <map>

#include <boost/spirit.hpp>

#include <boost/spirit/actor/insert_at_actor.hpp>

#include <boost/any.hpp>

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

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

 

using namespace std;

using namespace boost;

using namespace boost::spirit;

using namespace phoenix;

 

struct any_s_closure : boost::spirit::closure<any_s_closure, vector<any> >

{

      member1 values;

};

 

struct nv_map_closure : boost::spirit::closure<nv_map_closure, map<string,
any> >

{

      member1 values;

};

 

struct double_closure : boost::spirit::closure<double_closure, double>

{

      member1 double_closure_value;

};

 

struct name_closure : boost::spirit::closure<name_closure, string>

{

      member1 name;

};

 

struct value_closure : boost::spirit::closure<value_closure, any>

{

      member1 value_closure_value;

};

 

struct nvpair_closure : boost::spirit::closure<nvpair_closure, string, any>

{

      member1 name;

      member2 value;

};

 

typedef map<string, any> nv_map;

 

struct json_parser : public grammar<json_parser, value_closure::context_t>

{

    json_parser()

    {}

 

    template <typename ScannerT>

    struct definition

    {

        definition(json_parser const& self)

        {

                  p_nvpair = p_string[p_nvpair.name =
p_string.name]//construct_<std::string>(arg1, arg2)]

>> ':'

>> p_value[p_nvpair.value =
p_value.value_closure_value];//[p_nvpair.value =
construct_<std::string>(arg1, arg2)];

                  p_string = confix_p('"', *c_escape_ch_p,
'"')[p_string.name = construct_<std::string>(arg1, arg2)];

                  p_number = real_p[p_number.double_closure_value =
arg1];//assign_a(p_number.double_closure_value)];

                  p_object = '{'//ch_p('{')[p_object.value = nv_map()]

>>
!list_p(p_nvpair/*[insert_at_a(any_cast<nv_map>(p_object.value),
p_nvpair.name, p_nvpair.value)]*/, ',')

>> '}';

                  p_array = '['//ch_p('[')[p_array.value =
std::vector<any>()]

                        //>> !(p_value[push_back_a(any_cast<std::vector<any>
>(p_array.value), p_value.value)] %
',')//!list_p(p_value[push_back_a(any_cast<std::vector<any>&>(/*p_array.val*
/std::vector<any>()), /*p_value.val*/true)], ',')

>>
!(p_value[phoenix::stl::push_back(p_array.values)/*,
arg1)*/]/*[push_back_a(p_array.values, p_value.value)]*/ %
',')//!list_p(p_value[push_back_a(any_cast<std::vector<any>&>(/*p_array.val*
/std::vector<any>()), /*p_value.val*/true)], ',')

>> ']';

                  p_value = str_p("null")[p_value.value_closure_value =
any()]

                        || str_p("true")[p_value.value_closure_value = true]

                        || str_p("false")[p_value.value_closure_value =
false]

                        || p_number[p_value.value_closure_value = arg1]

                        || p_string[p_value.value_closure_value = arg1]

                        //|| p_object//[p_value.value_closure_value =
p_object.values]

                        || p_array[p_value.value_closure_value =
arg1];//[p_value.value_closure_value = p_array.values]

                  top = p_value[self.value_closure_value = arg1];

        }

 

            typedef rule<ScannerT, value_closure::context_t> rule_t;

        rule_t p_value;

            typedef rule<ScannerT, double_closure::context_t> rule_d;

        rule_d p_number;

            typedef rule<ScannerT, name_closure::context_t> rule1_t;

        rule1_t p_string;

            typedef rule<ScannerT, nvpair_closure::context_t> rule2_t;

        rule2_t p_nvpair;

            typedef rule<ScannerT, any_s_closure::context_t> rule_any_s;

        rule_any_s p_array;

            typedef rule<ScannerT, nv_map_closure::context_t> rule_nv_map;

        rule_nv_map p_object;

 

            rule<ScannerT> top;

        rule<ScannerT> const& start() const

            {

                  return top;

            }

    };

      bool isValid(char const* str, any& returnData) const

      {

            return boost::spirit::parse(str, (*this)[var(returnData) =
arg1], space_p).full;//parse_info<> info

      }

};

 

int _tmain(int argc, _TCHAR* argv[])

{

      try

      {

            any returnData;

            json_parser jp;

            cout << "Test 1: \"\"Hello\nWorld\"\" = " <<
jp.isValid("\"Hello\nWorld\"", returnData) << endl;

            cout << "Return: Type = " << returnData.type().name() << ",
Value = " << any_cast<string>(returnData) << endl;

            cout << "Test 2: \"45.62\" = " << jp.isValid("45.62",
returnData) << endl;

            cout << "Return: Type = " << returnData.type().name() << ",
Value = " << any_cast<double>(returnData) << endl;

            cout << "Test 3: \"[1, 2, 3, 4, 5]\" = " << jp.isValid("[1, 2,
3, 4, 5]", returnData) << endl;

            cout << "Return Type = " << returnData.type().name() << endl;

            cout << "The array has " << any_cast<vector<any>
>(returnData).size() << " items." << endl;

            //cout << "Return Value = " << any_cast<vector<any>
>(returnData) << endl;

            //cout << "Return: Type = " << returnData.type().name() << ",
Value = " << any_cast<<vector<any> >(returnData) << endl;

            cout << "Test 4: \"{\"field1\" : 7, \"field2\" : 45.32,
\"field3\" : \"www.goto.com\"}\" = " << jp.isValid("{\"field1\" : 7,
\"field2\" : 45.32, \"field3\" : \"www.goto.com\"}", returnData) << endl;

            cout << "Test 5: \"true\" = " << jp.isValid("true", returnData)
<< endl;

            cout << "Return: Type = " << returnData.type().name() << ",
Value = " << any_cast<bool>(returnData) << endl;

            cout << "Test 6: \"false\" = " << jp.isValid("false",
returnData) << endl;

            cout << "Return: Type = " << returnData.type().name() << ",
Value = " << any_cast<bool>(returnData) << endl;

            cout << "Test 7: \"null\" = " << jp.isValid("null", returnData)
<< endl;

            cout << "Return: Value = " << (returnData.empty() ? "null" :
"not null") << endl;

            cout << "Test 8: \"'Hello\nWorld'\" = " <<
jp.isValid("'Hello\nWorld'", returnData) << endl;

            cout << "Test 9: \"45.62f\" = " << jp.isValid("45.62f",
returnData) << endl;

            cout << "Test 10: \"[1, 2, 3, 4, 5)\" = " << jp.isValid("[1, 2,
3, 4, 5)", returnData) << endl;

            cout << "Test 11: \"{\"field1\" : 7, 'field2' : 45.32,
\"field3\" : \"www.goto.com\"}\" = " << jp.isValid("{\"field1\" : 7,
'field2' : 45.32, \"field3\" : \"www.goto.com\"}", returnData) << endl;

            cout << "Test 12: \"TRUE\" = " << jp.isValid("TRUE", returnData)
<< endl;

            cout << "Test 13: \"FALSE\" = " << jp.isValid("FALSE",
returnData) << endl;

            cout << "Test 14: \"NULL\" = " << jp.isValid("NULL", returnData)
<< endl;

      }

      catch(exception& e)

      {

            cout << e.what() << endl;

      }

      return 0;

}

 

Concluding Remarks

I hate parsing unfortunately it is necessary and Spirit looks like it can
make parsing fun. Creating grammars and doing validation is easy but getting
past the semantic actions learning curve is time consuming. Additional
documentation on slightly more complex hierarchies that doesn't use globals
but instead uses closures would be appreciated in the future. P.S. For other
learners, '#include "stl_containers.hpp" needs to come before any boost
header due to macro redefinitions.

 


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk