What is the right way to transform some expression to AST using Boost.Spirit?
I tried to build it, but I think its messy and can be simplified a lot.
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
namespace ast {
struct unary_operator;
struct binary_operator;
struct expression {
typedef boost::variant<
double,
std::string,
boost::recursive_wrapper<unary_operator>,
boost::recursive_wrapper<binary_operator>,
boost::recursive_wrapper<expression>
> type;
expression() {
}
template<typename Expr>
expression(const Expr &expr)
: expr(expr) {
}
expression &operator+=(expression rhs);
expression &operator-=(expression rhs);
expression &operator*=(expression rhs);
expression &operator/=(expression rhs);
expression &and_(expression rhs);
expression &or_(expression rhs);
expression &equals(expression rhs);
expression ¬_equals(expression rhs);
expression &less_than(expression rhs);
expression &less_equals(expression rhs);
expression &greater_than(expression rhs);
expression &greater_equals(expression rhs);
expression &factor(expression rhs);
expression &dot(expression rhs);
type expr;
};
struct unary_operator {
std::string op;
expression rhs;
unary_operator() {}
unary_operator(std::string op, expression rhs)
: op(std::move(op)), rhs(std::move(rhs)) {
}
};
struct binary_operator {
std::string op;
expression lhs;
expression rhs;
binary_operator() {}
binary_operator(std::string op, expression lhs, expression rhs)
: op(std::move(op)), lhs(std::move(lhs)), rhs(std::move(rhs)) {
}
};
expression &expression::operator+=(expression rhs) {
expr = binary_operator("+", std::move(expr), std::move(rhs));
return *this;
}
expression &expression::operator-=(expression rhs) {
expr = binary_operator("-", std::move(expr), std::move(rhs));
return *this;
}
expression &expression::operator*=(expression rhs) {
expr = binary_operator("*", std::move(expr), std::move(rhs));
return *this;
}
expression &expression::operator/=(expression rhs) {
expr = binary_operator("/", std::move(expr), std::move(rhs));
return *this;
}
expression &expression::and_(expression rhs) {
expr = binary_operator("&&", std::move(expr), std::move(rhs));
return *this;
}
expression &expression::or_(expression rhs) {
expr = binary_operator("||", std::move(expr), std::move(rhs));
return *this;
}
expression &expression::equals(expression rhs) {
expr = binary_operator("==", std::move(expr), std::move(rhs));
return *this;
}
expression &expression::not_equals(expression rhs) {
expr = binary_operator("!=", std::move(expr), std::move(rhs));
return *this;
}
expression &expression::less_than(expression rhs) {
expr = binary_operator("<", std::move(expr), std::move(rhs));
return *this;
}
expression &expression::less_equals(expression rhs) {
expr = binary_operator("<=", std::move(expr), std::move(rhs));
return *this;
}
expression &expression::greater_than(expression rhs) {
expr = binary_operator(">", std::move(expr), std::move(rhs));
return *this;
}
expression &expression::greater_equals(expression rhs) {
expr = binary_operator(">=", std::move(expr), std::move(rhs));
return *this;
}
expression &expression::factor(expression rhs) {
expr = binary_operator("**", std::move(expr), std::move(rhs));
return *this;
}
expression &expression::dot(expression rhs) {
expr = binary_operator(".", std::move(expr), std::move(rhs));
return *this;
}
struct printer {
void operator()(const double n) const {
std::cout << n;
}
void operator()(const std::string &s) const {
std::cout << s;
}
void operator()(const expression &ast) const {
boost::apply_visitor(*this, ast.expr);
}
void operator()(const binary_operator &expr) const {
std::cout << "op:" << expr.op << "(";
boost::apply_visitor(*this, expr.lhs.expr);
std::cout << ", ";
boost::apply_visitor(*this, expr.rhs.expr);
std::cout << ')';
}
void operator()(const unary_operator &expr) const {
std::cout << "op:" << expr.op << "(";
boost::apply_visitor(*this, expr.rhs.expr);
std::cout << ')';
}
};
struct operators {
struct and_ {
};
struct or_ {
};
struct equals {
};
struct not_equals {
};
struct less_than {
};
struct less_equals {
};
struct greater_than {
};
struct greater_equals {
};
struct factor {
};
struct dot {
};
expression &operator()(expression &lhs, expression rhs, and_) const {
return lhs.and_(std::move(rhs));
}
expression &operator()(expression &lhs, expression rhs, or_) const {
return lhs.or_(std::move(rhs));
}
expression &operator()(expression &lhs, expression rhs, equals) const {
return lhs.equals(std::move(rhs));
}
expression &operator()(expression &lhs, expression rhs, not_equals) const {
return lhs.not_equals(std::move(rhs));
}
expression &operator()(expression &lhs, expression rhs, less_than) const {
return lhs.less_than(std::move(rhs));
}
expression &operator()(expression &lhs, expression rhs, less_equals) const {
return lhs.less_equals(std::move(rhs));
}
expression &operator()(expression &lhs, expression rhs, greater_than) const {
return lhs.greater_than(std::move(rhs));
}
expression &operator()(expression &lhs, expression rhs, greater_equals) const {
return lhs.greater_equals(std::move(rhs));
}
expression &operator()(expression &lhs, expression rhs, factor) const {
return lhs.factor(std::move(rhs));
}
expression &operator()(expression &lhs, expression rhs, dot) const {
return lhs.dot(std::move(rhs));
}
};
}
namespace qi = boost::spirit::qi;
struct expectation_handler {
template<typename Iterator>
void operator()(Iterator first, Iterator last, const boost::spirit::info &info) const {
std::stringstream msg;
msg << "Expected " << info << " at \"" << std::string(first, last) << "\"";
throw std::runtime_error(msg.str());
}
};
template<typename Iterator>
struct grammar : qi::grammar<Iterator, ast::expression(), qi::ascii::space_type> {
grammar()
: grammar::base_type(expression) {
variable = qi::lexeme[qi::alpha >> *(qi::alnum | '_')];
expression = logical.alias() > qi::eoi;
logical = equality[qi::_val = qi::_1]
>> *(
((qi::lit("&&") > equality[op(qi::_val, qi::_1, ast::operators::and_{})]) |
(qi::lit("||") > equality[op(qi::_val, qi::_1, ast::operators::or_{})]))
);
equality = relational[qi::_val = qi::_1]
>> *(
((qi::lit("==") > relational[op(qi::_val, qi::_1, ast::operators::equals{})]) |
(qi::lit("!=") > relational[op(qi::_val, qi::_1, ast::operators::not_equals{})]))
);
relational = additive[qi::_val = qi::_1]
>> *(
((qi::lit("<") > relational[op(qi::_val, qi::_1, ast::operators::less_than{})]) |
(qi::lit("<=") > relational[op(qi::_val, qi::_1, ast::operators::less_equals{})]) |
(qi::lit(">") > relational[op(qi::_val, qi::_1, ast::operators::greater_than{})]) |
(qi::lit(">=") > relational[op(qi::_val, qi::_1, ast::operators::greater_equals{})]))
);
additive = multiplicative[qi::_val = qi::_1]
>> *(
((qi::lit("+") > multiplicative[qi::_val += qi::_1]) |
(qi::lit("-") > multiplicative[qi::_val -= qi::_1]))
);
multiplicative = factor[qi::_val = qi::_1]
>> *(
((qi::lit("*") > factor[qi::_val *= qi::_1]) |
(qi::lit("/") > factor[qi::_val /= qi::_1]))
);
factor = primary[qi::_val = qi::_1]
>> *((qi::lit("**")) > primary[op(qi::_val, qi::_1, ast::operators::factor{})]);
primary =
qi::double_[qi::_val = qi::_1]
| ('(' > expression[qi::_val = qi::_1] > ')')
>> *(qi::char_('.') > variable[qi::_val = op(qi::_val, qi::_1, ast::operators::dot{})])
| variable[qi::_val = qi::_1]
>> *(qi::char_('.') > variable[qi::_val = op(qi::_val, qi::_1, ast::operators::dot{})]);
qi::on_error<qi::fail>(
expression,
boost::phoenix::bind(boost::phoenix::ref(err_handler), qi::_3, qi::_2, qi::_4));
}
qi::rule<Iterator, ast::expression(), qi::ascii::space_type> expression, logical, equality, relational, additive, multiplicative, factor, unary, binary, primary;
qi::rule<Iterator, std::string()> variable;
boost::phoenix::function<ast::operators> op;
expectation_handler err_handler;
};
int main(int argc, const char *argv[]) {
std::string input("2 + 5 + t.a");
auto it_begin(input.begin()), it_end(input.end());
grammar<decltype(it_begin)> parser;
ast::expression expression;
qi::phrase_parse(it_begin, it_end, parser, qi::ascii::space, expression);
ast::printer printer;
printer(expression);
return 0;
}
Prints
op:+(op:+(2, 5), op:.(t, a))