编译实践学习 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.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 上评测,为什么非要支持单横线呢?
杂
加了几个小脚本。