After following the sample in the spirit-classic FAQ to eliminate Left Recursion, I am unable to figure out the right placeholders for Phoenix semantic actions. My non-working grammar is shown below:
template <typename It, typename Skipper = qi::space_type>
struct parser : qi::grammar<It, expr(), Skipper>
{
parser() : parser::base_type(expression)
{
using namespace qi;
expression =
term [_val = _1]
>> *( (char_('+') >> term) [_val = phx::construct<binop<op_add>>(_1, _2)]
| (char_('-') >> term) [_val = phx::construct<binop<op_sub>>(_1, _2)]
) ;
term =
factor [_val = _1]
>> *( (char_('*') >> factor) [_val = phx::construct<binop<op_mul>>(_1, _2)]
| (char_('/') >> factor) [_val = phx::construct<binop<op_div>>(_1, _2)]
);
factor =
uint_ [_val = _1]
| var_ [_val = _1]
| ('(' >> expression >> ')') [_val = _1]
| (char_('-') > factor) [_val = phx::construct<unop<op_uminus>>(_1)]
| (char_('+') > factor) [_val = _1]
;
var_ = qi::lexeme[ +alpha ];
BOOST_SPIRIT_DEBUG_NODE(expression);
BOOST_SPIRIT_DEBUG_NODE(term);
BOOST_SPIRIT_DEBUG_NODE(factor);
BOOST_SPIRIT_DEBUG_NODE(var_);
}
private:
qi::rule<It, var() , Skipper> var_;
qi::rule<It, expr(), Skipper> expression, term, factor;
};
Any help on the proper way to handle attributes would be greatly appreciated.
Thanks.
I suppose you don't actually want to
>> *( (char_('+') >> term) [_val = phx::construct<binop<op_add>>(_1, _2)]
| (char_('-') >> term) [_val = phx::construct<binop<op_sub>>(_1, _2)]
Pass '+'
as the first constructor parameter, because the type binop<op_add>
already reflects the kind of operator. So, you would likely want to have the left-hand operand as the first argument.
This is the argument that you now parse here:
term [_val = _1]
This should probably clue you in: you just assigned it to... _val
! So, there's your solution:
>> *( (char_('+') >> term) [_val = phx::construct<binop<op_add>>(_val, _2)]
| (char_('-') >> term) [_val = phx::construct<binop<op_sub>>(_val, _2)]
However, since the exposed attribute from char_(...)
isn't used, you can replace it:
>> *( (lit('+') >> term) [_val = phx::construct<binop<op_add>>(_val, _1)]
| (lit('-') >> term) [_val = phx::construct<binop<op_sub>>(_val, _1
)]