Created
March 13, 2011 23:27
-
-
Save na-ka-na/868550 to your computer and use it in GitHub Desktop.
C++ PEG expression grammar using Boost::Spirit
This file contains 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
/* | |
* expression_evaluator.cpp | |
* | |
* Created on: Mar 13, 2011 | |
* Author: ka | |
*/ | |
#define BOOST_SPIRIT_QI_DEBUG | |
#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/spirit/home/phoenix/object/new.hpp> | |
#include <boost/fusion/include/adapt_struct.hpp> | |
#include <boost/variant/recursive_variant.hpp> | |
#include <boost/foreach.hpp> | |
#include <iostream> | |
#include <fstream> | |
#include <string> | |
#include <vector> | |
namespace egr | |
{ | |
namespace fusion = boost::fusion; | |
namespace phoenix = boost::phoenix; | |
namespace qi = boost::spirit::qi; | |
namespace ascii = boost::spirit::ascii; | |
//enum T {x, y, z}; | |
struct T{ | |
int t; | |
void print(); | |
int eval(); | |
}; | |
struct E; | |
struct V { | |
T t; | |
E* e; | |
bool isE; | |
void print(); | |
int eval(); | |
}; | |
struct A { | |
std::vector<V> vs; | |
void print(); | |
int eval(); | |
}; | |
struct O { | |
std::vector<A> as; | |
void print(); | |
int eval(); | |
}; | |
struct E { | |
O o; | |
void print(); | |
int eval(); | |
}; | |
void T::print(){ | |
std::cout << "T:" << t << std::endl; | |
} | |
void V::print(){ | |
std::cout << "V: " << isE << std::endl; | |
isE ? (*e).print() : t.print(); | |
} | |
void A::print(){ | |
std::cout << "A: " << vs.size() << std::endl; | |
for (std::vector<V>::iterator it = vs.begin(); it != vs.end(); ++it){ | |
(*it).print(); | |
} | |
} | |
void O::print(){ | |
std::cout << "O: " << as.size() << std::endl; | |
for (std::vector<A>::iterator it = as.begin(); it != as.end(); ++it){ | |
(*it).print(); | |
} | |
} | |
void E::print(){ | |
std::cout << "E:" << std::endl; | |
o.print(); | |
} | |
int T::eval(){ | |
return t; | |
} | |
int V::eval(){ | |
return isE ? (*e).eval() : t.eval(); | |
} | |
int A::eval(){ | |
int r=1; | |
for (std::vector<V>::iterator it = vs.begin(); it != vs.end(); ++it){ | |
r *= (*it).eval(); | |
} | |
return r; | |
} | |
int O::eval(){ | |
int r=0; | |
for (std::vector<A>::iterator it = as.begin(); it != as.end(); ++it){ | |
r += (*it).eval(); | |
} | |
return r; | |
} | |
int E::eval(){ | |
return o.eval(); | |
} | |
} | |
BOOST_FUSION_ADAPT_STRUCT( | |
egr::T, | |
(int, t) | |
) | |
BOOST_FUSION_ADAPT_STRUCT( | |
egr::V, | |
(egr::T, t) | |
(egr::E*, e) | |
(bool, isE) | |
) | |
BOOST_FUSION_ADAPT_STRUCT( | |
egr::A, | |
(std::vector<egr::V>, vs) | |
) | |
BOOST_FUSION_ADAPT_STRUCT( | |
egr::O, | |
(std::vector<egr::A>, as) | |
) | |
BOOST_FUSION_ADAPT_STRUCT( | |
egr::E, | |
(egr::O, o) | |
) | |
namespace egr | |
{ | |
template <typename Iterator> | |
struct expression_grammar : qi::grammar<Iterator, E(), ascii::space_type>{ | |
qi::rule<Iterator, E(), ascii::space_type> e; | |
qi::rule<Iterator, O(), ascii::space_type> o; | |
qi::rule<Iterator, A(), ascii::space_type> a; | |
qi::rule<Iterator, V(), ascii::space_type> v; | |
qi::rule<Iterator, T(), ascii::space_type> t; | |
expression_grammar() : expression_grammar::base_type(e) | |
{ | |
using qi::lit; | |
using qi::lexeme; | |
using ascii::char_; | |
using ascii::string; | |
using namespace qi::labels; | |
using qi::int_; | |
using phoenix::at_c; | |
using phoenix::push_back; | |
using phoenix::new_; | |
//e = o; | |
//o = a >> *("+" >> a); | |
//a = v >> *("*" >> v); | |
//v = t | '(' >> e >> ')'; | |
//t = int_; | |
e = o [at_c<0>(_val) = _1]; | |
o = a [push_back(at_c<0>(_val), _1)] >> *("+" >> a [push_back(at_c<0>(_val), _1)]); | |
a = v [push_back(at_c<0>(_val), _1)] >> *("*" >> v [push_back(at_c<0>(_val), _1)]); | |
v = t [at_c<0>(_val) = _1] | |
[at_c<2>(_val) = false] | |
| ('(' >> e [at_c<1>(_val) = new_<E>()] | |
[*(at_c<1>(_val)) = _1] | |
[at_c<2>(_val) = true] | |
>> ')'); | |
t = int_ [at_c<0>(_val) = _1]; | |
//BOOST_SPIRIT_DEBUG_NODE(e); | |
//BOOST_SPIRIT_DEBUG_NODE(o); | |
//BOOST_SPIRIT_DEBUG_NODE(a); | |
//BOOST_SPIRIT_DEBUG_NODE(v); | |
//BOOST_SPIRIT_DEBUG_NODE(t); | |
} | |
}; | |
} | |
int main(int argc, char **argv){ | |
typedef egr::expression_grammar<std::string::const_iterator> expression_grammar; | |
expression_grammar exp_gr; // Our grammar | |
egr::E exp_ast; // Our tree | |
using boost::spirit::ascii::space; | |
std::string s; | |
while (getline(std::cin, s)){ | |
std::cout << "-------------------------\n"; | |
std::cout << "Parsing: " << s << std::endl; | |
std::string::const_iterator iter = s.begin(); | |
std::string::const_iterator end = s.end(); | |
bool r = phrase_parse(iter, end, exp_gr, space, exp_ast); | |
if (r && iter == end){ | |
std::cout << "Parsing succeeded\n"; | |
std::cout << "-------------------------\n"; | |
//exp_ast.print(); | |
std::cout << "eval: " << exp_ast.eval() << std::endl; | |
std::cout << std::endl; | |
} | |
else{ | |
std::string::const_iterator some = iter+30; | |
std::string context(iter, (some>end)?end:some); | |
std::cout << "Parsing failed\n"; | |
std::cout << "stopped at: \": " << context << "...\"\n"; | |
std::cout << "-------------------------\n"; | |
} | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment