Boost::spirit::qi defining a calculator for nullaries

耗尽温柔 提交于 2019-11-29 15:14:19

The parser expression looks okay.

What you are confused over is on constructing the AST. Apparently, you have decided to use Semantic Actions to do so, but your effort is too sketchy for me to see just how (or even decide what sample you are basing this on).

In essence: What is it that you want to do with the instances of 'ADD'/'SUB' that you seem to magically "will" into your rules?

Right now, you just use the instance directly as a semantic action. This leads to the error message shown, which tells you, directly, that the instance is not valid as a semantic action.

I assume you really wanted to use Phoenix assignment to assign the binary operation to the exposed attribute, instead. This looks like:

expression = term
     >> *( (lit('+') >> term[ _val = phx::construct<ADD>(_val, _1)])
         | (lit('-') >> term[ _val = phx::construct<SUB>(_val, _1)])
         );

You'll see this matches much more closely with traditional expression grammars.

For fun I adapted a complete expression parser based on your Value type and created this working demonstration: http://liveworkspace.org/code/3kgPJR$0

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/include/phoenix.hpp>

namespace qi    = boost::spirit::qi;
namespace karma = boost::spirit::karma;
namespace phx   = boost::phoenix;

typedef std::function<double()> Value;

#define BINARY_FUNCTOR(name, op)                        \
struct name                                             \
{                                                       \
  name(Value x, Value y): x_(x), y_(y) {}               \
  double operator()() { return x_() op y_(); }          \
  Value x_, y_;                                         \
}; 

BINARY_FUNCTOR(ADD, +)
BINARY_FUNCTOR(SUB, -)
BINARY_FUNCTOR(MUL, *)
BINARY_FUNCTOR(DIV, /)

struct LIT
{
  LIT(double x): x_(x) {}
  double operator()() { return x_; }
  double x_;
}; 

struct NEG
{
  NEG(Value x): x_(x) {}
  double operator()() { return -x_(); }
  Value x_;
}; 


template <typename It, typename Skipper = qi::space_type>
    struct parser : qi::grammar<It, Value(), Skipper>
{
    parser() : parser::base_type(expression)
    {
        using namespace qi;
        expression =
            term                    [_val = _1]
            >> *( ('+' >> term  [_val = phx::construct<ADD>(_val, _1)])
                | ('-' >> term  [_val = phx::construct<SUB>(_val, _1)])
                );

        term =
            factor                [_val = _1]
            >> *( ('*' >> factor  [_val = phx::construct<MUL>(_val, _1)])
                | ('/' >> factor  [_val = phx::construct<DIV>(_val, _1)])
                );

        factor =
            double_               [_val = phx::construct<LIT>(_1)]
            |   '(' >> expression [_val = _1] >> ')'
            |   ('-' >> factor    [_val = phx::construct<NEG>(_1)])
            |   ('+' >> factor    [_val = _1]);

        BOOST_SPIRIT_DEBUG_NODE(expression);
        BOOST_SPIRIT_DEBUG_NODE(term);
        BOOST_SPIRIT_DEBUG_NODE(factor);
    }

  private:
    qi::rule<It, Value(), Skipper> expression, term, factor;
};

Value doParse(const std::string& input)
{
    typedef std::string::const_iterator It;
    parser<It, qi::space_type> p;
    Value eval;

    auto f(begin(input)), l(end(input));

    if (!qi::phrase_parse(f,l,p,qi::space,eval))
        std::cerr << "parse failed: '" << std::string(f,l) << "'\n";
    if (f!=l) 
        std::cerr << "trailing unparsed: '" << std::string(f,l) << "'\n";

    return eval;
}

int main()
{
    auto area = doParse("2 * (3.1415927 * (10*10))");
    std::cout << "Area of a circle r=10: " << area() << "\n";
}

It will print

Area of a circle r=10: 628.319
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!