原創|使用教程|編輯:鄭恭琳|2018-01-04 13:14:28.000|閱讀 1033 次
概述:語法有兩種主要格式:BNF(及其變體)和PEG。本章節旨在讓大家了解這些不同的格式以及何時應該使用它們。
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
相關鏈接:
語法有兩種主要格式:BNF(及其變體)和PEG。許多工具都實現了這些理想格式的變體。 一些工具完全使用自定義格式。頻繁的自定義格式由三部分語法組成:結合自定義代碼的選項,其次是詞法分析部分,最后是解析器部分。
鑒于類似BNF的格式通常是上下文無關語法的基礎,您還可以看到它以CFG格式標識。
Backus-Naur Form(BNF)是最成功的格式,甚至是PEG的基礎。但是,這個過程很簡單,因此它的基本形式并不常用。我們通常使用更強大的變體。
為了說明為什么這些變體是必要的,我們來展示一個BNF的例子:一個字符的描述。
< letter > ::= "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z" < digit > ::= "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" < character > ::= < letter > | < digit >
符號< letter >可以在英文字母的任何字母中轉換,盡管在我們的例子中只有小寫字母是有效的。類似的過程發生在< digit >,它可以指示任何替代數字。第一個問題是你必須單獨列出所有的選擇;像使用正則表達式一樣,不能使用字符類。這很煩人,但通常是可以管理的,除非你必須列出所有的Unicode字符。
一個更難的問題是,沒有簡單的方法來表示可選的元素或重復。所以,如果你想這樣做,你必須依靠布爾邏輯(boolean logic)和替代(|)符號。
< text > ::= < character > | < text > < character >
該規則規定< text >可以由一個字符或一個短的< text >和一個< character >組成。這將是dog的分析樹:
BNF還有許多其他限制:在語法中使用空字符串或格式使用的符號(即:: =)使得復雜,它有一個詳細的語法(即你必須在< and >之間包含終端)等等。
為了解決這些限制,Niklaus Wirth創建了Extended Backus-Naur Form(EBNF),其中包含了他自己的Wirth語法表示法的一些概念。
EBNF是最常用的當代解析工具,盡管工具可能偏離標準符號。EBNF有一個更清潔的符號,并采用更多的運算符來處理連接或可選的元素。
我們來看看如何在EBNF中編寫前面的例子。
letter = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z" ; digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ; character = letter | digit ; text = character , { character } ;
文字符號在連接運算符(,)和可選符號({..})的幫助下更容易描述。得到的分析樹也會更簡單。標準的EBNF仍然存在一些問題,如不熟悉的語法。為了克服這個問題,大多數解析工具都采用了受正則表達式啟發的語法,并且還支持像字符類這樣的附加元素。
Augmented BNF (ABNF)是BNF的另一種變體,主要用于描述雙向通信協議,并由IETF和幾個文檔(參見和更新)進行形式化。
ABNF可以和EBNF一樣有效,但是有一些怪癖限制了它在互聯網協議之外的采用。例如,直到最近,標準規定字符串以不區分大小寫的方式進行匹配,這在許多編程語言中匹配標識符是個問題。
ABNF與EBNF有不同的語法;例如,替代運算符是斜杠(/),有時它更好。例如,不需要連接運算符。它還比標準的EBNF有更多的東西。例如,它允許您定義數字范圍,如%x30-39,相當于[0-9]。 這也被設計師自己用來包含標準的字符類,比如最終用戶可以使用的基本規則。這種規則的一個例子是ALPHA,相當于[a-zA-Z]。
解析表達語法(PEG)是。從技術上講,它來源于一種稱為自頂向下解析語言(Top-Down Parsing Language,TDPL)的舊式正式語法。然而,描述它的一個簡單的方法是在現實世界中的EBNF。
實際上,它看起來和EBNF相似,但也直接支持廣泛使用的東西,比如字符范圍(字符類)——雖然它也有一些實際上并不那么實際的差異,比如使用更正式的箭頭符號(←) 更常見的等號(=)。前面的例子可以用PEG來寫。
letter ← [a-z] digit ← [0-9] character ← letter / digit text ← character+
正如你所看到的,這是程序員寫的最明顯的方式:用字符類和正則表達式運算符。唯一的異常是替代運算符(/)和箭頭字符,事實上,PEG的許多實現使用“equals”字符。
實用的方法是PEG形式化的基礎:創建它是為了描述更自然的編程語言。這是因為上下文無關文法起源于描述自然語言的工作。從理論上講,CFG是一個生成語法,而PEG是一個分析語法。
第一個應該是用語法描述的語言只生成有效句子的一種配方。它不必與解析算法相關。相反,第二種類型直接定義了該語言的解析器的結構和語義。
這種理論差異的實際意義是有限的:PEG與packrat算法更密切相關,但基本上這是它。例如,一般來說,PEG(packrat)不允許左遞歸。雖然可以修改算法本身來支持它,但是這消除了線性時間解析屬性。另外,PEG解析器通常是無掃描器的解析器。
PEG和CFG之間最重要的區別可能是PEG的選擇順序是有意義的,而CFG則不是。如果有許多可能的有效方法來解析輸入,則CFG將不明確,因此將返回錯誤。通常錯誤的意思是,一些采用CFG的解析器可以處理模糊的語法;例如,向開發者提供所有可能的有效結果,并讓他們把它整理出來。相反,由于第一個適用的選擇將被選擇,PEG完全消除了歧義。因此,PEG永遠不會含糊不清。
這種方法的缺點是,在列出可能的備選方案時必須更加小心,否則可能會產生意想不到的后果。也就是說,有些選擇永遠無法匹配。
在下面的例子中,doge永遠不會被匹配。由于dog先來,它每次都會被挑選。
dog ← 'dog' / 'doge'
PEG是否可以描述所有可以用CFG定義的語法,這是一個開放的研究領域,但是對于所有的實際目的,它們都可以。
請繼續關注第6部分!
本站文章除注明轉載外,均為本站原創或翻譯。歡迎任何形式的轉載,但請務必注明出處、不得修改原文相關鏈接,如果存在內容上的異議請郵件反饋至chenjj@fc6vip.cn