# 簡單的生成規則

作為使用 EBNF 描述文法的範例，考慮下面的生成規則：

```
expr = num ("+" num | "-" num)*
```

`num`可以想成已經在其他的規則中被定義，是代表數值的符號的意思。在這個文法中，`expr`首先有一個`num`，隨後跟著0個以上的「`+`和`num`或`-`和`num`」。這個規則其實就是表達加減法算式的文法。

從`expr`開始展開，可以組合出任意的加減法的字串，舉例來說像`1`或`10+5`或`42-30+25`。底下為展開式：

{% code title="1" %}

```
expr → num → "1"
```

{% endcode %}

{% code title="10+5" %}

```
expr → num "+" num
     → "10" "+" "5"
```

{% endcode %}

{% code title="42-30+25" %}

```
expr → num "-" num "+" num
     → "42" "-" "30" "+" "2"
```

{% endcode %}

這樣的展開順序不只可以用箭頭表達，也可以用樹來表示。上列算式的語法樹如以下所示：

![1的語法樹](https://416395721-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjokrNdcE1H2E8hE2Dc%2F-LnB0g16uqzstwf702_e%2F-LnAwxlqYuZnUDhbF0r2%2Findex.svg?alt=media\&token=181424de-3a65-46db-a19e-bced6fc8c51c)

![10+5的語法樹](https://416395721-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjokrNdcE1H2E8hE2Dc%2F-LnB0g16uqzstwf702_e%2F-LnAx3lZNSFFC5Gxhxd1%2Findex.svg?alt=media\&token=954d21c8-11ac-45d6-a655-8722b05a7a67)

![42-20+2的語法樹](https://416395721-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LjokrNdcE1H2E8hE2Dc%2F-LnB0g16uqzstwf702_e%2F-LnAxAj2ppAk8M5xjtrw%2Findex.svg?alt=media\&token=f481b0af-5f9a-44cf-9e0e-f70b689f1a4b)

用樹結構來表示，就可以很清楚看出哪個非終端符號會展開成什麼樣子。

向上圖這樣和文法一一對應的語法樹也被稱為「具體語法樹」（concrete syntax tree）。這個說法在和抽象語法樹作對比的時候較常用到。

此外，上述的具體語法樹中，並沒有把加減法從左到右的規則表現在樹上。這類規則在此處說明的文法中，並不是以 EBNF 描述，而是在語言的規格書裡有加註「加減法必須從左到右計算」。分析器必須同時考慮 EBNF 和這些說明，讀進代表算式的標記列，妥當地建立能符合算式順序的抽象語法樹。

因此，在以上的文法中，EBNF 表現的具體語法樹和分析器所輸出的抽象語法樹其實看起來差滿多的。要定義出具體語法樹和抽象語法樹儘可能一致的文法不是不可能，但是該類文法會變得非常地冗長，會導致實作分析器時不知道該從何下手。上述的文法是在形式文法的嚴謹性，和以自然語言描述的易於理解上取得平衡，是一個較好上手的描述方式。
