#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/variant/variant.hpp>
#include <iostream>
#include <string>
#include <vector>
#include <cmath>
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
struct STNode
{
enum {ROOT, DOUBLE, STRING, ADD, SUB, MUL, DIV, POW, MINUS, PRINT};
STNode() : type(ROOT) {}
int type;
boost::variant<double, std::vector<char>, boost::spirit::unused_type> value;
std::vector<STNode> children;
double Eval(std::ostream & os = std::cout)
{
switch(type)
{
case ROOT : return children[0].Eval();
case DOUBLE : return boost::get<double>(value);
case ADD : return children[1].Eval() + children[0].Eval();
case SUB : return children[1].Eval() - children[0].Eval();
case MUL : return children[1].Eval() * children[0].Eval();
case DIV : return children[1].Eval() / children[0].Eval();
case POW : return std::pow(children[1].Eval(), children[0].Eval());
case MINUS : return - children[0].Eval();
case PRINT : return children[0].Eval();
case STRING :
{
std::vector<char> str = boost::get<std::vector<char> >(value);
os << std::string(str.begin(), str.end()) << std::endl; return 0.0;
}
}
}
} st;
struct AddNode
{
int nodeType;
STNode & root;
AddNode(STNode & r, int type) : nodeType(type), root(r) {}
void operator()(boost::variant<double, std::vector<char>, boost::spirit::unused_type> value,
boost::spirit::unused_type, boost::spirit::unused_type) const
{
STNode newNode;
newNode.type = nodeType;
newNode.value = value;
if (nodeType == STNode::DOUBLE || nodeType == STNode::STRING)
root.children.push_back(newNode);
else
{
newNode.children.push_back(root.children.back());
root.children.pop_back();
if (!root.children.empty())
{
newNode.children.push_back(root.children.back());
root.children.pop_back();
}
root.children.push_back(newNode);
}
}
};
template <typename Iterator>
struct interpreter_grammar : qi::grammar<Iterator, int(), ascii::space_type>
{
interpreter_grammar() : interpreter_grammar::base_type(entry)
{
entry = math_expression [qi::_val = 1] | print_expression [qi::_val = qi::_1] ;
math_expression = term >>
*( ('+' >> term) [AddNode(st, STNode::ADD)]
| ('-' >> term) [AddNode(st, STNode::SUB)]);
term = factor >>
*( ('*' >> factor) [AddNode(st, STNode::MUL)]
| ('/' >> factor) [AddNode(st, STNode::DIV)]);
factor = primary >> *('^' >> primary [AddNode(st, STNode::POW)]);
primary = qi::double_ [AddNode(st, STNode::DOUBLE)]
| '(' >> math_expression >> ')'
| '-' >> !(qi::lit('-')|'+') >> primary [AddNode(st, STNode::MINUS)]
| '+' >> !(qi::lit('-')|'+') >> primary;
print_expression = qi::lexeme["print" >> qi::space] >> (
math_expression [qi::_val = 1]
| qi::lexeme[('"' >> (*(qi::char_ - '"')) [AddNode(st, STNode::STRING)]
>> qi::lit('"') [AddNode(st, STNode::PRINT)] ) [qi::_val = 2]]);
}
qi::rule<Iterator, int(), ascii::space_type> entry, print_expression, math_expression;
qi::rule<Iterator, ascii::space_type> term, factor, primary;
};
int main()
{
using namespace std;
cout << "type an expression... or empty line to quit\n\n";
interpreter_grammar<string::const_iterator> my_grammar;
string str;
while (getline(cin, str))
{
if (str.empty()) break;
string::const_iterator iter = str.begin();
string::const_iterator end = str.end();
int exp_type; st = STNode();
bool r = phrase_parse(iter, end, my_grammar, ascii::space, exp_type);
if (r && iter == end)
{
double result = st.Eval();
if (exp_type == 1) cout << result << endl;
}
else cout << "invalid expression..." << endl;
}
return 0;
}