开发自己的编程语言(五)—— CIL中间代码的生成
来源:互联网 发布:现货投资交易软件 编辑:程序博客网 时间:2024/05/22 02:23
在编译原理中,最难的步骤应该是代码的优化。只有通过不停的优化代码才能得到更好的性能,而性能又是商业编译器的重要指标。这一切就注定了码优化是一个没有止境的过程。但是对于不争早夕的初级语言来说,这一步骤就显得可有可无,因为有足够的时间让我去等待一个结果的出现。就像我花了很长很长的时间去等待斐波那契第30个结果的出现,而一个经过优化的编译器能在很短的时间内完成计算。
除了代码的优化,中间语言的生成好像也是一根难啃的骨头。Snail Language的最终目标是成为一款.NET语言,所以将自己编译成CIL的过程也在所难免。在我实现编译器之前,我对中间语言生成的步骤一直处于雾里看花终隔一层。但随着实践的深入,有一朝我突然顿悟:将snail language翻译成CIL,其实就是用CIL实现当前的语义;和将snail language翻译成java、C的过程是一致的;翻译的过程不存在一个标准的教程,好坏都凭作者对语言的理解能力和写代码的功力。于是乎,我开始了自己的试验。
我的目标是翻译Snail Language的一小段特定的代码到CIL。(目前的release版本只支持下面片段)
Snail Language:
if(1 < 2){ print(100)}
我们用TR()函数对表达式进行翻译,TR函数有两个重载TR(node)和TR("string"),一个对节点进行递归操作,如果当前node是一个终结符,就调用字符串求值。
分析过程如下:
- 如果是 if 表达,肯定有一个跳转语句,语句有两部分组成ifnode和跳转标签IFLabel:TR(ifnode) + TR("IFEnd");
- ifnode由两部分组成,括号表达式和块表达式:TR(parent_expr) + TR(Block_expr);
- parent_expr:TR(Number1) + TR(Opt) + TR(Number2)。由于在汇编中两个操作符必须先压栈,然后调用操作符。所有表达式的过程如下:
- parent_expr:TR(Number1) + TR(Number2) + TR(Opt)。现在例子中的数据为TR(1) + TR(2) + TR("<")。
- 1和2是操作数需要压栈:TR("ldc.i4 1") + TR("ldc.i4 2") + TR("bgt IFLabel")。这一步表示对两个操作数压栈,然后进行比较:如果number1 > number2,则不执行Block_expr,直接跳转到ifnode的结尾,也就是IFLabel。
- 对print表达式,也要做节点求值顺序的变换:TR(number) + TR(printnode)。我们知道print的操作数为int,所以就用call void[mscorlib]System.Console::WriteLine(int32)替换print语句。
得到的CIL结果:
ldc.i4 1ldc.i4 2bgt IFEndldc.i4 100call void [mscorlib]System.Console::WriteLine(int32)IFEnd:
验证结果:
将上面的CIL片段,放入CIL文件中。
.assembly extern mscorlib {}.assembly Test{.ver 1:0:1:0}.module test.exe.method static void main() cil managed{ .maxstack 3 .entrypoint ldc.i4 1 ldc.i4 2 bgt IFEnd ldc.i4 100 call void [mscorlib]System.Console::WriteLine(int32)IFEnd:Exit: ret}
执行CIL:
我们用ilasm.exe编译Snail Language生成的CIL。ilasm是一个MS提供的可执行文件,用于将CIL文件编译成exe文件。实验结果和我们预期的一致。
- > ilasm test.il
- > test.exe
- ==> 100
两种实现方案:
将Snail Language编译成CIL,有两种可选的方案。第一:将Snail用上述的方式打包成exe文件。第二,对于生成的CIL文件,我们不直接打包成exe,而是用snail从新解析执行CIL,得到运行结果。第一种方案完全依赖于.NET runtime,而不需要自己去解析代码的逻辑。第二种方案比较灵活,以后可以进一步脱离.NET,实现自己的虚拟机。
软件下载:
http://download.csdn.net/detail/u012813593/6844057
选择生成中间语言:菜单 -> 编译 -> 中间语言(打勾)
测试代码:
if(1 < 2){ print(1)}else if (2 < 3){ print(3)}else{ print(4)}
结果:
ldc.i4 1ldc.i4 2bgt IfEnd1ldc.i4 1call void [mscorlib]System.Console::WriteLine(int32)br ElseEnd1IfEnd1:ldc.i4 2ldc.i4 3bgt IfEnd2ldc.i4 3call void [mscorlib]System.Console::WriteLine(int32)br ElseEnd2IfEnd2:ldc.i4 4call void [mscorlib]System.Console::WriteLine(int32)ElseEnd2:ElseEnd1:
目前还只有实现上述简单的代码,如果其他代码有bug,请关注后期修改。
1 0
- 开发自己的编程语言(五)—— CIL中间代码的生成
- CIL(通用中间语言)
- CIL中间语言浅谈
- CIL----公共中间语言
- CIL----公共中间语言
- 开发自己的编程语言(九)—— 生成EXE文件
- 编写自己的代码生成工具五:代码生成实现
- 开发自己的编程语言(一)
- 开发自己的编程语言(二)
- 开发自己的编程语言(三)
- 开发自己的编程语言(四)
- 开发自己的编程语言
- 软件动态更新技术总结之1 CIL:程序分析与变换的中间语言工具(sec0-sec3)
- [C#]一步一步开发自己的自动代码生成工具之五:DAL层模板
- 开发自己的编程语言(七)—— 字典数(相关联数组)
- 开发自己的编程语言(六)—— First-Class Value
- 开发自己的编程语言(八)—— 在Snail中调用C#函数
- CIL之——field的存储与加载
- 平时学习心得
- 影星在南京拍跳桥大戏 市民不知情纷围观劝说(图
- Android上传文件到服务器--带进度条
- Android 70道面试题汇总不再愁面试
- 【Java】抽象类的几点误区
- 开发自己的编程语言(五)—— CIL中间代码的生成
- unity 3D登录界面C#脚本
- 线程池的原理和连接池的原理
- java文件路径操作详细
- 推荐决策之协同过滤
- 浅析 微信公共平台消息 开发原理
- VisualSVN Server安装时无法启动服务的解决
- 数据结构之双线链表
- highcharts useUTC:针对xAxis的type为datetime类型