簡體   English   中英

boost :: spirit qi解析運行時錯誤

[英]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::stringstd::vector<char> ),那么可以合法地將生成的屬性分配為字符串。

樣品

舉一個簡單的例子,看一下(我在這里“模仿” QVariant可能是的東西):

生活在Coliru

#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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM