Related
I'm trying to parse some expression. I started from impressive answers of llonesmiz and Sehe
I wanted to add some:
(1) defined parameters. These prams are given as map by another class. They may have no argument (integer) one or two :
imf ---> $imf
imf(1) ---> $imf(1)
imf(1,2) ---> $imf(1,2)
I'm traying to fist get the parameter name "imf" an then its arguments if they exist (1), (2,2) ...
(2) defined function given as a map by another class. They may have one, two or three argument :
cos(1) ---> cos(1)
cross(imf(1),1) ---> cross($imf(1),1)
fun3(1,2,1) ---> fun3(1,2,1)
custom_fold_directive.hpp
namespace custom
{
namespace tag
{
struct fold { BOOST_SPIRIT_IS_TAG() };
}
template <typename Exposed, typename Expr>
boost::spirit::stateful_tag_type<Expr, tag::fold, Exposed>
fold(Expr const& expr)
{
return boost::spirit::stateful_tag_type<Expr, tag::fold, Exposed>(expr);
}
}
namespace boost { namespace spirit
{
template <typename Expr, typename Exposed>
struct use_directive<qi::domain
, tag::stateful_tag<Expr, custom::tag::fold, Exposed> >
: mpl::true_ {};
}}
namespace custom
{
template <typename Exposed, typename InitialParser, typename RepeatingParser>
struct fold_directive
{
fold_directive(InitialParser const& initial, RepeatingParser const& repeating):initial(initial),repeating(repeating){}
template <typename Context, typename Iterator>
struct attribute
{
typedef typename boost::spirit::traits::attribute_of<InitialParser,Context,Iterator>::type type;//This works in this case but is not generic
};
template <typename Iterator, typename Context
, typename Skipper, typename Attribute>
bool parse(Iterator& first, Iterator const& last
, Context& context, Skipper const& skipper, Attribute& attr_) const
{
Iterator start = first;
typename boost::spirit::traits::attribute_of<InitialParser,Context,Iterator>::type initial_attr;
if (!initial.parse(first, last, context, skipper, initial_attr))
{
first=start;
return false;
}
typename boost::spirit::traits::attribute_of<RepeatingParser,Context,Iterator>::type repeating_attr;
if(!repeating.parse(first, last, context, skipper, repeating_attr))
{
boost::spirit::traits::assign_to(initial_attr, attr_);
return true;
}
Exposed current_attr(initial_attr,repeating_attr);
while(repeating.parse(first, last, context, skipper, repeating_attr))
{
boost::spirit::traits::assign_to(Exposed(current_attr,repeating_attr),current_attr);
}
boost::spirit::traits::assign_to(current_attr,attr_);
return true;
}
template <typename Context>
boost::spirit::info what(Context& context) const
{
return boost::spirit::info("fold");
}
InitialParser initial;
RepeatingParser repeating;
};
}
namespace boost { namespace spirit { namespace qi
{
template <typename Expr, typename Exposed, typename Subject, typename Modifiers>
struct make_directive<
tag::stateful_tag<Expr, custom::tag::fold, Exposed>, Subject, Modifiers>
{
typedef custom::fold_directive<Exposed, Expr, Subject> result_type;
template <typename Terminal>
result_type operator()(Terminal const& term, Subject const& subject, Modifiers const&) const
{
typedef tag::stateful_tag<
Expr, custom::tag::fold, Exposed> tag_type;
using spirit::detail::get_stateful_data;
return result_type(get_stateful_data<tag_type>::call(term),subject);
}
};
}}}
main.cpp
//#define BOOST_SPIRIT_DEBUG
#include <iostream>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include "custom_fold_directive.hpp"
namespace qi = boost::spirit::qi;
// DEFINING TYPES
struct op_not {};
struct op_or {};
struct op_and {};
struct op_equal {};
struct op_unequal {};
struct op_sum {};
struct op_difference {};
struct op_factor {};
struct op_division {};
struct op_component{};
namespace Expression{
typedef std::string var;
template <typename tag> struct binop;
template <typename tag> struct unop;
/*
* tree structure definition
*/
typedef boost::variant<var,
boost::recursive_wrapper<unop <op_not> >,
boost::recursive_wrapper<binop<op_equal> >,
boost::recursive_wrapper<binop<op_unequal> >,
boost::recursive_wrapper<binop<op_and> >,
boost::recursive_wrapper<binop<op_or> >,
boost::recursive_wrapper<binop<op_difference> >,
boost::recursive_wrapper<binop<op_sum> >,
boost::recursive_wrapper<binop<op_factor> >,
boost::recursive_wrapper<binop<op_division> >,
boost::recursive_wrapper<binop<op_component> >
> expressionContainer;
template <typename tag> struct binop
{
explicit binop(const expressionContainer& l
, const expressionContainer& r)
: oper1(l), oper2(r) { }
expressionContainer oper1, oper2;
};
template <typename tag> struct comop
{
explicit comop(const expressionContainer& l
, const expressionContainer& r)
: oper1(l), oper2(r) { }
expressionContainer oper1, oper2;
};
template <typename tag> struct unop
{
explicit unop(const expressionContainer& o) : oper1(o) { }
expressionContainer oper1;
};
struct printer : boost::static_visitor<void>
{
printer(std::ostream& os) : _os(os) {}
std::ostream& _os;
//
void operator()(const var& v) const { _os << v;}
// Logical
void operator()(const binop<op_and>& b) const { print(" & ", b.oper1, b.oper2); }
void operator()(const binop<op_or >& b) const { print(" || ", b.oper1, b.oper2); }
void operator()(const binop<op_equal>& b) const { print(" == ", b.oper1, b.oper2); }
void operator()(const binop<op_unequal>& b) const { print(" != ", b.oper1, b.oper2); }
//Math operators
void operator()(const binop<op_difference>& b) const { print("-", b.oper1, b.oper2); }
void operator()(const binop<op_sum>& b) const { print("+", b.oper1, b.oper2); }
void operator()(const binop<op_factor>& b) const { print("*", b.oper1, b.oper2); }
void operator()(const binop<op_division>& b) const { print("/", b.oper1, b.oper2); }
void operator()(const binop<op_component>& b) const { print(",", b.oper1, b.oper2); }
//unique operators
void operator()(const unop<op_not>& u) const{printUnique("!",u.oper1);}
//Printer
void print(const std::string& op, const expressionContainer& l, const expressionContainer& r) const
{
_os << "(";
boost::apply_visitor(*this, l);
_os << op;
boost::apply_visitor(*this, r);
_os << ")";
}
void printUnique(const std::string& op, const expressionContainer& l) const
{
_os << op;
boost::apply_visitor(*this, l);
}
void printPower(const std::string& op, const expressionContainer& l, const expressionContainer& r) const
{
boost::apply_visitor(*this, l);
_os << op;
boost::apply_visitor(*this, r);
}
void printOutSide(const std::string& op, const expressionContainer& l, const expressionContainer& r) const
{
_os << op;
_os << "(";
boost::apply_visitor(*this, l);
_os << ",";
boost::apply_visitor(*this, r);
_os << ")";
}
/**
* void printConst( const expressionContainer& l) const
{
std::map<std::string, std::string> consts;
consts["#pi"] = "3.14";
consts["#ro"]="1.5";
std::string key="#"+l.
boost::apply_visitor(*this, consts(key));
}
* #param l
*/
};
std::ostream& operator<<(std::ostream& os, const expressionContainer& e)
{ boost::apply_visitor(printer(os), e); return os; }
}
/*
* EXPRESSION PARSER DEFINITION
*/
template <typename It, typename Skipper = boost::spirit::standard_wide::space_type>
struct parserExpression : qi::grammar<It, Expression::expressionContainer(), Skipper>
{
parserExpression() : parserExpression::base_type(expr_)
{
using namespace qi;
using namespace Expression;
using custom::fold;
expr_ = or_.alias();
// Logical Operators
or_ = fold<binop<op_or> >(and_.alias())[orOperator_ >> and_];
and_ = fold<binop<op_and> >(equal_.alias())[andOperator_ >> equal_];
equal_ = fold<binop<op_equal> >(unequal_.alias())[equalOperator_ >> unequal_];
unequal_ = fold<binop<op_unequal> >(sum_.alias())[unequalOperator_ >>sum_];
// Numerical Operators
sum_ = fold<binop<op_sum> >(difference_.alias())[sumOperator_ >> difference_];
difference_ = fold<binop<op_difference> >(factor_.alias())[differenceOperator_ >> factor_];
factor_ = fold<binop<op_factor> >(division_.alias())[factorOperator_ >> division_];
division_ = fold<binop<op_division> >(not_.alias())[divisionOperator_ >> not_];
// UNARY OPERATION
not_ = (notOperator_ > param_) [_val = boost::phoenix::construct<Expression::unop <op_not>>(_1)] | param_[_val=_1];
param_ = (definedParams ) [_val =_1] | component_[_val = _1];
component_=definedParams >> '(' >> args_[_val=_1] >>')'| simple[_val = _1];
simple = (('(' > expr_ > ')') | var_);
var_ %= qi::raw[+qi::double_];
args_%=qi::raw[+qi::int_ % ','];
notOperator_ = qi::char_('!');
andOperator_ = qi::string("&&");
orOperator_ = qi::string("||");
xorOperator_ = qi::char_("^");
equalOperator_ = qi::string("==");
unequalOperator_ = qi::string("!=");
sumOperator_ = qi::char_("+");
differenceOperator_ = qi::char_("-");
factorOperator_ = qi::char_("*");
divisionOperator_ = qi::char_("/");
greaterOperator_ = qi::char_(">");
greaterOrEqualOperator_ = qi::string(">=");
lowerOrEqualOperator_ = qi::string("<=");
lowerOperator_ = qi::char_("<");
componentOperator_=qi::char_(",");
// Defined Function
std::map<std::string, std::string> functions;
functions["fun1"] = "cos";
functions["fun2"] = "sin";
for(auto const&x:functions){
definedFunctions.add (x.first, x.second) ;
}
//defined parameters
std::map<std::string, std::string> paramsList;
paramsList["imf"] = "imf";
paramsList["spect"] = "spectro";
for(auto const&x:paramsList){
definedParams.add (x.first, x.second) ;
}
BOOST_SPIRIT_DEBUG_NODES((expr_)(or_)(xor_)(and_)(equal_)(unequal_)(greaterOrEqual_)(lowerOrEqual_)(lower_)(sum_)
(difference_)(factor_)(division_)(simple)(notOperator_)(andOperator_)(orOperator_)(xorOperator_)(equalOperator_)(unequalOperator_)
(sumOperator_)(differenceOperator_)(factorOperator_)(divisionOperator_)(greater_)(lower_));
}
private:
qi::rule<It, Expression::var(), Skipper> var_, args_;
qi::rule<It, Expression::expressionContainer(), Skipper> not_
, and_
, xor_
, or_
, equal_
, unequal_
, sum_
, difference_
, factor_
, division_
, simple
, expr_
,plusSign_
,minusSign_
,greater_
,greaterOrEqual_
,lowerOrEqual_
,lower_
,functions_
,param_
,component_;
qi::rule<It, Skipper> notOperator_
, andOperator_
, orOperator_
, xorOperator_
, equalOperator_
, unequalOperator_
, sumOperator_
, differenceOperator_
, factorOperator_
, divisionOperator_
, greaterOperator_
, greaterOrEqualOperator_
,lowerOrEqualOperator_
,lowerOperator_
,componentOperator_;
qi::symbols<char, std::string> definedFunctions;
qi::symbols<char, std::string> definedParams;
};
void parse(const std::string& str)
{
std::string::const_iterator iter = str.begin(), end = str.end();
parserExpression<std::string::const_iterator,qi::space_type> parser;
Expression::expressionContainer expr;
bool result = qi::phrase_parse(iter,end,parser,qi::space, expr);
if(result && iter==end)
{
std::cout << "Success." << std::endl;
std::cout << str << " => " << expr << std::endl;
}
else
{
std::cout << "Failure." << std::endl;
}
}
int main()
{
parse("imf");
parse("spect");
parse("imf(1)");
parse("spect(1,2)");
}
Success.
imf => imf thats working
Success.
spect => spectro thats working
imf(1) => Failure. expected imf(1)
spect(1,2) => Failure. expected spectro(1,2)
The output for (1) isn't empty. It's ASCII 0x01:
00000000: 2831 2920 3d3e 2001 0a (1) => ..
That's because
var_ %= qi::lexeme[+qi::int_];
doesn't do what you want. It parses 1 as an integer and then puts that into the container of char (std::string is a container). To simply parse a number, only parse int_ and to treat is as a string, consider raw[]:
var_ = qi::raw[qi::int_];
Now it prints:
Success.
(1) => 1
Success.
1+1 => (1+1)
With regards to the rest, it's completely unclear to me how you want to parse things. I have a suspicion it's unclear to yourself too:
unary operators are unary, not unique
unary operators are operators, not expression subtypes or identifiers
if you want functions to take argument lists, why is there no rule that says so
if the "definedParams" are arguments - what's the difference between that and a variable?
For inspiration look at these answers that already do parser function calls with parameters:
Spirit qi parsing to an Abstract Syntax Tree for nested functions
Nice for comparison: This answer to Boost::spirit how to parse and call c++ function-like expressions interprets the parsed expressions on-the-fly (this mimics the approach with [std::cout << "Parse multiplication: " << (qi::_1 * qi::_2)] in your own parser)
The other answer there (Boost::spirit how to parse and call c++ function-like expressions) achieves the goal but using a dedicated AST representation, and a separate interpretation phase.
More slightly advanced/related:
Defining functions as well detecting function call with regex
Implementing operator precedence with boost spirit
Highly advanced: How to provider user with autocomplete suggestions for given boost::spirit grammar?
Following sehe suggestions, I added rules for parameters and functions. For function I build 3 lists “qi::symbols” depending on the number of arguments.
The parser works fine.
custom_fold_directive.hpp
namespace custom
{
namespace tag
{
struct fold { BOOST_SPIRIT_IS_TAG() };
}
template <typename Exposed, typename Expr>
boost::spirit::stateful_tag_type<Expr, tag::fold, Exposed>
fold(Expr const& expr)
{
return boost::spirit::stateful_tag_type<Expr, tag::fold, Exposed>(expr);
}
}
namespace boost { namespace spirit
{
template <typename Expr, typename Exposed>
struct use_directive<qi::domain
, tag::stateful_tag<Expr, custom::tag::fold, Exposed> >
: mpl::true_ {};
}}
namespace custom
{
template <typename Exposed, typename InitialParser, typename RepeatingParser>
struct fold_directive
{
fold_directive(InitialParser const& initial, RepeatingParser const& repeating):initial(initial),repeating(repeating){}
template <typename Context, typename Iterator>
struct attribute
{
typedef typename boost::spirit::traits::attribute_of<InitialParser,Context,Iterator>::type type;//This works in this case but is not generic
};
template <typename Iterator, typename Context
, typename Skipper, typename Attribute>
bool parse(Iterator& first, Iterator const& last
, Context& context, Skipper const& skipper, Attribute& attr_) const
{
Iterator start = first;
typename boost::spirit::traits::attribute_of<InitialParser,Context,Iterator>::type initial_attr;
if (!initial.parse(first, last, context, skipper, initial_attr))
{
first=start;
return false;
}
typename boost::spirit::traits::attribute_of<RepeatingParser,Context,Iterator>::type repeating_attr;
if(!repeating.parse(first, last, context, skipper, repeating_attr))
{
boost::spirit::traits::assign_to(initial_attr, attr_);
return true;
}
Exposed current_attr(initial_attr,repeating_attr);
while(repeating.parse(first, last, context, skipper, repeating_attr))
{
boost::spirit::traits::assign_to(Exposed(current_attr,repeating_attr),current_attr);
}
boost::spirit::traits::assign_to(current_attr,attr_);
return true;
}
template <typename Context>
boost::spirit::info what(Context& context) const
{
return boost::spirit::info("fold");
}
InitialParser initial;
RepeatingParser repeating;
};
}
namespace boost { namespace spirit { namespace qi
{
template <typename Expr, typename Exposed, typename Subject, typename Modifiers>
struct make_directive<
tag::stateful_tag<Expr, custom::tag::fold, Exposed>, Subject, Modifiers>
{
typedef custom::fold_directive<Exposed, Expr, Subject> result_type;
template <typename Terminal>
result_type operator()(Terminal const& term, Subject const& subject, Modifiers const&) const
{
typedef tag::stateful_tag<
Expr, custom::tag::fold, Exposed> tag_type;
using spirit::detail::get_stateful_data;
return result_type(get_stateful_data<tag_type>::call(term),subject);
}
};
}}}
main.cpp
#include <boost/mpl/list.hpp>
//#define BOOST_SPIRIT_DEBUG
#include <iostream>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include "custom_fold_directive.hpp"
namespace qi = boost::spirit::qi;
// Expression::triop <fun_generic>
// DEFINING TYPES
struct op_not {};
struct op_or {};
struct op_and {};
struct op_xor {};
struct op_equal {};
struct op_unequal {};
struct op_sum {};
struct op_difference {};
struct op_factor {};
struct op_division {};
struct op_power{};
struct op_powerTen{};
struct op_plusSign {};
struct op_minusSign {};
struct op_const {};
struct fun_three{};
struct fun_two{};
struct fun_one{};
namespace Expression{
typedef std::string var;
template <typename tag> struct binop;
template <typename tag> struct unop;
template <typename tag> struct triop;
template <typename tag> struct forop;
/*
* tree structure definition
*/
typedef boost::variant<var,
boost::recursive_wrapper<unop <op_not> >,
boost::recursive_wrapper<binop<op_equal> >,
boost::recursive_wrapper<binop<op_unequal> >,
boost::recursive_wrapper<binop<op_and> >,
boost::recursive_wrapper<binop<op_xor> >,
boost::recursive_wrapper<binop<op_or> >,
boost::recursive_wrapper<binop<op_difference> >,
boost::recursive_wrapper<binop<op_sum> >,
boost::recursive_wrapper<binop<op_factor> >,
boost::recursive_wrapper<binop<op_division> >,
boost::recursive_wrapper<binop<op_power> >,
boost::recursive_wrapper<binop<op_powerTen> >,
boost::recursive_wrapper<unop<op_minusSign> >,
boost::recursive_wrapper<unop<op_plusSign> >,
boost::recursive_wrapper<unop<op_const> >,
boost::recursive_wrapper<binop<fun_one> >,
boost::recursive_wrapper<triop<fun_two> >,
boost::recursive_wrapper<forop<fun_three> >
> expressionContainer;
template <typename tag> struct binop
{
explicit binop(const expressionContainer& l
, const expressionContainer& r)
: oper1(l), oper2(r) { }
expressionContainer oper1, oper2;
};
template <typename tag> struct unop
{
explicit unop(const expressionContainer& o) : oper1(o) { }
expressionContainer oper1;
};
template <typename tag> struct triop
{
explicit triop(const expressionContainer& functionId,
const expressionContainer& l
, const expressionContainer& r)
: oper1(functionId), oper2(l), oper3(r) { }
expressionContainer oper1, oper2, oper3;
};
template <typename tag> struct forop
{
explicit forop(const expressionContainer& functionId,
const expressionContainer& l,
const expressionContainer& m,
const expressionContainer& r)
: oper1(functionId), oper2(l), oper3(m),oper4(r) { }
expressionContainer oper1, oper2, oper3,oper4;
};
struct printer : boost::static_visitor<void>
{
printer(std::ostream& os) : _os(os) {}
std::ostream& _os;
void operator()(const var& v) const { _os << v; }
// Logical
void operator()(const binop<op_and>& b) const { print(" & ", b.oper1, b.oper2); }
void operator()(const binop<op_or >& b) const { print(" || ", b.oper1, b.oper2); }
void operator()(const binop<op_xor>& b) const { print(" | ", b.oper1, b.oper2); }
void operator()(const binop<op_equal>& b) const { print(" == ", b.oper1, b.oper2); }
void operator()(const binop<op_unequal>& b) const { print(" != ", b.oper1, b.oper2); }
//Math operators
void operator()(const binop<op_difference>& b) const { print("-", b.oper1, b.oper2); }
void operator()(const binop<op_sum>& b) const { print("+", b.oper1, b.oper2); }
void operator()(const binop<op_factor>& b) const { print("*", b.oper1, b.oper2); }
void operator()(const binop<op_division>& b) const { print("/", b.oper1, b.oper2); }
//Power Math operators
void operator()(const binop<op_power>& b) const { print("pow", b.oper1, b.oper2); }
void operator()(const binop<op_powerTen>& b) const { printPower("e", b.oper1, b.oper2); }
//unique operators
void operator()(const unop<op_not>& u) const{printUnique("!",u.oper1);}
void operator()(const unop<op_plusSign>& u) const{printUnique("",u.oper1);}
void operator()(const unop<op_minusSign>& u) const{printUnique("-",u.oper1);}
void operator()(const unop<op_const>& u) const{printUnique("",u.oper1);}
// print Functions
void operator()(const forop<fun_three>& b) const { printFunctionThree(b.oper1, b.oper2, b.oper3, b.oper4); }
void operator()(const triop<fun_two>& b) const { printFunctionTwo(b.oper1, b.oper2, b.oper3); }
void operator()(const binop<fun_one>& b) const { printFunctionOne(b.oper1, b.oper2); }
//Printer
void print(const std::string& op, const expressionContainer& l, const expressionContainer& r) const
{
_os << "(";
boost::apply_visitor(*this, l);
_os << op;
boost::apply_visitor(*this, r);
_os << ")";
}
void printUnique(const std::string& op, const expressionContainer& l) const
{
_os << op;
boost::apply_visitor(*this, l);
}
void printPower(const std::string& op, const expressionContainer& l, const expressionContainer& r) const
{
boost::apply_visitor(*this, l);
_os << op;
boost::apply_visitor(*this, r);
}
void printOutSide(const std::string& op, const expressionContainer& l, const expressionContainer& r) const
{
_os << op;
_os << "(";
boost::apply_visitor(*this, l);
_os << ",";
boost::apply_visitor(*this, r);
_os << ")";
}
void printFunctionThree(const expressionContainer& functionId, const expressionContainer& l, const expressionContainer& m, const expressionContainer& r) const
{
boost::apply_visitor(*this, functionId);
_os << "(";
boost::apply_visitor(*this, l);
_os << ',';
boost::apply_visitor(*this, m);
_os << ',';
boost::apply_visitor(*this, r);
_os << ")";
}
void printFunctionTwo(const expressionContainer& functionId, const expressionContainer& l, const expressionContainer& r) const
{
boost::apply_visitor(*this, functionId);
_os << "(";
boost::apply_visitor(*this, l);
_os << ',';
boost::apply_visitor(*this, r);
_os << ")";
}
void printFunctionOne(const expressionContainer& functionId, const expressionContainer& l) const
{
boost::apply_visitor(*this, functionId);
_os << "(";
boost::apply_visitor(*this, l);
_os << ")";
}
};
std::ostream& operator<<(std::ostream& os, const expressionContainer& e)
{ boost::apply_visitor(printer(os), e); return os; }
}
/*
* EXPRESSION PARSER DEFINITION
*/
template <typename It, typename Skipper = boost::spirit::standard_wide::space_type>
struct parserExpression : qi::grammar<It, Expression::expressionContainer(), Skipper>
{
parserExpression() : parserExpression::base_type(expr_)
{
using namespace qi;
using namespace Expression;
using custom::fold;
expr_ = or_.alias();
// Logical Operators
or_ = fold<binop<op_or> >(and_.alias())[orOperator_ >> and_];
and_ = fold<binop<op_and> >(equal_.alias())[andOperator_ >> equal_];
equal_ = fold<binop<op_equal> >(unequal_.alias())[equalOperator_ >> unequal_];
unequal_ = fold<binop<op_unequal> >(sum_.alias())[unequalOperator_ >>sum_];
// Numerical Operators
sum_ = fold<binop<op_sum> >(difference_.alias())[sumOperator_ >> difference_];
difference_ = fold<binop<op_difference> >(factor_.alias())[differenceOperator_ >> factor_];
factor_ = fold<binop<op_factor> >(division_.alias())[factorOperator_ >> division_];
division_ = fold<binop<op_division> >(functions_.alias())[divisionOperator_ >> functions_];
functions_ = (threeArgsFunction>>"(">>funArgs_>>componentOperator_>>funArgs_>>componentOperator_>>funArgs_>>")")[_val= boost::phoenix::construct<Expression::forop <fun_three>>(_1,_2,_3,_4)] ||
(twoArgsFunction>>"(">>funArgs_>>componentOperator_>>funArgs_>>")")[_val= boost::phoenix::construct<Expression::triop <fun_two>>(_1,_2,_3)]||
(oneArgsFunction>>"(">>funArgs_>>")")[_val= boost::phoenix::construct<Expression::binop <fun_one>>(_1,_2)]|not_[_val=_1];
// UNARY OPERATION
not_ = (notOperator_ > param_) [_val = boost::phoenix::construct<Expression::unop <op_not>>(_1)] | param_[_val=_1];
param_= (definedParams >>('(' >> (spectArgs_|vectorArgs_)>>')'))[_val='$'+_1+"("+qi::_2+")"] ||
definedParams[_val='$'+_1]| simple[_val = _1];
funArgs_=((expr_ |var_) |functions_);
simple = (('(' > expr_ > ')') | var_);
var_ = (+qi::char_('0','9') >> -qi::char_('.') >> -(+qi::char_('0','9'))) | ((qi::char_('.') >> +qi::char_('0','9')));
vectorArgs_%=qi::raw[qi::int_ > -(qi::char_(',')>>qi::int_) ];
spectArgs_ %=qi::raw[(qi::int_>>qi::char_(',')>>'*')|(qi::char_('*')>>qi::char_(',')>>qi::int_)];
notOperator_ = qi::char_('!');
andOperator_ = qi::string("&&");
orOperator_ = qi::string("||");
xorOperator_ = qi::char_("^");
equalOperator_ = qi::string("==");
unequalOperator_ = qi::string("!=");
sumOperator_ = qi::char_("+");
differenceOperator_ = qi::char_("-");
factorOperator_ = qi::char_("*");
divisionOperator_ = qi::char_("/");
greaterOperator_ = qi::char_(">");
greaterOrEqualOperator_ = qi::string(">=");
lowerOrEqualOperator_ = qi::string("<=");
lowerOperator_ = qi::char_("<");
componentOperator_=qi::char_(",");
// Defined Function
std::map<std::string, std::string> oneFunctions;
oneFunctions["fun1_1"] = "f11";
oneFunctions["fun1_2"] = "f12";
for(auto const&x:oneFunctions){
oneArgsFunction.add (x.first, x.second) ;
}
std::map<std::string, std::string> twoFunctions;
twoFunctions["fun2_1"] = "f21";
twoFunctions["fun2_2"] = "f22";
for(auto const&x:twoFunctions){
twoArgsFunction.add (x.first, x.second) ;
}
std::map<std::string, std::string> threeFunctions;
threeFunctions["fun3_1"] = "f31";
threeFunctions["fun3_2"] = "f32";
for(auto const&x:threeFunctions){
threeArgsFunction.add (x.first, x.second) ;
}
//defined parameters
std::map<std::string, std::string> paramsList;
paramsList["imf"] = "imf";
paramsList["param"] = "param";
for(auto const&x:paramsList){
definedParams.add (x.first, x.second) ;
}
BOOST_SPIRIT_DEBUG_NODES((expr_)(or_)(xor_)(and_)(equal_)(unequal_)(sum_)(difference_)(factor_)(division_)
(simple)(notOperator_)(andOperator_)(orOperator_)(xorOperator_)(equalOperator_)(unequalOperator_)
(sumOperator_)(differenceOperator_)(factorOperator_)(divisionOperator_)(functions_));
}
private:
qi::rule<It, Expression::var(), Skipper> var_, vectorArgs_, spectArgs_;
qi::rule<It, Expression::expressionContainer(), Skipper> not_
, and_
, xor_
, or_
, equal_
, unequal_
, sum_
, difference_
, factor_
, division_
, simple
, expr_
,plusSign_
,minusSign_
,greater_
,greaterOrEqual_
,lowerOrEqual_
,lower_
,functions_
,param_
,funArgs_;
qi::rule<It, Skipper> notOperator_
, andOperator_
, orOperator_
, xorOperator_
, equalOperator_
, unequalOperator_
, sumOperator_
, differenceOperator_
, factorOperator_
, divisionOperator_
, greaterOperator_
, greaterOrEqualOperator_
,lowerOrEqualOperator_
,lowerOperator_
,componentOperator_;
qi::symbols<char, std::string> twoArgsFunction;
qi::symbols<char, std::string> oneArgsFunction;
qi::symbols<char, std::string> threeArgsFunction;
qi::symbols<char, std::string> definedParams;
};
void parse(const std::string& str)
{
std::string::const_iterator iter = str.begin(), end = str.end();
parserExpression<std::string::const_iterator,qi::space_type> parser;
Expression::expressionContainer expr;
bool result = qi::phrase_parse(iter,end,parser,qi::space, expr);
if(result && iter==end)
{
std::cout << "Success." << std::endl;
std::cout << str << " => " << expr << std::endl;
}
else
{
std::cout << "Failure." << std::endl;
}
}
int main()
{
parse("1");
parse("1+1");
parse("(1+1)");
//
parse("fun1_1((1))");
//
parse("fun2_1(1,2)");
parse("fun2_1( (fun2_1(1,1)), (2))");
//
parse("fun3_1(fun1_1(1),fun2_1(2,3),imf(1,1))");
}
output
Success.
1 => 1
Success.
imf => $imf
Success.
imf(1) => $imf(1)
Success.
(1+1) => (1+1)
Success.
fun1_1((1)) => f11(1)
Success.
fun2_1(1,2) => f21(1,2)
Success.
fun2_1( (fun2_1(1,1)), (2)) => f21(f21(1,1),2)
Success.
fun3_1(fun1_1(1),fun2_1(2,3),imf(1,1)) => f31(f11(1),f21(2,3),$imf(1,1))
I've learned a lot in the last couple of weeks about this stuff, but not enough. The code below compiles and runs but the code in TEST_ADAPT is incomplete, I'm not sure how to make the connection.
The object is to parse into a plane jane container that has no variant dependency. I have figured out I can get a tuple of references to my storage which spirit likes well enough. (see TEST_REF). The kleene operator is looking for a single sequential container but on a set of alternatives, that doesn't look to be possible. So I guess I need to hand it something that is a proxy for that container but has gear work to locate in a tuple the destination references.
I think it will be a great exercise for me to write this ContainerAdaptor even if it is the wrong way to approach this. So I'm wondering if I'm in right field or on the right track.
The best I know I can complete is to use the TEST_VECT method and make a pass over the vector to copy the data into my ALL container. But that's just not right.
Update:
I have made Target::All fusion adapted and made ContainerAdaptor partially functional. Enough so that the kleene operator accepts it. I should be able to connect to the Target::All object, maybe...
#include <iostream>
#include <boost/fusion/include/as_vector.hpp>
#include <boost/fusion/adapted.hpp>
#include <boost/fusion/adapted/std_tuple.hpp>
#include <boost/fusion/include/boost_tuple.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/ast/variant.hpp>
//parse kleene operator to a set of alternatives, adaptor? with spirit x3
#define TEST_VECT
#define TEST_REF
#define TEST_ADAPT
// l.......................................................................
namespace Target {
struct Int
{
int int_val;
};
using IntVect = std::vector<Int>;
struct Word
{
std::string word_val;
};
using WordVect = std::vector<Word>;
struct All
{
IntVect int_vect;
WordVect word_vect;
};
}
BOOST_FUSION_ADAPT_STRUCT(Target::Int, int_val)
BOOST_FUSION_ADAPT_STRUCT(Target::Word, word_val)
BOOST_FUSION_ADAPT_STRUCT(Target::All, int_vect, word_vect)
std::ostream& operator << (std::ostream& o, const Target::Int& in) { o << in.int_val; return o; }
std::ostream& operator << (std::ostream& o, const Target::Word& in) { o << in.word_val; return o; }
std::ostream& operator << (std::ostream& o, const Target::IntVect& in) { for( auto& i : in ) o << i << " "; return o; }
std::ostream& operator << (std::ostream& o, const Target::WordVect& in) { for (auto& i : in) o << i << " "; return o; }
#define DEF_RULE( RuleName, Attr ) static auto const RuleName = rule<struct Attr##_def, Attr>( #RuleName )
namespace Target {
using namespace boost::spirit::x3;
auto const bare_word = lexeme[+char_("a-z")];
DEF_RULE(int_rule, Int) = int_;
DEF_RULE(word_rule, Word) = bare_word;
auto const int_vect_rule= "int" >> *int_rule;
auto const word_vect_rule= "word" >> *(word_rule - "int");
//another test
DEF_RULE(f_int_vect_rule, IntVect) = int_vect_rule;
DEF_RULE(f_word_vect_rule, IntVect) = word_vect_rule;
}//namespace Target
namespace Target {
struct Printer {
Printer(std::ostream& out) : out(out) {};
using result_type = void;
void operator()(const IntVect& expression) {
out << "IntVect: ";
for (auto& t : expression)
out << t << " ";
out << std::endl;
}
void operator()(const WordVect& expression) {
out << "Word: ";
for (auto& t : expression)
out << t << " ";
out << std::endl;
}
private:
std::ostream& out;
};
}//namespace Target
template<class Arg>
class ContainerAdaptor
{
public:
ContainerAdaptor(Arg& arg) :arg(arg) { }
typedef boost::spirit::x3::variant<Target::IntVect,Target::WordVect> value_type;
typedef size_t size_type;
struct Vis : public boost::static_visitor<>
{
void operator()(const Target::IntVect & i) const
{
std::cout << i << std::endl;
}
void operator()(const Target::WordVect & i) const
{
std::cout << i << std::endl;
}
};
void insert(value_type* e, const value_type& v) {
std::cout << "haha! ";
boost::apply_visitor(Vis(), v);
}
value_type* end() { return nullptr; }
value_type* begin() { return nullptr; }
size_t size;
private:
Arg & arg;
};
int main()
{
using namespace Target;
std::string thestr("word test more int 1 2 3 4 word this and that int 5 4 int 99 22");
std::string::iterator end = thestr.end();
#if defined(TEST_ADAPT)
{
std::cout << "\nTEST_ADAPT\n";
std::string::iterator begin = thestr.begin();
All all;
auto fwd = std::forward_as_tuple(all.word_vect, all.int_vect);
ContainerAdaptor<All>attr( all );
phrase_parse(begin, end, *( int_vect_rule | word_vect_rule), space, attr);
Printer printer(std::cout);
}
#endif
#if defined(TEST_VECT)
{
std::cout << "TEST_VECT\n";
std::string::iterator begin = thestr.begin();
using Vars = variant<Target::IntVect, Target::WordVect>;
std::vector< Vars > a_vect;
bool r = phrase_parse(begin, end, *( int_vect_rule | word_vect_rule), space, a_vect);
Printer printer(std::cout);
for (auto& i : a_vect)
i.apply_visitor(printer);
}
#endif
#if defined(TEST_REF)
{
std::cout << "\nTEST_REF\n";
std::string::iterator begin = thestr.begin();
All all;
auto fwd = std::forward_as_tuple(all.word_vect,all.int_vect);
phrase_parse(begin, end, word_vect_rule >> int_vect_rule, space, fwd);
Printer printer(std::cout);
std::_For_each_tuple_element(fwd, printer);
}
#endif
return 0;
}
The ContainerAdaptor Hack
Sufficiently simplified, it works:
Live On Coliru
#include <iostream>
#include <boost/fusion/adapted.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/ast/variant.hpp>
namespace Target {
struct Int { int int_val; };
struct Word { std::string word_val; };
using IntVect = std::vector<Int>;
using WordVect = std::vector<Word>;
struct All {
IntVect int_vect;
WordVect word_vect;
};
}
BOOST_FUSION_ADAPT_STRUCT(Target::Int, int_val)
BOOST_FUSION_ADAPT_STRUCT(Target::Word, word_val)
std::ostream& operator << (std::ostream& o, const Target::Int& in) { o << in.int_val; return o; }
std::ostream& operator << (std::ostream& o, const Target::Word& in) { o << in.word_val; return o; }
std::ostream& operator << (std::ostream& o, const Target::IntVect& in) { for( auto& i : in ) o << i << " "; return o; }
std::ostream& operator << (std::ostream& o, const Target::WordVect& in) { for (auto& i : in) o << i << " "; return o; }
namespace Target {
using namespace boost::spirit::x3;
static auto const int_rule = rule<struct Int_def, Int>("int_rule") = int_;
static auto const word_rule = rule<struct Word_def, Word>("word_rule") = lexeme[+char_("a-z")];
static auto const int_vect_rule = "int" >> *int_rule;
static auto const word_vect_rule = "word" >> *(word_rule - "int");
}
template<class Arg> struct ContainerAdaptor
{
typedef boost::spirit::x3::variant<Target::IntVect,Target::WordVect> value_type;
void insert(value_type* /*e*/, const value_type& v) {
std::cout << "haha! ";
struct Vis {
//using result_type = void;
void operator()(const Target::IntVect & i) const { std::cout << i << std::endl; }
void operator()(const Target::WordVect & i) const { std::cout << i << std::endl; }
};
boost::apply_visitor(Vis(), v);
}
value_type* end() { return nullptr; }
value_type* begin() { return nullptr; }
Arg & arg;
};
int main() {
using namespace Target;
std::string const thestr("word test more int 1 2 3 4 word this and that int 5 4 int 99 22");
All all;
ContainerAdaptor<All> attr { all };
if (phrase_parse(begin(thestr), end(thestr), *( int_vect_rule | word_vect_rule), space, attr)) {
std::cout << "Parsed: \n";
std::cout << all.int_vect << "\n";
std::cout << all.word_vect << "\n";
}
}
Prints:
haha! test more
haha! 1 2 3 4
haha! this and that
haha! 5 4
haha! 99 22
Parsed:
Why Not Semantic Actions?
Live On Coliru
#include <iostream>
#include <boost/fusion/adapted.hpp>
#include <boost/spirit/home/x3.hpp>
namespace Target {
struct Int { int int_val; };
struct Word { std::string word_val; };
using IntVect = std::vector<Int>;
using WordVect = std::vector<Word>;
struct All {
IntVect int_vect;
WordVect word_vect;
};
}
BOOST_FUSION_ADAPT_STRUCT(Target::Int, int_val)
BOOST_FUSION_ADAPT_STRUCT(Target::Word, word_val)
std::ostream& operator << (std::ostream& o, const Target::Int& in) { o << in.int_val; return o; }
std::ostream& operator << (std::ostream& o, const Target::Word& in) { o << in.word_val; return o; }
std::ostream& operator << (std::ostream& o, const Target::IntVect& in) { for( auto& i : in ) o << i << " "; return o; }
std::ostream& operator << (std::ostream& o, const Target::WordVect& in) { for (auto& i : in) o << i << " "; return o; }
namespace x3 = boost::spirit::x3;
namespace Target {
using namespace x3;
static auto const int_rule = rule<struct Int_def, Int>("int_rule") = int_;
static auto const word_rule = rule<struct Word_def, Word>("word_rule") = lexeme[+char_("a-z")];
static auto const int_vect_rule = "int" >> *int_rule;
static auto const word_vect_rule = "word" >> *(word_rule - "int");
}
int main() {
std::string const thestr("word test more int 1 2 3 4 word this and that int 5 4 int 99 22");
Target::All all;
struct {
Target::All& _r;
void operator()(Target::IntVect const&v) const { _r.int_vect.insert(_r.int_vect.end(), v.begin(), v.end()); }
void operator()(Target::WordVect const&v) const { _r.word_vect.insert(_r.word_vect.end(), v.begin(), v.end()); }
} push_back { all };
auto unary = [](auto f) { return [f](auto& ctx) { return f(x3::_attr(ctx)); }; };
auto action = unary(push_back);
if (phrase_parse(begin(thestr), end(thestr), *(Target::int_vect_rule[action] | Target::word_vect_rule[action]), x3::space)) {
std::cout << "Parsed: \n";
std::cout << all.int_vect << "\n";
std::cout << all.word_vect << "\n";
}
}
Prints
Parsed:
1 2 3 4 5 4 99 22
test more this and that
Using Traits
Re-introducing the variant "value_type":
Live On Coliru
#include <iostream>
#include <boost/fusion/adapted.hpp>
#include <boost/spirit/home/x3.hpp>
namespace Target {
struct Int { int int_val; };
struct Word { std::string word_val; };
using IntVect = std::vector<Int>;
using WordVect = std::vector<Word>;
struct All {
IntVect int_vect;
WordVect word_vect;
};
}
BOOST_FUSION_ADAPT_STRUCT(Target::Int, int_val)
BOOST_FUSION_ADAPT_STRUCT(Target::Word, word_val)
std::ostream& operator << (std::ostream& o, const Target::Int& in) { o << in.int_val; return o; }
std::ostream& operator << (std::ostream& o, const Target::Word& in) { o << in.word_val; return o; }
std::ostream& operator << (std::ostream& o, const Target::IntVect& in) { for( auto& i : in ) o << i << " "; return o; }
std::ostream& operator << (std::ostream& o, const Target::WordVect& in) { for (auto& i : in) o << i << " "; return o; }
namespace boost { namespace spirit { namespace x3 { namespace traits {
template<>
struct container_value<Target::All> {
using type = boost::variant<Target::IntVect, Target::WordVect>;
};
template<>
struct push_back_container<Target::All> {
template <typename V>
static bool call(Target::All& c, V&& v) {
struct {
Target::All& _r;
void operator()(Target::IntVect const&v) const { _r.int_vect.insert(_r.int_vect.end(), v.begin(), v.end()); }
void operator()(Target::WordVect const&v) const { _r.word_vect.insert(_r.word_vect.end(), v.begin(), v.end()); }
} vis {c};
boost::apply_visitor(vis, v);
return true;
}
};
} } } }
namespace x3 = boost::spirit::x3;
namespace Target {
using namespace x3;
static auto const int_rule = rule<struct Int_def, Int>("int_rule") = int_;
static auto const word_rule = rule<struct Word_def, Word>("word_rule") = lexeme[+char_("a-z")];
static auto const int_vect_rule = "int" >> *int_rule;
static auto const word_vect_rule = "word" >> *(word_rule - "int");
}
int main() {
std::string const thestr("word test more int 1 2 3 4 word this and that int 5 4 int 99 22");
Target::All all;
if (phrase_parse(begin(thestr), end(thestr), *(Target::int_vect_rule | Target::word_vect_rule), x3::space, all)) {
std::cout << "Parsed: \n";
std::cout << all.int_vect << "\n";
std::cout << all.word_vect << "\n";
}
}
Prints
Parsed:
1 2 3 4 5 4 99 22
test more this and that
I have a following code to evaluate a Boolean string based on an string input.
The code supposed to work like this:
Boolean string: "((0|1)&3);"
Sting input: "101"
how's it working? each character in the input string is supposed to be substituted by corresponding character in Boolean string.
for example:
1 in the input string by 0 in Boolean string
0 in the input string by 1 in Boolean string
1 in the input string by 3 in Boolean string
I know it is confusing, My problem is that the code was used to work for many cases, but I don't understand why it is not working for above example.
I added the live version for editing here.
#include <iostream>
#include <fstream>
#include <vector>
#include <boost/lexical_cast.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/variant/recursive_wrapper.hpp>
namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;
struct op_or {};
struct op_and {};
struct op_not {};
typedef std::string var;
template <typename tag> struct binop;
template <typename tag> struct unop;
typedef boost::variant<var,
boost::recursive_wrapper<unop <op_not> >,
boost::recursive_wrapper<binop<op_and> >,
boost::recursive_wrapper<binop<op_or> >
> expr;
template <typename tag> struct binop
{
explicit binop(const expr& l, const expr& r) : oper1(l), oper2(r) { }
expr oper1, oper2;
};
template <typename tag> struct unop
{
explicit unop(const expr& o) : oper1(o) { }
expr oper1;
};
struct eval2 : boost::static_visitor<bool>
{
eval2(const std::string& pk): pkey(pk) { iter = 0; }
//
bool operator()(const var& v) const
{
std:: cout << "**** " << v << "\titer: " << iter << std::endl;
iter ++;
return boost::lexical_cast<bool>(pkey[iter-1]);
}
bool operator()(const binop<op_and>& b) const
{
return recurse(b.oper1) && recurse(b.oper2);
}
bool operator()(const binop<op_or>& b) const
{
return recurse(b.oper1) || recurse(b.oper2);
}
bool operator()(const unop<op_not>& u) const
{
return !recurse(u.oper1);
}
private:
mutable int iter;
const std::string pkey;
template<typename T>
bool recurse(T const& v) const
{ return boost::apply_visitor(*this, v); }
};
struct printer : boost::static_visitor<void>
{
printer(std::ostream& os) : _os(os) {}
std::ostream& _os;
//
void operator()(const var& v) const { _os << v; }
void operator()(const binop<op_and>& b) const { print(" & ", b.oper1, b.oper2); }
void operator()(const binop<op_or >& b) const { print(" | ", b.oper1, b.oper2); }
void print(const std::string& op, const expr& l, const expr& r) const
{
_os << "(";
boost::apply_visitor(*this, l);
_os << op;
boost::apply_visitor(*this, r);
_os << ")";
}
void operator()(const unop<op_not>& u) const
{
_os << "(";
_os << "!";
boost::apply_visitor(*this, u.oper1);
_os << ")";
}
};
bool evaluate2(const expr& e, const std::string s)
{
return boost::apply_visitor(eval2(s), e);
}
std::ostream& operator<<(std::ostream& os, const expr& e)
{ boost::apply_visitor(printer(os), e); return os; }
template <typename It, typename Skipper = qi::space_type>
struct parser : qi::grammar<It, expr(), Skipper>
{
parser() : parser::base_type(expr_)
{
using namespace qi;
expr_ = or_.alias();
or_ = (and_ >> '|' >> or_ ) [ qi::_val = phx::construct<binop<op_or > >(qi::_1, qi::_2) ] | and_ [ qi::_val = qi::_1 ];
and_ = (not_ >> '&' >> and_) [ qi::_val = phx::construct<binop<op_and> >(qi::_1, qi::_2) ] | not_ [ qi::_val = qi::_1 ];
not_ = ('!' > simple ) [ qi::_val = phx::construct<unop <op_not> >(qi::_1) ] | simple [ qi::_val = qi::_1 ];
simple = (('(' > expr_ > ')') | var_);
var_ = qi::lexeme[ +(alpha|digit) ];
BOOST_SPIRIT_DEBUG_NODE(expr_);
BOOST_SPIRIT_DEBUG_NODE(or_);
BOOST_SPIRIT_DEBUG_NODE(and_);
BOOST_SPIRIT_DEBUG_NODE(not_);
BOOST_SPIRIT_DEBUG_NODE(simple);
BOOST_SPIRIT_DEBUG_NODE(var_);
}
private:
qi::rule<It, var() , Skipper> var_;
qi::rule<It, expr(), Skipper> not_, and_, or_, simple, expr_;
};
bool string2BooleanExe(std::string bStatement, std::string bKey)
{
typedef std::string::const_iterator It;
It f(bStatement.begin()), l(bStatement.end());
parser<It> p;
try
{
expr result;
bool ok = qi::phrase_parse(f,l,p > ';',qi::space,result);
if (!ok)
std::cerr << "invalid input\n";
else
{
std::cout << "result:\t" << result << "\n";
bool returnResult = evaluate2(result, bKey);
std::cout << "evaluated:\t" << returnResult << "\n";
return returnResult;
}
} catch (const qi::expectation_failure<It>& e)
{
std::cerr << "expectation_failure at '" << std::string(e.first, e.last) << "'\n";
}
if (f!=l) std::cerr << "unparsed: '" << std::string(f,l) << "'\n";
return false;
}
int main()
{
bool res = string2BooleanExe("((0|1)&3);", "101");
std::cout << "res: " << res << std::endl;
return 0;
}
Please note I can only use C++03.
So you want variables. And they are implicit.
And you denote them with integers in the expression. Yes, that's confusing, but why not, I guess.
The grammar suggests that variables could be any length of alphanumeric characters, though. Let's do this, and fix the sample to be:
bool res = string2BooleanExe("((a|b)&c);", {
{ "a", true }, { "b", false }, { "c", true } }); // was: 101
Now in your implementation there are two big problems:
you are using names 0, 1, 2 for the placeholders in the source expression but these are ignored (this means that ((0|1)&2) is functionally equivalent to ((1|2)&0)... I doubt that's what anyone wanted)
your eval2¹ visitor is stateful. You need to pass and use it by reference if you're going to retain state. Alternatively, make sure your copy constructor actually copies the value of iter
Here's my take on things, using
typedef std::map<std::string, bool> VarMap;
Let's use it in the evaluator visitor:
struct evaluator : boost::static_visitor<bool>
{
evaluator(VarMap const& pk) : pk(pk) { }
bool operator()(const var& v) const { return pk.at(v); }
bool operator()(const binop<op_and>& b) const { return recurse(b.oper1) && recurse(b.oper2); }
bool operator()(const binop<op_or>& b) const { return recurse(b.oper1) || recurse(b.oper2); }
bool operator()(const unop<op_not>& u) const { return !recurse(u.oper1); }
private:
template<typename T> bool recurse(T const& v) const { return boost::apply_visitor(*this, v); }
const VarMap pk;
};
Splitting the evaluate and parse functions:
static const parser<std::string::const_iterator> s_parser_instance;
expr parse(std::string const& bStatement) {
std::string::const_iterator f = bStatement.begin(), l = bStatement.end();
expr parsed;
qi::parse(f, l, s_parser_instance, parsed);
return parsed;
}
bool evaluate(expr const& e, VarMap const& vars) {
return boost::apply_visitor(evaluator(vars), e);
}
Now let's see the full demo
Full Demo
Live On Coliru
//#define BOOST_SPIRIT_DEBUG
#include <iostream>
#include <fstream>
#include <vector>
#include <boost/lexical_cast.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/variant/recursive_wrapper.hpp>
namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;
typedef std::map<std::string, bool> VarMap;
struct op_or {};
struct op_and {};
struct op_not {};
typedef std::string var;
template <typename tag> struct binop;
template <typename tag> struct unop;
typedef boost::variant<var,
boost::recursive_wrapper<unop <op_not> >,
boost::recursive_wrapper<binop<op_and> >,
boost::recursive_wrapper<binop<op_or> >
> expr;
template <typename tag> struct binop {
explicit binop(const expr& l, const expr& r) : oper1(l), oper2(r) { }
expr oper1, oper2;
};
template <typename tag> struct unop {
explicit unop(const expr& o) : oper1(o) { }
expr oper1;
};
struct evaluator : boost::static_visitor<bool>
{
evaluator(VarMap const& pk) : pk(pk) { }
bool operator()(const var& v) const { return pk.at(v); }
bool operator()(const binop<op_and>& b) const { return recurse(b.oper1) && recurse(b.oper2); }
bool operator()(const binop<op_or>& b) const { return recurse(b.oper1) || recurse(b.oper2); }
bool operator()(const unop<op_not>& u) const { return !recurse(u.oper1); }
private:
template<typename T> bool recurse(T const& v) const { return boost::apply_visitor(*this, v); }
const VarMap pk;
};
struct printer : boost::static_visitor<void>
{
printer(std::ostream& os) : _os(os) {}
std::ostream& _os;
//
void operator()(const var& v) const { _os << v; }
void operator()(const binop<op_and>& b) const { print(" & ", b.oper1, b.oper2); }
void operator()(const binop<op_or >& b) const { print(" | ", b.oper1, b.oper2); }
void print(const std::string& op, const expr& l, const expr& r) const
{
_os << "(";
boost::apply_visitor(*this, l);
_os << op;
boost::apply_visitor(*this, r);
_os << ")";
}
void operator()(const unop<op_not>& u) const
{
_os << "(";
_os << "!";
boost::apply_visitor(*this, u.oper1);
_os << ")";
}
};
std::ostream& operator<<(std::ostream& os, const expr& e)
{ boost::apply_visitor(printer(os), e); return os; }
template <typename It>
struct parser : qi::grammar<It, expr()>
{
parser() : parser::base_type(start) {
using namespace qi;
start = skip(space) [expr_ > ';' > eoi];
expr_ = or_.alias();
or_ = (and_ >> '|' >> or_ ) [ _val = phx::construct<binop<op_or > >(_1, _2) ] | and_ [ _val = _1 ];
and_ = (not_ >> '&' >> and_) [ _val = phx::construct<binop<op_and> >(_1, _2) ] | not_ [ _val = _1 ];
not_ = ('!' > simple ) [ _val = phx::construct<unop <op_not> >(_1) ] | simple [ _val = _1 ];
simple = ('(' > expr_ > ')') | var_;
var_ = lexeme[ +(alpha|digit) ];
BOOST_SPIRIT_DEBUG_NODES((expr_) (or_) (and_) (not_) (simple) (var_));
}
private:
qi::rule<It, expr()> start;
qi::rule<It, var() , qi::space_type> var_;
qi::rule<It, expr(), qi::space_type> not_, and_, or_, simple, expr_;
};
static const parser<std::string::const_iterator> s_parser_instance;
expr parse(std::string const& bStatement) {
std::string::const_iterator f = bStatement.begin(), l = bStatement.end();
expr parsed;
qi::parse(f, l, s_parser_instance, parsed);
return parsed;
}
bool evaluate(expr const& e, VarMap const& vars) {
return boost::apply_visitor(evaluator(vars), e);
}
void test(std::string const& expression, VarMap const& vars, bool expected) {
try {
std::cout << "'" << expression << "'";
expr parsed = parse(expression);
std::cout << " -> " << parsed;
bool actual = evaluate(parsed, vars);
std::cout
<< " - evaluates to " << std::boolalpha << actual
<< (expected == actual? " Correct." : " INCORRECT!!!")
<< "\n";
} catch(std::exception const& e) {
std::cout << " EXCEPTION(" << e.what() << ")\n";
}
}
int main() {
VarMap vars;
vars["a"] = true;
vars["b"] = false;
vars["c"] = true;
test("a;", vars, true);
test("b;", vars, false);
test("c;", vars, true);
test("((a|b)&c);", vars, true);
vars["c"] = false;
test("((a|b)&c);", vars, false);
// let's use an undefined variable - should throw
test("((z|y)&x);", vars, false|true);
// you CAN still use confusing numeric placeholders:
vars["0"] = true;
vars["1"] = false;
vars["2"] = true;
test("((0|1)&2);", vars, true);
test("((2|0)&1);", vars, false);
test("((1|0)&2);", vars, true);
// note you can also have "special variables"; no need for single-letter names
vars["TRUE"] = true;
vars["FALSE"] = false;
test("TRUE | FALSE;", vars, true);
test("TRUE & FALSE;", vars, false);
}
Prints:
'a;' -> a - evaluates to true Correct.
'b;' -> b - evaluates to false Correct.
'c;' -> c - evaluates to true Correct.
'((a|b)&c);' -> ((a | b) & c) - evaluates to true Correct.
'((a|b)&c);' -> ((a | b) & c) - evaluates to false Correct.
'((z|y)&x);' -> ((z | y) & x) EXCEPTION(map::at)
'((0|1)&2);' -> ((0 | 1) & 2) - evaluates to true Correct.
'((2|0)&1);' -> ((2 | 0) & 1) - evaluates to false Correct.
'((1|0)&2);' -> ((1 | 0) & 2) - evaluates to true Correct.
'TRUE | FALSE;' -> (TRUE | FALSE) - evaluates to true Correct.
'TRUE & FALSE;' -> (TRUE & FALSE) - evaluates to false Correct.
¹ FIX BAD NAMING. Also, single-responsibility. Make a parse function and an evaluate function. Put ';' and the skipper inside the grammar. Check for qi::eoi inside the grammar. Propagate exceptions instead of doing magic console output inside your parse/evaluate function.
I am trying to implement the Tseitin transformation over boolean formulas. The idea is that you transform boolean formulas in CNF, using transformation rules. For example, if the formula f = l OR r, we assign to each formula a new variable, let's say v_f, v_l and v_r, and we transform f = l OR r into (!v_f OR v_l OR v_r) AND (v_f OR !v_l) AND (v_f OR !v_r).
I use something like (v_f, v_l and v_r are replaced by p, p1 and p2. m is a variable that permits us to now what next variable we can use) :
int m = 0;
std::vector<std::vector<int> > formules;
struct op_or {};
struct op_and {};
struct op_not {};
struct op_impl {};
typedef int var;
template <typename tag> struct binop;
template <typename tag> struct unop;
typedef boost::variant<var,
boost::recursive_wrapper<unop <op_not> >,
boost::recursive_wrapper<binop<op_and> >,
boost::recursive_wrapper<binop<op_or> >,
boost::recursive_wrapper<binop<op_impl> >
> expr;
template <typename tag> struct binop
{
explicit binop(const expr& l, const expr& r) : oper1(l), oper2(r) { }
expr oper1, oper2;
};
template <typename tag> struct unop
{
explicit unop(const expr& o) : oper1(o) { }
expr oper1;
};
struct tseitin : boost::static_visitor<void>
{
tseitin() {}
void operator()(const var& v, int p = 0) {}
void operator()(const binop<op_and>& b, int p = m++) { proceed(0, b.oper1, b.oper2, p); }
void operator()(const binop<op_or>& b, int p = m++) { proceed(1, b.oper1, b.oper2, p);}
void operator()(const unop<op_not>& u, int p = m++) {}
void proceed(int nop, const expr& l, const expr& r, int p)
{
int p1 = m+1;
int p2 = m+2;
m += 2;
// Do the transformation
recurse(l, p1);
recurse(r, p2);
}
private:
template<typename T, typename U>
bool recurse(T const& v, U const& p)
{ return boost::apply_visitor(*this, v, p); }
};
And in the main, I call this transformation with : boost::apply_visitor(tseitin(), result, 0);
But I encounter errors like : error: no matching function for call to ‘apply_visitor(tseitin, expr&, int)’
boost::apply_visitor(tseitin(), result, 0);
And : error: request for member ‘apply_visitor’ in ‘visitable’, which is of non-class type ‘const int’
I don't really understand the error, do you have any ideas ?
As you may notice, I used How to calculate boolean expression in Spirit and boost spirit tutorial to implement the operators over the transformation.
I you need the whole code, let me now.
Thanks in advance !
I don't really understand the error, do you have any ideas ?
You are calling the binary version of boost::variant::apply_visitor. But you pass it a variant and an int. An int, as the error message announces, is not visitable.
To make this work, just bind the argument:
boost::apply_visitor(boost::bind(tseitin(), _1, 0), result);
This means that the _1 placeholder will receive the variant element and the second parameter is passed through.
You will also want to carry this through in recurse:
bool recurse(T const& v, U const& p)
{ return boost::apply_visitor(boost::bind(*this, _1, p), v); }
Update
Here's the demo of the linked answer, but using extra bound arguments instead of a stateful printer functor:
struct printer : boost::static_visitor<void>
{
//
void operator()(std::ostream& os, const var& v) const { os << v; }
void operator()(std::ostream& os, const binop<op_and>& b) const { print(os, " & ", b.oper1, b.oper2); }
void operator()(std::ostream& os, const binop<op_or >& b) const { print(os, " | ", b.oper1, b.oper2); }
void print(std::ostream& os, const std::string& op, const expr& l, const expr& r) const
{
os << "(";
boost::apply_visitor(boost::bind(*this, boost::ref(os), _1), l);
os << op;
boost::apply_visitor(boost::bind(*this, boost::ref(os), _1), r);
os << ")";
}
void operator()(std::ostream& os, const unop<op_not>& u) const
{
os << "(";
os << "!";
boost::apply_visitor(boost::bind(*this, boost::ref(os), _1), u.oper1);
os << ")";
}
};
Full Code:
Live On Coliru
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/variant/recursive_wrapper.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/bind.hpp>
namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;
struct op_or {};
struct op_and {};
struct op_not {};
typedef std::string var;
template <typename tag> struct binop;
template <typename tag> struct unop;
typedef boost::variant<var,
boost::recursive_wrapper<unop <op_not> >,
boost::recursive_wrapper<binop<op_and> >,
boost::recursive_wrapper<binop<op_or> >
> expr;
template <typename tag> struct binop
{
explicit binop(const expr& l, const expr& r) : oper1(l), oper2(r) { }
expr oper1, oper2;
};
template <typename tag> struct unop
{
explicit unop(const expr& o) : oper1(o) { }
expr oper1;
};
struct eval : boost::static_visitor<bool>
{
eval() {}
//
bool operator()(const var& v) const
{
if (v=="T" || v=="t" || v=="true" || v=="True")
return true;
else if (v=="F" || v=="f" || v=="false" || v=="False")
return false;
return boost::lexical_cast<bool>(v);
}
bool operator()(const binop<op_and>& b) const
{
return recurse(b.oper1) && recurse(b.oper2);
}
bool operator()(const binop<op_or>& b) const
{
return recurse(b.oper1) || recurse(b.oper2);
}
bool operator()(const unop<op_not>& u) const
{
return !recurse(u.oper1);
}
private:
template<typename T>
bool recurse(T const& v) const
{ return boost::apply_visitor(*this, v); }
};
struct printer : boost::static_visitor<void>
{
//
void operator()(std::ostream& os, const var& v) const { os << v; }
void operator()(std::ostream& os, const binop<op_and>& b) const { print(os, " & ", b.oper1, b.oper2); }
void operator()(std::ostream& os, const binop<op_or >& b) const { print(os, " | ", b.oper1, b.oper2); }
void print(std::ostream& os, const std::string& op, const expr& l, const expr& r) const
{
os << "(";
boost::apply_visitor(boost::bind(*this, boost::ref(os), _1), l);
os << op;
boost::apply_visitor(boost::bind(*this, boost::ref(os), _1), r);
os << ")";
}
void operator()(std::ostream& os, const unop<op_not>& u) const
{
os << "(";
os << "!";
boost::apply_visitor(boost::bind(*this, boost::ref(os), _1), u.oper1);
os << ")";
}
};
bool evaluate(const expr& e)
{ return boost::apply_visitor(eval(), e); }
std::ostream& operator<<(std::ostream& os, const expr& e)
{ boost::apply_visitor(boost::bind(printer(), boost::ref(os), _1), e); return os; }
template <typename It, typename Skipper = qi::space_type>
struct parser : qi::grammar<It, expr(), Skipper>
{
parser() : parser::base_type(expr_)
{
using namespace qi;
expr_ = or_.alias();
or_ = (and_ >> '|' >> or_ ) [ _val = phx::construct<binop<op_or > >(qi::_1, qi::_2) ] | and_ [ _val = qi::_1 ];
and_ = (not_ >> '&' >> and_) [ _val = phx::construct<binop<op_and> >(qi::_1, qi::_2) ] | not_ [ _val = qi::_1 ];
not_ = ('!' > simple ) [ _val = phx::construct<unop <op_not> >(qi::_1) ] | simple [ _val = qi::_1 ];
simple = (('(' > expr_ > ')') | var_);
var_ = qi::lexeme[ +(alpha|digit) ];
BOOST_SPIRIT_DEBUG_NODE(expr_);
BOOST_SPIRIT_DEBUG_NODE(or_);
BOOST_SPIRIT_DEBUG_NODE(and_);
BOOST_SPIRIT_DEBUG_NODE(not_);
BOOST_SPIRIT_DEBUG_NODE(simple);
BOOST_SPIRIT_DEBUG_NODE(var_);
}
private:
qi::rule<It, var() , Skipper> var_;
qi::rule<It, expr(), Skipper> not_, and_, or_, simple, expr_;
};
int main()
{
const std::string inputs[] = {
std::string("true & false;"),
std::string("true & !false;"),
std::string("!true & false;"),
std::string("true | false;"),
std::string("true | !false;"),
std::string("!true | false;"),
std::string("T&F;"),
std::string("T&!F;"),
std::string("!T&F;"),
std::string("T|F;"),
std::string("T|!F;"),
std::string("!T|F;"),
std::string("") // marker
};
for (const std::string *i = inputs; !i->empty(); ++i)
{
typedef std::string::const_iterator It;
It f(i->begin()), l(i->end());
parser<It> p;
try
{
expr result;
bool ok = qi::phrase_parse(f,l,p > ';',qi::space,result);
if (!ok)
std::cerr << "invalid input\n";
else
{
std::cout << "result:\t" << result << "\n";
std::cout << "evaluated:\t" << evaluate(result) << "\n";
}
} catch (const qi::expectation_failure<It>& e)
{
std::cerr << "expectation_failure at '" << std::string(e.first, e.last) << "'\n";
}
if (f!=l) std::cerr << "unparsed: '" << std::string(f,l) << "'\n";
}
return 0;
}
I found a really good example about boolean translator,
* Boolean expression (grammar) parser in c++
What I am thinking now is to do a further step, translate (!T|F)&T into F or 0, so it is very convenient for calculating a very long boolean expression.
Is there some examples about this using spirit? What I have done is making a calculator first, and then let it calculate '(T+!F*T)', which equal to (T||!F&&T)but when I type (), there is an error. How to modify it? Thanks a lot!
#include <iostream>
#include <stack>
#include <boost/lexical_cast.hpp>
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
using namespace std;
namespace phoenix = boost::phoenix;
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
struct calculator
{
bool interpret(const string& s);
void do_neg();
void do_add();
void do_sub();
void do_mul();
void do_div();
void do_number(const char* first, const char* last);
int val() const;
private:
stack<int> values_;
int *pn1_, n2_;
void pop_1();
void pop_2();
};
template <typename Iterator>
struct calc_grammar : qi::grammar<Iterator, ascii::space_type>
{
calc_grammar(calculator& calc)
: calc_grammar::base_type(add_sub_expr)
, calc_(calc)
{
using namespace qi;
using boost::iterator_range;
#define LAZY_FUN0(f) phoenix::bind(&calculator::f, calc_)
#define LAZY_FUN2(f) phoenix::bind(&calculator::f, calc_, phoenix::bind(&iterator_range<Iterator>::begin, qi::_1), phoenix::bind(&iterator_range<Iterator>::end, qi::_1))
add_sub_expr =
(
-lit('+') >> mul_div_expr |
(lit('-') >> mul_div_expr)[LAZY_FUN0(do_neg)]
) >>
*(
lit('+') >> mul_div_expr[LAZY_FUN0(do_add)] |
lit('-') >> mul_div_expr[LAZY_FUN0(do_sub)]
) >> eoi;
mul_div_expr =
basic_expr >>
*(
lit('*') >> basic_expr[LAZY_FUN0(do_mul)] |
lit('/') >> basic_expr[LAZY_FUN0(do_div)]
);
basic_expr =
raw[number][LAZY_FUN2(do_number)] |
lit('(') >> add_sub_expr >> lit(')');
number = lexeme[+digit];
}
qi::rule<Iterator, ascii::space_type> add_sub_expr, mul_div_expr, basic_expr, number;
calculator& calc_;
};
bool calculator::interpret(const string& s)
{
calc_grammar<const char*> g(*this);
const char* p = s.c_str();
return qi::phrase_parse(p, p + s.length(), g, ascii::space);
}
void calculator::pop_1()
{
pn1_ = &values_.top();
}
void calculator::pop_2()
{
n2_ = values_.top();
values_.pop();
pop_1();
}
void calculator::do_number(const char* first, const char* last)
{
string str(first, last);
int n = boost::lexical_cast<int>(str);
values_.push(n);
}
void calculator::do_neg()
{
pop_1();
*pn1_ = -*pn1_;
}
void calculator::do_add()
{
pop_2();
*pn1_ += n2_;
}
void calculator::do_sub()
{
pop_2();
*pn1_ -= n2_;
}
void calculator::do_mul()
{
pop_2();
*pn1_ *= n2_;
}
void calculator::do_div()
{
pop_2();
*pn1_ /= n2_;
}
int calculator::val() const
{
assert(values_.size() == 1);
return values_.top();
}
int main()
{
for(;;){
cout << ">>> ";
string s;
getline(cin, s);
if(s.empty()) break;
calculator calc;
if(calc.interpret(s))
cout << calc.val() << endl;
else
cout << "syntax error" << endl;
}
return 0;
}
Here goes a quick and dirty demo based on my old Boolean Parser answer. This is a visitor that evaluates the AST you pass it:
struct eval : boost::static_visitor<bool>
{
eval() {}
//
bool operator()(const var& v) const
{
if (v=="T" || v=="t" || v=="true" || v=="True")
return true;
else if (v=="F" || v=="f" || v=="false" || v=="False")
return false;
return boost::lexical_cast<bool>(v);
}
bool operator()(const binop<op_and>& b) const
{
return recurse(b.oper1) && recurse(b.oper2);
}
bool operator()(const binop<op_or>& b) const
{
return recurse(b.oper1) || recurse(b.oper2);
}
bool operator()(const unop<op_not>& u) const
{
return !recurse(u.oper1);
}
private:
template<typename T>
bool recurse(T const& v) const
{ return boost::apply_visitor(*this, v); }
};
bool evaluate(const expr& e)
{ return boost::apply_visitor(eval(), e); }
I hope I can find some time later to explain. Note that _var is a misnomer now, since you wanted to treat all operands as literals. Also note that the evaluation of a literal is a bit ... quick and dirty right now :)
Full Code
Live On Coliru
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/variant/recursive_wrapper.hpp>
#include <boost/lexical_cast.hpp>
namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;
struct op_or {};
struct op_and {};
struct op_not {};
typedef std::string var;
template <typename tag> struct binop;
template <typename tag> struct unop;
typedef boost::variant<var,
boost::recursive_wrapper<unop <op_not> >,
boost::recursive_wrapper<binop<op_and> >,
boost::recursive_wrapper<binop<op_or> >
> expr;
template <typename tag> struct binop
{
explicit binop(const expr& l, const expr& r) : oper1(l), oper2(r) { }
expr oper1, oper2;
};
template <typename tag> struct unop
{
explicit unop(const expr& o) : oper1(o) { }
expr oper1;
};
struct eval : boost::static_visitor<bool>
{
eval() {}
//
bool operator()(const var& v) const
{
if (v=="T" || v=="t" || v=="true" || v=="True")
return true;
else if (v=="F" || v=="f" || v=="false" || v=="False")
return false;
return boost::lexical_cast<bool>(v);
}
bool operator()(const binop<op_and>& b) const
{
return recurse(b.oper1) && recurse(b.oper2);
}
bool operator()(const binop<op_or>& b) const
{
return recurse(b.oper1) || recurse(b.oper2);
}
bool operator()(const unop<op_not>& u) const
{
return !recurse(u.oper1);
}
private:
template<typename T>
bool recurse(T const& v) const
{ return boost::apply_visitor(*this, v); }
};
struct printer : boost::static_visitor<void>
{
printer(std::ostream& os) : _os(os) {}
std::ostream& _os;
//
void operator()(const var& v) const { _os << v; }
void operator()(const binop<op_and>& b) const { print(" & ", b.oper1, b.oper2); }
void operator()(const binop<op_or >& b) const { print(" | ", b.oper1, b.oper2); }
void print(const std::string& op, const expr& l, const expr& r) const
{
_os << "(";
boost::apply_visitor(*this, l);
_os << op;
boost::apply_visitor(*this, r);
_os << ")";
}
void operator()(const unop<op_not>& u) const
{
_os << "(";
_os << "!";
boost::apply_visitor(*this, u.oper1);
_os << ")";
}
};
bool evaluate(const expr& e)
{ return boost::apply_visitor(eval(), e); }
std::ostream& operator<<(std::ostream& os, const expr& e)
{ boost::apply_visitor(printer(os), e); return os; }
template <typename It, typename Skipper = qi::space_type>
struct parser : qi::grammar<It, expr(), Skipper>
{
parser() : parser::base_type(expr_)
{
using namespace qi;
expr_ = or_.alias();
or_ = (and_ >> '|' >> or_ ) [ _val = phx::construct<binop<op_or > >(_1, _2) ] | and_ [ _val = _1 ];
and_ = (not_ >> '&' >> and_) [ _val = phx::construct<binop<op_and> >(_1, _2) ] | not_ [ _val = _1 ];
not_ = ('!' > simple ) [ _val = phx::construct<unop <op_not> >(_1) ] | simple [ _val = _1 ];
simple = (('(' > expr_ > ')') | var_);
var_ = qi::lexeme[ +(alpha|digit) ];
BOOST_SPIRIT_DEBUG_NODE(expr_);
BOOST_SPIRIT_DEBUG_NODE(or_);
BOOST_SPIRIT_DEBUG_NODE(and_);
BOOST_SPIRIT_DEBUG_NODE(not_);
BOOST_SPIRIT_DEBUG_NODE(simple);
BOOST_SPIRIT_DEBUG_NODE(var_);
}
private:
qi::rule<It, var() , Skipper> var_;
qi::rule<It, expr(), Skipper> not_, and_, or_, simple, expr_;
};
int main()
{
const std::string inputs[] = {
std::string("true & false;"),
std::string("true & !false;"),
std::string("!true & false;"),
std::string("true | false;"),
std::string("true | !false;"),
std::string("!true | false;"),
std::string("T&F;"),
std::string("T&!F;"),
std::string("!T&F;"),
std::string("T|F;"),
std::string("T|!F;"),
std::string("!T|F;"),
std::string("") // marker
};
for (const std::string *i = inputs; !i->empty(); ++i)
{
typedef std::string::const_iterator It;
It f(i->begin()), l(i->end());
parser<It> p;
try
{
expr result;
bool ok = qi::phrase_parse(f,l,p > ';',qi::space,result);
if (!ok)
std::cerr << "invalid input\n";
else
{
std::cout << "result:\t" << result << "\n";
std::cout << "evaluated:\t" << evaluate(result) << "\n";
}
} catch (const qi::expectation_failure<It>& e)
{
std::cerr << "expectation_failure at '" << std::string(e.first, e.last) << "'\n";
}
if (f!=l) std::cerr << "unparsed: '" << std::string(f,l) << "'\n";
}
return 0;
}
Output:
result: (true & false)
evaluated: 0
result: (true & (!false))
evaluated: 1
result: ((!true) & false)
evaluated: 0
result: (true | false)
evaluated: 1
result: (true | (!false))
evaluated: 1
result: ((!true) | false)
evaluated: 0
result: (T & F)
evaluated: 0
result: (T & (!F))
evaluated: 1
result: ((!T) & F)
evaluated: 0
result: (T | F)
evaluated: 1
result: (T | (!F))
evaluated: 1
result: ((!T) | F)
evaluated: 0