Last active
August 29, 2015 14:04
-
-
Save hsk/1af9ac2c3820841491c6 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <boost/config/warning_disable.hpp> | |
#include <boost/spirit/include/qi.hpp> | |
#include <boost/variant/recursive_variant.hpp> | |
#include <boost/variant/apply_visitor.hpp> | |
#include <boost/spirit/include/phoenix_operator.hpp> | |
#include <boost/spirit/include/phoenix_function.hpp> | |
#include <iostream> | |
#include <vector> | |
#include <string> | |
#define rw boost::recursive_wrapper | |
#define visit(v) boost::apply_visitor(*this, v) | |
#define match(t) public boost::static_visitor<t> | |
#define case(a) operator()(a) const | |
struct E1; | |
struct E2; | |
typedef boost::variant<int, rw<E1>, rw<E2> > E; | |
struct E2 { | |
char op;E a;E b; | |
E2(char op, E const& a, E const& b) : op(op), a(a), b(b) {} | |
}; | |
struct E1 { | |
char op; E e; | |
E1() : op('n'),e(0) {} | |
E1(char op, E const& a) : op(op), e(a) {} | |
template <typename T> E1(T const& e): op('m'),e(e) {} | |
E1& operator+=(E1 const& rhs) { | |
e = E2(rhs.op, e, rhs.e); | |
return *this; | |
} | |
}; | |
struct EOp { | |
char op; | |
EOp(char op):op(op){} | |
template <typename T> struct result { | |
typedef T type; | |
}; | |
E1 operator()(E1 const& e) const { | |
return E1(op, e); | |
} | |
}; | |
typedef boost::phoenix::function<EOp> eop; | |
namespace qi = boost::spirit::qi; | |
namespace ascii = boost::spirit::ascii; | |
using qi::_val; | |
using qi::_1; | |
using qi::int_; | |
template <typename Iterator> | |
struct parser : qi::grammar<Iterator, E1(), ascii::space_type> { | |
qi::rule<Iterator, E1(), ascii::space_type> expr, term, fact; | |
parser() : parser::base_type(expr) { | |
expr = term [_val = _1] >> *( | |
'+' >> term [_val += eop('+')(_1)] | | |
'-' >> term [_val += eop('-')(_1)] | |
); | |
term = fact [_val = _1] >> *( | |
'*' >> fact [_val += eop('*')(_1)] | | |
'/' >> fact [_val += eop('/')(_1)] | |
); | |
fact = int_ [_val = _1] | |
| '(' >> expr [_val = _1] >> ')' | |
| '-' >> fact [_val = eop('-')(_1)]; | |
} | |
}; | |
struct cnv : match(E) { | |
E case(int n) { return n; } | |
E case(E1 const& e) { | |
switch(e.op) { | |
case 'm': return visit(e.e); | |
default: return E1(e.op,visit(e.e)); | |
} | |
} | |
E case(E2 const& e) { | |
return E2(e.op,visit(e.a),visit(e.b)); | |
} | |
}; | |
E parse(std::string const& str) { | |
using boost::spirit::ascii::space; | |
typedef std::string::const_iterator iterator_type; | |
E1 e; | |
std::string::const_iterator iter = str.begin(); | |
std::string::const_iterator end = str.end(); | |
bool r = phrase_parse(iter, end, parser<iterator_type>(), space, e) && iter == end; | |
if(!r)e.op='e'; | |
return cnv()(e); | |
} | |
struct print : match(void) { | |
void case(int n) { | |
std::cout << n; | |
} | |
void case(E1 const& e) { | |
std::cout << e.op << "("; | |
visit(e.e); | |
std::cout << ')'; | |
} | |
void case(E2 const& e) { | |
std::cout << e.op << "("; | |
visit(e.a); | |
std::cout << ", "; | |
visit(e.b); | |
std::cout << ')'; | |
} | |
}; | |
struct eval : match(int) { | |
int case(int n) { return n; } | |
int case(E1 const& e) { | |
switch(e.op) { | |
case '-': return -visit(e.e); | |
default: return visit(e.e); | |
} | |
} | |
int case(E2 const& e) { | |
switch(e.op) { | |
case '+': return visit(e.a) + visit(e.b); | |
case '-': return visit(e.a) - visit(e.b); | |
case '*': return visit(e.a) * visit(e.b); | |
case '/': return visit(e.a) / visit(e.b); | |
default: return 0; | |
} | |
} | |
}; | |
int main(int argv, char** args) { | |
std::cout << args[1] << std::endl; | |
E e = parse(args[1]); | |
print()(e); std::cout << std::endl; | |
std::cout << eval()(e) << std::endl; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment