扩展巴科斯-瑙尔范式(EBNF)是表达作为描述计算机编程语言和形式语言的正规方式的上下文无关文法的元语法符号表示法。它是基本巴科斯范式(BNF)元语法符号表示法的一种扩展。
它最初由尼古拉斯·沃斯开发,最常用的 EBNF 变体由标准,特别是 ISO-14977 所定义。
代码,如由终结符即可视字符、数字、标点符号、空白字符等组成的计算机程序的源代码。
digit excluding zero = "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ; digit = "0" | digit excluding zero ;
这个产生规则定义了在这个指派的左端的非终结符 digit。竖杠表示可供选择,而终结符被引号包围,最后跟着分号作为终止字符。所以 digit 是一个 0 或可以是 1 或 2 或 3 直到 9 的一个 digit excluding zero。
产生规则还可以包括由逗号分隔的一序列终结符或非终结符:
twelve = "1" , "2" ; two hundred one = "2" , "0" , "1" ; three hundred twelve = "3" , twelve ; twelve thousand two hundred one = twelve , two hundred one ;
可以省略或重复的表达式可以通过花括号 { ... } 表示:
natural number = digit excluding zero , { digit } ;
在这种情况下,字符串 1, 2, ...,10,...,12345,... 都是正确的表达式。要表示这种情况,于花括号内设立的所有东西可以重复任何次,包括根本不出现。
可选项可以通过方括号 [ ... ] 表示:
integer = "0" | [ "-" ] , natural number ;
所以 integer 是一个零(0)或可能前导可选的负号的一个自然数。
EBNF 还包括描述指定次数的重复,和排除产生式的某部分或向 EBNF 文法插入注释的语法。
依据 ISO 14977 标准,提供了两个设施来扩展 EBNF。其一是在 EBNF 文法部分的特殊序列,它是在问号包围内的任意文本,其解释超出了 EBNF 标准的范围。例如,空格字符可以用如下规则定义:
space = ? US-ASCII character 32 ?;
其二利用圆括号在 EBNF 中不能放置到紧随标识符之后的事实。下列不是有效的 EBNF:
something = foo ( bar );
所以 EBNF 的扩展可以使用这种表示法。例如,在 Lisp 文法中,函数应用可以用如下规则定义:
function application = list( symbol , [ { expression } ] );
BNF 有着可选项和重复不能直接表达的问题。作为替代,它们需要利用中介规则或两选一规则,对于可选项,定义要么是空的要么是可选的产生式的规则,对于重复,递归的定义要么是被重复的产生式要么是自身的规则。同样的构造仍可用在 EBNF 中。
可选项:
signed number = [ sign , ] number ;
可按 BNF-风格定义为:
signed number = sign , number | number ;
或
signed number = optional sign , number ; optional sign = ε | sign ; (* 使用 ε 来更清晰的指示空产生式 *)
重复:
number = { digit } ;
可按 BNF-风格定义为:
number = digit | number digit;
EBNF 排除了 BNF 的一些缺陷:
EBNF 解决了这些问题:
进一步还提供了定义重复次数,排除法选择(比如除了引号的所有字符)和注释等的增强机制。
不管所有这些增强,EBNF 在能定义的语言的意义上不比 BNF 更强大。在原理上用 EBNF 定义的任何文法都可以用 BNF 表达。但是经常导致可观的更多规则的表示。
EBNF 已经被ISO用代码 ISO/IEC 14977:1996(E) 标准化了。
在某些场合任何扩展的 BNF 都被称为 EBNF。例如 W3C 使用 one EBNF 来规定 XML。
只允许赋值的简单编程语言可以用 EBNF 定义为:
(* a simple program in EBNF − Wikipedia *) program = 'PROGRAM' , white space , identifier , white space , 'BEGIN' , white space , { assignment , ";" , white space } , 'END.' ; identifier = alphabetic character , [ { alphabetic character | digit } ] ; number = [ "-" ] , digit , [ { digit } ] ; string = '"' , { all characters − '"' } , '"' ; assignment = identifier , ":=" , ( number | identifier | string ) ; alphabetic character = "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" ; white space = ? white space characters ? ; all characters = ? all visible characters ? ;
一个语法上正确的程序:
PROGRAM DEMO1 BEGIN A0:=3; B:=45; H:=-100023; C:=A; D123:=B34A; BABOON:=GIRAFFE; TEXT:="Hello world!"; END.
这个语言可以轻易的扩展上控制流,算术表达式和输入/输出指令。就可以开发出一个小的、可用的编程语言了。
使用了在标准中提议为正规表示的下列字符:
用途 | 符号表示 |
---|---|
定义 | = |
串接 | , |
终止 | ; |
分隔 | | |
可选 | [ ... ] |
重复 | { ... } |
分组 | ( ... ) |
双引号 | " ... " |
单引号 | ' ... ' |
注释 | (* ... *) |
特殊序列 | ? ... ? |
除外 | - |
1. 使用了如下约定:
2. 表示扩展 BNF 的每个操作符的正常字符和它所蕴涵的优先级(顶部为最高优先级)为:
* repetition-symbol - except-symbol , concatenate-symbol | definition-separator-symbol = defining-symbol ; terminator-symbol
3. 下列括号对超越正常优先级:
´ first-quote-symbol first-quote-symbol ´ " second-quote-symbol second-quote-symbol " (* start-comment-symbol end-comment-symbol *) ( start-group-symbol end-group-symbol ) [ start-option-symbol end-option-symbol ] { start-repeat-symbol end-repeat-symbol } ? special-sequence-symbol special-sequence-symbol ?
作为例子,下列语法规则展示了表达重复的设施:
aa = "A"; bb = 3 * aa, "B"; cc = 3 * [aa], "C"; dd = {aa}, "D"; ee = aa, {aa}, "E"; ff = 3 * aa, 3 * [aa], "F"; gg = {3 * aa}, "D";
这些规则定义的终结字符串如下:
aa: A bb: AAAB cc: C AC AAC AAAC dd: D AD AAD AAAD AAAAD etc. ee: AE AAE AAAE AAAAE AAAAAE etc. ff: AAAF AAAAF AAAAAF AAAAAAF gg: D AAAD AAAAAAD etc.