I have the following rule in my parser for parsing inequalities, which works fine:
rel = sum [ _val = _1 ]
>> *( ('<' >> sum [_val = _val < _1])
| ('>' >> sum [_val = _val > _1] ) );
Now I'd like to add the <=
and >=
operators. So I try the following:
rel = sum [ _val = _1 ]
>> *( ('<' >> sum [_val = _val < _1])
| ('>' >> sum [_val = _val > _1])
| (lexeme["<="] >> sum [ _val = _val <= _1])
| (lexeme[">="] >> sum [ _val = _val >= _1]) );
However this fails to parse expressions like x >= y
, presumably because the parser can't look ahead one character to find the =
after the >
.
How should I modify this parser to support the <=
and >=
operators?
Does Spirit Qi automatically build a lexer from the lexeme expressions?
Here's the complete parser:
template <typename Iterator>
struct grammar : qi::grammar<Iterator, expression_ast(), ascii::space_type>
{
grammar() : grammar::base_type(expr) {
using qi::lexeme;
using qi::double_;
using qi::lit;
using qi::_val;
using qi::_1;
using qi::_2;
using qi::_3;
var = lexeme[qi::alpha >> *qi::alnum];
expr = eq [_val = _1] >> *( ('?' >> expr >> ':' >> expr ) [_val = cond(_val, _1, _2)]);
eq = rel [ _val = _1]
>> *( lexeme["=="] >> rel [_val = equal(_val, _1)] );
rel = sum [ _val = _1 ]
>> *( ('<' >> sum [_val = _val < _1])
| ('>' >> sum [_val = _val > _1])
| (lexeme["<="] >> sum [ _val = _val <= _1])
| (lexeme[">="] >> sum [ _val = _val >= _1]) );
sum = term [_val = _1]
>> *( ('+' >> term [_val += _1] )
| ('-' >> term [_val -= _1] ) );
term = exp [_val = _1]
>> *( ('*' >> exp [_val *= _1])
| ('/' >> exp [_val /= _1]) );
exp = factor [_val = _1]
>> *( '^' >> factor [ _val = power(_val, _1)] );
factor = '-' >> atom [_val = neg(_1)]
| atom [_val = _1];
atom = double_ [_val = _1]
| var [_val = _1] >> -( '(' >> exprlist [_val = call(_val, _1)] >> ')' )
| '(' >> expr [_val = _1] >> ')';
exprlist = expr % ',';
}
qi::rule<Iterator, std::string(void), ascii::space_type> var;
qi::rule<Iterator, expression_ast(), ascii::space_type> expr, eq, rel, factor, sum, term, exp, atom;
qi::rule<Iterator, std::vector<expression_ast>(), ascii::space_type> exprlist;
};
According to boost::spirit
documentation, the alternative parser tries its operands
one by one on a first-match-wins basis starting from the leftmost operand
So you could simply put your '<=' and '>=' parsers before the '<' and '>'.
Alternatively you can make your '<' and '>' not match the '<=' and '>=' by using the not-predicate parser which are lookahead. So it would look like:
('<' >> !char_('=') >> sum [_val = _val < _1])