c – Boost ::精神表达解析器

c – Boost ::精神表达解析器,第1张

概述我的boost :: spirit解析器有另一个问题. template<typename Iterator>struct expression: qi::grammar<Iterator, ast::expression(), ascii::space_type> { expression() : expression::base_type(expr) { 我的boost :: spirit解析器有另一个问题.
template<typename Iterator>struct Expression: qi::grammar<Iterator,ast::Expression(),ascii::space_type> {    Expression() :        Expression::base_type(expr) {        number %= lexeme[double_];        varname %= lexeme[Alpha >> *(alnum | '_')];        binop = (expr >> '+' >> expr)[_val = construct<ast::binary_op<ast::add>>(_1,_2)]              | (expr >> '-' >> expr)[_val = construct<ast::binary_op<ast::sub>>(_1,_2)]              | (expr >> '*' >> expr)[_val = construct<ast::binary_op<ast::mul>>(_1,_2)]              | (expr >> '/' >> expr)[_val = construct<ast::binary_op<ast::div>>(_1,_2)] ;        expr %= number | varname | binop;    }    qi::rule<Iterator,ascii::space_type> expr;    qi::rule<Iterator,ascii::space_type> binop;    qi::rule<Iterator,std::string(),ascii::space_type> varname;    qi::rule<Iterator,double(),ascii::space_type> number;};

这是我的解析器.它解析了“3.1415”和“var”就好了,但是当我试图解析“1 2”时,它告诉我解析失败.然后我尝试将binop规则更改为

binop = expr >>           (('+' >> expr)[_val = construct<ast::binary_op<ast::add>>(_1,_2)]          | ('-' >> expr)[_val = construct<ast::binary_op<ast::sub>>(_1,_2)]          | ('*' >> expr)[_val = construct<ast::binary_op<ast::mul>>(_1,_2)]          | ('/' >> expr)[_val = construct<ast::binary_op<ast::div>>(_1,_2)]);

但是现在当然不能构建AST,因为_1和_2设置不同.我只看到像_r1这样的提到,但作为一个提升 – 新手,我不太了解如何boost :: phoenix和boost :: spirit相互作用.

如何解决这个问题?

解决方法 对我来说,这是不完全清楚的.最重要的是,你不担心运算符的联系吗?我将使用右递归来显示简单的答案 – 这导致左关联运算符被解析.

对于可见问题的直接回答将是进行融合:: vector2< char,ast :: Expression> – 这不是真的有趣,特别是在凤凰lambda语义行动. (我将在下面显示,看起来像什么).

同时我想你应该读圣灵文件

> here在老精神文件(消除左递归);虽然语法不再适用,但Spirit仍然生成LL递归下降解析器,因此左递归的概念仍然适用.下面的代码显示了这个应用于Spirit Qi的代码
> here:Qi的例子包含三个计算器样本,这应该给你一个提示,为什么 *** 作符关联性重要,以及你如何表达一个捕获二进制运算符的关联性的语法.显然,它还显示如何支持括号表达式来覆盖默认评估顺序.

码:

我有三个版本的代码工作,解析输入如下:

std::string input("1/2+3-4*5");

分组成一个ast ::表达式(使用BOOST_SPIRIT_DEBUG):

<expr>  ....  <success></success>  <attributes>[[1,[2,[3,[4,5]]]]]</attributes></expr>

The links to the code are here:

07002 07003 07004

步骤1:Reduce semantic actions

首先,我会摆脱每个 *** 作符的替代解析表达式;这导致过度的回溯1.另外,正如你所发现的,它使语法难以维持.所以,这是一个更简单的变体,它使用语义动作的函数:

1检查使用BOOST_SPIRIT_DEBUG!

static ast::Expression make_binop(char discriminant,const ast::Expression& left,const ast::Expression& right){    switch(discriminant)    {        case '+': return ast::binary_op<ast::add>(left,right);        case '-': return ast::binary_op<ast::sub>(left,right);        case '/': return ast::binary_op<ast::div>(left,right);        case '*': return ast::binary_op<ast::mul>(left,right);    }    throw std::runtime_error("unreachable in make_binop");}// rules:number %= lexeme[double_];varname %= lexeme[Alpha >> *(alnum | '_')];simple = varname | number;binop = (simple >> char_("-+*/") >> expr)     [ _val = phx::bind(make_binop,qi::_2,qi::_1,qi::_3) ]; expr = binop | simple;

步骤2:Remove redundant rules,use _val

如您所见,这有可能降低复杂性.现在只是一小步,去除二进制中间件(已经变得相当多余):

number %= lexeme[double_];varname %= lexeme[Alpha >> *(alnum | '_')];simple = varname | number;expr = simple [ _val = _1 ]     > *(char_("-+*/") > expr)             [ _val = phx::bind(make_binop,_val,qi::_2) ]    > eoi;

如你看到的,

>在expr规则中,_val懒惰占位符用作累加binops的伪局部变量.根据规则,你必须使用qi :: locals< ast :: Expression>对于这种方法. (这是关于_r1的问题).
>现在有明确的期望点,使语法更加健壮
> expr规则不再需要自动规则(expr =而不是expr%=)

步骤0:Wrestle fusion types directly

最后,为了乐趣和血腥,让我展示如何处理你建议的代码,以及_1,_2等的移动绑定:

static ast::Expression make_binop(        const ast::Expression& left,const boost::fusion::vector2<char,ast::Expression>& op_right){    switch(boost::fusion::get<0>(op_right))    {        case '+': return ast::binary_op<ast::add>(left,boost::fusion::get<1>(op_right));        case '-': return ast::binary_op<ast::sub>(left,boost::fusion::get<1>(op_right));        case '/': return ast::binary_op<ast::div>(left,boost::fusion::get<1>(op_right));        case '*': return ast::binary_op<ast::mul>(left,boost::fusion::get<1>(op_right));    }    throw std::runtime_error("unreachable in make_op");}// rules:Expression::base_type(expr) {number %= lexeme[double_];varname %= lexeme[Alpha >> *(alnum | '_')];simple = varname | number;binop %= (simple >> (char_("-+*/") > expr))     [ _val = phx::bind(make_binop,qi::_2) ]; // note _2!!!expr %= binop | simple;

正如你所看到的那样,没有几乎有趣的写make_binop函数!

总结

以上是内存溢出为你收集整理的c – Boost ::精神表达解析器全部内容,希望文章能够帮你解决c – Boost ::精神表达解析器所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1232706.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-06
下一篇 2022-06-06

发表评论

登录后才能评论

评论列表(0条)

保存