这是上学期写的东西了,debug那里写得过于简单了,其实我找了四五天bug,有过好多,来不及记下来。现在仅供参考。(2022.1.9)


去年调了龙芯杯,今年调编译器,马上就要ddl了,我感觉我差不多要死了。
什么才算独当一面呢?我什么时候才能成为独当一面的忍者呢?

文章目录

  • 一、做编译器前端的过程
    • AST
    • flex-bison工具
    • 实现思路
      • 结构体定义
    • 一些知识
      • sprintf
      • char*
      • Makefile相关
      • graphiz工具使用方法
      • 某些冲突的解决
  • 二、debug过程
    • 第n个bug
      • 现象
      • 思考
      • 解决过程和结果
    • 第n+1个bug
      • 现象
      • 解决
    • 第n+2个bug
      • 解决
    • 第n+3个bug
      • 起因
      • 分析
      • 解决
  • 三、推荐书目
  • 四、后记:悟道

一、做编译器前端的过程

老师的要求是:生成ast还有四元式(线性IR)

AST

首先我就不知道ast该咋画,我基本找了全网有图的所有ast,排列如下(大家不用费心继续找了,因为网上的图都一个样,就是全不全的问题 ):

flex-bison工具

这个工具的使用

实现思路

结构体定义

一些知识

遇到很多问题,C语言边用边查(大一的时候就没记住什么库函数——因为我忘性实在是太好了)

sprintf

对于将字符串和数字合并,我扒拉了全网,翻了一些书,总结了一些方法

char*

字符串数组使用时应该注意什么呢?我也总结了一下。

Makefile相关

这个还有一些零碎的知识(我问的老师,算是一些小台阶),看这篇文章。

graphiz工具使用方法

同志们,f ge q吧,wai net资料真的良心
文章一、关键词:
文章二、关键词:
文章三、关键词:
很久以后(在程序宕掉多次之后)我才知道,如何打印特殊字符“+ - * /”,就是把它们用双引号引起来

某些冲突的解决

朋友,你见过minus和nminus的写法吗?

二、debug过程

从第n个bug开始(n>5),有时间的话再补之前的

第n个bug

现象

思考

解决过程和结果

现在是6月20号的晚上九点半
第一张能正经地画出来的图:

第n+1个bug

现象

可以看到上面那个图不怎么样:

  1. 我的函数里对于符号这个东西,T_IDENT归做一类,序号递增,但是此处看起来就及其别扭(main和后面的abc甚至是赋值语句里的a都有增长序号,但是没有区分)
  2. 原本Localdef的地方写的是global_define
  3. 还有那个array_1,那个位置本该是赋值语句,没有等号就算了,没有数字也就算了,咋还多个array?

但是还是要夸一下:基本框架和父子关系倒是出来了;而且可视化成功对于之后的调试会很有帮助;而且我学到了一个调试的小方法——bug砸下来,我就是gdb!(手工产生式推导)

解决

大早晨起来改了改代码,它就给我宕掉了。改的是打印树的逻辑。查找bug的时候添加了观察点,对于程序的pre-mid-aft都有分隔,对于每个if分支语句都如此,这样的结果是找到了最终宕掉的地方以及bug所在。

另外,关于那个莫名的factor和array,在产生式中采用输出的方式发现本会出现那个东西的位置并没有走过,所以猜测不是产生式走到不该走的地方,而是输出的时候有问题。忘记当时怎么造的table表了,但是对比了一下table和enum中的各项,发现少了一个!错位了!就这样,程序居然还能运行,我也是醉了!(我是不是可以靠写bug,然后debug,然后给大家观赏我的脑残过程娱乐大家来赚钱呢? )

第n+2个bug

对于测试代码

int main()
{int a,b,c;a = 3;b = 3+4;
}

可以看出,虽然array改了,但是,那个factor还是让人不太舒服,不过现在已经不怎么影响强迫症了,强迫症现在要解决的是,这玩意儿咋不按照预定的输出?输出我的赋值变量呢?

解决

找到原因了,其实不算bug,只是输出有点问题

错误是onevone_replace(),每次都是简单地改一下标签,然后就把叶结点和根节点替换掉,设计思想本来是想着ast有抽象的重任,要把那些乱七八糟的中间文法改造带来的乱七八糟的表签屏蔽掉,但是该屏蔽的屏蔽了,不该屏蔽的也被我屏蔽掉了。
另外补充一点,这个函数,出过不下三次错了,每次程序都因为这个出一些莫名的错,这除了和这个函数应用广泛有关外还和这个函数本身考虑不够全面有关——一个本该适用广泛的函数却泛化能力不强,灾难就来了。
这其实也有点软件工程那个二八定律的意思了,百分之八十的错,来自这百分之二十的代码。
现在的它被我改为了:

struct ast_node* onevone_replace(struct ast_node* node, struct ast_node* node1, int type, char* name)
{if(node1 != nullptr){node = node1;if(node1->ast_type != NUM && node1->ast_type != REAL){node->ast_type = type;node->ast_name = name;}        }else{node = nullptr;}return node;
}

这样一种形式。其实,这样模块简直是软件工程中的偶然内聚,最不提倡的那种!希望我的软工老师不要看到我写的这个代码。

第n+3个bug

起因

顺手修了几个小bug,关于输出yacc和lex中的自带的那些变量,.dot文件不支持±*/=这些玩意儿,所以我改了一波。

正当我自鸣得意,觉得这些东西都正常输出了的时候,我发现,那个global又出来了,翻看前一张图片,也是有这个global的,也就是加了global_arraytail,不错位了之后,本该在这里的东西就出现了(妖孽!现出原形吧! )

分析

  1. 这意味着:我一开始对产生式的理解有点问题,我要看看写着global的地方是不是global的
  2. 你看着这个树,它够抽象吗?

我想,我应该解决两个问题:

  1. 产生式global不global
  2. 多进行几个测试用例的测试,总体来看,产生的树的情况,然后总体来改,那个抽象不抽象的问题

解决

首先,把第一个功能点的图展示一下:

我们可以看到,应该把assignstat的子语句中的factor去掉;global_paradata其实也该去掉,这算一个没用的中间层。(为什么会有这么多没用的中间层! )

另外,我突然想到,应该把LOP和ROP都拆开,写成++和–的形式,这样才好显示语法树,可能写四元式的时候也会方便些。
还有那么多测试用例没有过……包括我觉得观感最不好的if-else语句,不晓得之后还需要多久。

  1. 对于global的去除:

  2. 对于factor的去除:

<asstail> → '='  <assexpr>  <asstail> | ε
<orexpr> → <andexpr> <ortail>
<ortail> → '||' <andexpr> <ortail> | ε
<andexpr> → <cmpexpr> <andtail>
<andtail> → '&&' <cmpexpr> <andtail> |  ε
<cmpexpr> → <aloexpr> <cmptail>
<cmptail> → <cmps> <aloexpr> <cmptail>| ε
<cmps> → '>=' | '>' | '<' | '<=' | '==' | '!='
<aloexpr> → <item> <alotail>
<alotail> → <addsub> <item> <alotail> | ε
<addsub> → '+' | '-'
<item> → <factor> <itemtail>
<itemtail> → <muldiv> <factor> <itemtail> | ε
<muldiv> → '*' | '/'
<factor> → <lop> <factor> | <val>

这段涉及到一连串的加减和逻辑运算,本来想着这些会比较难,看起来应该不舒服,也不容易看懂,但是我突然抓住了几个关键点:
从assignstat出发,到factor附近找错即可对于类似于以下的结构,那个xxxtail其实是不用管的,因为要是有它,其实就得出现||之类的东西

<orexpr> → <andexpr> <ortail>
<ortail> → '||' <andexpr> <ortail> | ε

于是我一路找到我写的这段代码:

Factor : //表达式啊表达式,分优先级的表达式,此处为最高的一级MINUS Factor %prec UMINUS{$$ = alloc_astnode(MINUS, strdup($1));$$->son_node[0] = $2;$2->parent = $$;} | LOP Factor{$$ = alloc_astnode(LOP, strdup($1));$$->son_node[0] = $2;$2->parent = $$;} | Val {$$ = onevone_replace($$, $1, FACTOR, nullptr);};

看完我乐了,好嘛,又是onevone_replace()小宝贝!让我来用科学的方法评估一下,会不会按下葫芦浮起瓢,看到上面抽象语法树里,factor这些产生式明显都有些问题,但是问题顶多有两类:一类是它本身的问题,一类是它给它的父亲们造成的问题。
我想到了早上学的软件工程,它说,尽量改动最小化,对于这个问题,要想最小化改动,我想只有把Factor->Val那条式子改下了(这样不会影响到全局的问题):

| Val {$$ = $1;}

首先看下这样改的结果对不对,再回头审视一下上一个bug可否这样改动(这样就影响最小了)。
结果矛盾转移了,发现还是上一个bug没改好,其实应该把关于Elem的产生式中的动作改一下的。

修改结果如下:

Val : //方括号指的是可扩展项,但是我总感觉它和{}除了递归定义就没区别了Elem {$$ = $1;}


555,这个ast好清爽!虽然我感觉expr那个还是一个阴影,不过要是这种表达式之后统一是expr了的话也算很好的结果了——这样可能对线性IR产生就有好处了。
该吃晚饭了!
等会儿边复习软工边过完功能点看看,该思考符号表的事情了(还有关于“一个节点的名称和属性不是同一个”的问题,看看对应的可以怎么解决。)

三、推荐书目

《flex与bison中文版》
《Makefile》(从github上下载)

《编译原理(龙书第2版)》
《编译原理及实践》


四、后记:悟道

  1. 武功是什么样子,对不懂的人来说,大概就像看到武侠片里那种打斗场景,嘿吼一下,就像放了个二踢脚一般的特效,课本不救小白,实践操作书里其实也不针对小白,小白是连数据结构的定义刚开始都模模糊糊的那种白。所以我才想写博客,记录一下每段历程,从小白到不那么白的过程,也算留下了点什么。
  2. 从大一开始,我就对自己的能力和对自己的代码有着深深的不信任感,不敢尝试,不敢犯错,但是这种感觉近一年渐渐收束了,这不仅是能力提升,还有心态提升,我更加敢于坚定地推进自己的工作,遇到bug找bug,而不是畏手畏脚,遇到困难就想撤退换路。大概是更加从容和无畏了。(这种从容和无畏大概来源于学分绩正好离门槛差一点,正好我又想考研,所以那种过分在意就没了 )
  3. 如果你感觉眼大漏光找不到错误,你可能需要减小字体,使每页为25行左右代码。
  4. 可视化对于调代码真的超级有用!越明显的可视化越好!

最后,要吹爆zlj老师,太负责任了,不论是做的过程的指导,还是检查的时候的认真,还有心慈手软 ……
记得有天我把问题发到实验群里,老师立刻一个电话过来问我问题是啥,虽然上别的课摸鱼的我(欠打)给老师挂了,但是后来早晨八点老师给我讲了一个多小时,不管我多菜老师都没放弃我。

西北工业大学 编译原理实验 minic文法 编译器前端 flex-bison实现 的 debug手记相关推荐

  1. 编译原理上机实习c语言小子集编译程序的实现报告,合肥工业大学编译原理实验报告(完整代码版)...

    <合肥工业大学编译原理实验报告(完整代码版)>由会员分享,可在线阅读,更多相关<合肥工业大学编译原理实验报告(完整代码版)(58页珍藏版)>请在人人文库网上搜索. 1.计算机与 ...

  2. 北航2021编译原理实验样例编译器-PCODE实现总结

    Pcode编译器实验总结 前言 历时一个月实现了满足SysY文法,生成目标代码为Pcode的编译器.下面是笔者按照编译器实验流程:词法分析.语法分析.错误处理.中间代码生成和目标代码生成等五个阶段,总 ...

  3. 编译原理实验二、 编译器认知实验报告

    目录 一.实验目的 二.实验内容 三.实验环境 四.数据准备 五.实验过程描述

  4. 编译原理实验c语言cfg文法,编译原理

    地址在符号表中引入指针previous,来连接上一个符号的首地址运行时存储空间组织活动记录用于管理函数变量的信息栈式存储过程进入和返回通过变更top和sp指针,实现活动记录的栈式处理静态链实现局部变量 ...

  5. 编译原理实验 -- 文法分析

    编译原理实验 – 文法分析 终结符 和 非终结符 终结符 通常使用小写字母表示,例如 abcdef 非终结符 通常使用大写字母表示,例如 ABCDEF 产生式 通俗来说,就是由终结符和非终结符组合成的 ...

  6. 跟vczh看实例学编译原理——三:Tinymoe与无歧义语法分析

    文章中引用的代码均来自https://github.com/vczh/tinymoe. 看了前面的三篇文章,大家应该基本对Tinymoe的代码有一个初步的感觉了.在正确分析"print su ...

  7. 跟vczh看实例学编译原理——一:Tinymoe的设计哲学

    自从<序>胡扯了快一个月之后,终于迎来了正片.之所以系列文章叫<看实例学编译原理>,是因为整个系列会通过带大家一步一步实现Tinymoe的过程,来介绍编译原理的一些知识点. 但 ...

  8. 编译原理实验:代码生成作业(1)

    编译原理实验4:中间代码生成实验包-C++文档类资源-CSDN下载编译原理实验4:中间代码生成实验包更多下载资源.学习资料请访问CSDN下载频道.https://download.csdn.net/d ...

  9. 编译实验 lr c语言代码,编译原理-实验5-LR(1)分析法

    <编译原理-实验5-LR(1)分析法>由会员分享,可在线阅读,更多相关<编译原理-实验5-LR(1)分析法(6页珍藏版)>请在人人文库网上搜索. 1.编译原理实验报告项目名称 ...

  10. 编译原理实验二:Bison

    编译原理实验二:Bison 实验要求 1.了解Bision基础知识,如何将文法产生式转换为Bison语句 2.阅读/src/common/SyntaxTree.c,对应头文件 /include/Syn ...

最新文章

  1. Android踩坑日记:RecyclerView中EditText和ImageView的ViewHolder复用坑
  2. 库函数、系统调用和内核函数的区别
  3. 纯js实现人脸识别眨眨眼张张嘴案例——alive_face.js
  4. 【codevs1262】不要把球传给我,非常无语的一道题目
  5. JavaScript中的(内置)方式来检查字符串是否为有效数字
  6. Microsoft Excel设置单元格下拉框的方法
  7. C语言程序设计(谭浩强)学习总结
  8. 最新QQ勋章墙+防撤回V9.6.1版本+实测可用
  9. ildasm、ilasm修改、反编译 已经编译的 dll文件(c#)
  10. T3 登陆报错 3709
  11. 学习笔记3--车载传感器之毫米波雷达和超声波雷达
  12. 免费域名邮箱如何申请?怎么给国外发邮件?
  13. PowerDesigner如何自定义报表模板
  14. centos7 ipv4配置
  15. 拆弹专家(密码BFS)
  16. c语言中矩形法求定积分
  17. 3d在线展示_手表三维商品展示解决方案
  18. 使用 Entrust 扩展包在 Laravel 5 中实现 RBAC 权限管理与安装配置
  19. 红帽Linux安装Mysql
  20. 2022单片机筑基教程

热门文章

  1. 大气数据计算机仿真算法,自适应光学系统中大气湍流的模型分析与计算机仿真...
  2. 声卡中的 line in line out
  3. mac安装win10_mac磁盘空间 mac安装win10分割多少磁盘空间合适
  4. 【学习笔记】统计学入门(5/7)——二项分布
  5. DIY的U盘量产CD-ROM做PE启动盘教程(银灿IS903-A4主控+东芝SLC颗粒)
  6. 物联网工程毕业设计简介
  7. html5调用js播放视频,h5+js实现视频播放的方法
  8. matlab动刚度仿真,基于ANSYS的转子支承动刚度计算分析.doc
  9. Matlab 的fspecial函数用法
  10. MLAPP————第十四章 核方法