由于經(jīng)常研究東西,所以經(jīng)常涉及語(yǔ)法的定義檩互;以前我都是按照我自己定義的一套語(yǔ)法格式描述規(guī)則來(lái)進(jìn)行嚴(yán)謹(jǐn)?shù)孛枋稣Z(yǔ)法格式特幔,但是我自己設(shè)計(jì)的這套語(yǔ)法格式描述規(guī)則并不通用,所以決定改為通用的語(yǔ)法格式描述規(guī)則--EBNF(擴(kuò)展的巴科斯范式) 或 ABNF(增強(qiáng)型巴科斯范式)闸昨,本文就詳細(xì)講講 BNF蚯斯、EBNF、ABNF 這三者之間的關(guān)系與區(qū)別;
1. 簡(jiǎn)介
-
BNF
是最原始饵较,最簡(jiǎn)單的方法拍嵌,主要用于理論背景的學(xué)術(shù)論文中,以與人類(lèi)進(jìn)行交流循诉。(與在編譯器/解析器中使用相反)横辆。BNF 沒(méi)有確切的規(guī)范。 -
EBNF
是Extended BNF
(擴(kuò)展的BNF)的縮寫(xiě)茄猫。沒(méi)有一個(gè)標(biāo)準(zhǔn)的 EBNF狈蚤,因?yàn)槊總€(gè)作者或程序都定義了自己的稍有不同的 EBNF 變體。 -
ABNF
是augmented BNF
(增強(qiáng)型BNF)的縮寫(xiě)募疮,ABNF 的語(yǔ)法 與 BNF 完全不同炫惩,但是更加標(biāo)準(zhǔn)化僻弹,利于解析器的翻譯阿浓,但不利于閱讀;
BNF
蹋绽、EBNF
芭毙、ABNF
這三者的表達(dá)能力是等效的;它們只是語(yǔ)法上的差異卸耘。
- 舉例1:在傳統(tǒng)的 BNF 中退敦,左式 和 右式 的 分隔符(即:定義符)通常是
::=
,而在書(shū)籍中通常是→
蚣抗,在 EBNF 和 ABNF 中是=
侈百; - 舉例2:在傳統(tǒng)的 BNF 中,非終結(jié)符用尖括號(hào)括起來(lái),例如钝域,
<EXPR>
終結(jié)符不用加任何額外的符號(hào)讽坏,用普通字符表示即可。而在 ABNF 中例证,非終結(jié)符用普通字符表示路呜,終結(jié)符需要用雙引號(hào)括起來(lái),例如"+" 织咧; - 舉例3:在 BNF 和 EBNF 中胀葱,替代符號(hào)(選項(xiàng)符號(hào))是
|
,在 ABNF 中笙蒙,替代符號(hào)是/
抵屿; - 舉例4:EBNF 和 ABNF 還具有快捷語(yǔ)法語(yǔ)法,比如指定 0個(gè) 或 多個(gè) 重復(fù)項(xiàng)捅位。要將其用 BNF 表示晌该,則需要引入更多規(guī)則。
通常绿渣,BNF 更適合教學(xué)朝群、解釋和理論討論。EBNF 和 ABNF 經(jīng)常用于語(yǔ)法定義 和 解析器解析中符,其中 ABNF 更加利于解析器解析姜胖;
2. 巴科斯范式BNF
巴科斯范式的英文縮寫(xiě)為BNF,它是以美國(guó)人巴科斯(Backus)和丹麥人諾爾(Naur)的名字命名的一種形式化的語(yǔ)法表示方法淀散,用來(lái)描述語(yǔ)法的一種形式體系右莱,是一種典型的元語(yǔ)言。又稱(chēng)巴科斯-諾爾形式(Backus-Naur form)档插。它不僅能?chē)?yán)格地表示語(yǔ)法規(guī)則慢蜓,而且所描述的語(yǔ)法是與上下文無(wú)關(guān)的。它具有語(yǔ)法簡(jiǎn)單郭膛,表示明確晨抡,便于語(yǔ)法分析和編譯的特點(diǎn)。
BNF表示語(yǔ)法規(guī)則的方式為:
- 非終結(jié)符用尖括號(hào)括起则剃。
- 每條規(guī)則的左部是一個(gè)非終結(jié)符恶复,右部是由非終結(jié)符和終結(jié)符組成的一個(gè)符號(hào)串驳阎,中間一般以
::=
分開(kāi)。 - 具有相同左部的規(guī)則可以共用一個(gè)左部,各右部之間以直豎“|”隔開(kāi)培己。
BNF中常用的元字符及其表示的意義如下:
-
::=
:是“被定義為”的意思巾乳;示例:字符串 ::= 用引號(hào)包圍的字符序列
主穗,表示字符串
就是用引號(hào)包圍的字符序列
-
"..."
:終結(jié)符,即引號(hào)中的字符序列本身悲关,并非指代其它字。而終結(jié)符雙引號(hào)"
用double_quote
用來(lái)表示娄柳;示例:函數(shù)調(diào)用 ::= 名字 "()"
表示函數(shù)的調(diào)用
是 由名字
加上左右括號(hào)字符()
組成坚洽; -
double_quote
:代表終結(jié)符 雙引號(hào)"
; 示例:字符串 ::= double_quote ... double_quote
西土,表示字符串
是由被字符"
包圍的字符序列組成讶舰; - 在雙引號(hào)外的字代表著語(yǔ)法部分;示例:
基本類(lèi)型 ::= 字符串 | 數(shù)字 | 布爾
需了,表示字符串
或數(shù)字
或布爾
都是基本類(lèi)型
跳昼,但字符串
、數(shù)字
肋乍、布爾
具體是什么鹅颊,由其它 規(guī)則定義; -
<...>
:必選項(xiàng)墓造;示例:名字 ::= [姓] <名>
表示名字
中的名
是必須要有的堪伍,但姓
是可有可無(wú)的,即:姓 名
是名字
觅闽,名
也是名字
帝雇; -
[...]
:可選,可有可無(wú)蛉拙;示例:名字 ::= [姓] <名>
表示名字
中的名
是必須要有的尸闸,但姓
是可有可無(wú)的,即:姓 名
是名字
孕锄,名
也是名字
吮廉; -
{...}
:重復(fù),0 或 任意次重復(fù)畸肆;示例:AB ::= "a" {"b"}
宦芦,表示AB
是由 一個(gè)a
后面跟上任意數(shù)量(包括0個(gè))個(gè)b
組成,如a
轴脐、a b
调卑、a bb
、a bbb
-
(...)
:分組豁辉,用來(lái)控制表達(dá)式的優(yōu)先級(jí)令野;示例:AX ::= "a" ("m"|"n")
舀患,表示AX
是由 一個(gè)a
后面跟上m
或n
組成徽级; -
|
:替換,即或
的意思聊浅;示例:布爾 ::= "true" | "false"
餐抢,表示true
或false
都是布爾
现使; -
...
:表示各種列舉或省略的代碼片斷;示例:a...z
表示 從a
到z
的字符旷痕,"..."
表示 由 雙引號(hào)"
包圍起來(lái)的任意字符碳锈; - 斜體字: 參數(shù),在其它地方有解釋?zhuān)?/li>
3. 擴(kuò)展的巴科斯范式EBNF
EBNF欺抗,EBNF
是 Extended BNF
的縮寫(xiě)售碳,意思是擴(kuò)展的巴科斯范式。用來(lái)描述計(jì)算機(jī)語(yǔ)言語(yǔ)法的符號(hào)集〗食剩現(xiàn)在贸人,幾乎每一位新編程語(yǔ)言書(shū)籍的作者都使用巴科斯范式來(lái)定義編程語(yǔ)言的語(yǔ)法規(guī)則。
擴(kuò)展巴科斯-瑙爾范式(EBNF)是表達(dá)作為描述計(jì)算機(jī)編程語(yǔ)言和形式語(yǔ)言的正規(guī)方式的上下文無(wú)關(guān)文法的元語(yǔ)法符號(hào)表示法佃声。它是基本巴科斯范式(BNF)元語(yǔ)法符號(hào)表示法的一種擴(kuò)展艺智。
它最初由尼古拉斯·沃斯開(kāi)發(fā),最常用的 EBNF 變體由標(biāo)準(zhǔn)圾亏,特別是 ISO-14977 所定義十拣。
3.1. EBNF符號(hào)表
下面是 推薦標(biāo)準(zhǔn)ISO/IEC 14977
所定義的符號(hào)及其含義
-
=
:定義;示例:字符串 = 用引號(hào)包圍的字符序列
志鹃,表示字符串
就是用引號(hào)包圍的字符序列
-
,
:串接夭问;示例:郭斌勇 = 'guo' , 'binyong'
表示郭斌勇
是 由guo
和binyong
串接而成的guobinyong
而不是guo binyong
; -
;
:終止,表示一個(gè)定義語(yǔ)句結(jié)束了曹铃,在沒(méi)有歧義的情況下可省略甲喝;示例:變量名字 = 標(biāo)識(shí)符 ; 類(lèi)型名字 = 標(biāo)識(shí)符
-
|
:替換,即或
的意思铛只;示例:布爾 = 'true' | 'false'
埠胖,表示true
或false
都是布爾
; -
[...]
:可選淳玩,可有可無(wú)直撤;示例:名字 = [姓] 名
表示名字
中的姓
是可有可無(wú)的,即:姓 名
是名字
蜕着,名
也是名字
谋竖; -
{...}
:重復(fù),0 或 任意次重復(fù)承匣;示例:AB = 'a' {'b'}
蓖乘,表示AB
是由 一個(gè)a
后面跟上任意數(shù)量(包括0個(gè))個(gè)b
組成,如a
韧骗、a b
嘉抒、a bb
、a bbb
-
(...)
:分組袍暴,用來(lái)控制表達(dá)式的優(yōu)先級(jí)些侍;示例:AX = 'a' ('m'|'n')
隶症,表示AX
是由 一個(gè)a
后面跟上m
或n
組成; -
'...'
:終結(jié)符岗宣,即引號(hào)中的字符序列本身蚂会,并非指代其它字;示例:函數(shù)調(diào)用 = 名字 '()'
表示函數(shù)的調(diào)用
是 由名字
加上左右括號(hào)字符()
組成耗式; -
"..."
:終結(jié)符胁住,同'...'
; -
(*...*)
:注釋?zhuān)f(shuō)明性文本刊咳,不表示任何語(yǔ)法措嵌; -
?...?
:特殊序列 -
-
:排除,除去芦缰;
3.2. EBNF語(yǔ)法的定義
用 EBNF范式 來(lái)描述 EBNF 的語(yǔ)法
生成式 = 生成式名 '=' [ 表達(dá)式 ] [';'] ;
表達(dá)式 = 選擇項(xiàng) { '|' 選擇項(xiàng) } ;
選擇項(xiàng) = 條目 { 條目 } ;
條目 = 生成式名 | 標(biāo)記 [ '…' 標(biāo)記 ] | 分組 | 可選項(xiàng) | 重復(fù)項(xiàng) ;
分組 = '(' 表達(dá)式 ')' ;
可選項(xiàng) = '[' 表達(dá)式 ']' ;
重復(fù)項(xiàng) = '{' 表達(dá)式 '}' ;
生成式由表達(dá)式構(gòu)造企巢,表達(dá)式通過(guò)術(shù)語(yǔ)及以下操作符構(gòu)造,自上而下優(yōu)先級(jí)遞增(低=>高):
| 選擇
() 分組
[] 可選(0 或 1 次)
{} 重復(fù)(0 到 n 次)
小寫(xiě)生成式名用于標(biāo)識(shí)詞法標(biāo)記让蕾。非終結(jié)符使用駝峰記法浪规。 位于引號(hào) '...'
內(nèi)的即為終結(jié)符。
形式 a … b
表示把從 a
到 b
的字符集作為選擇項(xiàng)探孝。 橫向省略號(hào) …
也在本文檔中非正式地表示各種列舉或簡(jiǎn)略的代碼片斷笋婿。
4. 增強(qiáng)型巴科斯范式ABNF
RFC2234 定義了增加型巴科斯范式(ABNF)。近年來(lái)在Internet的定義中 ABNF 被廣泛使用顿颅。ABNF 做了更多的改進(jìn)缸濒。增強(qiáng)型巴科斯-瑙爾范式(ABNF)基于了巴科斯-瑙爾范式(BNF),但由它自己的語(yǔ)法和推導(dǎo)規(guī)則構(gòu)成粱腻。這種元語(yǔ)言的發(fā)起原則是描述作為通信協(xié)議(雙向規(guī)范)的語(yǔ)言的形式系統(tǒng)庇配。它建檔于 RFC 4234 中通常充當(dāng) IETF 通信協(xié)議的定義語(yǔ)言。
4.1. 推導(dǎo)規(guī)則
ABNF 規(guī)定是一組推導(dǎo)規(guī)則绍些,寫(xiě)為:
規(guī)則 = 定義 ; 注釋 CR LF
說(shuō)明:
- 這里的規(guī)則是大小寫(xiě)敏感的非終結(jié)符捞慌,定義是由定義這個(gè)規(guī)則的符號(hào)序列、一個(gè)文檔注釋組成柬批,并結(jié)束于回車(chē)換行啸澡。
- 規(guī)則名字是大小寫(xiě)不敏感的: <rulename>, <Rulename>, <RULENAME> 和 <rUlENamE> 都提及同一個(gè)規(guī)則。規(guī)則名字由開(kāi)始于一個(gè)字母的字母氮帐、數(shù)字和連字符組成嗅虏。不要求用尖括號(hào)(“<”, “>”) (如 BNF 那樣)包圍規(guī)則名字。但是它們可以用來(lái)界定規(guī)則名字上沐,比如在冗文中識(shí)別出規(guī)則名字的時(shí)候皮服。ABNF 使用 7-位 ASCII 編碼,在 8-位域中把高位置零。
- 終結(jié)符由一個(gè)或多個(gè)數(shù)值字符指定冰更。數(shù)值字符可以指定為跟隨著基數(shù)(b = 二進(jìn)制, d = 十進(jìn)制, x = 十六進(jìn)制)的一個(gè)百分號(hào)“%”产徊,隨后是這個(gè)數(shù)值昂勒,或數(shù)值的串聯(lián)(用“.” 來(lái)指示)蜀细。例如回車(chē)可以指定為十進(jìn)制的 %d13 或十六進(jìn)制的 %x0D「暧回車(chē)換行可以指定為 %d13.10奠衔。
- 文字正文通過(guò)使用包圍在引號(hào)(")中字符串來(lái)指定。這些字符串是大小寫(xiě)不敏感的塘娶,使用的字符集是 US-ASCII归斤。所以字符串“abc”將匹配“abc”, “Abc”, “aBc”, “abC”, “ABc”, “AbC”, “aBC” 和 “ABC”。對(duì)于大小寫(xiě)敏感匹配刁岸,必須定義明確的字符: 要匹配 “aBc” 定義將是 %d97 %d66 %d99脏里。
4.2. 操作符
空白被用來(lái)分隔定義的各個(gè)元素: 要使空格被識(shí)別為分割符則必須明確的包含它。
4.3. 串聯(lián)
規(guī)則1 規(guī)則2
規(guī)則可以通過(guò)列出一序列的規(guī)則名字來(lái)定義虹曙。
示例:
要匹配字符串“aba”可以使用下列規(guī)則:
fu = %x61; a
bar = %x62; b
mumble = fu bar fu
4.4. 選擇
規(guī)則1 / 規(guī)則2
規(guī)則可以通過(guò)用反斜杠(“/”)分隔的多選一規(guī)則來(lái)定義迫横。
示例:
要接受規(guī)則 <fu> 或規(guī)則 <bar> 可構(gòu)造如下規(guī)則:
fubar = fu / bar
4.5. 遞增選擇
規(guī)則1 =/ 規(guī)則2
可以通過(guò)使用在規(guī)則名字和定義之間的“=/”來(lái)向一個(gè)規(guī)則增加補(bǔ)充選擇。
示例:
規(guī)則
ruleset = alt1 / alt2 / alt3 / alt4 / alt5
等價(jià)于
ruleset = alt1 / alt2
ruleset =/ alt3
ruleset =/ alt4 / alt5
4.6. 值范圍
%c##-##
數(shù)值范圍可以通過(guò)使用連字符(“-”)來(lái)指定酝碳。
示例:
規(guī)則
OCTAL = "0" / "1" / "2" / "3" / "4" / "5" / "6" / "7"
等價(jià)于
OCTAL = %x30-37
4.7. 序列分組
(規(guī)則1 規(guī)則2)
元素可以放置在圓括號(hào)中來(lái)組合定義中的規(guī)則矾踱。
示例:
要匹配“elem fubar snafu”或“elem tarfu snafu”可以構(gòu)造下列規(guī)則:
group = elem (fubar / tarfu) snafu
要匹配“elem fubar”或“tarfu snafu”可以構(gòu)造下列規(guī)則:
group = elem fubar / tarfu snafu
group = (elem fubar) / (tarfu snafu)
4.8. 可變重復(fù)
n*m規(guī)則
要指示一個(gè)元素的重復(fù)可以使用形式 <a>*<b>元素
∈杌可選的 <a>
給出要包括的元素的最小數(shù)目呛讲,缺省為 0》捣睿可選的 <b>
給出要包括的元素的最大數(shù)目贝搁,缺省為無(wú)窮。
對(duì)零或多個(gè)元素使用 *元素
芽偏,對(duì)一或多個(gè)元素使用 1*元素
徘公,對(duì)二或三個(gè)元素使用 2*3元素
。
4.9. 特定重復(fù)
n規(guī)則
要指示明確數(shù)目的元素可使用形式 <a>元素
哮针,它等價(jià)于 <a>*<a>元素
关面。
使用 2DIGIT 得到兩個(gè)數(shù)字,使用 3DIGIT 得到三個(gè)數(shù)字十厢。(DIGIT 在下面的核心規(guī)則中定義)等太。
4.10. 可選序列
[規(guī)則]
示例:
要指示可選元素下列構(gòu)造是等價(jià)的:
[fubar snafu]
*1(fubar snafu)
0*1(fubar snafu)
4.11. 注釋
; 注釋
分號(hào)(“;”)開(kāi)始一個(gè)注釋并持續(xù)到此行的結(jié)束。
4.12. 操作符優(yōu)先級(jí)
上述操作符有從最緊綁定(binding)到最松綁定的給定優(yōu)先級(jí):
- 字符串蛮放,名字形成(formation)
- 注釋
- 值范圍
- 重復(fù)
- 分組缩抡,可選
- 串聯(lián)
- 選擇
與串聯(lián)一起使用選擇操作符可以造成混淆,建議使用分組來(lái)做明確串聯(lián)分組包颁。
4.13. 核心規(guī)則
核心規(guī)則定義于 ABNF 標(biāo)準(zhǔn)中瞻想;
5. 郭斌勇版巴科斯范式EBNF-GBY
對(duì)于會(huì)正則表達(dá)工式的人來(lái)說(shuō)压真,可能不喜歡喜歡EBNF的重復(fù)規(guī)則,而更喜歡正則表達(dá)工的重復(fù)規(guī)則(正如我的喜好一樣)蘑险,為了實(shí)現(xiàn)類(lèi)正則的巴科斯范式滴肿,我便定義了郭斌勇版巴科斯范式EBNF-GBY;
郭斌勇版巴科斯范式EBNF-GBY是基本ABNF修改和擴(kuò)展的佃迄,相對(duì)于EBNF泼差,有如下區(qū)別:
5.1. 修改
棄用 ABNF中的重復(fù)規(guī)則 和 EBNF中的可重復(fù)項(xiàng)表示{ }
,改用如下正則表達(dá)式的重復(fù)規(guī)則呵俏,如下:
規(guī)則{min,max}
表示規(guī)則
重復(fù)次數(shù)大于或等于min
次堆缘,小于或等于max
次;
min表示最小的重復(fù)次數(shù)普碎,默認(rèn)值為0
吼肥;
max表示最大的重復(fù)次數(shù),默認(rèn)值為無(wú)窮大
麻车;
當(dāng)min
或者max
被省略時(shí)缀皱,min或者max取相應(yīng)默認(rèn)值;
規(guī)則{n}
等價(jià)于:
規(guī)則{n,n}
表示規(guī)則
重復(fù)n次绪氛;
5.2. 增加
相對(duì)ABNF唆鸡,增加以下元字符:
? : 表示前面的規(guī)則重復(fù)零次或一次;等價(jià)于`{0,1}`枣察;
+ : 表示前面的規(guī)則重復(fù)一次或多次(大于等于1次)争占;等價(jià)于`{1,}`;
* : 表示前面的規(guī)則重復(fù)任意次;等價(jià)于`{0,}`序目;