2013-12-11 25 views
1

我正在使用bison/flex在C++中爲用戶可以在gui中鍵入字段的表達式開發解析器。我希望能夠在用戶輸入時向用戶反饋允許的令牌(基本上是自動完成的)。 '%error-verbose'產生的信息就足夠了,但它只能作爲一個字符串使用。有沒有一種方法可以在處理解析錯誤時編程訪問意外標記和預期標記列表?如何找出C++ bison解析器中的意外標記?

回答

3

令牌本身在變量yychar中。這部分很容易。

尋找可能性列表更棘手。

從概念上講,您可以重新解析當前輸入,但不包括錯誤的標記;保存解析器狀態;然後嘗試每個其他可能的標記來查看是否產生錯誤。

您需要重新分析的原因是LALR解析器可能在遇到語法錯誤之前執行錯誤的縮減。 (儘管他們從不執行錯誤的轉換。)爲了發現解析器狀態的有效前瞻,這些縮減將不得不撤銷,並且沒有機制來做到這一點。一般而言,減少信息會丟失信息,因此甚至在理論上都不可能。

如果啓用LAC(劑適量),你需要爲了得到精確的錯誤做,error-verbose解析器做一個探索性的解析(沒有減排行動)上的每個令牌可能引發了不正確的減少避免減少問題。如果此解析失敗,則解析器狀態可用於構建選項列表;如果成功了,那麼它會重新進行還原操作。不幸的是,野牛不提供用於「複製解析器狀態」的API;但是,野牛不提供用於「複製解析器狀態」的API;但是,野牛不提供用於「複製解析器狀態」的API。你可以很容易地進行逆向工程,但那會很脆弱。所以如果你想在沒有訪問生成的解析器內部的情況下嘗試這個,你實際上必須多次重新分析輸入,一次對於每個可能的lookahead標記。

您可以使用規範LR解析器,該解析器具有在任何縮減之前檢測到錯誤的屬性。完整的LR解析表可能非常龐大,但如果您的語法足夠簡單,這可能不成問題。但是,您仍然沒有乾淨的方式來保存解析器狀態,因此除非您進行逆向工程,否則您仍然必須重新解析每個成功的先行令牌。 (或者足夠構建一個有效的錯誤信息,Bison的詳細錯誤設置最多隻能輸出五種可能性,並且有很好的理由)。

可能最簡單的解決方案是解析野牛錯誤消息,簡單的固定格式。如果您要這樣做,我會建議您將令牌名稱簡單易懂,並在您的yyerror處理程序中替換易讀的文本。

啓用LAC肯定會減慢解析速度。一般而言,所有精確的錯誤檢測和報告修改會減慢解析器的速度,有時甚至會顯着;這包括保存位置信息(儘管這對於調試輸出也很有用,所以實際上它可能是必要的)。

我總是給出的建議,因爲它在實踐中運行良好,我建立了兩個解析器:一個針對無錯代碼進行了優化,並且不會嘗試做任何事情,而不是嘗試拒絕第一個錯誤的輸入,另一個(可能慢得多)可以處理錯誤檢測和恢復。然後錯誤的輸入被解析兩次,一次用快速解析器,然後再用慢速解析器解析;正確的輸入只需要使用快速解析器解析一次。這使得項目建立得很快,並且通常不會減慢最初的寫 - 「編譯」 - 編輯循環,只要快速解析器實際上是快速的。保持兩個解析器同步可能會很煩人,但大多數時候錯誤恢復解析器只需要一些其他方法,這些方法可以轉換爲空操作,然後在快速解析器中進行優化。通過這種策略,您可能能夠使用快速解析器來執行「法律預見」生成,並且它可能會變得足夠快。

與往常一樣,情況因人而異。祝你好運。

+0

感謝您的回答@rici。你已經涵蓋了很多我只是部分意識到的細節,我發現它很有趣。儘管你的一些建議似乎不適用於C++解析器。我的部分問題是,我甚至無法在C++解析器中訪問'yychar'作爲其局部變量。 LAC選項也似乎只適用於C語言分析器。作爲一個單獨的答案,我列出瞭解決問題的方法。 – Dan

+0

@Dan:是的,afaik LAC目前僅適用於C語言分析器。說實話,我不是生成的C++解析器的粉絲,除了一些玩具之外,我從來沒有用過它:生成的「純」C解析器似乎可以用C++編譯,它不像解析器那樣呈現複雜的界面,所以我可以在沒有課程的情況下生活。但那是我。你的解決方法對我來說也是合理的。您可能也會對Russ Cox關於在Go解析器中定製野牛錯誤報告的文章感興趣:http://research.swtch.com/yyerror – rici

0

我結束了自定義的是野牛用來給我獲得我想要的信息的骨架。這是一個黑客因爲@rici說,在他的回答野牛不給我感興趣的是公衆獲取信息,我修改了error功能採取yytokenyystate作爲額外的參數,被傳遞到yysyntax_error_相同的變量。然後,我使用yysyntax_error_用於生成的相同算法來生成其「詳細」消息,以生成預期令牌列表並將它們傳遞迴驅動程序。這很混亂,但是現在我的簡單語法達到了我想要的。

相關問題