diff --git "a/book/image/\347\256\227\345\274\217\345\261\225\351\226\213\345\220\214\347\265\220\346\236\234.png" "b/book/image/\347\256\227\345\274\217\345\261\225\351\226\213\345\220\214\347\265\220\346\236\234.png" new file mode 100644 index 0000000..bf8b25c Binary files /dev/null and "b/book/image/\347\256\227\345\274\217\345\261\225\351\226\213\345\220\214\347\265\220\346\236\234.png" differ diff --git "a/book/\351\233\266\357\274\216\344\270\200\347\211\210/\345\211\226\346\236\220\357\274\210\350\252\236\346\263\225\345\210\206\346\236\220\357\274\211.md" "b/book/\351\233\266\357\274\216\344\270\200\347\211\210/\345\211\226\346\236\220\357\274\210\350\252\236\346\263\225\345\210\206\346\236\220\357\274\211.md" index cd545f8..d1d942a 100644 --- "a/book/\351\233\266\357\274\216\344\270\200\347\211\210/\345\211\226\346\236\220\357\274\210\350\252\236\346\263\225\345\210\206\346\236\220\357\274\211.md" +++ "b/book/\351\233\266\357\274\216\344\270\200\347\211\210/\345\211\226\346\236\220\357\274\210\350\252\236\346\263\225\345\210\206\346\236\220\357\274\211.md" @@ -57,14 +57,69 @@ 變數宣告式 = "元"・"・"・變數・"="・算式 ``` -算式則較為複雜,敏銳的道友可能已經注意到,算式也蘊含了遞回,。 +算式則較為複雜,敏銳的道友可能已經注意到,算式也蘊含了遞回。 ```語法 -算式 = 運算元・運算子・運算元 | "("・算式・")" -運算元 = 變數 | 數字 | 算式 +算式 = 變數 + | 數字 + | "("・算式・")" + | 算式・運算子・算式 運算子 = "+" | "−" | "*" | "/" ``` -`算式 = 運算元・運算子・運算元 | "("・算式・")"`將`算式`定義為`運算元・運算子・運算元`,而在算式兩側加上括號後,依然是合法括號,也就是說,`1+2`是`算式`,而`(1+2)`、`((1+2))`、`(((1+2)))`...也都是合法算式。 +`算式`可以只是一個變數或數字,`算式・運算子・算式`表明`算式`也可以是加減乘除的結果,`"("・算式・")"`,而在算式兩側加上括號後,依然是合法括號,也就是說,`1+2`是`算式`,而`(1+2)`、`((1+2))`、`(((1+2)))`...也都是合法算式,`0`、`(0)`、`((0))`也都合法。 思考題:有沒有辦法定義上下文無關語法,把同一層級的括號限制在一對,禁止`((1+2))`、`(((1+2)))`之無意義括號? + +為方便觀看,以下將音界咒零・一版全部語法定義寫在一起,並將其縮排: + +```語法 +音界咒 = 句 + | 句・音界咒 + +句 = 變數宣告式 + | 算式 + +變數宣告式 = "元"・"・"・變數・"="・算式 + +算式 = 變數 + | 數字 + | "("・算式・")" + | 算式・運算子・算式 + +運算子 = "+" + | "−" + | "*" + | "/" +``` + +## 語法歧義 +前文寫出的語法定義,定義的是如何**生成**合乎語法的字串,而非如何將字串的語法**剖析**出來。 + +這意思是說,當吾人想生成出所有(長度小於 n)的`算式`時,可以遍歷`算式`的兩個分支得到`變數宣告式`、`算式`兩種語法,這兩種語法又可以繼續分支下去,如此遞迴,便能得出所有(長度小於 n)的`算式`。 + +但是在遞迴遍歷的過程中,不同路徑很可能會造出重複的句子。 + +以`1+2*3`為例,其生成方式可能是`算式` => `算式+算式` => `算式+算式*算式`,先以`+`展開,接著展開後的第二個再以`*`展開,也可能是`算式` => `算式*算式` => `算式+算式*算式`,初始算式先以`*`展開,展開後的第二個算式再以`+`展開,如圖: + +![算式展開同結果](../image/算式展開同結果.png) + +一種語法出現不同展開過程但同結果這種情況,該語法就是「有歧義的」,亦有人稱「模糊」、「模稜兩可」、「二義性」。 + +歧義是一項不良性質,若對上圖中得到的兩棵語法樹做後序運算求值,所得將會不相同,一個是先乘除後加減,另個則是先加減後乘除。 + +即使語法存在歧義,還是有辦法剖析的,舉個例子,透過回溯來得到所有可能的語法樹,再依照某種方式挑選,如此還是能用一套算法總是從一套源碼中得到相同的語法樹。 + +遇到歧義與法時,也可以嘗試直接修原語法定義,寫出一套無歧義的語法。`算式`的例子可以透過額外增加`乘除式`、`原子式`兩層級來迫使先乘除後加減: + +``` +算式 = 乘除式 | 乘除式・加減・乘除式 +乘除式 = 原子式 | 原子式・乘除・原子式 +原子式 = 數字 + | 變數 + | "("・算式・")" +乘除 = "*" + | "/" +加減 = "+" + | "−" +```