Skip to content

Commit 9bc6d3f

Browse files
committed
計算施術
1 parent 355f4b9 commit 9bc6d3f

File tree

1 file changed

+32
-1
lines changed

1 file changed

+32
-1
lines changed

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

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,38 @@ fn 計算(
248248
}
249249
}
250250
```
251+
### 計算施術
251252

252253
相比零.一版,此處增加了一種算式——`施術`,依然可用堆疊機來完成,先分別計算各個實參,將實參的值壓入棧中,等實參都計算完畢後,將實參值載入參數暫存器後,施術(call)。
253254

254-
### 計算施術
255+
```rust
256+
// 結束時,棧頂 = t0 = 術的歸值
257+
fn 施術(真言檔: &mut File, 術: &O施術, 符號表: &O符號表) -> io::Result<()> {
258+
writeln!(真言檔, "# 施展「{}」", 術.術名)?;
259+
260+
assert!(術.實參.len() <= 8, "音界咒暫不支援超過八個術參");
261+
262+
// 將參數計算結果逐一推入棧中
263+
// NOTE: 不可將計算結果直接賦值給暫存器
264+
// 因其下個參數的計算過程中,可能又會汙染掉參數暫存器
265+
for 參數 in &.實參 {
266+
// 任何計算完成後,棧會擴大一個字長
267+
// 計算結果會被置於棧頂
268+
Self::計算(真言檔, 參數, 符號表)?;
269+
}
270+
// 將參數從棧中逐一載入參數暫存器
271+
for 編號 in (0...實參.len()).rev() {
272+
writeln!(真言檔, "\tld a{}, 0(sp)", 編號)?;
273+
writeln!(真言檔, "\taddi sp, sp, 8")?; // 將參數計算結果彈出
274+
}
275+
276+
writeln!(真言檔, "\tcall {}", 術.術名)?;
277+
278+
// 歸值放回 t0
279+
writeln!(真言檔, "\tmv t0, a0")?;
280+
writeln!(真言檔, "\taddi sp, sp, -8")?; // 增加棧 64 位元的空間
281+
writeln!(真言檔, "\tsd t0, 0(sp)") // t0 放入棧頂
282+
}
283+
```
284+
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)

0 commit comments

Comments
 (0)