扩充巴科斯范式

在計算機科學中，**擴充巴科斯 - 瑙爾範式**（ABNF）是一種基於巴科斯 - 瑙爾範式（BNF）的元語言，但它有自己的語法和派生規則。ABNF 的原動原則是描述一種作為雙向通信協議的語言的形式系統。它是由_第 68 號網際網路標準_ （頁面存檔備份，存於網際網路檔案館）（"STD 68"，大小寫樣式按照原文）定義的，也就是 RFC 5234，經常用於網際網路工程任務組（IETF）通信協議的定義語言。

RFC 5234 取代了 RFC 4234 (取代了 RFC 2234).

## 介紹

一個 ABNF 規範是一些推導規則的集合，書寫為：

```
规则 = 定义;注释CR LF
```

其中：

* 「規則」是不區分大小寫的非最終符號
* 「定義」由定義該規則的一系列符號組成
* 「注釋」用於記錄
* 「CR LF」（回車、換行）用來結束

規則名字是不區分大小寫的: `<rulename>`, `<Rulename>`, `<RULENAME>` 和 `<rUlENamE>` 都指的是同一個規則。規則名字由一個字母以及後續的多個字母、數字和連字符（減號）組成。

用尖括號（「`<`」，「`>`」）包圍規則名並不是必需的（如同它們在 BNF 里那樣），但是它們可以用來在散文中界定規則名，以方便識別出規則名。

## 最終值

最終值由一個或多個數值字符指定。

數值字符可按下面的方式指定：先是一個百分號「`%`」，緊跟著基數（b = 二進位，d = 十進位，x = 十六進位），再其後是這個數值或數值串（用「`.`」來指示串聯）。例如：「回車」可以用十進位的 `%d13` 或十六進位的 `%x0D` 來指定，而「回車換行」則可以用 `%d13.10` 來指定。

字面文本是通過包含在在雙引號（`"`）中字符串來指定的。這些字符串是不區分大小寫的，使用的字符集是（US-）ASCII。所以字符串「abc」將匹配「abc」,「Abc」,「aBc」,「abC」,「ABc」,「AbC」,「aBC」和「ABC」。對於區分大小寫的匹配，必須定義明確的字符，例如：若要匹配「aBc」，定義必須是 `%d97 %d66 %d99`。

## 操作符

### 空白字符

空白字符被用來分隔定義中的各個元素：要使空格被識別為分割符則必須明確的包含它。

### 串聯

```
规则1规则2
```

規則可以通過列出一系列的規則名來定義。

要匹配字符串「aba」可以使用下列規則:

1. `foo = %x61 ; a`
2. `bar = %x62 ; b`
3. `mumble = foo bar foo`

### 選擇 /

```
规则1 / 规则2
```

一個規則可以通過用斜槓（「`/`」）分隔的可供選擇的子規則列表來定義。

要接受規則 <foo> 或規則 <bar> 可構造如下規則:

1. `foobar = foo / bar`

### 增量選擇 =/

```
规则1 =/ 规则2
```

可以通過在_規則名_和_定義_之間使用「`=/`」來向一個規則增加補充選擇。

規則

1. `ruleset = alt1 / alt2 / alt3 / alt4 / alt5`

等價於

1. `ruleset = alt1 / alt2`
2. `ruleset =/ alt3`
3. `ruleset =/ alt4 / alt5`

### 值範圍 % c##-##

```
%c##-##
```

數值範圍可以通過使用連字符（「`-`」）來指定。

規則

1. `OCTAL = "0" / "1" / "2" / "3" / "4" / "5" / "6" / "7"`

等價於

1. `OCTAL = %x30-37`

### 序列組合 ()

```
(规则1规则2)
```

在_定義_中，元素可以放置在圓括號中來將_規則_組合起來，該組合視為單個元素。

要匹配「elem foobar snafoo」或「elem tarfoo snafoo」可以構造下列規則:

1. `group = elem _(foobar / tarfoo)_ snafoo`

要匹配「elem foobar」或「tarfoo snafoo」可以構造下列規則:

1. `group = elem foobar / tarfoo snafoo`
2. `group = _(elem foobar)_ / _(tarfoo snafoo)_`

### 不定量重複 m\*n

元素前面的星號 `*` 表示重複，其完整形式是：

```
m*n规则
```

要表示一個元素的重複，就要使用 `<m>*<n>元素` 形式。可選的 `<m>` 給出要包含的元素的最小數目，默認為 0；可選的 `<n>` 給出要包含的元素的最大數目，默認為無窮大。

例子：

* `*元素` 表示零個或更多元素
* `1*元素` 表示一個或更多元素
* `2*4元素` 表示兩個至四個元素

### 定量重複 n

```
n规则
```

要表示特定數目的元素可使用形式 `<n>元素`，相當於用不定量重複形式表示的 `<n>*<n>元素`。

使用 `2DIGIT` 得到兩個數字，使用 `3DIGIT` 得到三個數字。(DIGIT 在下面的核心規則中定義，也見例子中的 _zip-code_)。

### 可選序列 []

```
[规则]
```

要表示可選元素，下列構造是等價的:

1. `[foobar snafoo]`
2. `*1(foobar snafoo)`
3. `0*1(foobar snafoo)`

### 注釋；

```
;注释
```

注釋從一個分號（「`;`」）開始，並持續到此行的結束。

### 操作符優先級

下面的操作符給出了從高（結合最緊密）到低（結合最鬆散）的優先級:

1. 規則名、最終值
2. 注釋；
3. 值範圍 % c##-##
4. 重複 \*
5. 組合 ()、可選 []
6. 串聯
7. 選擇 /

_選擇_操作符與_串聯_一起使用會造成混淆，因此建議使用_組合_來確保串聯組的明確。

例如：

```
我们 = 你 我/他 她
```

會產生下面兩種歧義：

1. `(你 我)/(他 她)`
2. `(你) (我/他) (她)`

所以，使用_組合_來確保不會產生歧義：

```
(你 我)/(他 她)
```

### 核心規則

核心規則定義於 ABNF 標準中。

## 例子

在巴科斯範式（BNF）條目中的郵政地址的例子可以被指定為:

`` ```
postal-address = name-part street zip-part

name-part = *(personal-part SP) last-name [SP suffix] CRLF
name-part = / personal-part CRLF

personal-part = first-name / (initial ".")
first-name = *ALPHA
initial = ALPHA
last-name = *ALPHA
suffix = ("Jr." / "Sr." / 1*("I" / "V" / "X"))

street = [apt SP] house-num SP street-name CRLF
apt = 1*4DIGIT
house-num = 1*8（DIGIT / ALPHA）
street-name = 1*VCHAR

zip-part = town-name "," SP state 1*2SP zip-code CRLF
town-name = 1*(ALPHA / SP)
state = 2ALPHA
zip-code = 5DIGIT ["-" 4DIGIT]
``` ``

## 隱患

RFC 5234 （頁面存檔備份，存於網際網路檔案館）加入了一條結合 LWSP 的警告，如下:

> 若使用該直線空白規則，將允許存在只包含空白字符的行，而這樣的行在郵件頭中已不再合法，並且已在其他環境中導致了互操作問題。
> 不要在定義郵件頭時使用它，在其他環境下使用時也要格外注意。
> 
> 

## 參考