Skip to content

Commit 4148a74

Browse files
committed
精五真言生成(四)編譯若語句
1 parent 9bc6d3f commit 4148a74

File tree

4 files changed

+233
-2
lines changed

4 files changed

+233
-2
lines changed

book/.vitepress/config.mts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,10 @@ export default defineConfig({
101101
text: "精五真言生成(三)實作:術的編譯",
102102
link: "/零.二版/精五真言生成(三)實作:術的編譯.md",
103103
},
104+
{
105+
text: "精五真言生成(四)編譯若語句",
106+
link: "/零.二版/精五真言生成(四)編譯若語句.md",
107+
},
104108
],
105109
},
106110
{

book/零.二版/精五真言生成(三)實作:術的編譯.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,4 +282,4 @@ fn 施術(真言檔: &mut File, 術: &O施術, 符號表: &O符號表) -> io
282282
}
283283
```
284284

285-
至此,術的編譯大致講解完畢,部分與零.一版重複的程式碼就先不貼上來了。若有興趣,可直接參考[音界咒源碼](https://github.com/MROS/yinjie-lang/blob/3c6389823284722338642e3de672ef48d8e8ac9e/%E9%9B%B6%E8%99%9F%E7%B7%A8%E8%AD%AF%E5%99%A8/src/%E7%9C%9F%E8%A8%80%E7%94%9F%E6%88%90/%E7%9C%9F%E8%A8%80%E7%94%9F%E6%88%90%E5%99%A8.rs)
285+
至此,術的編譯大致講解完畢,部分與零.一版重複的程式碼就先不貼上來了。若有興趣,可直接參考[音界咒源碼](https://github.com/MROS/yinjie-lang/blob/8aab11a3a6640fbe7691dbbe25cb48f8c4f69532/%E9%9B%B6%E8%99%9F%E7%B7%A8%E8%AD%AF%E5%99%A8/src/%E7%9C%9F%E8%A8%80%E7%94%9F%E6%88%90/%E7%9C%9F%E8%A8%80%E7%94%9F%E6%88%90%E5%99%A8.rs)
Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
最後只剩下若語句還無法編譯了!在討論若語句之前,先來看看零.二版加入的運算子會如何編譯。
2+
3+
## 比較運算(及餘運算)
4+
5+
精五僅提供 slt (及其立即數版本 slit),也就是小於真言,其餘運算都是透過調整暫存器順序與組合 xor 等等運算來完成的,下方源碼是其中一種作法。
6+
7+
```rust
8+
match 運算子 {
9+
// 加減乘除...
10+
O運算子::=> {
11+
// rem 指令是有號整數取餘
12+
// 尚有 urem 指令,乃無號整數取餘,但音界咒並不支援
13+
writeln!(真言檔, "\trem t0, t0, t1")?;
14+
}
15+
O運算子::等於 => {
16+
writeln!(真言檔, "\txor t2, t0, t1")?; // t2 = t0 ^ t1
17+
writeln!(真言檔, "\tseqz t0, t2")?; // t0 = (t2 == 0) ? 1 : 0
18+
}
19+
O運算子::異於 => {
20+
writeln!(真言檔, "\txor t2, t0, t1")?; // t2 = t0 ^ t1
21+
writeln!(真言檔, "\tsnez t0, t2")?; // t0 = (t2 != 0) ? 1 : 0
22+
}
23+
// 以下比較運算僅 slt 為精五真言
24+
O運算子::小於 => {
25+
writeln!(真言檔, "\tslt t0, t0, t1")?; // t0 = (t0 < t1)
26+
}
27+
O運算子::大於 => {
28+
// 組譯為 slt t0, t1, t0
29+
writeln!(真言檔, "\tsgt t0, t0, t1")?; // t0 = (t0 > t1)
30+
}
31+
O運算子::小於等於 => {
32+
// 甲<=乙,即 !(甲>乙)
33+
writeln!(真言檔, "\tsgt t0, t0, t1")?; // t0 = (t0 > t0)
34+
writeln!(真言檔, "\txori t0, t0, 1")?; // t0 = t0 ^ 1
35+
}
36+
O運算子::大於等於 => {
37+
// 甲>=乙,即 !(甲<乙)
38+
writeln!(真言檔, "\tslt t0, t0, t1")?; // t0 = (t0 < t1)
39+
writeln!(真言檔, "\txori t0, t0, 1")?; // t0 = t0 ^ 1
40+
}
41+
}
42+
```
43+
44+
## 精五決策
45+
46+
精五的決策分為兩種,一是條件決策,一是無條件跳躍。
47+
48+
### 條件決策
49+
精五提供了 `beq`(相等則跳), `bne`(相異則跳), `bge`(大於等於則跳), `blt`(小於則跳)等多個條件決策真言。貧道實在不曉得為何比較運算只提供了一個 `slt` ,其他比較都要組合兩個真言才能做,而決策就如此大方。
50+
51+
條件決策真言的用法與形式皆雷同,僅語義不同。由於音界咒尚不注重優化,所以接下來僅使用與介紹 `beq`
52+
53+
`beq` 接受三個參數
54+
55+
```
56+
beq 暫存器甲, 暫存器乙, 立即數
57+
```
58+
59+
`暫存器甲``暫存器乙`相等時,將 `立即數 * 2` 加到咒指針(program counter)上,這個立即數是一個 12 位元的有號整數,所以總共可以移動正負 4KB 的距離,在一個術之內跳躍綽綽有餘了。
60+
61+
補充:每個精五真言都佔 4 個位元組,那為和立即數是乘 2 不是乘 4 ?因為精五還支援壓縮指令,指令可以被壓縮到只佔用 2 個位元組。
62+
63+
64+
### 無條件跳躍
65+
若需要更遠的跳躍,則需要 `j` 系列的決策真言,例如偽真言 `call` 會呼叫另一個術,而術與術之間的距離可能很遠,所以 `call` 通常會被組譯成 `jal``jal` 在跳躍的同時還能將當下咒指針存入指定暫存器,以待未來返回原執行位置。
66+
67+
有時候吾人僅想要跳躍,但不在意當下咒指針,那可以直接用 `j` 偽真言。
68+
69+
```assembly
70+
j 立即數
71+
```
72+
73+
會被組譯為
74+
75+
```
76+
jal x0, 立即數
77+
```
78+
79+
`x0` 是一個永遠為 0 的暫存器,咒指針就像丟垃圾一樣被丟到 `x0` 這個垃圾桶去。
80+
81+
在組合語言中,其實不用知道這些細節,決策真言可以直接搭配標籤來使用,組譯器會自動算好立即數填上去:
82+
83+
```assembly
84+
beq t0, x0, 標籤1
85+
# ...
86+
# t0 != 0 時該做的事
87+
# ...
88+
89+
標籤1:
90+
# ...
91+
# 繼續做事
92+
# ...
93+
94+
```
95+
96+
## 若語句真言生成
97+
98+
以上組語就類似於
99+
100+
```音界
101+
若(算式)【
102+
// 算式 != 0 時該做的事
103+
104+
// 繼續做事
105+
```
106+
的編譯結果。
107+
108+
若要支援`或若``不然`,就多加幾個標籤:
109+
110+
```音界
111+
若(算式1)【
112+
...
113+
】或若(算式2)【
114+
...
115+
】不然【
116+
...
117+
118+
繼續做事
119+
```
120+
121+
可編譯為
122+
123+
```
124+
# 計算算式1
125+
beq t0, x0, 標籤1
126+
...
127+
...若區塊
128+
...
129+
j 標籤3
130+
131+
132+
標籤1:
133+
# 計算算式2
134+
beq t0, x0, 標籤2
135+
...
136+
...或若區塊
137+
...
138+
j 標籤3
139+
140+
141+
標籤2:
142+
...
143+
...不然區塊
144+
...
145+
j 標籤3
146+
147+
148+
149+
區塊群結尾標籤:
150+
...
151+
繼續做事
152+
...
153+
```
154+
155+
由於```或若``不然`區塊僅有其一會執行,在區塊結尾都要跳躍到`區塊群結尾標籤`,以避免執行到其他區塊。
156+
157+
## 實作
158+
159+
標籤在同一個真言檔裡不可同名,需要謹慎管理標籤:
160+
161+
```rust
162+
fn 新分支標籤名(&mut self) -> String {
163+
self.分支標籤計數 += 1;
164+
format!("分支標籤——{}", self.分支標籤計數)
165+
}
166+
fn 上標籤(&mut self, 標籤名: &String) -> io::Result<()> {
167+
writeln!(self.真言檔, "{}:", 標籤名)
168+
}
169+
fn t00則跳至標籤(&mut self, 標籤名: &String) -> io::Result<()> {
170+
writeln!(self.真言檔, "\tbeq t0, x0, {}", 標籤名)
171+
}
172+
fn 新區塊群結尾標籤名(&mut self) -> String {
173+
self.區塊群結尾標籤計數 += 1;
174+
format!("區塊群結尾標籤——{}", self.區塊群結尾標籤計數)
175+
}
176+
fn 跳至標籤(&mut self, 標籤名: &String) -> io::Result<()> {
177+
writeln!(self.真言檔, "j {}", 標籤名)
178+
}
179+
fn 生成若(&mut self, 若: &O若, 符號表: &O符號表) -> io::Result<()> {
180+
//
181+
self.計算(&.條件, 符號表)?;
182+
self.彈出()?;
183+
let mut 分支標籤名 = self.新分支標籤名();
184+
self.t0為0則跳至標籤(&分支標籤名)?;
185+
// 區塊內的新增區域變數,在區塊外不應被擷取
186+
// 故需複製符號表,以免原符號表被影響
187+
self.生成區塊(&.區塊, 符號表.clone())?;
188+
189+
if.或若列表.len() == 0 &&.不然.is_none() {
190+
// 僅有若,無或若、不然。
191+
self.上標籤(&分支標籤名)?;
192+
return Ok(());
193+
}
194+
195+
let 區塊群結尾標籤名 = self.新區塊群結尾標籤名();
196+
self.跳至標籤(&區塊群結尾標籤名)?;
197+
198+
// 或若
199+
for 或若 in &.或若列表 {
200+
self.上標籤(&分支標籤名)?;
201+
self.計算(&或若.條件, 符號表)?;
202+
self.彈出()?;
203+
分支標籤名 = self.新分支標籤名();
204+
self.t0為0則跳至標籤(&分支標籤名)?;
205+
self.生成區塊(&或若.區塊, 符號表.clone())?;
206+
self.跳至標籤(&區塊群結尾標籤名)?;
207+
}
208+
209+
// 不然
210+
self.上標籤(&分支標籤名)?;
211+
if let Some(不然) = &.不然 {
212+
self.生成區塊(&不然.區塊, 符號表.clone())?;
213+
}
214+
215+
self.上標籤(&區塊群結尾標籤名)
216+
}
217+
fn 生成區塊(
218+
&mut self, 區塊: &Vec<O句>, mut 符號表: O符號表
219+
) -> io::Result<()> {
220+
forin 區塊 {
221+
self.生成句(句, &mut 符號表)?;
222+
}
223+
Ok(())
224+
}
225+
```
226+
227+
完整程式碼可見[音界咒源碼](https://github.com/MROS/yinjie-lang/blob/8aab11a3a6640fbe7691dbbe25cb48f8c4f69532/%E9%9B%B6%E8%99%9F%E7%B7%A8%E8%AD%AF%E5%99%A8/src/%E7%9C%9F%E8%A8%80%E7%94%9F%E6%88%90/%E7%9C%9F%E8%A8%80%E7%94%9F%E6%88%90%E5%99%A8.rs)

book/零.二版/語義分析:類型檢查.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,4 @@
4242

4343
在施術時,應檢查欲施之術名是否確實為術,若是,還要進一步檢查它的形參與實參數長度是否相當。
4444

45-
類型檢查的實作可以參考[音界咒源碼](https://github.com/MROS/yinjie-lang/blob/1034459a443f44730b5ecec737062444738a7628/%E9%9B%B6%E8%99%9F%E7%B7%A8%E8%AD%AF%E5%99%A8/src/%E7%AC%A6%E8%99%9F%E6%AA%A2%E6%9F%A5.rs)
45+
類型檢查的實作可以參考[音界咒源碼](https://github.com/MROS/yinjie-lang/blob/8aab11a3a6640fbe7691dbbe25cb48f8c4f69532/%E9%9B%B6%E8%99%9F%E7%B7%A8%E8%AD%AF%E5%99%A8/src/%E7%AC%A6%E8%99%9F%E6%AA%A2%E6%9F%A5.rs)

0 commit comments

Comments
 (0)