编译实践学习 Part2

本文以 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 上评测,为什么非要支持单横线呢?

加了几个小脚本。

posted @ 2024-03-16 19:52  383494  阅读(24)  评论(0编辑  收藏  举报