[Spirit] question about alternative list expressions
/* 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; }
/* 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; }
On 13 May 2010, at 4:39 PM, Hartmut Kaiser wrote:
/* 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
/* This code (compilable copy attached) compiles to recognize dotlists, ie (string % '.'), with the added expectation that an id will follow a '.'. The solution is unsatisfactory because it requires a structure to contain a dotlist, and because it uses explicit semantic actions. Do you have any suggestions about how to obviate the semantic actions? The following pseudo-code illustrates something I don't know how to do, although I am pretty sure the solution is obvious to Spirit/ Fusion users. If that's true, I think it will solve the problem of the extraneous structure. This pseudo-grammar exposes attribute vector<string> instead of some structure. What I want is to push a recognized string onto that vector, rather than onto a part of a structure. That is what I mean below by "_val.push_back(_1)" If you can show me the expression which does what I need, I thank you. template <typename Iterator> struct slotchain_grammar : qi::grammar<Iterator, vector<string> (), space> { slotchain_grammar() : slotchain_grammar::base_type(start) { using namespace qi::labels; using phoenix::at_c; using phoenix::push_back; start = id [ "_val.push_back(_1)" ] >> *('.' > id [ "_val.push_back(_1)" ]) ; } id_grammar<Iterator> id; qi::rule<Iterator, vector<string>(), space> start; }; */
participants (2)
-
Hartmut Kaiser
-
philip tucker