1

I've been using spirit::qi quite often for the past several months. However, this time I got a segfault that I really can't make any sense out of.

I have reduced it to an extremely minimal test case, the grammar definition is 12 lines of code.

This feels a lot like an earlier question but the solution there, of adding .alias() to some of the terminals so that qi doesn't make copies of them, doesn't seem to fix this.

I'm concerned that there's something fundamental I'm missing here, since I've managed to make way more complicated grammars than this that test out exactly the way I expect.

The only thing that occurs to me now is that, maybe qi just doesn't like for the main grammar return type to be a boost variant? I don't know if I have made any grammars that do that before. I guess I'll test this next but honestly I've been spinning my wheels fiddling with things like that for a while.

I can confirm that, if the line that sets up the mod_ rule is commented out, then no segfault occurs and the program runs normally to completion.

Edit: Actually, it segfaults even if all of the grammar attributions are deleted.

#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/spirit/include/qi.hpp>
#include <iostream>

typedef unsigned int uint;

namespace qi = boost::spirit::qi;

/***
 * Grammar
 */
template <typename Iterator>
struct op_grammar : qi::grammar<Iterator> {
  qi::rule<Iterator> constant_;
  qi::rule<Iterator> mod_;
  qi::rule<Iterator> expr_;

  op_grammar() : op_grammar::base_type(expr_) {
    constant_ = qi::uint_;
    expr_ = mod_ | constant_;
    mod_ = expr_ >> qi::lit('%') >> expr_; 
  }
};

/***
 * Test
 */
int main() {
//  std::string str{"n % 2"};
  std::string str{"2"};

  typedef std::string::const_iterator str_it;
  str_it it = str.begin();
  str_it end = str.end();
  op_grammar<str_it> grammar;

  if (qi::parse(it, end, grammar) && it == end) {
    std::cerr << "Good\n";
  } else {
    std::cerr << "Bad\n";
  }
}
Community
  • 1
  • 1
Chris Beck
  • 15,614
  • 4
  • 51
  • 87

1 Answers1

1

Actually, I figured it out...

The problem is that as written, the grammar is flawed and there's no way that it can be parsed. Because, the first non-terminal of expr_ is mod_, and the first nonterminal of mod_ is expr_, so there's no way even to begin to figure out how to parse either of them, it's circular.

The grammar can be fixed by changing the first expr_ of mod_ to constant_ and then it works as expected.

I will leave this answer here I guess because the question already got an up-vote, but possibly I should just delete the question, not sure.

Chris Beck
  • 15,614
  • 4
  • 51
  • 87
  • 1
    The term is "left-recursion". PEG doesn't support left-recursion. You have to unfactor the left-recursion like you describe – sehe Oct 25 '15 at 09:39