减少齐精神中替代解析器的更改 [英] Rolling back changes in alternative parsers in qi spirit
问题描述
我在使用替代解析器时遇到了一些麻烦,如果第一个选项失败,我需要解析器回滚更改.我尝试使用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[]
在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屋!