Skip to content

Commit 7e6ae9e

Browse files
committed
零點一版符號檢查
1 parent 84ce2c5 commit 7e6ae9e

2 files changed

Lines changed: 84 additions & 0 deletions

File tree

book/.vitepress/config.mts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ export default defineConfig({
5151
text: "剖析(語法分析)",
5252
link: "/零.一版/剖析(語法分析)",
5353
},
54+
{
55+
text: "符號檢查",
56+
link: "/零.一版/符號檢查",
57+
},
5458
],
5559
},
5660
],

book/零.一版/符號檢查.md

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
```音界
2+
元・甲=1
3+
乙+1
4+
```
5+
6+
這個範例的語法完全正確,但``並沒有先宣告再使用,因此仍是非法的程式。
7+
8+
由此可見,一份源碼能被剖析成語法樹,吾人仍需對它進行更多檢查,以確認它是否任何意義不明之處。從「符合語法的程式」中過濾掉「不能編譯執行的程式」,這就是語義分析做的事情。
9+
10+
## 語義分析
11+
12+
有沒有可能設計一種上下文無關語法,得以強迫在`算式`中用到的變數全都是已經宣告的呢?這恐怕辦不到,上下文無關語法天生就記憶不了上下文。`音界咒 = 句 | 句・音界咒`一旦分離成多個``之後,句與句之間就再無關聯,無法互相影響。
13+
14+
或許更強的語法系統能夠做到這點,但以符號檢查來說,在語法樹遍歷一趟就能完成,大可不必大費周章,非得要設計出語法。
15+
16+
讓語法定義完成它擅長的任務就行,剩下的交由語義分析來做。畢竟語法規則寫起來也並不容易是吧!
17+
18+
## 符號檢查
19+
符號檢查很容易,遍歷語法樹的過程中,讀到`變數宣告式`時,將變數名稱加入一集合,後續任何`算式`中使用到變數時,檢查該變數名是否存在於集合中即可。
20+
21+
這種檢查也可以在遞迴下降法的剖析函式中順手做完,但貧道就先讓剖析過程純粹一些吧!
22+
23+
### 實作
24+
25+
```rust
26+
pub fn 檢查語法樹(語法樹: O語法樹) -> bool {
27+
let mut 通過 = true;
28+
29+
let mut 變數集 = HashSet::<String>::new();
30+
31+
forin 語法樹.句 {
32+
通過 = match 句 {
33+
O句::變數宣告(宣告) => {
34+
let 通過 = 檢查算式(&變數集, &宣告.算式);
35+
變數集.insert(宣告.變數名.clone());
36+
通過
37+
}
38+
O句::算式(算式) => 檢查算式(&變數集, &算式),
39+
} && 通過 // 「通過」寫在 && 後面,避免短路
40+
}
41+
42+
通過
43+
}
44+
45+
46+
fn 檢查算式(變數集: &HashSet<String>, 算式: &O算式) -> bool {
47+
match 算式 {
48+
O算式::變數(變數名) => {
49+
if 變數集.contains(變數名) {
50+
true
51+
} else {
52+
println!("{} 未宣告", 變數名);
53+
false
54+
}
55+
}
56+
O算式::數字(_) => true,
57+
O算式::二元運算(二元運算) => {
58+
let 左通過 = 檢查算式(變數集, 二元運算..as_ref());
59+
let 右通過 = 檢查算式(變數集, 二元運算..as_ref());
60+
左通過 && 右通過
61+
}
62+
}
63+
}
64+
65+
```
66+
67+
## 符號重定義
68+
69+
音界咒允許變數重新宣告,類似於 Rust,後面的宣告覆蓋前面宣告。
70+
71+
```音界
72+
元・甲=1
73+
74+
// 此處甲都是1
75+
76+
元・甲=2
77+
78+
// 此處甲都是2
79+
80+
```

0 commit comments

Comments
 (0)