[英]boost::spirit qi parsing runtime error
為什么在解析帶有該語法的字符串時出現運行時錯誤?
template <typename Iterator, typename Skipper>
struct grammar : qi::grammar<Iterator, QVariant(), Skipper>
{
grammar() : grammar::base_type(object)
{
identifier = qi::raw[qi::lexeme[qi::alpha >> *(qi::alnum | '_' | ('-' >> qi::alnum))]];
self = (qi::raw[qi::lexeme["self"]]);
object = (self >> '.' >> identifier)
|(object >> '.' >> identifier); // there is no runtime error without that line
}
}
其他語法都運行良好,但我想解析如下內容:
self.foo.bar2.baz
運行時錯誤拋出
qi::phrase_parse(it, str.end(), g, ascii::space, v) && it == str.end())
呼叫。
在我看來,作為起點的object
規則必須聲明為
qi::rule<It, QVariant(), Skipper> object;
盡管我不知道QVariant是什么,但我知道:
為了使屬性傳播正常工作,您需要使用內置的Qi轉換啟發式方法來具有屬性類型兼容性。
對於第一個分支( self>>'.'>>identifier
),這/很簡單。 假設identifier
符合成了一個字符串兼容的屬性(例如std::string
或std::vector<char>
),那么可以合法地將生成的屬性分配為字符串。
舉一個簡單的例子,看一下(我在這里“模仿” QVariant
可能是的東西):
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
using QVariant = boost::variant<std::string, int>;
template <typename Iterator, typename Skipper>
struct grammar : qi::grammar<Iterator, QVariant(), Skipper>
{
grammar() : grammar::base_type(object)
{
identifier = qi::raw[qi::lexeme[qi::alpha >> *(qi::alnum | '_' | ('-' >> qi::alnum))]];
self = (qi::raw[qi::lexeme["self"]]);
object =
qi::as_string [self >> '.' >> identifier]
//|qi::as_string [object >> '.' >> identifier] // there is no runtime error without that line
;
}
private:
qi::rule<Iterator, QVariant(), Skipper> object;
qi::rule<Iterator, std::string(), Skipper> identifier;
qi::rule<Iterator, std::string(), Skipper> self;
};
int main() {
using It = std::string::const_iterator;
std::string input = "self.foo.bar2.baz";
It f = input.begin(), l = input.end();
QVariant parsed;
bool ok = qi::phrase_parse(f, l, grammar<It, qi::space_type>{}, qi::space, parsed);
if (ok)
std::cout << "Parsed: " << parsed << "\n";
else
std::cout << "Parse failed\n";
if (f!=l)
std::cout << "Remaining unparsed: '" << std::string(f,l) << "'\n";
}
印刷:
Parsed: selffoo
Remaining unparsed: '.bar2.baz'
第二支
qi::as_string [object >> '.' >> identifier]
必須將其合成為tuple<QVariant, std::string>
才能與其余聲明保持一致。 Spirit無法自動進行轉換。 啟發式系統可能會開始陷入困境,並嘗試將bound屬性(請記住,這是神秘的QVariant)視為容器。 如果成功的話,事情就會編譯。 顯然,在運行時事情崩潰了,因為為QVariant的實際-運行時-值調用了錯誤的接口。
這是理論。
在觀看工作演示時,請注意'.'
被排除。 這使我懷疑您實際上是否不需要對象引用的任何復雜鏈式“列表”,而是可能只想將整個匹配的輸入視為原始字符串 ? 在這種情況下,最簡單的解決方案是將raw[]
提升一個級別,並可能使用字符串而不是QVariant
。
¹例如,因為QVariant接口有點草率/不安全,並且直接在變體接口上公開了.begin / .end / value_type / insert成員?
在像boost :: spirit這樣的LL解析器中無法使用“ A =(A >> a)| b”之類的左遞歸。 它們應轉換為LL友好形式:A = bR R = aR | e其中R-新的非終端,e-epsilon(空終端)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.