本文以 CC BY-SA 4.0 協議釋出。
閒話
重寫了 Part1 裡因為手滑而刪除的 AST。
LunarVim IDE,你值得擁有(
程式碼傳上了 github(推薦 https://mirror.ghproxy.com 加速).
Koopa IR
遍歷 AST,然後根據 Koopa IR 語法輸出字串。
發現 std::ostringstream
還挺好用。
比如:
constexpr const char* INDENT = " ";
using Ost = std::ostringstream;
// ...
class FuncDefAST: public BaseAST{
public:
std::unique_ptr<BaseAST> func_typ;
std::string ident;
std::unique_ptr<BaseAST> block;
void output(Ost &outstr, std::string prefix) const override{
outstr << prefix << "fun @" << ident << "():";
func_typ->output(outstr, "");
outstr << "{\n";
block->output(outstr, prefix + INDENT);
outstr << "\n" << prefix << "}";
}
};
// ...
想輸出到 stderr
時直接把 Ost
型別改了就行。
為什麼不用 template
?因為 C++ 的虛擬函式不能是模板。(可能不準確,如果錯了請大佬指出)
然後用 koopa_parse_from_string
把字串轉成 koopa_raw_program_t
.
注意 std::ostringstream::str()
返回的是臨時物件,也就是說還要用一個 std::string
儲存.
risc-v
為什麼 Koopa IR 裡的宏定義要寫成 RSIK
啊……
感覺遍歷 Koopa IR 然後生成彙編的過程和遍歷 AST 然後生成 Koopa IR 的過程差不多。
新開了檔案 ir.cpp
和 ir.hpp
來處理 Koopa IR \(\rightarrow\) RISC-V.
然後就完事了。
命令列引數
getopt
,你值得擁有。
大概就是配置一下長命令引數然後就能用了。
PKU 文件裡要求形如 -koopa
的命令列引數,所以只能用 getopt_long_only
.
extern char* optarg;
extern int optind, opterr, optopt;
static const struct option long_opt_args[] = {
{"koopa", no_argument, NULL, 1001},
{"riscv", no_argument, NULL, 1002},
{"output", required_argument, NULL, 1003},
{"o", required_argument, NULL, 1003},
{0, 0, 0, 0}
};
bool output_koopa = false;
int main(int argc, char **argv) {
int now_opt = 0;
std::string outp;
while((now_opt = getopt_long_only(argc, argv, "", long_opt_args, NULL)) != -1){
switch(now_opt){
case 1001:
output_koopa = true;
break;
case 1002:
output_koopa = false;
break;
case 1003:
outp = optarg;
break;
case '?':
return 114514;
default:
assert(0);
}
}
// ...
}
話說回來,我又不在他們的 OJ 上評測,為什麼非要支援單橫線呢?
雜
加了幾個小指令碼。