I'm currently building an expression parser in Boost.Parser. It should be able to do
- Parentheses (
( ... )) and abs (| ... |) - Unary minus
- Power (
x^y) - (other arithmetic operations, not relevant for the question).
Here's my set-up so far:
class ExpressionAst { /* ... */ };
class NumberNode : public ExpressionAst { /* ... */ };
class UnaryOpNode : public ExpressionAST { /* ... */ };
class BinaryOpNode : public ExpressionAST { /* ... */ };
bp::rule<struct number_tag, SharedExprPtr> number = "number";
bp::rule<struct primary_tag, SharedExprPtr> primary = "primary";
bp::rule<struct unary_tag, SharedExprPtr> unary = "unary";
bp::rule<struct power_tag, SharedExprPtr> power = "power";
bp::rule<struct expression_tag, SharedExprPtr> expression = "expression";
auto make_unary_minus_node = [](auto& ctx) {
auto attr = _attr(ctx);
_val(ctx) = std::make_shared<UnaryOpNode>(std::move(attr), UnaryOpNode::Op::Negate);
};
auto make_parentheses_node = [](auto& ctx) { _val(ctx) = _attr(ctx); };
auto make_abs_node = [](auto& ctx) {
auto attr = _attr(ctx);
_val(ctx) = std::make_shared<UnaryOpNode>(std::move(attr), UnaryOpNode::Op::Abs);
};
auto const number_def = (-sign >> (hex_literal | octal_literal | binary_literal | decimal_literal) >> -quantifier)[make_number_node];
auto const primary_def = number //
| ('(' >> expression >> ')')[make_parentheses_node] //
| ('|' >> expression >> '|')[make_abs_node];
auto const unary_def = ('-' >> unary)[make_unary_minus_node] //
| primary;
auto const power_def = (unary >> -('^' >> power))[make_power_node];
auto const expression_def = power;
BOOST_PARSER_DEFINE_RULES(number, primary, unary, power, expression);
Now it comes to the implementation of my make_power_node semantic action:
auto make_power_node = [](auto& ctx) {
using attr = std::remove_cvref_t<decltype(_attr(ctx))>;
static_assert(!std::is_same_v<attr, SharedExprPtr>);
// Make compiler happy for now
_val(ctx) = std::make_shared<BinaryOpNode>(nullptr, nullptr, BinaryOpNode::Op::Pow);
};
I would've expected _attr(ctx) to just be a tuple<SharedExprPtr, std::optional<SharedExprPtr>>, and to just be able to destructure it. This doesn't seem to be the case. What am I doing wrong?