我希望有人可以通过我使用的无知闪耀光>
和>>
在精神分析的运营商。
我有一个工作的语法,其中顶层规则如下
test = identifier >> operationRule >> repeat(1,3)[any_string] >> arrow >> any_string >> conditionRule;
它依赖于属性自动分配解析值的融合适应结构(即,元组升压)。
但是,我知道,一旦我们的operationRule匹配,我们必须继续或失败(即我们不希望允许回溯尝试与其他开头的规则identifier
)。
test = identifier >>
operationRule > repeat(1,3)[any_string] > arrow > any_string > conditionRule;
这将导致一个神秘的编译器错误( 'boost::Container' : use of class template requires template argument list
)。 Futz了一下周围和下面的编译:
test = identifier >>
(operationRule > repeat(1,3)[any_string] > arrow > any_string > conditionRule);
但属性设置不再工作 - 我的数据结构包含解析后的垃圾。 这可以通过添加动作等进行固定[at_c<0>(_val) = _1]
但似乎有点笨重-以及根据升压文档使事情慢。
所以,我的问题是
- 是否值得防止反向追踪?
- 为什么我需要的分组运算符
()
- 请问我的最后一个例子上面真的停下来后回溯
operationRule
匹配(我不怀疑,看来,如果里面的整个分析器(...)
失败回溯将被允许)? - 如果回答前一个问题是/否/,我该如何构建允许回溯的规则,如果
operation
是/不是/匹配,但不允许的,一旦操作/是/匹配回溯? - 为什么分组操作破坏属性语法 - 需要采取行动?
我知道这是一个相当宽泛的问题 - 在正确的方向指向任何暗示将不胜感激!
是否值得防止反向追踪?
绝对。 预防早在一般跟踪是提高性能分析器一个行之有效的方法。
- 减少使用(负)前瞻的(运营商,运营商 - 和一些运营商)
- 为了分支(运营商|,操作||,运营商^和一些运营商* / - / +),使得最频繁的/有可能分支排在第一位,或者说,最昂贵的分支试图最后
使用期望点( >
)基本上不减少回溯: 它只是禁止它 。 这将使针对性的错误信息,避免无用的“解析成 - 的未知”。
为什么我需要的分组operator ()
我不确定。 我有一个支票使用我what_is_the_attr
助手从这里
ident >> op >> repeat(1,3)[any] >> "->" >> any
综合属性:
fusion::vector4<string, string, vector<string>, string>
ident >> op > repeat(1,3)[any] > "->" > any
综合属性:
fusion::vector3<fusion::vector2<string, string>, vector<string>, string>
我还没有发现使用圆括号(东西编译) 需要组子表达式,但显然DataT
需要进行修改,以符合变化的布局。
typedef boost::tuple< boost::tuple<std::string, std::string>, std::vector<std::string>, std::string > DataT;
下面的完整代码显示了如何宁愿做,使用适合结构。
请问我上面的例子中真止operationRule匹配后回溯(我不怀疑,看来,如果里面的(...)失败回溯将被允许在整个分析器)?
绝对。 如果期望(或多个)不被满足,一个qi::expectation_failure<>
则抛出异常。 这在默认情况下将中止解析。 你可以使用气:: ON_ERROR到retry
, fail
, accept
或rethrow
。 该MiniXML例如对使用的期望点具有非常好的例子qi::on_error
如果回答前一个问题是/否/, 我该如何构建允许回溯的规则,如果操作是/不是/匹配,但不允许的,一旦操作/是/匹配回溯?
为什么分组操作破坏属性语法-需要采取行动?
它不破坏属性语法,它只是改变了暴露的类型。 所以,如果你绑定一个适当的属性根据规则/语法,你不需要语义动作。 现在,我觉得应该有办法去没有分组,所以让我试试吧(最好是在你的短期自备的样品)。 事实上我发现没有这样的必要 。 我添加了一个完整的例子来帮助你看到正在发生的事情在我的测试,并没有使用语义动作。
完整的代码
完整的代码显示5种情景:
显然,定义OPTION
编译之前所需的值。
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/fusion/adapted.hpp>
#include <iostream>
namespace qi = boost::spirit::qi;
namespace karma = boost::spirit::karma;
#ifndef OPTION
#define OPTION 5
#endif
#if OPTION == 1 || OPTION == 5 // original without expectations (OR lookahead hack)
typedef boost::tuple<std::string, std::string, std::vector<std::string>, std::string> DataT;
#elif OPTION == 2 // with expectations
typedef boost::tuple<boost::tuple<std::string, std::string>, std::vector<std::string>, std::string> DataT;
#elif OPTION == 3 // adapted struct, without expectations
struct DataT
{
std::string identifier, operation;
std::vector<std::string> values;
std::string destination;
};
BOOST_FUSION_ADAPT_STRUCT(DataT, (std::string, identifier)(std::string, operation)(std::vector<std::string>, values)(std::string, destination));
#elif OPTION == 4 // adapted struct, with expectations
struct IdOpT
{
std::string identifier, operation;
};
struct DataT
{
IdOpT idop;
std::vector<std::string> values;
std::string destination;
};
BOOST_FUSION_ADAPT_STRUCT(IdOpT, (std::string, identifier)(std::string, operation));
BOOST_FUSION_ADAPT_STRUCT(DataT, (IdOpT, idop)(std::vector<std::string>, values)(std::string, destination));
#endif
template <typename Iterator>
struct test_parser : qi::grammar<Iterator, DataT(), qi::space_type, qi::locals<char> >
{
test_parser() : test_parser::base_type(test, "test")
{
using namespace qi;
quoted_string =
omit [ char_("'\"") [_a =_1] ]
>> no_skip [ *(char_ - char_(_a)) ]
> lit(_a);
any_string = quoted_string | +qi::alnum;
identifier = lexeme [ alnum >> *graph ];
operationRule = string("add") | "sub";
arrow = "->";
#if OPTION == 1 || OPTION == 3 // without expectations
test = identifier >> operationRule >> repeat(1,3)[any_string] >> arrow >> any_string;
#elif OPTION == 2 || OPTION == 4 // with expectations
test = identifier >> operationRule > repeat(1,3)[any_string] > arrow > any_string;
#elif OPTION == 5 // lookahead hack
test = &(identifier >> operationRule) > identifier > operationRule > repeat(1,3)[any_string] > arrow > any_string;
#endif
}
qi::rule<Iterator, qi::space_type/*, qi::locals<char> */> arrow;
qi::rule<Iterator, std::string(), qi::space_type/*, qi::locals<char> */> operationRule;
qi::rule<Iterator, std::string(), qi::space_type/*, qi::locals<char> */> identifier;
qi::rule<Iterator, std::string(), qi::space_type, qi::locals<char> > quoted_string, any_string;
qi::rule<Iterator, DataT(), qi::space_type, qi::locals<char> > test;
};
int main()
{
std::string str("addx001 add 'str1' \"str2\" -> \"str3\"");
test_parser<std::string::const_iterator> grammar;
std::string::const_iterator iter = str.begin();
std::string::const_iterator end = str.end();
DataT data;
bool r = phrase_parse(iter, end, grammar, qi::space, data);
if (r)
{
using namespace karma;
std::cout << "OPTION " << OPTION << ": " << str << " --> ";
#if OPTION == 1 || OPTION == 3 || OPTION == 5 // without expectations (OR lookahead hack)
std::cout << format(delimit[auto_ << auto_ << '[' << auto_ << ']' << " --> " << auto_], data) << "\n";
#elif OPTION == 2 || OPTION == 4 // with expectations
std::cout << format(delimit[auto_ << '[' << auto_ << ']' << " --> " << auto_], data) << "\n";
#endif
}
if (iter!=end)
std::cout << "Remaining: " << std::string(iter,end) << "\n";
}
所有选项输出:
for a in 1 2 3 4 5; do g++ -DOPTION=$a -I ~/custom/boost/ test.cpp -o test$a && ./test$a; done
OPTION 1: addx001 add 'str1' "str2" -> "str3" --> addx001 add [ str1 str2 ] --> str3
OPTION 2: addx001 add 'str1' "str2" -> "str3" --> addx001 add [ str1 str2 ] --> str3
OPTION 3: addx001 add 'str1' "str2" -> "str3" --> addx001 add [ str1 str2 ] --> str3
OPTION 4: addx001 add 'str1' "str2" -> "str3" --> addx001 add [ str1 str2 ] --> str3
OPTION 5: addx001 add 'str1' "str2" -> "str3" --> addx001 add [ str1 str2 ] --> str3
文章来源: boost::spirit::qi Expectation Parser and parser grouping unexpected behaviour