Boost logo

Boost Users :

Subject: [Boost-users] [Spirit] question about alternative list expressions
From: philip tucker (phhht_at_[hidden])
Date: 2010-05-13 17:32:48


/*
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

but it won't compile. Neither will this

     start %= (id >> (*('.' >> id))) ; // XXX

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.

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;
}




Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net