$include_dir="/home/hyper-archives/boost-users/include"; include("$include_dir/msg-header.inc") ?>
From: Markus Werle (numerical.simulation_at_[hidden])
Date: 2008-08-25 10:32:08
> [gmane anti-top-poster-complaint-header]
Hi!
[OK, Joel, it's not as trivial as I thought. Show me the way, master]
Below is my first toy implementation of string_to_list_of_tuples for 
tr1::tuple. Unfortunately this code only parses the text, but does not store
the data. Any idea how to add the correct semantic actions in a pure and 
elegant way?
Markus
---snip---
#define BOOST_SPIRIT_DEBUG_OUT std::cerr
#define BOOST_SPIRIT_DEBUG
// #include "Enforce.h"
#include <iostream>
#include <iterator>
#include <boost/tr1/tuple.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/mpl/at.hpp>
#include <boost/spirit/include/classic_spirit.hpp>
#include <list>
#include <string>
namespace sp = boost::spirit::classic;
namespace fusion = boost::fusion;
namespace mpl = boost::mpl; 
namespace
{
struct parser_traits
{
    template <typename T, int Dummy = 0> struct parser;
#define PARSER_TRAITS(TYPE, PARSER_T)                        \
    template <int Dummy> struct parser<TYPE, Dummy>          \
    {                                                         \
        typedef PARSER_T type;                               \
                                                             \
        static inline                                          \
        PARSER_T p()                                          \
        {                                                     \
            PARSER_T result;                                 \
            return result;                                     \
        }                                                     \
    } 
    PARSER_TRAITS(int, sp::int_parser<int>);
    PARSER_TRAITS(unsigned int, sp::uint_parser<unsigned>);
    typedef sp::real_parser
    <double, sp::ureal_parser_policies<double> > real_parser_t;
    PARSER_TRAITS(float, real_parser_t);
    PARSER_TRAITS(double, real_parser_t);
    template <int Dummy> struct parser<std::string, Dummy>          
    {        
        typedef sp::contiguous
        <sp::confix_parser
         <sp::strlit<const char*>, 
          sp::kleene_star
          <sp::anychar_parser>, 
          sp::strlit<const char*>, 
          sp::unary_parser_category, 
          sp::non_nested, 
          sp::non_lexeme> > parser_t;
                                                 
        static inline                                          
        parser_t p()                                          
        {                                                     
            using namespace phoenix;
            
            parser_t result = sp::lexeme_d[sp::confix_p("\"" ,
(*sp::anychar_p) , "\"")];
            return result;
        }                                                     
                                                             
        static inline                                          
        sp::strlit<char const *> comma()          
        {                                                      
            sp::strlit<char const *> str_p(",");  
            return str_p;                                    
        }                                                    
    }; 
};
template <typename Tuple, long I>
struct
rule_generator_helper
{
    typedef typename std::tr1::tuple_element<I, Tuple>::type element_type;
    typedef typename parser_traits::parser<element_type> pt_type;
    typedef typename rule_generator_helper<Tuple, (I-1)>::type element_1_t;
    typedef typename 
    sp::sequence<sp::sequence<element_1_t, sp::chlit<char> >, typename 
pt_type::type> type;
    static 
    type
    apply()
    {
        return 
            rule_generator_helper<Tuple, (I-1)>::apply()
            >> sp::ch_p(',') 
            >> pt_type::p()
            ;
    }
};
template <typename Tuple>
struct
rule_generator_helper<Tuple, 0L> 
{
    typedef typename std::tr1::tuple_element<0, Tuple>::type element_type;
    typedef typename parser_traits::parser<element_type> pt_type;
    typedef typename pt_type::type type;
    static 
    type
    apply()
    {
        return pt_type::p();
    }
};
template <typename Tuple>
struct
rule_generator
{
    typedef std::tr1::tuple_size<Tuple> tuple_size;
    
    BOOST_MPL_ASSERT_RELATION(tuple_size::value, >, 0);
    typedef 
    rule_generator_helper<Tuple, (tuple_size::value - 1)> helper_t;
    static 
    inline 
    typename helper_t::type
    apply()
    {
        return helper_t::apply();
    }
};
template <typename Tuple>
struct
string_to_list_of_tuples
{
    static
    std::list<Tuple>
    apply(std::string const & s)
    {
        std::list<Tuple> result;
        typedef sp::rule<sp::phrase_scanner_t> rule_t;
        rule_t rule_tuple_rep = 
            '(' >> rule_generator<Tuple>::apply() >> ')';
        rule_t rule_tuple_list = 
            *(rule_tuple_rep) 
            >> sp::end_p // for trailing whitespace
            ;
        BOOST_SPIRIT_DEBUG_RULE(rule_tuple_rep);
        BOOST_SPIRIT_DEBUG_RULE(rule_tuple_list);
        sp::parse_info<> info;
        try
        {
            info = sp::parse(s.c_str(), rule_tuple_list, sp::space_p);
        }
        catch (std::exception const & e)
        {
            std::cerr << e.what() << std::endl;
        }
        
//         ENFORCE(info.full) 
//             ("Failed to generate a list of tuples from ")
//             ("string representation\n'")
//             (s)("'\n");
        
        return result;
    }
};
} // namespace
int main()
{
    try
    {
        {
            typedef std::tr1::tuple<int, int> tuple_t;
            std::list<tuple_t> test = 
                string_to_list_of_tuples<tuple_t>::apply(" (  1, 2 )   ( 3,  4)
(5,6)");
            std::copy(test.begin(), test.end(), 
                      std::ostream_iterator<tuple_t>(std::cout, "\n"));
        }
        {
            typedef std::tr1::tuple<unsigned int, int, double> tuple_t;
            std::list<tuple_t> test = 
                string_to_list_of_tuples<tuple_t>::apply
                (" (  1, -2 , 5.123)   ( 3,  4,7.9)(5,6,8.6789)");
            std::copy(test.begin(), test.end(), 
                      std::ostream_iterator<tuple_t>(std::cout, "\n"));
        }
    }
    catch (std::exception const & e)
    {
        std::cerr << e.what() << std::endl;
    }
}