Skip to content

Instantly share code, notes, and snippets.

@sehe
Created December 12, 2011 00:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sehe/267acc43ac7ee276e889 to your computer and use it in GitHub Desktop.
Save sehe/267acc43ac7ee276e889 to your computer and use it in GitHub Desktop.
#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/fusion/tuple.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/variant/recursive_variant.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/variant/apply_visitor.hpp>
#include <string>
#include <vector>
namespace ast {
struct add;
struct sub;
struct mul;
struct div;
struct func_call;
template<typename OpTag> struct binary_op;
typedef boost::variant<
double,
std::string,
boost::recursive_wrapper<binary_op<add>>,
boost::recursive_wrapper<binary_op<sub>>,
boost::recursive_wrapper<binary_op<mul>>,
boost::recursive_wrapper<binary_op<div>>,
boost::recursive_wrapper<func_call>
> expression;
template<typename OpTag>
struct binary_op {
expression left;
expression right;
binary_op(const expression & lhs, const expression & rhs) :
left(lhs), right(rhs) {
}
};
struct func_call {
std::string callee;
std::vector<expression> args;
func_call(const std::string func, const std::vector<expression> &args) :
callee(func), args(args) {
}
};
struct prototype {
std::string name;
std::vector<std::string> args;
prototype(const std::string &name, const std::vector<std::string> &args) :
name(name), args(args) {
}
};
struct function {
prototype proto;
expression body;
function(const prototype &proto, const expression &body) :
body(body), proto(proto) {
}
};
}
BOOST_FUSION_ADAPT_STRUCT(ast::binary_op<ast::add>, (ast::expression, left) (ast::expression, right));
BOOST_FUSION_ADAPT_STRUCT(ast::binary_op<ast::sub>, (ast::expression, left) (ast::expression, right));
BOOST_FUSION_ADAPT_STRUCT(ast::binary_op<ast::mul>, (ast::expression, left) (ast::expression, right));
BOOST_FUSION_ADAPT_STRUCT(ast::binary_op<ast::div>, (ast::expression, left) (ast::expression, right));
BOOST_FUSION_ADAPT_STRUCT(ast::func_call, (std::string, callee) (std::vector<ast::expression>, args));
namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;
using namespace qi;
template<typename Iterator>
struct expression: qi::grammar<Iterator, ast::expression(), ascii::space_type> {
static ast::expression make_binop(
const ast::expression& left,
const boost::fusion::vector2<char, ast::expression>& op_right)
{
switch(boost::fusion::get<0>(op_right))
{
case '+': return ast::binary_op<ast::add>(left, boost::fusion::get<1>(op_right));
case '-': return ast::binary_op<ast::sub>(left, boost::fusion::get<1>(op_right));
case '/': return ast::binary_op<ast::div>(left, boost::fusion::get<1>(op_right));
case '*': return ast::binary_op<ast::mul>(left, boost::fusion::get<1>(op_right));
}
throw std::runtime_error("unreachable in make_binop");
}
expression() :
expression::base_type(expr) {
number %= lexeme[double_];
varname %= lexeme[alpha >> *(alnum | '_')];
simple = varname | number;
binop %= (simple >> (char_("-+*/") > expr)) [ _val = phx::bind(make_binop, qi::_1, qi::_2) ];
expr %= binop | simple;
BOOST_SPIRIT_DEBUG_NODE(number);
BOOST_SPIRIT_DEBUG_NODE(varname);
BOOST_SPIRIT_DEBUG_NODE(binop);
BOOST_SPIRIT_DEBUG_NODE(simple);
BOOST_SPIRIT_DEBUG_NODE(expr);
}
qi::rule<Iterator, ast::expression(), ascii::space_type> simple, expr, binop;
qi::rule<Iterator, std::string(), ascii::space_type> varname;
qi::rule<Iterator, double(), ascii::space_type> number;
};
int main(int argc, const char *argv[])
{
typedef std::string::const_iterator It;
std::string input("1/2+3-4*5");
It f(input.begin()), l(input.end());
expression<It> parser;
ast::expression out;
bool ok = qi::phrase_parse(f,l,parser,qi::ascii::space,out);
if (ok)
std::cout << "Ok!" << std::endl;
else
std::cerr << "Oops: '" << std::string(f,l) << std::endl;
return 0;
}
#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/variant/recursive_variant.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/variant/apply_visitor.hpp>
#include <string>
#include <vector>
namespace ast {
struct add;
struct sub;
struct mul;
struct div;
struct func_call;
template<typename OpTag> struct binary_op;
typedef boost::variant<
double,
std::string,
boost::recursive_wrapper<binary_op<add>>,
boost::recursive_wrapper<binary_op<sub>>,
boost::recursive_wrapper<binary_op<mul>>,
boost::recursive_wrapper<binary_op<div>>,
boost::recursive_wrapper<func_call>
> expression;
template<typename OpTag>
struct binary_op {
expression left;
expression right;
binary_op(const expression & lhs, const expression & rhs) :
left(lhs), right(rhs) {
}
};
struct func_call {
std::string callee;
std::vector<expression> args;
func_call(const std::string func, const std::vector<expression> &args) :
callee(func), args(args) {
}
};
struct prototype {
std::string name;
std::vector<std::string> args;
prototype(const std::string &name, const std::vector<std::string> &args) :
name(name), args(args) {
}
};
struct function {
prototype proto;
expression body;
function(const prototype &proto, const expression &body) :
body(body), proto(proto) {
}
};
}
BOOST_FUSION_ADAPT_STRUCT(ast::binary_op<ast::add>, (ast::expression, left) (ast::expression, right));
BOOST_FUSION_ADAPT_STRUCT(ast::binary_op<ast::sub>, (ast::expression, left) (ast::expression, right));
BOOST_FUSION_ADAPT_STRUCT(ast::binary_op<ast::mul>, (ast::expression, left) (ast::expression, right));
BOOST_FUSION_ADAPT_STRUCT(ast::binary_op<ast::div>, (ast::expression, left) (ast::expression, right));
BOOST_FUSION_ADAPT_STRUCT(ast::func_call, (std::string, callee) (std::vector<ast::expression>, args));
namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;
using namespace qi;
template<typename Iterator>
struct expression: qi::grammar<Iterator, ast::expression(), ascii::space_type> {
static ast::expression make_binop(char discriminant, const ast::expression& left, const ast::expression& right)
{
switch(discriminant)
{
case '+': return ast::binary_op<ast::add>(left, right);
case '-': return ast::binary_op<ast::sub>(left, right);
case '/': return ast::binary_op<ast::div>(left, right);
case '*': return ast::binary_op<ast::mul>(left, right);
}
throw std::runtime_error("unreachable in make_binop");
}
expression() :
expression::base_type(expr) {
number %= lexeme[double_];
varname %= lexeme[alpha >> *(alnum | '_')];
simple = varname | number;
binop %= (simple >> char_("-+*/") >> expr) [ _val = phx::bind(make_binop, qi::_2, qi::_1, qi::_3) ];
expr %= binop | simple;
BOOST_SPIRIT_DEBUG_NODE(number);
BOOST_SPIRIT_DEBUG_NODE(varname);
BOOST_SPIRIT_DEBUG_NODE(binop);
BOOST_SPIRIT_DEBUG_NODE(simple);
BOOST_SPIRIT_DEBUG_NODE(expr);
}
qi::rule<Iterator, ast::expression(), ascii::space_type> simple, expr, binop;
qi::rule<Iterator, std::string(), ascii::space_type> varname;
qi::rule<Iterator, double(), ascii::space_type> number;
};
int main(int argc, const char *argv[])
{
typedef std::string::const_iterator It;
std::string input("1/2+3-4*5");
It f(input.begin()), l(input.end());
expression<It> parser;
ast::expression out;
bool ok = qi::phrase_parse(f,l,parser,qi::ascii::space,out);
if (ok)
std::cout << "Ok!" << std::endl;
else
std::cerr << "Oops: '" << std::string(f,l) << std::endl;
return 0;
}
#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/variant/recursive_variant.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/variant/apply_visitor.hpp>
#include <string>
#include <vector>
namespace ast {
struct add;
struct sub;
struct mul;
struct div;
struct func_call;
template<typename OpTag> struct binary_op;
typedef boost::variant<
double,
std::string,
boost::recursive_wrapper<binary_op<add>>,
boost::recursive_wrapper<binary_op<sub>>,
boost::recursive_wrapper<binary_op<mul>>,
boost::recursive_wrapper<binary_op<div>>,
boost::recursive_wrapper<func_call>
> expression;
template<typename OpTag>
struct binary_op {
expression left;
expression right;
binary_op(const expression & lhs, const expression & rhs) :
left(lhs), right(rhs) {
}
};
struct func_call {
std::string callee;
std::vector<expression> args;
func_call(const std::string func, const std::vector<expression> &args) :
callee(func), args(args) {
}
};
struct prototype {
std::string name;
std::vector<std::string> args;
prototype(const std::string &name, const std::vector<std::string> &args) :
name(name), args(args) {
}
};
struct function {
prototype proto;
expression body;
function(const prototype &proto, const expression &body) :
body(body), proto(proto) {
}
};
}
BOOST_FUSION_ADAPT_STRUCT(ast::binary_op<ast::add>, (ast::expression, left) (ast::expression, right));
BOOST_FUSION_ADAPT_STRUCT(ast::binary_op<ast::sub>, (ast::expression, left) (ast::expression, right));
BOOST_FUSION_ADAPT_STRUCT(ast::binary_op<ast::mul>, (ast::expression, left) (ast::expression, right));
BOOST_FUSION_ADAPT_STRUCT(ast::binary_op<ast::div>, (ast::expression, left) (ast::expression, right));
BOOST_FUSION_ADAPT_STRUCT(ast::func_call, (std::string, callee) (std::vector<ast::expression>, args));
namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;
using namespace qi;
template<typename Iterator>
struct expression: qi::grammar<Iterator, ast::expression(), ascii::space_type> {
static ast::expression make_binop(char discriminant, const ast::expression& left, const ast::expression& right)
{
switch(discriminant)
{
case '+': return ast::binary_op<ast::add>(left, right);
case '-': return ast::binary_op<ast::sub>(left, right);
case '/': return ast::binary_op<ast::div>(left, right);
case '*': return ast::binary_op<ast::mul>(left, right);
}
throw std::runtime_error("unreachable in make_binop");
}
expression() :
expression::base_type(expr) {
number %= lexeme[double_];
varname %= lexeme[alpha >> *(alnum | '_')];
simple = varname | number;
expr = simple [ _val = _1 ]
> *(char_("-+*/") > expr) [ _val = phx::bind(make_binop, qi::_1, _val, qi::_2) ]
> eoi;
BOOST_SPIRIT_DEBUG_NODE(number);
BOOST_SPIRIT_DEBUG_NODE(varname);
BOOST_SPIRIT_DEBUG_NODE(simple);
BOOST_SPIRIT_DEBUG_NODE(expr);
}
qi::rule<Iterator, ast::expression(), ascii::space_type> simple, expr;
qi::rule<Iterator, std::string(), ascii::space_type> varname;
qi::rule<Iterator, double(), ascii::space_type> number;
};
int main(int argc, const char *argv[])
{
typedef std::string::const_iterator It;
std::string input("1/2+3-4*5");
It f(input.begin()), l(input.end());
expression<It> parser;
ast::expression out;
bool ok = qi::phrase_parse(f,l,parser,qi::ascii::space,out);
if (ok)
std::cout << "Ok!" << std::endl;
else
std::cerr << "Oops: '" << std::string(f,l) << std::endl;
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment