# lab3 实验报告 PB20111654 李晓奇 ## 实验要求 ## 实验难点 1. syntax_tree和ast的区别、为什需要ast? 阅读AST的构造函数,`AST(syntax_tree *)` 实际上这部分在上个实验就有看calc_ast的代码,但是印象不深刻。。 2. 访问者模式究竟有什么用? 比如这样一系列函数调用: ```cpp ASTPrinter::visit(ASTProgram &) { //... for (auto decl : node.declarations) { decl->accept(*this); } //... } ASTVarDeclaration::accept(ASTVisitor &) { //... auto var_decl = dynamic_cast(this); if (var_decl) { var_decl->accept(visitor); return; } //... } void ASTVarDeclaration::accept(ASTVisitor &visitor) { visitor.visit(*this); } ``` 假设就是vardeclaration,直接调用(在`ASTPrinter::visit`内)`visit(dynamic_cast(this))`不是一样的吗? 参考[攻略](https://www.jianshu.com/p/1f1049d0a0f4),接受一点,感觉还是不太明白,但是不影响写实验。因为经过反复的阅读,我已经知道了我们要实现的`CminusfBuilder`是一个访问者类! 3. 无从下手! 从变量开始! 自底向上做自然多了,不然像在摸黑拧魔方。 4. 如何获得返回值? 加入一个全局变量保存语句的返回值。 5. 数组or指针?这个关乎地址的计算、类型转换…… 答案在于:中间代码是如何生成的? 按我的理解, - 在翻译为中间代码时,函数内部声明的只能是数组,计算地址时会得到指针。 - 在传递给函数时,只能传递数组,但是传递为指针。 6. 记录遇到的坑 - 形如这种产生式子`term→term mulop factor ∣ factor`,我为了图方便先求了`factor`,在根据`term`的有调用`accept()`,但是这样会导致左右操作数颠倒。 - 我对于类型转换的控制比较严格,没考虑到的一率abort,因此很快发现了漏掉了bool类型的转换。 - 接上条,一些类型转换的bug:`i32`到`i1`也是需要转换的,开始做的时候还没意识到这些(主要是没意识到`i1`的存在)。 - **核心问题**:函数调用是值传递,比如`f(a)`,这里在中间代码看来,a返回的是一个指针,需要load出来再传过去。 但是对于字面量,又不需这样提取数据。可以使用`dynamic_cast`尝试解决。 但是出现了加减乘除时,这个又不能动态类型转换。 换句话说,访问`ASTCall`时,需要依次调用args的`accept()`,但是这个args!!!!expression应该返回的就是值才对。问题出现在变量的访问那里。 这个在访问`ASTVar`时解决掉: - 如果做左值,返回指针元素 - 如果做右值,返回值 ```cpp struct ASTCall : ASTFactor { virtual void accept(ASTVisitor &) override final; std::string id; std::vector> args; }; ``` - 全局变量要特殊对待 - 数组下标为负时要调用`neg_idx_except()` ## 实验设计 请写明为了顺利完成本次实验,加入了哪些亮点设计,并对这些设计进行解释。 可能的阐述方向有: 1. 如何设计全局变量 2. 遇到的难点以及解决方案 3. 如何降低生成 IR 中的冗余 4. ... ### 实验总结 此次实验有什么收获 ### 实验反馈 (可选 不计入评分) 对本次实验的建议