簡體   English   中英

Ply(Yacc) 出錯時如何得到文法產生式?

[英]How to get the grammar production when there is an error with Ply(Yacc)?

yacc.py文件中我定義了語法的 output 和一個錯誤,像這樣:

def p_error(p):
  if p:
    print("Error when trying to read the symbol '%s' (Token type: %s)" % (p.value, p.type))
  else:
    print("Syntax error at EOF")
  exit()

除了這個錯誤消息,我還想打印錯誤發生時產品讀取的內容,例如:

print("Error in production: ifstat -> IF LPAREN expression RPAREN statement elsestat")

我怎樣才能做到這一點?

真的,你不能。 您尤其不能使用像 Ply 生成的那樣的自下而上的解析器,但即使使用自上而下的解析器,“當時的生產讀取”也不是一個定義明確的概念。

例如,考慮錯誤代碼:

if (x < y return 42;

其中錯誤是缺少括號。 至少,這就是我描述錯誤的方式。 但是右括號並不是唯一可以跟在 0 之后的東西。例如,正確的程序可能包括以下任何內容:

if (x < y) return 42;
if (x < y + 10) return 42;
if (x < y && give_up_early) return 42;

還有很多。

那么解析器在看到令牌return時試圖完成哪個產生式? 顯然,它仍在嘗試完成expression (它實際上可能具有不同表達式類型的層次結構,或者可能依賴於優先級聲明成為單個非終結符,或者兩者的某種組合。)但這並不是真的幫助將錯誤識別為缺少右括號。

在自上而下的解析器中,可以向上遍歷解析器堆棧以按包含順序獲取部分完成的產品列表。 (至少,如果解析器維護自己的堆棧,那將是可能的。如果它是遞歸下降解析器,檢查堆棧會更復雜。)

但是在自下而上的解析器中,解析器 state 更復雜。 自下而上的解析器比自上而下的解析器更靈活正是因為它們實際上可以同時考慮多個產生式。 所以通常真的沒有一個單獨的部分生產; 解析器將通過逐漸消除所有不起作用的可能性來決定它正在查看哪個產品。

這種描述聽起來像是自下而上的解析器做了很多工作,這是一種誤導。 這項工作已經由解析器生成器完成,它編譯一個簡單的 state 轉換表來指導解析。 這實際上意味着解析器知道如何在解析的每個時刻處理每個可能正確的標記。 因此,例如,當它看到)跟隨if (x < y ) 時,它立即知道它必須完成expression生成並繼續執行if語句的 rest。

Bison——yacc 的一個 C 實現——有一個可選的特性,允許它在遇到錯誤時列出可能的正確標記。 這並不像聽起來那么簡單,正確實施它會在解析時間上產生明顯的開銷,但它有時很有用。 (雖然它通常沒有用,因為可能的標記列表可能很長。在我用作示例的錯誤的情況下,該列表將包括每個算術運算符,以及可能開始的標記后綴運算符。bison 擴展錯誤處理程序在到達第六個可能的標記時停止嘗試,這意味着如果解析位於表達式的中間,它很少會生成擴展錯誤消息。)無論如何,Ply 沒有這樣的功能。

Ply 和 bison 一樣,確實是通過error pseudo-token 來實現錯誤恢復的。 錯誤恢復算法最適用於具有明確重新同步點的語言,如具有明確語句終止符的語言(與類 C 語言不同,其中許多語句不以;結尾)。 但是您可以使用error產生式強制解析器將其堆棧彈出回某些包含產生式,以便產生更好的錯誤消息。 根據我的經驗,需要進行大量實驗才能使該策略正確。

簡而言之,生成有意義的錯誤消息很難。 我的建議是首先關注讓您的解析器處理正確的輸入。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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