【HUST】网安|编译原理实验|实验四攻略
【实验代码及报告地址:Gitee传送门】
不擅长写报告昂,很多地方能省全省了。
助力来年编译原理加大难度!(hhh)
MiniC语法分析及中间代码生成
我根据我的实验报告重置了攻略。
贴个完成时间。
文章目录
- MiniC语法分析及中间代码生成
- 实验内容
- 实验过程
- LLVM IR初识
- LLVM IR API
- 语义分析与中间代码生成(一)
- 难点
- 调试技巧
- Quick Start
- 正式开始
- 1. astnode.cpp需要修改的函数
- 2. astnode.h需要修改的函数
- 3. 一个分析过程
- 4. 举几个典型的例子
- 4.1. 各种List
- 4.2 错误判断
- 语义分析与中间代码生成(二)
- 1. astnode.cpp需要修改的函数
- 2. 难点
- 2.1 一些函数
- 2.2 NArgs如何解析
- 3. 错误判断
- 语义分析与中间代码生成(三)
- 1. astnode.cpp需要修改的函数
- 2. astnode.h需要修改的函数
- 3. 分析思路
- 3.1 if-else结构
- 3.2 变量的作用域问题
- 3.3 或运算||的解析
实验内容
将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】网安|编译原理实验|实验四攻略相关推荐
- 《编译原理》实验报告——递归下降语法分析器的构建
一.实验要求 运用递归下降法,针对给定的上下文无关文法,给出实验方案.预估实验中可能出现的问题. 二.实验方案 1.构造LL(1),通过设计.编制.调试递归下降语法分析程序,对输入的符号串进行分析匹配 ...
- 《编译原理》实验教学大纲
<编译原理>实验教学大纲 课程编号: 773033 课程名称:编译原理 英文名称:Compiler Principle 课程类型: 模块课 学 时:5 学 分:4 适用对象: 软件开发各专 ...
- 【SEUSE】编译原理 - 词法分析器实验报告
[SEU&SE]编译原理 - 词法分析器实验报告 README 一. 实验目的 二. 实验环境 1. 开发环境: 2. 运行环境 三. 实验内容 1. 主要内容 2. 主要功能 3. 种别码 ...
- 编译原理:实验一练习
编译原理:实验一练习 词法分析器 编译原理实验报告 上面的第一个链接中的词法分析器有一点问题,修改后的代码如下: #include "string.h"#include " ...
- c语言的适当大小的子集,编译原理上机实验报告
编译原理上机实验报告,编制C语言子集的词法分析程序,编制递归下降法的语法分析程序 编译技术上机实验题目 实验一 一.题目 编制C语言子集的词法分析程序 二.目的 通过设计.编制.调试一个具体的词法分析 ...
- c 语言编写编译原理语义分析实验,北邮 编译原理 语义分析实验报告
<北邮 编译原理 语义分析实验报告>由会员分享,可在线阅读,更多相关<北邮 编译原理 语义分析实验报告(14页珍藏版)>请在人人文库网上搜索. 1.编译原理第六章 语义分析目 ...
- c++实现编译原理词法分析实验(含代码)
c++实现编译原理词法分析实验(含代码) 一.实验目的: 通过设计编制调试一个具体的词法分析程序,加深对词法分析原理的理解.并掌握在对程序设计语言源程序进行扫描过程中将其分解为各类单词的词法分析方法. ...
- 设计师:设计师知识储备(硬装、软装、榻榻米、马卡龙、地台、公共空间、玄关、闭水实验)之详细攻略
设计师:设计师知识储备(硬装.软装.榻榻米.马卡龙.地台.公共空间.玄关.闭水实验)之详细攻略 目录 设计师知识储备(硬装.软装.榻榻米.马卡龙.地台.公共空间.玄关.闭水实验) 硬装
- 合宙Luat | 最新网红Cat.1开发板全攻略【使用教程+注意事项+设计图纸】
合宙Luat | 最新网红Cat.1开发板全攻略[使用教程+注意事项+设计图纸] 使用指南目录参考 特别注意事项 常见问题Q&A 很多朋友认识合宙,都源于合宙的Cat.1系列产品.Air724 ...
- VS2015编译TensorFlow C++程序完全攻略
VS2015编译TensorFlow C++程序完全攻略 本文参考和综合了多篇网络博客文章,加以自己的实践,最终终于在windows环境下,编译出可以用于C++程序调用tensorflow API的程 ...
最新文章
- android studio 导入库提示失败的处理方法以及androidstudio 清理缓存的方法
- 用例设计大全(整理)
- 隐藏滚动条,保留鼠标滚动效果
- java填空题 在非静态成员方法中_成本加成定价法的优点有
- java之点击一次之后失效_JavaScript 事件绑定只能执行一次了,再次点击就变得无效 ,求助怎么回事...
- 若依前后端分离部署到tomcat中详细教程
- mysql.8.0.13ZIP安装教程_关于mysql 8.0.13zip包安装方法
- Java字符串查找第一个不重复字符_java如何实现获取字符串中第一个出现不重复的字符...
- 超级复制shadowcopy
- PROFINET 链路简述
- linux下 fat32转ntfs,NTFS和FAT32区别和转换
- db_LINK详解东子
- ubuntu 16.04.7通过get-pip.py安装pip 20.3.4
- JVM生态系统2018调查报道
- 刚刚手贱把D盘设置为活动分区,导致无法进系统。来看看我的解决方法
- 大学物理(上)期中考试参考答案
- 【_ 記 】各类邮箱POP3和SMTP服务器地址和端口
- 基于FPGA的卷积神经网络实现(七)数据读写
- 日期加减天数计算,时间戳日期相互转换
- 青云霍秉杰:一文读懂Prometheus长期存储主流方案
热门文章
- 极域电子书包课堂管理系统
- goahead 的认证和自定义登陆页面的cookie使用
- mysql proxy maxscale_maxscale参数配置
- 免费而优秀的图表JS插件、js图表、html图表--百度的Echart、Highcharts、阿里的G2、Chart.js
- jenkins下载插件很慢
- springboot+quartz定时任务
- 随机过程 - 马尔可夫链
- PLC梯形图设计全自动洗衣机S7-1200博途以及PLC仿真实现之 1. 创建新工程
- 华为hicar支持车型列表_汽车大观| 华为的“汽车梦”
- python 实现 责任链模式