Skip to content

Instantly share code, notes, and snippets.

@na-ka-na
Created March 13, 2011 23:27
Show Gist options
  • Save na-ka-na/868550 to your computer and use it in GitHub Desktop.
Save na-ka-na/868550 to your computer and use it in GitHub Desktop.
C++ PEG expression grammar using Boost::Spirit
/*
* 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