編譯實踐學習 Part2

383494發表於2024-03-16

本文以 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.cppir.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 上評測,為什麼非要支援單橫線呢?

加了幾個小指令碼。

相關文章