From 9bc6d3ff4b44e8f6b7936b3b7d793a16028a3404 Mon Sep 17 00:00:00 2001 From: MROS Date: Wed, 16 Oct 2024 23:42:43 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A8=88=E7=AE=97=E6=96=BD=E8=A1=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...23\347\232\204\347\267\250\350\255\257.md" | 33 ++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git "a/book/\351\233\266\357\274\216\344\272\214\347\211\210/\347\262\276\344\272\224\347\234\237\350\250\200\347\224\237\346\210\220\357\274\210\344\270\211\357\274\211\345\257\246\344\275\234\357\274\232\350\241\223\347\232\204\347\267\250\350\255\257.md" "b/book/\351\233\266\357\274\216\344\272\214\347\211\210/\347\262\276\344\272\224\347\234\237\350\250\200\347\224\237\346\210\220\357\274\210\344\270\211\357\274\211\345\257\246\344\275\234\357\274\232\350\241\223\347\232\204\347\267\250\350\255\257.md" index 43feeb8..5102eab 100644 --- "a/book/\351\233\266\357\274\216\344\272\214\347\211\210/\347\262\276\344\272\224\347\234\237\350\250\200\347\224\237\346\210\220\357\274\210\344\270\211\357\274\211\345\257\246\344\275\234\357\274\232\350\241\223\347\232\204\347\267\250\350\255\257.md" +++ "b/book/\351\233\266\357\274\216\344\272\214\347\211\210/\347\262\276\344\272\224\347\234\237\350\250\200\347\224\237\346\210\220\357\274\210\344\270\211\357\274\211\345\257\246\344\275\234\357\274\232\350\241\223\347\232\204\347\267\250\350\255\257.md" @@ -248,7 +248,38 @@ fn 計算( } } ``` +### 計算施術 相比零.一版,此處增加了一種算式——`施術`,依然可用堆疊機來完成,先分別計算各個實參,將實參的值壓入棧中,等實參都計算完畢後,將實參值載入參數暫存器後,施術(call)。 -### 計算施術 +```rust +// 結束時,棧頂 = t0 = 術的歸值 +fn 施術(真言檔: &mut File, 術: &O施術, 符號表: &O符號表) -> io::Result<()> { + writeln!(真言檔, "# 施展「{}」", 術.術名)?; + + assert!(術.實參.len() <= 8, "音界咒暫不支援超過八個術參"); + + // 將參數計算結果逐一推入棧中 + // NOTE: 不可將計算結果直接賦值給暫存器 + // 因其下個參數的計算過程中,可能又會汙染掉參數暫存器 + for 參數 in &術.實參 { + // 任何計算完成後,棧會擴大一個字長 + // 計算結果會被置於棧頂 + Self::計算(真言檔, 參數, 符號表)?; + } + // 將參數從棧中逐一載入參數暫存器 + for 編號 in (0..術.實參.len()).rev() { + writeln!(真言檔, "\tld a{}, 0(sp)", 編號)?; + writeln!(真言檔, "\taddi sp, sp, 8")?; // 將參數計算結果彈出 + } + + writeln!(真言檔, "\tcall {}", 術.術名)?; + + // 歸值放回 t0 + writeln!(真言檔, "\tmv t0, a0")?; + writeln!(真言檔, "\taddi sp, sp, -8")?; // 增加棧 64 位元的空間 + writeln!(真言檔, "\tsd t0, 0(sp)") // t0 放入棧頂 +} +``` + +至此,術的編譯大致講解完畢,部分與零.一版重複的程式碼就先不貼上來了。若有興趣,可直接參考[音界咒源碼](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)。