Skip to content

Commit 4581405

Browse files
committed
視關鍵字為特殊識別子
1 parent f3b55bf commit 4581405

6 files changed

Lines changed: 104 additions & 6 deletions

File tree

378 Bytes
Loading
2.52 KB
Loading
37.9 KB
Loading

book/零.一版/分詞.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@
6363

6464
但無妨,早已有成熟的演算法能應對這類複雜狀況,在零・一版的簡單狀況,倒也不必構思出通用算法才能分詞,只要仔細分析所有狀況就可以了。
6565

66-
為了方便後續表達,先令 x 代表除了單字詞、[0-9]之外,所有的字元集合。
66+
為了方便後續表達,先令 x 代表除了特殊符號及[0-9]之外,所有的字元集合。
6767

6868
當目前讀取到的字串是...
6969

@@ -73,6 +73,7 @@
7373
- 可能是變數的前綴,當下一個字元屬於 x 或 [0-9] ,即確定該詞為變數
7474
- 當下個字元不是上述狀況時,是元關鍵字
7575
- [0-9]+
76+
- 可能是數字的前綴,當下一個字元屬於 [0-9] ,繼續讀取
7677
- 可能是變數的前綴,當下一個字元屬於 x ,即確定該詞為變數
7778
- 當下個字元不是上述狀況時,是數字
7879
- x

book/零.二版/再遇分詞.md

Lines changed: 101 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
欲再做分詞,需先細數零.二版加入了哪些新詞。
22

3+
## 新詞列表
4+
35
運算子方面,有:
46
-
57
- ==
@@ -12,6 +14,7 @@
1214
特殊符號有:
1315
-
1416
-
17+
-
1518

1619
關鍵字則有:
1720
-
@@ -30,11 +33,105 @@
3033

3134
以此為基礎繪製零.二版的分詞狀態機,貧道略去 1 字特殊符號的狀態,而 1 字關鍵字僅以``為代表,並以`不然`為 2 字關鍵字之代表,`>=```為前綴問題之代表。
3235

33-
此外,除變數名之外,術名也允許非特殊符字符任意組合,今統一稱此二者為`識別子`
36+
此外,除變數名之外,術名也允許非特殊符號、非數字任意組合,今統一稱此二者為`識別子`
3437

3538
![零・二版分詞狀態機](../image/零・二版分詞狀態機.png)
3639

37-
新圖中`x`的含義與零.一版並不相同,其意義改變為「其他出邊字符之外的所有非特殊字符」。
38-
TODO: 修改零.一版分詞狀態圖,使 x 之意義相同。
40+
提醒:`x`的含義是「非數字、非特殊字符、非其他出邊字元的所有字元集合」。
41+
42+
把狀態機完整畫完,再在零.一版的分詞器源碼的基礎上依狀態機畫葫蘆即可寫出分詞器。
43+
44+
## 先將關鍵字當識別子
45+
46+
但若真的把整套狀態機畫出來,會發現頗為繁雜,關鍵字製造出太多狀態,其每個狀態有都類似,只要沒接收到預期後傳,馬上就轉換成識別子。
47+
48+
這其實昭示關鍵字與識別子的關係十分接近,那吾人不妨先將關鍵字當識別子,等識別子被斷詞後,再去判定該識別子的內容是否是某個關鍵字。
49+
50+
如此狀態機會簡單得多:
51+
52+
![零・二版分詞狀態機簡化](../image/零・二版分詞狀態機簡化.png)
53+
54+
## 實作
55+
56+
零.二版開始有 2 字的特殊符號,但這不難處理,只要往前多看一個字元就能判斷:
57+
58+
``` rust
59+
fn 起點態(&mut self) -> Option<O詞> {
60+
let= self.字流.pop_front()?;
61+
match 字 {
62+
'+' => Some(O詞::運算子(O運算子::加)),
63+
'-' => Some(O詞::運算子(O運算子::減)),
64+
'*' => Some(O詞::運算子(O運算子::乘)),
65+
'/' => Some(O詞::運算子(O運算子::除)),
66+
'%' => Some(O詞::運算子(O運算子::餘)),
67+
'=' => match self.字流.front() {
68+
Some('=') => {
69+
self.字流.pop_front()?;
70+
Some(O詞::運算子(O運算子::等於))
71+
}
72+
_ => Some(O詞::賦值),
73+
},
74+
'!' => match self.字流.front() {
75+
Some('=') => {
76+
self.字流.pop_front()?;
77+
Some(O詞::運算子(O運算子::異於))
78+
}
79+
_ => panic!("!後必接="),
80+
},
81+
'<' => match self.字流.front() {
82+
Some('=') => {
83+
self.字流.pop_front()?;
84+
Some(O詞::運算子(O運算子::小於等於))
85+
}
86+
_ => Some(O詞::運算子(O運算子::小於)),
87+
},
88+
'>' => match self.字流.front() {
89+
Some('=') => {
90+
self.字流.pop_front()?;
91+
Some(O詞::運算子(O運算子::大於等於))
92+
}
93+
_ => Some(O詞::運算子(O運算子::大於)),
94+
},
95+
'(' => Some(O詞::左圓括號),
96+
')' => Some(O詞::右圓括號),
97+
'【' => Some(O詞::左基括號),
98+
'】' => Some(O詞::右基括號),
99+
'.' => Some(O詞::音界),
100+
'、' => Some(O詞::頓號),
101+
'\n' => Some(O詞::換行),
102+
'\t' | ' ' | ' ' => Some(O詞::空白),
103+
'1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '0' => {
104+
self.數字態(字.to_string())
105+
}
106+
_ => self.識別子態(字.to_string()),
107+
}
108+
}
109+
```
110+
111+
數字態實作維持不變,識別子態會在斷詞完成時,判定其內容是否恰為一關鍵字:
112+
113+
```rust
114+
fn 識別子態(&mut self, mut 前綴: String) -> Option<O詞> {
115+
let= self.字流.front()?;
116+
match 字類(字) {
117+
O字類::數字 | O字類::其他 => {
118+
前綴.push(self.字流.pop_front()?);
119+
self.識別子態(前綴)
120+
}
121+
O字類::特殊符號 => {
122+
// 遇到特殊符號,識別子截止
123+
// 判定是否是關鍵字
124+
match 前綴.as_str() {
125+
"" => Some(O詞::元),
126+
"" => Some(O詞::術),
127+
"" => Some(O詞::歸),
128+
"" => Some(O詞::若),
129+
"或若" => Some(O詞::或若),
130+
"不然" => Some(O詞::不然),
131+
_ => Some(O詞::識別子(前綴)),
132+
}
133+
}
134+
}
135+
}
136+
```
39137

40-
本次分詞就不再附上代碼,在零.一版的基礎上依狀態機畫葫蘆即可得。

book/零.二版/設計與概述.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@
9898
###
9999

100100
```
101-
術.輾轉相處(甲、乙)【
101+
術.輾轉相除(甲、乙)【
102102
若(乙==0)【
103103
歸.甲
104104

0 commit comments

Comments
 (0)