As suggested in chat , you can start with something like:
expression = addition | simple; addition = simple >> ( ('+' > expression) | ('-' > expression) ); simple = '(' > expression > ')' | call | unary | number; call = id >> *expression; unary = qi::char_("-+") > expression; // terminals id = qi::lexeme[+qi::char_("az")]; number = qi::double_;
Since then, I implemented this in C ++ with an AST presentation so that you can understand how this grammar actually creates an expression tree by typing it pretty.
All source code is on github: https://gist.github.com/2152518
There are two versions (scroll down to "Alternative" to read more
Grammar:
template <typename Iterator> struct mini_grammar : qi::grammar<Iterator, expression_t(), qi::space_type> { qi::rule<Iterator, std::string(), qi::space_type> id; qi::rule<Iterator, expression_t(), qi::space_type> addition, expression, simple; qi::rule<Iterator, number_t(), qi::space_type> number; qi::rule<Iterator, call_t(), qi::space_type> call; qi::rule<Iterator, unary_t(), qi::space_type> unary; mini_grammar() : mini_grammar::base_type(expression) { expression = addition | simple; addition = simple [ qi::_val = qi::_1 ] >> +( (qi::char_("+-") > simple) [ phx::bind(&append_term, qi::_val, qi::_1, qi::_2) ] ); simple = '(' > expression > ')' | call | unary | number; call = id >> *expression; unary = qi::char_("-+") > expression;
Corresponding AST structures are detected quickly and dirty using the very powerful Boost option:
struct addition_t; struct call_t; struct unary_t; typedef double number_t; typedef boost::variant< number_t, boost::recursive_wrapper<call_t>, boost::recursive_wrapper<unary_t>, boost::recursive_wrapper<addition_t> > expression_t; struct addition_t { expression_t lhs; char binop; expression_t rhs; }; struct call_t { std::string id; std::vector<expression_t> args; }; struct unary_t { char unop; expression_t operand; }; BOOST_FUSION_ADAPT_STRUCT(addition_t, (expression_t, lhs)(char,binop)(expression_t, rhs)); BOOST_FUSION_ADAPT_STRUCT(call_t, (std::string, id)(std::vector<expression_t>, args)); BOOST_FUSION_ADAPT_STRUCT(unary_t, (char, unop)(expression_t, operand));
In the full code, I also overloaded the <<operator for these structures.
Full demo
//#define BOOST_SPIRIT_DEBUG #include <iostream> #include <iterator> #include <string> #include <boost/spirit/include/qi.hpp>
Alternative:
I have an alternative version that builds addition_t iteratively instead of recursively, so to speak:
struct term_t { char binop; expression_t rhs; }; struct addition_t { expression_t lhs; std::vector<term_t> terms; };
This eliminates the need to use Phoenix to create an expression:
addition = simple >> +term; term = qi::char_("+-") > simple;