免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: 蔡万钊

一步步实现QBASIC编译器 [复制链接]

论坛徽章:
0
发表于 2012-11-20 17:06 |显示全部楼层
回复 1# 蔡万钊


    小弟也在学习编译器 跪求一个用c实现的LR语法分析器

论坛徽章:
2
摩羯座
日期:2013-10-10 14:29:04天蝎座
日期:2014-01-03 09:14:49
发表于 2012-11-20 17:24 |显示全部楼层
回复 2# 蔡万钊

稍微指出一下啊,呵呵,flex官方网页上是这么描述的:

Flex is a free (but non-GNU) implementation of the original Unix lex program.

我查了下源码,使用的不是GPL。


   

论坛徽章:
3
2015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:58:11数据库技术版块每日发帖之星
日期:2015-08-30 06:20:00
发表于 2012-11-20 21:47 |显示全部楼层
EricFisher 发表于 2012-11-20 17:24
回复 2# 蔡万钊

稍微指出一下啊,呵呵,flex官方网页上是这么描述的:


好, 谢谢! 我都没怎么关注 flex 到底是不是 gnu 的, 呵呵. 马上修改

论坛徽章:
0
发表于 2012-11-20 21:51 |显示全部楼层
支持 蔡蔡 ! 加油!

论坛徽章:
3
2015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:58:11数据库技术版块每日发帖之星
日期:2015-08-30 06:20:00
发表于 2012-11-20 21:52 |显示全部楼层
EricFisher 发表于 2012-11-20 17:24
回复 2# 蔡万钊

稍微指出一下啊,呵呵,flex官方网页上是这么描述的:



www.gnu.org/software/flex/

确实是 gnu 出品. 我没说是什么协议的, 我只说是  gnu 出品的, 呵呵. 不用改正了.

论坛徽章:
3
2015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:58:11数据库技术版块每日发帖之星
日期:2015-08-30 06:20:00
发表于 2012-11-20 21:58 |显示全部楼层
wgm001 发表于 2012-11-20 21:51
支持 蔡蔡 ! 加油!



ya ~~~ 那是

论坛徽章:
3
2015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:58:11数据库技术版块每日发帖之星
日期:2015-08-30 06:20:00
发表于 2012-11-21 00:25 |显示全部楼层

调用树

调用树

论坛徽章:
3
2015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:58:11数据库技术版块每日发帖之星
日期:2015-08-30 06:20:00
发表于 2012-11-21 21:23 |显示全部楼层
第三步骤 - 中间代码生成


llvm 是一个完善的编译器框架, 但这并不意味着, 你写了语法解析后就没事情做了

从 AST 生成 llvm 能使用的中间过程依然是一个充满挑战性的工作. llvm 是一个中间化的汇编语言, 意味着, 事实上你的代码生成器是在生成 llvm 汇编语言 , 所以依然是一个完备的编译器. 你如果觉得乐意, 完全可以不生成 llvm 汇编代码, 直接生成具体机器平台的汇编语言. llvm 的汇编语言依然是一个比较底层的语言. 和一般的汇编器不一样的是, llvm 的汇编器能对这个汇编语言进行 "优化" . 而其他平台的汇编器则需要编译器自己生成优化的结果. 注意, llvm 执行的优化是比较底层的, 专注于机器平台的, 比如 乘法指令转 SSE 指令, 指令重排序这样的优化. 语言层面的,如常量折叠, 死代码清除, 尾递归优化等 , 依然需要编译器作者进行优化. 所以千万不要认为有了 llvm 写编译器就是非常简单的事情了.

llvm 的好处就是可以专注于语言层面的实现和优化, 而具体机器指令层面的优化交给 llvm 来做, 分工协作.


生成 llvm 的代码有两种形式:

第一种是手动生成. 适用于实现编译器所使用的语言没有 llvm 可用的库的时候使用. 编译器生成文本格式的 llvm 汇编代码然后调用 llvm 汇编器生成本机代码.

第二种是使用 llvm 的 C++ 库.  llvm 提供了比较丰富的 类库用来简化 llvm 代码的生成.  我的QBASIC编译器就采用这种形式.


生成  llvm 代码的步骤非常简单, 为每个语法树节点调用 codegen 虚函数即可. 因为是虚函数, 所以调用基类的 codegen 会自动调用对应类的 codegen .


我在这里举一个加法表达式的 codegen


  1. llvm::Value * AddExprAST::Codegen( BasicBlocks * inserpoint)
  2. {
  3.     IRBuilder<>   builder(insertpoint); // 一个 LLVM 辅助库, 用来生成 llvm 代码

  4.     /// 因为加法这样的表达式是递归定义的, 所以 ...

  5.     LHS =  this->leftnode->Codegen(insertpoint); // 就像这里, 递归调用子节点, 获得的就是子节点生成的加法指令的结果的 llvm 寄存器的引用.
  6.     RHS = this->rightnode->Codegen(insertpoint);

  7. //  生成 llvm 加法指令. 并返回保存加法结果的寄存器的引用.
  8.     return     builder.CreateAdd( LHS, RHS); // 返回结果是 llvm::Value *  , 也就是一个 寄存器的引用.
  9. }


复制代码
注意 llvm 的 builder 构造一个加法(减乘除等都一样的啦) , 会生成(一系列, 有可能是一系列)的寄存器操作, 然后是加法指令, 然后是返回该加法指令的结果寄存器的引用

如果后续使用到了这个引用, 就告诉 llvm 的代码生成器, 要安排好这个寄存器的使用, 重新进入下一次运算操作哦 ~

llvm 实际上就是一个 寄存器分配器. 如果可用的寄存器不足, llvm 会自动生成压栈指令, 将一些暂时用不到的数据移出寄存器.

所以, 可以把 llvm 看成有无限个寄存器的机器. 这样像例子代码中的递归调用, 层层返回指令结果寄存器引用, 是可以的. llvm 生成机器代码的时候自动安排好寄存器的使用.







论坛徽章:
26
处女座
日期:2016-04-18 14:00:4515-16赛季CBA联赛之深圳
日期:2020-06-02 10:10:5015-16赛季CBA联赛之广夏
日期:2019-07-23 16:59:452016科比退役纪念章
日期:2019-06-26 16:59:1315-16赛季CBA联赛之天津
日期:2019-05-28 14:25:1915-16赛季CBA联赛之青岛
日期:2019-05-16 10:14:082016科比退役纪念章
日期:2019-01-11 14:44:062016科比退役纪念章
日期:2018-07-18 16:17:4015-16赛季CBA联赛之上海
日期:2017-08-22 18:18:5515-16赛季CBA联赛之江苏
日期:2017-08-04 17:00:4715-16赛季CBA联赛之佛山
日期:2017-02-20 18:21:1315-16赛季CBA联赛之天津
日期:2016-12-12 10:44:23
发表于 2012-11-22 18:48 |显示全部楼层
挖 牛人啊, 我倒是想参考你的设计做一个 javascript 编译器了

论坛徽章:
0
发表于 2012-11-23 11:51 |显示全部楼层
回复 19# evaspring


    我发现好多人都想做js的编译。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP