$include_dir="/home/hyper-archives/boost-users/include"; include("$include_dir/msg-header.inc") ?>
Subject: Re: [Boost-users] [Spirit] question about alternative list expressions
From: Hartmut Kaiser (hartmut.kaiser_at_[hidden])
Date: 2010-05-13 19:39:34
> /*
> Hello,
> 
> This code (second copy attached) compiles to recognize dotlists, ie "a",
> "a.b", etc.
> I want to report on incomplete list errors of the following kind
> 
>      a.
>      a.#
> 
> The parser now detects such errors by failing to parse them completely.
> Instead I want to expect an id after a '.'.
> 
> In dotlist_grammar() I wanted to replace this expression
> 
>      start %= (id % '.') ;
> 
> with this one
> 
>      start %= (id >> (*('.' > id))) ;  // XXX
'>>' has difference operator precedence than '>', which means that Spirit is
not able to flatten the whole expression leading to the attribute type
mismatch you're seeing.
> but it won't compile. Neither will this
> 
>      start %= (id >> (*('.' >> id))) ; // XXX
Attribute-wise this will work. The problem is that the function signature
you're attaching doesn't match the attribute type exposed by the expression
it is attached to. It now exposes a fusion::vector<std::string,
std::vector<std::string> >.
> What's wrong?  Is there a difference between the synthesized attributes of
> the two alternative list expressions?  Or is it a different bug?
> 
> P.S.  Both expressions seem to work for int_ instead of id.
HTH
Regards Hartmut
---------------
Meet me at BoostCon
www.boostcon.com
> 
> Thanks.
> 
> */
> #include <boost/config/warning_disable.hpp>
> #include <boost/spirit/include/qi.hpp>
> #include <boost/fusion/include/adapt_struct.hpp>
> #include <boost/spirit/include/phoenix_core.hpp>
> #include <boost/spirit/include/phoenix_operator.hpp>
> #include <boost/spirit/include/phoenix_fusion.hpp>
> #include <boost/spirit/include/phoenix_stl.hpp>
> #include <boost/spirit/include/phoenix_object.hpp>
> #include <boost/fusion/include/adapt_struct.hpp>
> #include <boost/fusion/include/io.hpp>
> #include <boost/fusion/sequence.hpp>
> #include <boost/fusion/include/sequence.hpp>
> 
> #include <boost/algorithm/string/trim.hpp>
> 
> #include <iostream>
> 
> namespace ecgp
> {
>    using namespace std;
> 
>    namespace qi = boost::spirit::qi;
>    namespace ascii = boost::spirit::ascii;
>    namespace fusion = boost::fusion;
>    namespace phoenix = boost::phoenix;
> 
>    typedef ascii::space_type space;
> 
>    // structures, etc.
>    struct structure
>    {
>      vector<string> dotlist;
>      int            filler;      // fusion requires >1 members?!
> 
>      void print(ostream& o) const
>      {
>        int i=0;
>        BOOST_FOREACH(string s, dotlist)
>        {
>          if(++i > 1) o << '.';
>          o << s;
>        }
>      }
>    };
> 
>    ostream& operator<<(ostream& o, structure const & c)
>    {
>      c.print(o);
>      return o;
>    };
> }
> 
> BOOST_FUSION_ADAPT_STRUCT(
>    ecgp::structure,
>    (std::vector<std::string>, dotlist)
>    (int, filler)                 // fusion requires >1 members?!
> )
> 
> namespace ecgp
> {
>    // actions
> 
>    void print_str(string const & v)
>    {
>      cout << "str: ";
>      cout << v << endl;
>    }
> 
>    void print_dotlist(vector<string> const & v)
>    {
>      cout << "dotlist: ";
>      int i=0;
>      BOOST_FOREACH(string s, v)
>      {
>        if(++i > 1) cout << '.';
>        cout << s;
>      }
>      cout << endl;
>    }
> 
>    void print_structure(structure const & v)
>    {
>      cout << "structure: ";
>      print_dotlist(v.dotlist);
>      cout << endl;
>    }
> 
>    // grammars
> 
>    template <typename Iterator> // recognize an identifier
>    struct id_grammar : qi::grammar<Iterator, string(), space>
>    {
>      id_grammar() : id_grammar::base_type(start)
>      {
>        using ascii::alpha;
>        using qi::lexeme;
> 
>        start
>        %=
>         lexeme[ +alpha ]
>         [ &print_str ]
>        ;
>      }
>      qi::rule<Iterator, string(), space> start;
>    };
> 
>    template <typename Iterator> // recognize a dotlist, ie (string %
> '.')
>    struct dotlist_grammar : qi::grammar<Iterator, vector<string>(),
> space>
>    {
>      dotlist_grammar() : dotlist_grammar::base_type(start)
>      {
>        using qi::int_;
>        using qi::lexeme;
> 
>        start %=
> //    (id >> (*('.' > id)))  // XXX
>        (id % '.')
>        [ &print_dotlist ]
>        ;
>      }
>      id_grammar<Iterator>                     id;
>      qi::rule<Iterator, vector<string>(), space> start;
>    };
> 
>    template <typename Iterator>
>    struct structure_grammar : qi::grammar<Iterator,structure(),space>
>    {
>      structure_grammar() : structure_grammar::base_type(start)
>      {
>        using qi::eps;
>        using qi::int_;
> 
>        start
>        %=
>        (  dotlist
>           >>
>           (int_ | eps) // filler
>        )
>        [ &print_structure ]
>        ;
>      }
>      dotlist_grammar<Iterator>              dotlist;
>      qi::rule<Iterator, structure(), space> start;
>    };
> }
> 
> int
> main()
> {
>    using namespace std;
>    using namespace ecgp;
>    using namespace boost;
> 
>    typedef string::const_iterator string_iterator;
> 
>    string s;
> 
>    cout << "enter a dotlist:\n";
> 
>    while (getline(cin, s))
>    {
>      trim(s);
> 
>      string_iterator iter = s.begin();
>      string_iterator  end = s.end();
> 
>      string target(iter, end);
> 
>      structure list_container;
>      structure_grammar<string_iterator> g;
> 
>      bool r = phrase_parse(iter, end, g, boost::spirit::ascii::space,
>        list_container);
> 
>      if (r && iter == end) {
>        cout << "OK: " << target;
>        cout << endl << endl;
>      }
>      else {
>        cout << "FAIL";
> 
>        if(! r) cout << "(p)";
>        if(iter != end) cout << "(e)";
> 
>        cout << ": " << target;
>        cout << endl << endl;
>      }
>      cout << "enter a dotlist:\n";
>    }
>    return 0;
> }