Skip to content

Commit

Permalink
零點一版符號檢查
Browse files Browse the repository at this point in the history
  • Loading branch information
MROS committed Oct 1, 2024
1 parent 84ce2c5 commit 7e6ae9e
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 0 deletions.
4 changes: 4 additions & 0 deletions book/.vitepress/config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ export default defineConfig({
text: "剖析(語法分析)",
link: "/零.一版/剖析(語法分析)",
},
{
text: "符號檢查",
link: "/零.一版/符號檢查",
},
],
},
],
Expand Down
80 changes: 80 additions & 0 deletions book/零.一版/符號檢查.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
```音界
元・甲=1
乙+1
```

這個範例的語法完全正確,但``並沒有先宣告再使用,因此仍是非法的程式。

由此可見,一份源碼能被剖析成語法樹,吾人仍需對它進行更多檢查,以確認它是否任何意義不明之處。從「符合語法的程式」中過濾掉「不能編譯執行的程式」,這就是語義分析做的事情。

## 語義分析

有沒有可能設計一種上下文無關語法,得以強迫在`算式`中用到的變數全都是已經宣告的呢?這恐怕辦不到,上下文無關語法天生就記憶不了上下文。`音界咒 = 句 | 句・音界咒`一旦分離成多個``之後,句與句之間就再無關聯,無法互相影響。

或許更強的語法系統能夠做到這點,但以符號檢查來說,在語法樹遍歷一趟就能完成,大可不必大費周章,非得要設計出語法。

讓語法定義完成它擅長的任務就行,剩下的交由語義分析來做。畢竟語法規則寫起來也並不容易是吧!

## 符號檢查
符號檢查很容易,遍歷語法樹的過程中,讀到`變數宣告式`時,將變數名稱加入一集合,後續任何`算式`中使用到變數時,檢查該變數名是否存在於集合中即可。

這種檢查也可以在遞迴下降法的剖析函式中順手做完,但貧道就先讓剖析過程純粹一些吧!

### 實作

```rust
pub fn 檢查語法樹(語法樹: O語法樹) -> bool {
let mut 通過 = true;

let mut 變數集 = HashSet::<String>::new();

forin 語法樹.句 {
通過 = match 句 {
O句::變數宣告(宣告) => {
let 通過 = 檢查算式(&變數集, &宣告.算式);
變數集.insert(宣告.變數名.clone());
通過
}
O句::算式(算式) => 檢查算式(&變數集, &算式),
} && 通過 // 「通過」寫在 && 後面,避免短路
}

通過
}


fn 檢查算式(變數集: &HashSet<String>, 算式: &O算式) -> bool {
match 算式 {
O算式::變數(變數名) => {
if 變數集.contains(變數名) {
true
} else {
println!("{} 未宣告", 變數名);
false
}
}
O算式::數字(_) => true,
O算式::二元運算(二元運算) => {
let 左通過 = 檢查算式(變數集, 二元運算..as_ref());
let 右通過 = 檢查算式(變數集, 二元運算..as_ref());
左通過 && 右通過
}
}
}

```

## 符號重定義

音界咒允許變數重新宣告,類似於 Rust,後面的宣告覆蓋前面宣告。

```音界
元・甲=1
// 此處甲都是1
元・甲=2
// 此處甲都是2
```

0 comments on commit 7e6ae9e

Please sign in to comment.