File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -59,6 +59,10 @@ export default defineConfig({
5959 text : "精五真言生成" ,
6060 link : "/零.一版/精五真言生成" ,
6161 } ,
62+ {
63+ text : "優化" ,
64+ link : "/零.一版/優化" ,
65+ } ,
6266 ] ,
6367 } ,
6468 ] ,
Original file line number Diff line number Diff line change 1+ ![ 零.一版前中後端] ( ../image/零.一版前後端.png )
2+
3+ 上圖展示了當前零.一版音界咒編譯器的各個部件。(除了目的平臺優化,在圖片中淡化)
4+
5+ 本章節將介紹零.一版編譯器的最後一步:優化。完成後,全部件如下圖:
6+
7+ ![ 零.一版前中後端] ( ../image/零.一版前中後端.png )
8+
9+ 語法樹在實質上扮演了中間碼的角色,優化器輸入語法樹,輸出還是語法樹。這樣一來,優化階段後端完全不需要改。要在命令行指定是否優化也很容易,打開優化參數時,額外應用優化器即可,其餘流程照舊。
10+
11+ ## 常數折疊
12+
13+ 常數折疊是零.一版音界咒唯一也究極的優化了。
14+
15+ 零.一版音界咒沒有使用者輸入、沒有亂數,它的輸出自然是一成不變的,這意味著,編譯器應當有能力在編譯期就計算好輸出。
16+
17+ ``` 音界
18+ 元・甲=3*(4-2)+5 # 計算出甲 = 11
19+ 元・乙=1+(1+3)*4 # 計算出乙 = 15
20+ 甲*乙 # 計算出結果是 11 * 15 = 165
21+ ```
22+
23+ 在零.一版音界咒做到這件事相當容易,核心概念是維護一張符號表,記錄各個變數當前的值。
24+
25+ 遍歷語法樹,遇到` 變數宣告式 ` ,求出要賦予給變數的值,寫入符號表;在算式中遇到變數,則去符號表中擷取當前變數值。
26+
27+ ### 實作
28+
29+ ``` rust
30+ pub fn 常數折疊(語法樹: O語法樹) -> O語法樹 {
31+ let mut 環境 = HashMap :: <String , i64 >:: new ();
32+
33+ let mut 答案: i64 = 0 ;
34+
35+ for 句 in 語法樹. 句 {
36+ match 句 {
37+ O句:: 變數宣告(變數宣告) => {
38+ let 算式值 = 求值(& 環境, & 變數宣告. 算式);
39+ 答案 = 算式值;
40+ 環境. insert (變數宣告. 變數名, 算式值);
41+ }
42+ O句:: 算式(算式) => {
43+ 答案 = 求值(& 環境, & 算式);
44+ }
45+ }
46+ }
47+
48+ // 優化到語法樹裡只剩一個`算式`
49+ O語法樹 {
50+ 句: vec! [O句:: 算式(O算式:: 數字(答案))],
51+ }
52+ }
53+
54+ fn 求值(環境: & HashMap <String , i64 >, 算式: & O算式) -> i64 {
55+ match 算式 {
56+ O算式:: 數字(數) => * 數,
57+ O算式:: 變數(變數) => * 環境. get (變數). unwrap (),
58+ O算式:: 二元運算(運算) => {
59+ let 左值 = 求值(環境, 運算. 左. as_ref ());
60+ let 右值 = 求值(環境, 運算. 右. as_ref ());
61+ match 運算. 運算子 {
62+ O運算子:: 加 => 左值 + 右值,
63+ O運算子:: 減 => 左值 - 右值,
64+ O運算子:: 乘 => 左值 * 右值,
65+ O運算子:: 除 => 左值 / 右值,
66+ }
67+ }
68+ }
69+ }
70+
71+ ```
You can’t perform that action at this time.
0 commit comments