#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/variant/recursive_variant.hpp>
#include <boost/foreach.hpp>
#include <iostream>
#include <string>
#include <vector>
namespace fun_lang {
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
namespace phoenix = boost::phoenix;
namespace fusion = boost::fusion;
struct number_node {
long value;
};
struct operation_node;
typedef boost::variant<
boost::recursive_wrapper<operation_node>,
number_node
> node;
struct operation_node {
node left, right;
char op;
};
struct program {
std::vector<node> nodes;
};
}
BOOST_FUSION_ADAPT_STRUCT(fun_lang::program, (std::vector<fun_lang::node>, nodes));
BOOST_FUSION_ADAPT_STRUCT(fun_lang::number_node, (long, value));
BOOST_FUSION_ADAPT_STRUCT(fun_lang::operation_node, (fun_lang::node, left) (char, op) (fun_lang::node, right));
namespace fun_lang {
template <typename Iterator, typename Skipper>
struct fun_grammar : qi::grammar<Iterator, program(), Skipper> {
fun_grammar() : fun_grammar::base_type(start) {
using ascii::char_;
using qi::ulong_;
using qi::_val;
using qi::_1;
using phoenix::push_back;
using phoenix::at_c;
expression = (integer | operation)[_val = _1];
oper = (char_('+') | char_('-') | char_('*') | char_('/'))[_val = _1];
integer = ulong_[at_c<0>(_val) = _1];
operation = expression[at_c<0>(_val) = _1] >> oper[at_c<1>(_val) = _1] >> expression[at_c<2>(_val) = _1];
start = *expression[push_back(at_c<0>(_val), _1)];
}
qi::rule<Iterator, program(), Skipper> start;
qi::rule<Iterator, number_node(), Skipper> integer;
qi::rule<Iterator, char(), Skipper> oper;
qi::rule<Iterator, node(), Skipper> expression;
qi::rule<Iterator, operation_node(), Skipper> operation;
};
struct node_printer : boost::static_visitor<> {
void operator()(number_node const &node) const {
std::cout << "number_node(" << node.value << ")\n";
}
void operator()(operation_node const &node) const {
std::cout << "operation_node(";
std::cout << " "; boost::apply_visitor(*this, node.left);
std::cout << " operator(" << node.op << ")\n";
std::cout << " "; boost::apply_visitor(*this, node.right);
std::cout << ")\n";
}
};
}
int main(int argc, char *argv[]) {
using std::cout;
std::string input;
getline(std::cin, input);
cout << "Received input \"" << input << "\"\n\n";
typedef fun_lang::fun_grammar<std::string::const_iterator, boost::spirit::ascii::space_type> fun_grammar;
fun_grammar grammar;
fun_lang::program program;
std::string::const_iterator begin = input.begin(), end = input.end();
bool success = phrase_parse(begin, end, grammar, boost::spirit::ascii::space, program);
if (success && begin == end) {
cout << "Successful\n\n";
fun_lang::node_printer printer;
BOOST_FOREACH(fun_lang::node const &node, program.nodes) {
boost::apply_visitor(printer, node);
}
} else {
std::string::const_iterator some = begin + 30;
std::string context(begin, (some > end) ? end : some);
cout << "Failure: \"" << context << "\"\n\n";
}
return 0;
}