簡體   English   中英

如何將PEG解析器轉換為模糊的解析器?

[英]How do I convert PEG parser into ambiguous one?

據我了解,大多數語言是無上下文的,但有一些例外。 例如, a * b在C ++中可能代表type * pointer_declaration或乘法。 哪個發生取決於上下文,第一個標識符的含義。 另一個例子是VHDL中的name生成

enum_literal ::= char_literal | identifer
physical_literal ::= [num] unit_identifier
func_call ::= func_identifier [parenthized_args]
array_indexing ::= arr_name (index_expr)
name ::= func_call | physical_literal | enum_litral | array_indexing

您會看到語法形式是不同的,但是如果省略了可選參數(例如f ,它們可以匹配,它是否代表func_call,physical_literal(例如隱含1米且可選量為1)或enum_literal。

與Scala插件設計人員交談時,我受過教育,知道您構建AST可以在依賴項更改時重新評估它。 如果您具有AST,則無需重新解析該文件。 AST也值得顯示文件內容。 但是,如果語法對上下文敏感,則AST無效(假設f是一個函數,在另一個文件中定義,但后來用戶將其重新限定為枚舉常量或未定義)。 在這種情況下,AST會發生變化。 AST會在您更改依賴項時更改。 我要求評估並讓我知道如何實現的另一種方法是構建模糊的AST。

據我所知,解析器組合器是PEG類的。 他們通過向您返回第一個匹配的產生式來掩蓋模糊性,f將匹配一個函數調用,因為它是我語法中的第一個選擇。 我要的是一個組合器,它不會退縮到第一次成功,而是繼續進行下一個選擇。 最后,它將返回所有匹配選項的列表。 這將使我產生歧義。

我不知道您將如何向用戶顯示不明確的文件內容樹,但是它將不需要重新解析從屬文件。 我也很高興知道現代語言設計如何解決這個問題。

一旦解析了歧義節點並返回了結果的歧義性,我希望解析器收斂,因為我想繼續解析name之外的內容,並且我不想在每次歧義性之后解析到文件末尾。 這種情況因f(10)類的情況而變得復雜,后者可能是帶有單個參數的函數調用,或者是返回數組的事后為null的函數調用,該數組隨后被索引。 因此,f(10)可以通過兩種方式匹配name,無論是直接使用func_call還是遞歸匹配,都使用arr_indexing -> name ~ (expr) 因此,不會像幾個並行規則(例如fcall | literal fcall | literal 在重新收斂之前,某些分支可能長於1個解析器,例如fcall ~ (expr) | fcall fcall ~ (expr) | fcall

您將如何解決它? 是否可以在PEG中添加歧義組合器?

首先,您聲稱“ 大多數語言都是上下文無關的,但有一些例外 ”,這並非完全正確。 在設計計算機語言時,由於CFG是事實上的標准,因此我們通常會盡量使其與上下文無關。 這將減輕很多工作。 但是,這並不總是可行的,並且許多[?]語言都依賴於語義分析階段來消除任何可能的歧義。

解析器組合器通常不使用形式模型。 另一方面,PEG和CFG一樣都是語法的形式化形式。 在過去的十年中,由於兩個事實,一些人決定在CGG上使用PEG:從設計上講,PEG是明確的,並且它們可能總是在線性時間內解析。 解析器組合器庫可能使用PEG作為基礎形式,但也可能使用CFG甚至根本不使用CFG。

PEG對於設計計算機語言很有吸引力,因為我們通常不希望處理歧義,這在使用CFG時很難避免(甚至無法避免)。 而且,因此,可以使用動態編程(所謂的packrat解析器)將它們解析O(n)時間。 出於幾個原因“添加歧義性”並非易事,最重要的是,因為它們識別的語言取決於選項是確定性的事實,例如在檢查前瞻性時使用 它不像“只是選擇第一選擇”那么簡單。 例如,您可以定義PEG:

S = "a" S "a" / "aa"

僅解析N個“ a”的序列,其中N是2的冪 因此,它可以識別2、4、8、16、32、64等字母“ a”的序列。 通過增加歧義性(就像CFG一樣),您將識別出任何偶數個“ a”(2、4、6、8、10等), 這是另一種語言

為了回答您的問題,

您將如何解決它? 是否可以在PEG中添加歧義組合器?

首先,我必須說這可能不是一個好主意。 如果您希望在AST上保持歧義,則可能應該使用CFG解析器。

例如,可以為PEG創建一個解析器,該解析器類似於布爾語法的解析器,但是隨后,通過保持所有替代項都有效並保持相同語言,我們的漸近解析時間將從O(n)增長到O(n 3 )。 。 實際上,我們實際上一次失去了關於PEG的兩個好處。

另一種方法是將packrat解析器保留在內存中,並橫穿其表以處理AST的語義。 這也不是一個好主意,因為這將意味着占用大量內存。

理想情況下,應該通過更改語法結構來構建一個AST,該AST已經具有有關可能的歧義的信息。 盡管這需要人工操作,並且通常並不簡單,但是您不必回溯一個階段即可再次檢查語法。

暫無
暫無

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

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