Skip to content

Commit 302849a

Browse files
committed
語法的歧義
1 parent c1fec8d commit 302849a

2 files changed

Lines changed: 59 additions & 4 deletions

File tree

27.5 KB
Loading

book/零.一版/剖析(語法分析).md

Lines changed: 59 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,69 @@
5757
變數宣告式 = "元"・"・"・變數・"="・算式
5858
```
5959

60-
算式則較為複雜,敏銳的道友可能已經注意到,算式也蘊含了遞回
60+
算式則較為複雜,敏銳的道友可能已經注意到,算式也蘊含了遞回。
6161

6262
```語法
63-
算式 = 運算元・運算子・運算元 | "("・算式・")"
64-
運算元 = 變數 | 數字 | 算式
63+
算式 = 變數
64+
| 數字
65+
| "("・算式・")"
66+
| 算式・運算子・算式
6567
運算子 = "+" | "−" | "*" | "/"
6668
```
67-
`算式 = 運算元・運算子・運算元 | "("・算式・")"``算式`定義為`運算元・運算子・運算元`,而在算式兩側加上括號後,依然是合法括號,也就是說,`1+2``算式`,而`(1+2)``((1+2))``(((1+2)))`...也都是合法算式。
69+
`算式`可以只是一個變數或數字,`算式・運算子・算式`表明`算式`也可以是加減乘除的結果,`"("・算式・")"`,而在算式兩側加上括號後,依然是合法括號,也就是說,`1+2``算式`,而`(1+2)``((1+2))``(((1+2)))`...也都是合法算式```(0)``((0))`也都合法
6870

6971

7072
思考題:有沒有辦法定義上下文無關語法,把同一層級的括號限制在一對,禁止`((1+2))``(((1+2)))`之無意義括號?
73+
74+
為方便觀看,以下將音界咒零・一版全部語法定義寫在一起,並將其縮排:
75+
76+
```語法
77+
音界咒 = 句
78+
| 句・音界咒
79+
80+
句 = 變數宣告式
81+
| 算式
82+
83+
變數宣告式 = "元"・"・"・變數・"="・算式
84+
85+
算式 = 變數
86+
| 數字
87+
| "("・算式・")"
88+
| 算式・運算子・算式
89+
90+
運算子 = "+"
91+
| "−"
92+
| "*"
93+
| "/"
94+
```
95+
96+
## 語法歧義
97+
前文寫出的語法定義,定義的是如何**生成**合乎語法的字串,而非如何將字串的語法**剖析**出來。
98+
99+
這意思是說,當吾人想生成出所有(長度小於 n)的`算式`時,可以遍歷`算式`的兩個分支得到`變數宣告式``算式`兩種語法,這兩種語法又可以繼續分支下去,如此遞迴,便能得出所有(長度小於 n)的`算式`
100+
101+
但是在遞迴遍歷的過程中,不同路徑很可能會造出重複的句子。
102+
103+
`1+2*3`為例,其生成方式可能是`算式` => `算式+算式` => `算式+算式*算式`,先以``展開,接著展開後的第二個再以``展開,也可能是`算式` => `算式*算式` => `算式+算式*算式`,初始算式先以``展開,展開後的第二個算式再以``展開,如圖:
104+
105+
![算式展開同結果](../image/算式展開同結果.png)
106+
107+
一種語法出現不同展開過程但同結果這種情況,該語法就是「有歧義的」,亦有人稱「模糊」、「模稜兩可」、「二義性」。
108+
109+
歧義是一項不良性質,若對上圖中得到的兩棵語法樹做後序運算求值,所得將會不相同,一個是先乘除後加減,另個則是先加減後乘除。
110+
111+
即使語法存在歧義,還是有辦法剖析的,舉個例子,透過回溯來得到所有可能的語法樹,再依照某種方式挑選,如此還是能用一套算法總是從一套源碼中得到相同的語法樹。
112+
113+
遇到歧義與法時,也可以嘗試直接修原語法定義,寫出一套無歧義的語法。`算式`的例子可以透過額外增加`乘除式``原子式`兩層級來迫使先乘除後加減:
114+
115+
```
116+
算式 = 乘除式 | 乘除式・加減・乘除式
117+
乘除式 = 原子式 | 原子式・乘除・原子式
118+
原子式 = 數字
119+
| 變數
120+
| "("・算式・")"
121+
乘除 = "*"
122+
| "/"
123+
加減 = "+"
124+
| "−"
125+
```

0 commit comments

Comments
 (0)