减少齐精神中替代解析器的更改 [英] Rolling back changes in alternative parsers in qi spirit

查看:125
本文介绍了减少齐精神中替代解析器的更改的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在使用替代解析器时遇到了一些麻烦,如果第一个选项失败,我需要解析器回滚更改.我尝试使用hold [],但收到错误消息无法推断出模板参数"

I'm having some trouble using the alternative parser, I need the parser to rollback changes if the first option failed. I tried using hold[] but I get the error that it "could not deduce template argument"

我正在尝试解析AST,并将其存储在:

I'm trying to parse an AST, and I'm storing it in:

struct node;

BOOST_FUSION_DEFINE_STRUCT(
    , node,
    (std::string, element)
    (std::string, category)
    (std::vector<node>, children)
    )

'element'是被解析的元素,'category'是其分类,然后我有一个向量来存储他的孩子

'element' is the element parsed, 'category' it's classification, and then I have a vector to store his children

因此,举例来说,我有几种类似的情况:

So, to exemplify I have several cases similar to:

ABC=
    (qi::char_('a')[at_c<0>(qi::_val) = "a", at_c<1>(qi::_val) = "ABC"]
    >> B[push_back(at_c<2>(qi::_val), qi::_1)]
    >> qi::char_('c'))
    ;

ABD=
    (qi::char_('a')[at_c<0>(qi::_val) = "a", at_c<1>(qi::_val) = "ABD"]
    >> B[push_back(at_c<2>(qi::_val), qi::_1)]
    >> qi::char_('d')
    )
    ;

test = ABC | ABD;

B是一些返回节点的规则.如果我运行此命令,我会在第二种选择中重复得到B,因为它是在第一种选择中被压入的.正如我所说的,我尝试过:

B is some rule that returns a node. If I run this I get B repeated for the second alternative, since it was pushed in the first. As I said I tried:

test = hold[ABC]| ABD;

但是我得到那个错误.我要解决的方法是将规则B的结果存储在局部变量中,然后仅在规则末尾推送它(意味着规则匹配).但这会导致非常复杂的语义动作,还有其他选择吗?

but I get that error. The solution I've come to is to store the result of rule B in a local variable and then push it only at the end of the rule (meaning the rule matches). But that results in very complicated semantic actions, any alternative?

推荐答案

在这里,我会说所有的语义动作都没有用. [1] .

I would say all the semantic actions are useless here[1].

所有这些都可以由放置良好的qi::attr代替,以简单地就地合成所需的属性,然后您可以再次使用Spirit的自动属性传播魔术.

All of them can be replaced by a well-placed qi::attr to simply synthesize the desired attribute in-place and you can again use the automatic attribute propagation magic of Spirit.

以我的经验,如果您开始将语义操作用于最简单的事情,那么最好是没有Spirit

先简化

所以,这是我对AST node类型的看法:

struct node {
    std::string element, category;
    std::vector<node> children;
};

BOOST_FUSION_ADAPT_STRUCT(node, element, category, children)

它在功能上与您的等效,但更像c ++,因此更友好.现在,您没有给出规则声明,因此可以想象"如下:

It's functionally equivalent to yours, but more c++-like, and therefore somewhat more friendly. Now, you didn't give the rule declarations, so "imagined" them as follows:

qi::rule<It, node(), qi::space_type> ABC, ABD, test;
qi::rule<It, std::vector<node>(), qi::space_type> B;

// also for demo purposes:
B = '{' >> -(test % ',') >> '}';

现在,我对您的建议简化了:

Now, my suggestion of you rules, simplified:

ABC = qi::string("a") >> qi::attr("ABC") >> B >> 'c';
ABD = qi::string("a") >> qi::attr("ABD") >> B >> 'd';

test = ABC | ABD;

实际上,您需要hold,因为/otherwise/两个ABC/ABD都将绑定到相同的内部综合属性node&:

Indeed, you need to hold because /otherwise/ both ABC/ABD will bind to the same internal synthesized attribut node&:

ABC = qi::hold[ qi::string("a") >> qi::attr("ABC") >> B >> 'c' ];
ABD = qi::hold[ qi::string("a") >> qi::attr("ABD") >> B >> 'd' ];

这就是您想要/需要的一切.

This is all you wanted/needed.

当我反向工程化"语法时,我为语法构建了一些测试用例,并添加了调试代码:

I constructed a few test cases for the grammar as I "reverse-engi-magined" it and added debug code:

在Coliru上直播 -没有qi::hold[]

//#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/adapted.hpp>

struct node {
    std::string element, category;
    std::vector<node> children;
};

BOOST_FUSION_ADAPT_STRUCT(node, element, category, children)

static std::ostream& operator<<(std::ostream& os, node const& n) {
    return os << boost::fusion::as_vector(n);
}

static std::ostream& operator<<(std::ostream& os, std::vector<node> const& v) {
    os << "{";
    for (size_t i = 0; v.size()>1 &&  i<v.size()-1; ++i)
        os << v.at(i) << ", ";

    if (!v.empty()) os << v.back();
    return os << "}";
}

namespace qi = boost::spirit::qi;

int main() {
    using It = std::string::const_iterator;

    qi::rule<It, node(), qi::space_type> ABC, ABD, test;
    qi::rule<It, std::vector<node>(), qi::space_type> B;

#if 1
    ABC = qi::hold[ qi::string("a") >> qi::attr("ABC") >> B >> 'c' ];
    ABD = qi::hold[ qi::string("a") >> qi::attr("ABD") >> B >> 'd' ];
#else
    ABC = qi::string("a") >> qi::attr("ABC") >> B >> 'c' ;
    ABD = qi::string("a") >> qi::attr("ABD") >> B >> 'd' ;
#endif

    test = ABC | ABD;
    B    = '{' >> -(test % ',') >> '}';

    for (std::string const s : {
            "a{a{}c}c",
            "a{a{}d}d",
            "a{a{}c}d",
            "a{a{}d,a{}c}c",
        })
    {
        std::cout << "\n-- Parsing '" << s << "'\n";
        It f = s.begin(), l = s.end();

        node parsed;
        bool ok = qi::phrase_parse(f, l, test, qi::space, parsed);

        if (ok)
            std::cout << "Parsed: " << parsed << "\n";
        else
            std::cout << "Parse failed\n";

        if (f!=l)
            std::cout << "Remaining unparsed input: '" << std::string(f,l) << "'\n";
    }
}

输出(保留):

-- Parsing 'a{a{}c}c'
Parsed: (a ABC {(a ABC {})})

-- Parsing 'a{a{}d}d'
Parsed: (a ABD {(a ABD {})})

-- Parsing 'a{a{}c}d'
Parsed: (a ABD {(a ABC {})})

-- Parsing 'a{a{}d,a{}c}c'
Parsed: (a ABC {(a ABD {}), (a ABC {})})


[1] .另请参见 Boost Spirit:语义行为是邪恶的"?


[1]. See also Boost Spirit: "Semantic actions are evil"?

这篇关于减少齐精神中替代解析器的更改的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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