0

It's my first time using boos spirit and i want to parse inputs like this to a struct :

fanout_n #(2, 0, 0) FANOUT_2 (c7552_wire_2, {c7552_wire_2_0, c7552_wire_2_1});

or

fanout_n #(2, 0, 0) FANOUT_2 ({wire1,wire2} , {c7552_wire_2_0, c7552_wire_2_1});

my struct is like this:

struct GateStruct { int numberOfInputs; std::string gateName; std::vector<std::string> wireNames_first; std::vector<std::string> wireNames_second; }; 

for example after parsing, gate has to contain these values :

struct GateStruct { int numberOfInputs = 2; std::string gateName = FANOUT_2; std::vector<std::string> wireNames_first = {wire1 , wire2}; std::vector<std::string> wireNames_second = {c7552_wire_2_0, c7552_wire_2_1}; };gate 

my grammar is this:

template <typename Iterator> struct gate_parser : qi::grammar<Iterator, GateStruct(), ascii::space_type> { gate_parser() : gate_parser::base_type(start) { using qi::int_; using qi::lit; using qi::double_; using qi::lexeme; using ascii::char_; using qi::_1; //using phoenix::ref; wirenameString %= lexeme[+(char_)]; numberString = lit("(") >> int_ >> *(lit(",") >> lit("0")) >> lit(")"); wireList = -(lit("{")) >> wirenameString >> *(lit(",") >> wirenameString) >> -(lit("}")); //will parse this: {wire1 , wire2 , ...,wiren} start %= lit("fanout_n") >> lit("#") >> numberString >> wirenameString >> lit("(") >> wireList >> lit(",") >> wireList >> lit(");") ; } qi::rule<Iterator , int() , ascii::space_type > numberString; qi::rule<Iterator , std::string(), ascii::space_type > wirenameString; qi::rule<Iterator , std::vector<std::string >() , ascii::space_type> wireList; qi::rule<Iterator , GateStruct(), ascii::space_type > start; }; 

and use this code to parse inputs into struct:

int main(){ using boost::spirit::ascii::space; typedef std::string::const_iterator iterator_type; typedef client::gate_parser<iterator_type> gate_parser; gate_parser g; std::string str; while (getline(std::cin, str)) { if (str.empty() || str[0] == 'q' || str[0] == 'Q') break; client::GateStruct gate; std::string::const_iterator iter = str.begin(); std::string::const_iterator end = str.end(); bool r = phrase_parse(iter, end, g, space, gate); if (r && iter == end) { std::cout << "-------------------------\n"; std::cout << "Parsing succeeded\n"; std::cout << "\n-------------------------\n"; } else { std::cout << "-------------------------\n"; std::cout << "Parsing failed\n"; std::cout << "Remaining unparsed: '" << std::string(iter,end) << "'\n"; std::cout << "-------------------------\n"; } } std::cout << "Bye... :-) \n\n"; return 0; 

}

it compiles without any error or warning but unfortunately it doesn't parse my inputs at all.

1
  • Removed the link with irrelevant code because it didn't compile. Try to make things a SSCCE next time (my answer shows how) Commented May 19, 2014 at 21:50

1 Answer 1

2

+qi::char_ consumes all input because everything matches.

Fixing the grammar: Live On Coliru

Notes:

  1. Enable BOOST_SPIRIT_DEBUG
  2. Print the unparsed part of the input
  3. Limit the characters that can make up a wirenameString so it doesn't "eat" all input:

    wirenameString = +char_("a-zA-Z_0-9"); // lexeme implicit because no skipper 
  4. write the wireList so either expects balanced {...}, or none.

    wireList = ('{' >> wirenameString % ',' >> '}') | wirenameString; 

    Note the use of the list parser operator (%)

  5. Now the start rule becomes

    start %= qi::lexeme[ "fanout_n" ] >> '#' >> numberString >> wirenameString >> '(' >> wireList >> ',' >> wireList >> ");" ; 

    All of this works because none of whitespace, (){}, are valid wirename string characters.

#define BOOST_SPIRIT_DEBUG #include <boost/fusion/include/adapt_struct.hpp> #include <boost/spirit/include/qi.hpp> #include <boost/spirit/include/phoenix.hpp> namespace client { namespace qi = boost::spirit::qi; namespace ascii = boost::spirit::ascii; struct GateStruct { int numberOfInputs; std::string gateName; std::vector<std::string> wireNames_first; std::vector<std::string> wireNames_second; }; } BOOST_FUSION_ADAPT_STRUCT(client::GateStruct , (int ,numberOfInputs) (std::string, gateName) (std::vector<std::string>, wireNames_first) (std::vector<std::string>, wireNames_second) ) namespace client { template <typename Iterator> struct gate_parser : qi::grammar<Iterator, GateStruct(), ascii::space_type> { gate_parser() : gate_parser::base_type(start) { using qi::int_; using qi::lit; using ascii::char_; wirenameString = +char_("a-zA-Z_0-9"); // lexeme implicit because no skipper numberString = "(" >> int_ >> *(',' >> lit('0')) >> ')'; wireList = ('{' >> wirenameString % ',' >> '}') | wirenameString; start %= qi::lexeme[ "fanout_n" ] >> '#' >> numberString >> wirenameString >> '(' >> wireList >> ',' >> wireList >> ");" ; BOOST_SPIRIT_DEBUG_NODES( (start)(numberString)(wirenameString)(wireList) ) } private: qi::rule<Iterator , int(), ascii::space_type> numberString; qi::rule<Iterator , std::string() /* lexeme */> wirenameString; qi::rule<Iterator , std::vector<std::string>(), ascii::space_type> wireList; qi::rule<Iterator , GateStruct(), ascii::space_type> start; }; } int main() { using boost::spirit::ascii::space; typedef std::string::const_iterator iterator_type; typedef client::gate_parser<iterator_type> gate_parser; gate_parser g; std::string str; while(getline(std::cin, str)) { if(str.empty() || str[0] == 'q' || str[0] == 'Q') { break; } client::GateStruct gate; std::string::const_iterator iter = str.begin(); std::string::const_iterator end = str.end(); bool r = phrase_parse(iter, end, g, space, gate); if(r) { std::cout << "-------------------------\n"; std::cout << "Parsing succeeded\n"; std::cout << "\n-------------------------\n"; } else { std::cout << "-------------------------\n"; std::cout << "Parsing failed\n"; std::cout << "-------------------------\n"; } if (iter != end) std::cout << "Remaining unparsed: '" << std::string(iter,end) << "'\n"; } std::cout << "Bye...\n"; } 
Sign up to request clarification or add additional context in comments.

8 Comments

why we shouldn't use "space_type" in ` qi::rule<Iterator , std::string() /* lexeme */> wirenameString;`
For the reason I commented at the rule! You can, but you have to "undo" it by specifying qi::lexeme[].
I have an input stream to parse. Except some lines, each line of this input stream has a pattern like the above example. When I parse this input stream spirit just parse successfully until it reaches line that has wrong pattern.can i use qi::on_error and qi::accept and force parser to skip this unmatched input?
I would say this is highly unorthodox and likely to break. Instead, don't fear the ---beast--- grammar and explicitly allow for your input format. If you show it (as a question on SO?) we could help.
Thanks @sehe. I used istream_iterator to read an input text file too. This is exactly what I wanted. I used qi::seek[].This is what i did for parsing.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.