[英]boost::spirit::qi Expectation Parser and parser grouping unexpected behaviour
我希望有人能夠通過我在精神解析中使用>
和>>
運算符的無知來發光。
我有一個工作語法,頂級規則看起來像
test = identifier >> operationRule >> repeat(1,3)[any_string] >> arrow >> any_string >> conditionRule;
它依賴於屬性來自動將解析后的值分配給融合自適應結構(即boost元組)。
但是,我知道一旦我們匹配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]
這樣的動作來修復,但這看起來有點笨拙 - 以及根據boost文檔使事情變慢。
所以,我的問題是
()
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
表達式進行分組,但顯然需要修改DataT
以匹配更改的布局。
typedef boost::tuple< boost::tuple<std::string, std::string>, std::vector<std::string>, std::string > DataT;
下面的完整代碼顯示了我喜歡如何使用改編的結構。
我的上述示例是否真的在operationRule匹配后停止回溯(我懷疑沒有,似乎如果(...)內的整個解析器失敗回溯將被允許)?
絕對。 如果未滿足qi::expectation_failure<>
則拋出qi::expectation_failure<>
異常。 這默認情況下會中止解析。 您可以使用qi :: on_error retry
, fail
, accept
或rethrow
。 MiniXML示例在使用qi::on_error
期望點方面有很好的例子
如果上一個問題的答案是/ no /,
如何構建一個規則,如果操作是/不匹配,則允許回溯,但是一旦操作/匹配,就不允許回溯?
為什么分組操作符會破壞屬性語法 - 需要操作?
它不會破壞屬性語法,只是更改了暴露的類型。 因此,如果將適當的屬性引用綁定到規則/語法,則不需要語義操作。 現在,我覺得應該有沒有分組的方法
,所以讓我嘗試一下(最好是你的短自我樣本)。
事實上,我沒有找到這樣的需要 。 我添加了一個完整的示例來幫助您了解我的測試中發生了什么,而不是使用語義操作。
完整代碼顯示了5個場景:
選項1:原始沒有期望
(無相關變化)
方案2:滿懷期望
使用修改后的typedef進行DataT(如上所示)
選項3:適應結構,沒有期望
將用戶定義的結構與BOOST_FUSION_ADAPT_STRUCT一起使用
選項4:適應結構,有期望
從OPTION 3修改改編的結構
選項5:前瞻黑客
這個利用了一個'聰明'(?)hack ,將所有>>
變為期望,並事先檢測出operationRule
-match的存在。 這當然不是最理想的,但允許您保持DataT
修改,而不使用語義操作。
顯然,在編譯之前將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";
}
所有OPTIONS的輸出:
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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.