From 4148a749253b3b61c925f67f9f61d4825c37eeb1 Mon Sep 17 00:00:00 2001 From: MROS Date: Fri, 18 Oct 2024 00:49:51 +0800 Subject: [PATCH] =?UTF-8?q?=E7=B2=BE=E4=BA=94=E7=9C=9F=E8=A8=80=E7=94=9F?= =?UTF-8?q?=E6=88=90=EF=BC=88=E5=9B=9B=EF=BC=89=E7=B7=A8=E8=AD=AF=E8=8B=A5?= =?UTF-8?q?=E8=AA=9E=E5=8F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- book/.vitepress/config.mts | 4 + ...23\347\232\204\347\267\250\350\255\257.md" | 2 +- ...57\350\213\245\350\252\236\345\217\245.md" | 227 ++++++++++++++++++ ...36\345\236\213\346\252\242\346\237\245.md" | 2 +- 4 files changed, 233 insertions(+), 2 deletions(-) create mode 100644 "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\345\233\233\357\274\211\347\267\250\350\255\257\350\213\245\350\252\236\345\217\245.md" diff --git a/book/.vitepress/config.mts b/book/.vitepress/config.mts index 6bf24ee..6adf7d3 100644 --- a/book/.vitepress/config.mts +++ b/book/.vitepress/config.mts @@ -101,6 +101,10 @@ export default defineConfig({ text: "精五真言生成(三)實作:術的編譯", link: "/零.二版/精五真言生成(三)實作:術的編譯.md", }, + { + text: "精五真言生成(四)編譯若語句", + link: "/零.二版/精五真言生成(四)編譯若語句.md", + }, ], }, { 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 5102eab..6f044c5 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" @@ -282,4 +282,4 @@ fn 施術(真言檔: &mut File, 術: &O施術, 符號表: &O符號表) -> io } ``` -至此,術的編譯大致講解完畢,部分與零.一版重複的程式碼就先不貼上來了。若有興趣,可直接參考[音界咒源碼](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)。 +至此,術的編譯大致講解完畢,部分與零.一版重複的程式碼就先不貼上來了。若有興趣,可直接參考[音界咒源碼](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)。 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\345\233\233\357\274\211\347\267\250\350\255\257\350\213\245\350\252\236\345\217\245.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\345\233\233\357\274\211\347\267\250\350\255\257\350\213\245\350\252\236\345\217\245.md" new file mode 100644 index 0000000..a99c634 --- /dev/null +++ "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\345\233\233\357\274\211\347\267\250\350\255\257\350\213\245\350\252\236\345\217\245.md" @@ -0,0 +1,227 @@ +最後只剩下若語句還無法編譯了!在討論若語句之前,先來看看零.二版加入的運算子會如何編譯。 + +## 比較運算(及餘運算) + +精五僅提供 slt (及其立即數版本 slit),也就是小於真言,其餘運算都是透過調整暫存器順序與組合 xor 等等運算來完成的,下方源碼是其中一種作法。 + +```rust +match 運算子 { + // 加減乘除... + O運算子::餘 => { + // rem 指令是有號整數取餘 + // 尚有 urem 指令,乃無號整數取餘,但音界咒並不支援 + writeln!(真言檔, "\trem t0, t0, t1")?; + } + O運算子::等於 => { + writeln!(真言檔, "\txor t2, t0, t1")?; // t2 = t0 ^ t1 + writeln!(真言檔, "\tseqz t0, t2")?; // t0 = (t2 == 0) ? 1 : 0 + } + O運算子::異於 => { + writeln!(真言檔, "\txor t2, t0, t1")?; // t2 = t0 ^ t1 + writeln!(真言檔, "\tsnez t0, t2")?; // t0 = (t2 != 0) ? 1 : 0 + } + // 以下比較運算僅 slt 為精五真言 + O運算子::小於 => { + writeln!(真言檔, "\tslt t0, t0, t1")?; // t0 = (t0 < t1) + } + O運算子::大於 => { + // 組譯為 slt t0, t1, t0 + writeln!(真言檔, "\tsgt t0, t0, t1")?; // t0 = (t0 > t1) + } + O運算子::小於等於 => { + // 甲<=乙,即 !(甲>乙) + writeln!(真言檔, "\tsgt t0, t0, t1")?; // t0 = (t0 > t0) + writeln!(真言檔, "\txori t0, t0, 1")?; // t0 = t0 ^ 1 + } + O運算子::大於等於 => { + // 甲>=乙,即 !(甲<乙) + writeln!(真言檔, "\tslt t0, t0, t1")?; // t0 = (t0 < t1) + writeln!(真言檔, "\txori t0, t0, 1")?; // t0 = t0 ^ 1 + } +} +``` + +## 精五決策 + +精五的決策分為兩種,一是條件決策,一是無條件跳躍。 + +### 條件決策 +精五提供了 `beq`(相等則跳), `bne`(相異則跳), `bge`(大於等於則跳), `blt`(小於則跳)等多個條件決策真言。貧道實在不曉得為何比較運算只提供了一個 `slt` ,其他比較都要組合兩個真言才能做,而決策就如此大方。 + +條件決策真言的用法與形式皆雷同,僅語義不同。由於音界咒尚不注重優化,所以接下來僅使用與介紹 `beq`。 + +`beq` 接受三個參數 + +``` +beq 暫存器甲, 暫存器乙, 立即數 +``` + +當 `暫存器甲` 與 `暫存器乙`相等時,將 `立即數 * 2` 加到咒指針(program counter)上,這個立即數是一個 12 位元的有號整數,所以總共可以移動正負 4KB 的距離,在一個術之內跳躍綽綽有餘了。 + +補充:每個精五真言都佔 4 個位元組,那為和立即數是乘 2 不是乘 4 ?因為精五還支援壓縮指令,指令可以被壓縮到只佔用 2 個位元組。 + + +### 無條件跳躍 +若需要更遠的跳躍,則需要 `j` 系列的決策真言,例如偽真言 `call` 會呼叫另一個術,而術與術之間的距離可能很遠,所以 `call` 通常會被組譯成 `jal`,`jal` 在跳躍的同時還能將當下咒指針存入指定暫存器,以待未來返回原執行位置。 + +有時候吾人僅想要跳躍,但不在意當下咒指針,那可以直接用 `j` 偽真言。 + +```assembly +j 立即數 +``` + +會被組譯為 + +``` +jal x0, 立即數 +``` + +`x0` 是一個永遠為 0 的暫存器,咒指針就像丟垃圾一樣被丟到 `x0` 這個垃圾桶去。 + +在組合語言中,其實不用知道這些細節,決策真言可以直接搭配標籤來使用,組譯器會自動算好立即數填上去: + +```assembly +beq t0, x0, 標籤1 +# ... +# t0 != 0 時該做的事 +# ... + +標籤1: +# ... +# 繼續做事 +# ... + +``` + +## 若語句真言生成 + +以上組語就類似於 + +```音界 +若(算式)【 + // 算式 != 0 時該做的事 +】 +// 繼續做事 +``` +的編譯結果。 + +若要支援`或若`、`不然`,就多加幾個標籤: + +```音界 +若(算式1)【 + ... +】或若(算式2)【 + ... +】不然【 + ... +】 +繼續做事 +``` + +可編譯為 + +``` +# 計算算式1 +beq t0, x0, 標籤1 +... +...若區塊 +... +j 標籤3 + + +標籤1: +# 計算算式2 +beq t0, x0, 標籤2 +... +...或若區塊 +... +j 標籤3 + + +標籤2: +... +...不然區塊 +... +j 標籤3 + + + +區塊群結尾標籤: +... +繼續做事 +... +``` + +由於`若`、`或若`、`不然`區塊僅有其一會執行,在區塊結尾都要跳躍到`區塊群結尾標籤`,以避免執行到其他區塊。 + +## 實作 + +標籤在同一個真言檔裡不可同名,需要謹慎管理標籤: + +```rust +fn 新分支標籤名(&mut self) -> String { + self.分支標籤計數 += 1; + format!("分支標籤——{}", self.分支標籤計數) +} +fn 上標籤(&mut self, 標籤名: &String) -> io::Result<()> { + writeln!(self.真言檔, "{}:", 標籤名) +} +fn t0為0則跳至標籤(&mut self, 標籤名: &String) -> io::Result<()> { + writeln!(self.真言檔, "\tbeq t0, x0, {}", 標籤名) +} +fn 新區塊群結尾標籤名(&mut self) -> String { + self.區塊群結尾標籤計數 += 1; + format!("區塊群結尾標籤——{}", self.區塊群結尾標籤計數) +} +fn 跳至標籤(&mut self, 標籤名: &String) -> io::Result<()> { + writeln!(self.真言檔, "j {}", 標籤名) +} +fn 生成若(&mut self, 若: &O若, 符號表: &O符號表) -> io::Result<()> { + // 若 + self.計算(&若.條件, 符號表)?; + self.彈出()?; + let mut 分支標籤名 = self.新分支標籤名(); + self.t0為0則跳至標籤(&分支標籤名)?; + // 區塊內的新增區域變數,在區塊外不應被擷取 + // 故需複製符號表,以免原符號表被影響 + self.生成區塊(&若.區塊, 符號表.clone())?; + + if 若.或若列表.len() == 0 && 若.不然.is_none() { + // 僅有若,無或若、不然。 + self.上標籤(&分支標籤名)?; + return Ok(()); + } + + let 區塊群結尾標籤名 = self.新區塊群結尾標籤名(); + self.跳至標籤(&區塊群結尾標籤名)?; + + // 或若 + for 或若 in &若.或若列表 { + self.上標籤(&分支標籤名)?; + self.計算(&或若.條件, 符號表)?; + self.彈出()?; + 分支標籤名 = self.新分支標籤名(); + self.t0為0則跳至標籤(&分支標籤名)?; + self.生成區塊(&或若.區塊, 符號表.clone())?; + self.跳至標籤(&區塊群結尾標籤名)?; + } + + // 不然 + self.上標籤(&分支標籤名)?; + if let Some(不然) = &若.不然 { + self.生成區塊(&不然.區塊, 符號表.clone())?; + } + + self.上標籤(&區塊群結尾標籤名) +} +fn 生成區塊( + &mut self, 區塊: &Vec<O句>, mut 符號表: O符號表 +) -> io::Result<()> { + for 句 in 區塊 { + self.生成句(句, &mut 符號表)?; + } + Ok(()) +} +``` + +完整程式碼可見[音界咒源碼](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)。 diff --git "a/book/\351\233\266\357\274\216\344\272\214\347\211\210/\350\252\236\347\276\251\345\210\206\346\236\220\357\274\232\351\241\236\345\236\213\346\252\242\346\237\245.md" "b/book/\351\233\266\357\274\216\344\272\214\347\211\210/\350\252\236\347\276\251\345\210\206\346\236\220\357\274\232\351\241\236\345\236\213\346\252\242\346\237\245.md" index a28b0f2..86c633f 100644 --- "a/book/\351\233\266\357\274\216\344\272\214\347\211\210/\350\252\236\347\276\251\345\210\206\346\236\220\357\274\232\351\241\236\345\236\213\346\252\242\346\237\245.md" +++ "b/book/\351\233\266\357\274\216\344\272\214\347\211\210/\350\252\236\347\276\251\345\210\206\346\236\220\357\274\232\351\241\236\345\236\213\346\252\242\346\237\245.md" @@ -42,4 +42,4 @@ 在施術時,應檢查欲施之術名是否確實為術,若是,還要進一步檢查它的形參與實參數長度是否相當。 -類型檢查的實作可以參考[音界咒源碼](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)。 +類型檢查的實作可以參考[音界咒源碼](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)。