
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.

Jarrad Waterloo wrote:
Question #1 of 3: How do I fix this error? [Note: This is still my original question.]
Hi Jarrad, Here's the mailing list for Spirit: https://lists.sourceforge.net/lists/listinfo/spirit-general Please post your question there for other Spirit folks to see. Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net
participants (2)
-
Jarrad Waterloo
-
Joel de Guzman