Boost::spirit::qi 为空值定义计算器 [英] Boost::spirit::qi defining a calculator for nullaries

查看:31
本文介绍了Boost::spirit::qi 为空值定义计算器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试为数学表达式编写一个解析器,其中命名变量是 boost::spirit(版本 1_51_0)中的空值,我对此完全陌生.我定义了 typedef boost::functionValue 和我的规则将像这样声明:qi::rule表达,术语,其他,...;

I'm trying to write a parser for math expressions where named variables are nullaries in boost::spirit (version 1_51_0), to which I'm completely new. I define typedef boost::function<double()> Value and my rules will be declared like so: qi::rule<Iterator, Value()> expression, term, others, ...;

我用这个宏在空值上定义了二元运算符

I define binary operators on nullaries with this macro

#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_;                                         
}; 

并且有 ADDSUB 等.从我看到的例子来看,我希望规则是这样定义的:

and have ADD, SUB, etc. From the examples I've seen, I'd expect the rules to be defined like this:

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

但这似乎不是正确的语法,因为我收到错误

but that doesn't seem to be the right syntax, as I get an error

boost/spirit/home/support/action_dispatch.hpp:162: error: no match for call to ‘(const<unnamed>::SUB) (boost::function<double ()()>&, boost::spirit::context<boost::fusion::cons<boost::function<double ()()>&, boost::fusion::nil>, boost::fusion::vector0<void> >&, bool&)’
SRParser.cpp:38: note: candidates are: double<unnamed>::SUB::operator()()

在我看来像 _1 并不完全符合我的预期,即与下一个术语相关的 Value.定义这样的规则的正确语法是什么?

which looks to me like _1 isn't quite what I expect it to be, namely the Value associated with the next term. What's the right syntax to define a rule like this?

推荐答案

解析器表达式看起来没问题.

The parser expression looks okay.

您对构建 AST 感到困惑.显然,您已决定使用语义操作来执行此操作,但您的努力过于粗略,我无法看到具体如何(甚至决定您基于什么样本).

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).

本质上:您想对ADD"/SUB"的实例做什么,您似乎神奇将"纳入您的规则?

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.

我假设您确实想使用 Phoenix 赋值来将二元运算分配给公开的属性.这看起来像:

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.

为了好玩,我根据您的 Value 类型改编了一个完整的表达式解析器并创建了这个工作演示:http://liveworkspace.org/code/3kgPJR$0

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) << "'
";
    if (f!=l) 
        std::cerr << "trailing unparsed: '" << std::string(f,l) << "'
";

    return eval;
}

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

它会打印

Area of a circle r=10: 628.319

这篇关于Boost::spirit::qi 为空值定义计算器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆