什么是BNF范式,什么又是EBNF范式?
巴科斯范式及其擴(kuò)展
BNF & Augmented BNF
什么是巴科斯范式?
巴科斯范式(BNF: Backus-Naur Form 的縮寫)是由 John Backus 和 Peter Naur 首先引入的用來描述計算機語言語法的符號集。
現(xiàn)在,幾乎每一位新編程語言書籍的作者都使用巴科斯范式來定義編程語言的語法規(guī)則。
巴科斯范式的內(nèi)容
在雙引號中的字("word")代表著這些字符本身。而double_quote用來代表雙引號。
在雙引號外的字(有可能有下劃線)代表著語法部分。
尖括號( < > )內(nèi)包含的為必選項。
方括號( [ ] )內(nèi)包含的為可選項。
大括號( { } )內(nèi)包含的為可重復(fù)0至無數(shù)次的項。
豎線( | )表示在其左右兩邊任選一項,相當(dāng)于"OR"的意思。
::= 是“被定義為”的意思。
巴科斯范式示例
這是用BNF來定義的Java語言中的For語句的實例:
FOR_STATEMENT ::= "for" "(" ( variable_declaration | ( expression ";" ) | ";" ) [ expression ] ";" [ expression ] ";" ")" statement |
這是Oracle packages的BNF定義:
package_body ::= "package" package_name "is" package_obj_body { package_obj_body } [ "begin" seq_of_statements ] "end" [ package_name ] ";" package_obj_body ::= variable_declaration | subtype_declaration | cursor_declaration | cursor_body | exception_declaration | record_declaration | plsql_table_declaration | procedure_body | function_body procedure_body ::= "procedure" procedure_name [ "(" argument { "," argument } ")" ] "return" return_type "is" [ "declare" declare_spec ";" { declare_spec ";" } ] "begin" seq_of_statements [ "exception" exception_handler { exception_handler } ] "end" [ procedure_name ] ";" statement ::= comment | assignment_statement | exit_statement | goto_statement | if_statement | loop_statement | null_statement | raise_statement | return_statement | sql_statement | plsql_block |
這是用BNF來定義的BNF本身的例子:
syntax ::= { rule } rule ::= identifier "::=" expression expression ::= term { "|" term } term ::= factor { factor } factor ::= identifier | quoted_symbol | "(" expression ")" | "[" expression "]" | "{" expression "}" identifier ::= letter { letter | digit } quoted_symbol ::= """ { any_character } """ |
擴(kuò)展的巴科斯范式 Augmented BNF
RFC2234 定義了擴(kuò)展的巴科斯范式(ABNF)。近年來在Internet的定義中ABNF被廣泛使用。ABNF做了更多的改進(jìn),比如說,在ABNF中,尖括號不再需要。
什么是EBNF?
基本 (EBNF)
定義有關(guān) EBNF
協(xié)定的詳細(xì)情況,可以參看 Computing Dictionary.
這里是要點一覽:
"..." : 術(shù)語符號 [...] : 選項:最多出現(xiàn)一次 {...} : 重復(fù)項: 任意次數(shù),包括 0 次 (...) : 分組 | : 并列選項,只能選一個 斜體字: 參數(shù),在其它地方有解釋 |
--------------------------------------------------------------------------------------------
<BNF>::= <非終結(jié)符>::=<或項列表>
<或項列表>::= <項> | <或項列表>|<項>
<項>::= <非終結(jié)符> | <終結(jié)符> | <項><非終結(jié)符> | <項><終結(jié)符>
<非終結(jié)符>::= <非終結(jié)符名>
( 但愿能有人看得懂:-) )
BNF就是巴科特·瑙爾式的縮寫,
在計算機的史前時代(1950s),曾有一位大師,他奠定了現(xiàn)代計算機的基礎(chǔ)
在他老人家的諸多成就之中,包括了對形式語言的研究,和發(fā)明了高級語言:
FORTRAN。
為了紀(jì)念他老人家,我們把他提出的一套描述語言的方法叫做BNF
其實BNF很簡單::=表示定義 |表示或 尖括號(<>)括起來的是非終結(jié)符
所謂非終結(jié)符就是語言中某些抽象的概念,終結(jié)符就是可以直接出現(xiàn)在
語言中的符號
比如:C語言的聲明語句可以用BNF這樣描述:
<聲明語句> ::= <類型><標(biāo)識符>; | <類型><標(biāo)識符>[<數(shù)字>];
這一句中<聲明語句>這個非終結(jié)符被定義成了兩種形式(上面用|隔開的兩部分)
在這里引入了三個終結(jié)符: 分號; 左右方括號[ ]
<類型> ::= <簡單類型> | <指針類型> | <自定義類型>
<指針類型> ::= <簡單類型> * | <自定義類型> *
<簡單類型> ::= int|char|double|float|long|short|void
<自定義類型> ::= enum<標(biāo)識符>|struct<標(biāo)識符>|union<標(biāo)識符>|<標(biāo)識符>
到這里就基本上把<類型>定義清楚了
<數(shù)字> ::= 0X<十六進(jìn)制數(shù)字串> | 0<八進(jìn)制數(shù)字串> | <十進(jìn)制數(shù)字串>
<十六進(jìn)制數(shù)字串> ::= <十六進(jìn)制數(shù)字> | <十六進(jìn)制數(shù)字串><十六進(jìn)制數(shù)字>
<八進(jìn)制數(shù)字串> ::= <八進(jìn)制數(shù)字> | <八進(jìn)制數(shù)字串><八進(jìn)制數(shù)字>
<十進(jìn)制數(shù)字串> ::= <十進(jìn)制數(shù)字> | <十進(jìn)制數(shù)字串><十進(jìn)制數(shù)字>
<十六進(jìn)制數(shù)字> ::= <十進(jìn)制數(shù)字> | A | B | C | D | E | F
<十進(jìn)制數(shù)字> ::= <八進(jìn)制數(shù)字> | 8 | 9
<八進(jìn)制數(shù)字> ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7
到這里就把<數(shù)字>定義清楚了
<標(biāo)識符> ::= <字母> | <標(biāo)識符> <字母數(shù)字串>
<字母數(shù)字串> ::= <字母>|<十進(jìn)制數(shù)字>|<字母數(shù)字串><字母>|<字母數(shù)字串><十進(jìn)制數(shù)字>
<字母> ::= _ | <大寫字母> | <小寫字母>
<小寫字母> ::= a|b|c|d|e|f|g|h|i|j …… (偷個懶)
<大寫字母> ::= A|B|C|D|E|F|G|H|I|J ……
到此為止整個聲明語句就定義完了(就是說已經(jīng)沒有非終結(jié)符了),雖然看起來很
繁,但前面定義的各種非終結(jié)符都可以很容易的在別的地方重用比如,函數(shù)聲明
可以定義成下面的樣子:
<函數(shù)聲明語句> ::= <類型><標(biāo)識符>(<形參表>);
<形參表> ::= <類型><標(biāo)識符> | <形參表>,<形參表>
只用兩句就描述完了,所以BNF實際上比用自然語言要簡練得多
(整個C語言只用一二百句就可以描述清楚)
而且相當(dāng)?shù)木_,不會有自然語言中那種模棱兩可的表達(dá)
如果你對BNF比較敏感的話,會發(fā)現(xiàn)C里面的標(biāo)識符不能由數(shù)字開頭
而且在C里面下劃線是被當(dāng)做字母看待的(也就是說能用字母的地方
都可以用下劃線)比如:(最好用老一點的編譯器比如PDP11上的cc)
#define ____ main
#define ___ for
typedef char* _____;
int (*______)(char *, ...) = printf; //如果這一句不靈,就用下面這句
//#define ______ printf //如果你用的是C++可以試一下下面這個
//int (*______)(const char *, ...) = printf;
____(_,char* __[]) //要是你編譯器不吃,可以改成int ____(int _,char*__[])
{
___( ; _ ; _ --)
{
______("%s\n", __[_]);
}
}
另外,還有一種EBNF就沒有正宗的BNF這么爽了,也有很多人在用,前面的
那些遞歸的定義被寫成了{(lán)}
有一段時間PASCAL愛好者們喜歡用一個叫語法圖的東西,畫出來很難看,但
功能和BNF差不多,現(xiàn)在好象已經(jīng)沒多少人用了
近幾年流行另一種東西:
digit = one of
0 1 2 3 4 5 6 7 8 9
這里非終結(jié)符digit用斜體表示,one of是這種方法里定義的一個量詞(常用斜黑體)
我不喜歡這個,因為我眼神不好,常常分不清那個是斜體,那個是正體
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請
點擊舉報。