【HUST】网安|编译原理实验|实验四攻略
【实验代码及报告地址:Gitee传送门】(已关闭传送大门,原因是抄袭过多,如需参考,请直接看博客,虽然下一届内容会变了)
不擅长写报告昂,很多地方能省全省了。
助力来年编译原理加大难度!(hhh)
MiniC语法分析及中间代码生成
我根据我的实验报告重置了攻略。
贴个完成时间。
实验内容
将Mini-C源程序,手工翻译或用LLVM API翻译成LLVM IR(一种中间语言),并完成语法检查。
实验过程
LLVM IR初识
结合给出的例子,认识并熟悉LLVM IR的语法。
主要涉及了align/alloca/store/load/call/icmp/br等。【可以自行结合代码展开说说】
主要是根据Mini-C语言翻译,有两个地方对我造成了困扰:【相信每个人困扰的点不一样,自圆其说即可】
- task2中我一开始将putchar写进了判断体中,导致状态不够用,不得不移出。
- task2中涉及标号label。不像asm,llvm的标号上面不能没有跳转语句直接顺序执行,它必须添加br label %8跳转。
LLVM IR API
熟悉并使用LLVM IR API,主要涉及了llvm::IRBuilderBase类的API,还有一些Constant、BasicBlock、Type类的API。【可以自行结合代码展开说说】
难点:【相信每个人的难点不一样,自圆其说即可】
- getchar是无参数函数,而builder->CreateCall需要接受1到3个参数,直接传递空vector行不通。
正解:builder->CreateCall(callgetfunc);
- task2中if-then-else涉及3个基本块,样例中是if-then,只涉及两个模块。而且并不好理解。
正解:根据官网的IF-THEN-ELSE写,它的解释很好。MyFirstLanguageFrontend/LangImpl05.html#code-generation-for-if-then-else。 - 一些个人遇到的问题:在进入第三个基本块我没有
f->getBasicBlockList().push_back(MergeBB);
,因为我以为到结尾了可以直接顺序执行下去,犯了和关卡1相似的错误。没有写这一句时,报错会一直提示then:错误,导致我一直没定位到真正的错误位置。
语义分析与中间代码生成(一)
【因为实在很长,所以实验报告里我没有写过程,只写了难点。不建议大家这样做,因为每个人的难点都是不一样的】
【如果没话写,可以着重写一下“错误判断”部分】
难点
- 咋声明变量?(答:抄NExtDefFunDec::codegen的arg声明)
- 我怎么知道一个函数里需要解析哪些参数、哪些参数是需要被特殊处理的?(答:看上面的分析,对照parser.y和astnode.h)
- 咋把分析结果存到变量里面?(答:实验二里做过,不记得的话,函数声明如是:
builder->CreateStore(Value, alloca);
) - 咋分析加?(答:实验二有提示。不记得的话,函数声明如是:
builder->CreateAdd(left, right, "add");
) - abort怎么炸了,返回之后就提示我
core dump
?
答:请检查是不是把nullptr
输入到一个函数中了,举个简单的例子(摘自NAssignment::codegen函数):
再检查是否未初始化指针就直接用了,举个retValue没初始化就返回的例子:
Value* retValue; if(false) retValue=nullptr; return retValue;
- module找不到,它什么意思?(答:字面意思,找不到就找不到。执行fundec成功了就能找到main)
- 为了实现功能,我参考函数定义的部分,即ExtDefFunc::codegen,添加了一个继承属性type,如函数
NDef
。
调试技巧
std::cout
调试,定位出错的位置。cat tokens.txt
调试,通过阅读生成的中间代码,判断语义分析的哪一步出了问题,或者根本没解析出来。vim ./task1case/1.in
修改样例调试。当你觉得是某个逻辑写得很有问题,但是样例太长了,中间代码眼花缭乱,就直接修改样例。p->parser();
输出语法树。将main.cpp中的p->parser();注释掉,再编译运行样例,能看到每个样例完整的语法树。建议顺着语法树的解析顺序,逐个填充codegen,每填充完一个,就去编译运行试试。
Quick Start
使用头歌命令行调试
打开头歌,打开命令行,进入对应的代码仓库。
cd /data/workspace/myshixun/llvmexp3
检查一下当前目录下的文件。
ls
应该能看到judge_taskx.sh
文件,以第三关为例,看一下judge_task1.sh
的内容。
具体内容就不贴了,总之是这样用的:
- 先编译(make)成
./minic
文件,它是一个可执行的文件,用来生成中间代码LLVM IR。
make
中间代码LLVM IR:类似于
br i1 %shandian7, label %then8, label %ifcont10
这种东西。
- 在代码仓库下有测试样例,以第3关为例,对应
task1case
。 - 用minic编译一个样例,并将中间代码(或报错)存储至
tokens.txt
。
./minic ./task1case/0.in > tokens.txt
- 如果生成中间代码成功了,
cat tokens.txt
看一下输出(你在cpp里写的std::cout、输出的报错Error信息也会在这个txt里)。 - 如果这是一个正确的中间代码,而且它需要编译运行,并接收一定的输入,请这样:
echo "你要给程序输入的值(就是stdin)" > tmp
lli tokens.txt < tmp
正式开始
1. astnode.cpp需要修改的函数
正好十个。
NIdentifier
蛮麻烦的,如下:
注:写第三题的时候可以乱来,写第五题就得考虑作用域了。
2. astnode.h需要修改的函数
写第五关的时候发现,VarDec::codegen返回值设为AllocaInst *才行。
3. 一个分析过程
4. 举几个典型的例子
4.1. 各种List
直到第五题才能发现的错误:注意一个特殊的,NDec::codegen,根据Dec: VarDec | VarDec ASSIGNOP Exp,它的Exp是要用来给VarDec的alloca赋值的,不要只是单纯地解析它然后就不管了喔。
4.2 错误判断
++ 错误类型 1:变量在使用时未经定义。
思路就是调用的时候找找curNamedValues里有没有。(摘自NAssignment::codegen函数)
++ 错误类型 2:函数在调用时未经定义。
思路就是调用的时候找找theModule里有没有。(摘自NMethodCall::codegen函数)
++ 错误类型 3:变量出现重复定义。
思路就是声明的时候找找curNamedValues里有没有。(摘自NExtDefFunDec::codegen函数)
语义分析与中间代码生成(二)
有了第3关的基础,第四关明显简单了许多。
【实验报告我依旧只写了难点,注意口语书面化】
【如果没话写,可以着重写一下“错误判断”部分】
1. astnode.cpp需要修改的函数
只有四个,非常快乐。
注:由于第3关的时候,我顺手把NFloat::codegen之类的全部写好了,所以这里没有特意标注。
好像有同学找不到Float的取值函数,如下:
2. 难点
2.1 一些函数
出现了很多老师没给样例的函数。
如CreateSub
、getType()方法
、getReturnType()
参考classllvm_1_1IRBuilderBase.html找到CreateSub函数,
参考classllvm_1_1Function.html得知getReturnType(),
参考classllvm_1_1Value.html得知Value有自己的getType()函数。
我是如何查找的?【经验分享】
例如,我想获得auto *
类型的变量retValue
的type。
- 很自然地写出了
retValue.type
的代码,然后报错,说retValue是个指针,建议用->来访问它的成员
。 - 于是订正为
retValue->type
,再次报错,说class llvm::Value *没有type成员
。 - 那么
llvm::Value
有什么呢?搜索llvm::Value
,跳转官网,找到getType()
函数。 - 订正为
retValue->getType()
,成功。
2.2 NArgs如何解析
引言:
- 明显,NArgs对应多个参数,但是它的codegen()只返回一个Value*,这不合适啊!
- 难道参考List函数的解析方式,修改NArgs::codegen(),依次展开?不行啊,每个返回值都要用,依次展开没办法返回回去啊!
正解:参考NFunDec::funcodegen中对NVarList的解析即可。
std::vector<Type *> argsTypes;
std::vector<std::string> argNames;
for (NVarList *item = arguments; item; item = item->nVarList) {
auto tmp = item->nParamDec.getType();
argNames.push_back(tmp.first);
argsTypes.push_back(tmp.second);
}
注意,exp解析得到的Value*的类型,直接用getType就可以取到了,很好写,不要想太复杂了。
3. 错误判断
++ 错误类型 4:函数出现重复定义(即同样的函数名被多次定义)。
这个老师写好了。在NFunDec::funcodegen里。
++ 错误类型 5:赋值号两边的表达式类型不匹配。
++ 错误类型 6:赋值号左边出现一个只有右值的表达式。
++ 错误类型 7:return 语句的返回类型与函数定义的返回类型不匹配。
++ 销误类型 8:函数调用时实参与形参的数目或类型不匹配。
没什么好说的叭,能写出第三题没理由写不出错误判断。
语义分析与中间代码生成(三)
【报告只写了分析思路部分】
1. astnode.cpp需要修改的函数
主要是因为我前面偷懒偷得比较多,所以改动也很多。
2. astnode.h需要修改的函数
这个地方真的是,我没太动脑,返回值设错了一通乱解析。
3. 分析思路
首先看样例:
这个题没有涉及任何错误判断,需要完成的是算术运算+-*/
和逻辑符号||
,以及三个结构:if
/ifelse
/while
。
3.1 if-else结构
其中ifelse结构直接参考实验2的,对应的是NIfElseStmt::codegen,应该没什么好说的吧。写了这个之后样例1就都过了。
样例1:
int read(){
int a=0;
a = getchar();
return a - 48;
}
int main(){
int m,n;
int i=48;
m = read();
n = read();
if(m == n ){
putchar(i);
}else{
i = i + 1;
putchar(i);
}
i = i + 1;
putchar(i);
return 0;
}
3.2 变量的作用域问题
因为一些因素,我没有用样例分析,而是用了更复杂的深层结构,分析以及伪代码如下。
3.3 或运算||的解析
提示:用基本块。多看看生成的中间代码和预期的区别。
贴一下报错,这个报错是因为while循环过多栈炸了,可能是因为条件判断写得有问题,心态稳住。
【HUST】网安|编译原理实验|实验四攻略的更多相关文章
- windows环境VS2015编译TensorFlow C++程序完全攻略
本文参考和综合了多篇网络博客文章,加以自己的实践,最终终于在windows环境下,编译出可以用于C++程序调用tensorflow API的程序,并执行成功. 考虑到网络上关于这方面的资料还较少,特总 ...
- 编译原理实验之SLR1文法分析
---内容开始--- 这是一份编译原理实验报告,分析表是手动造的,可以作为借鉴. 基于 SLR(1) 分析法的语法制导翻译及中间代码生成程序设计原理与实现1 .理论传授语法制导的基本概念,目标代码结 ...
- 【黑金原创教程】【FPGA那些事儿-驱动篇I 】实验十四:储存模块
实验十四比起动手笔者更加注重原理,因为实验十四要讨论的东西,不是其它而是低级建模II之一的模块类,即储存模块.接触顺序语言之际,“储存”不禁让人联想到变量或者数组,结果它们好比数据的暂存空间. . i ...
- 20145221 《Java程序设计》实验报告四:Android开发基础
20145221 <Java程序设计>实验报告四:Android开发基础 实验要求 基于Android Studio开发简单的Android应用并部署测试; 了解Android组件.布局管 ...
- 慕课网Hibernate初探之一对多映射实验及总结
慕课网Hibernate初探之一对多映射实验及总结 一.本课核心 * 1.如何在MyEclipse中使用Hibernate * 2.如何实现Hibernate中一对多的映射 * 3.如何创建Sessi ...
- 201671010447 杨露露 实验十四 团队项目评审&课程学习总结
项目 内容 这个作业属于哪个课程 2016计算机科学与工程学院软件工程(西北师范大学) 这个作业的要求在哪里 实验十四 团队项目评审&课程学习总结 作业学习目标 总结这学期软件工程学习获得 一 ...
- 201671030113 李星宇 实验十四 团队项目评审&课程学习总结
项目 内容 所属课程 [所属课程(https://www.cnblogs.com/nwnu-daizh/) 作业要求 作业要求 课程学习目标 (1)掌握软件项目评审会流程:(2)反思总结课程学习内容 ...
- 201671010426 孙锦喆 实验十四 团队项目评审&课程学习总结
徐明锦 徐明锦 2 95 2019-06-30T14:54:00Z 2019-06-30T14:54:00Z 9 608 3472 28 8 4072 14.00 Clean Clean false ...
- 201671010446姚良实验十四团队项目评审&课程总结
实验十四 团队项目评审&课程学习总结 项目 内容 这个作业属于哪个课程 http://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cn ...
- 201671030114 马秀丽 实验十四 团队项目评审&课程学习总结
项目 内容 作业所属课程 所属课程 作业要求 作业要求 课程学习目标 (1)掌握软件项目评审会流程:(2)反思总结课程学习内容 任务一:团队项目审核已完成.项目验收过程意见表已上交. 任务二:课程学习 ...
随机推荐
- Asp.Net Core3.0 微信小程序统一下单
微信统一下单开发文档:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_1 微信支付小程序支付文档:https://pay.wei ...
- [BZOJ3600] 没有人的算术 题解
妙不可言!妙绝人寰! 单点修,区间查,包是线段树的.考虑如何比较两节点大小. 考虑二叉搜索树,我们只要再给每个节点附一个权值,就可以比较了! 注意力相当惊人的注意到,假如给每个点一个区间 \([l_x ...
- pnpm:无法加载文件 C:\Users\Five\AppData\Roaming\npm\pnpm.ps1 ,因为在此系统上禁止运行脚本
前言 重装完了电脑系统,运行pnpm 无法加载文件,pnpm -V也不行 解决方案 用管理员方式启动power shell 输入命令:set-ExecutionPolicy RemoteSigned ...
- helm部署redis集群
Redis 集群部署流程 前提:K8s+helm安装完成 1. 安装 NFS 服务器 1.1 安装 NFS 工具包 在 NFS 服务器上安装 nfs-utils 包: sudo yum install ...
- Windows 提权-PrintNightmare
本文通过 Google 翻译 PrintNightmare – Windows Privilege Escalation 这篇文章所产生,本人仅是对机器翻译中部分表达别扭的字词进行了校正及个别注释补充 ...
- 解决kali虚拟机无法联网问题
解决kali虚拟机无法联网问题 1.排查虚拟机网络连接-检查ipv4设置,确定好手动连接还是DHCP 如图一 2.排查虚拟网络编辑器-网卡配置,确定虚拟机直连外部网络是否为同一网口 如图二 3.排查虚 ...
- 下载文件,后端返回的是文件流,我们需要请求并下载到本地,发现下载后打开只有个undefined
在项目里做完上传,做下载的时候,把下载的文件打开,内容却时undefined,而且接口调用成功,但是postman校验接口时下载的文件正常的,那问题又出现在前端了. 我的前端代码如下图 前端代码的话我 ...
- 四大AI编程工具组合测评
在当今数字化浪潮中,AI 编程工具如雨后春笋般涌现,极大地提升了编程效率与体验.本文将详细剖析四类 AI 编程工具组合,从开发工具.大模型.插件搭配,到编程能力.费用体系及综合评价,为开发者提供全面 ...
- docker网络冲突解决(修改docker_gwbridge网段)
1·问题 一次生产搭建服务的时候,出现客户端服务器到docker服务断开不通的情况,在docker服务器上抓包可以抓到客户端服务器的包,但是docker服务器不做任何响应 于是ip route 查看本 ...
- 分析 AIX 和 Linux 性能的免费工具。
一.软件介绍1.分析工具nmon 工具可以帮助在一个屏幕上显示所有重要的性能优化信息,并动态地对其进行更新.这个高效的工具可以工作于任何哑屏幕.telnet 会话.甚至拨号线路.另外,它并不会消耗大量 ...