开发自己的编程语言(五)—— 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是一个终结符,就调用字符串求值。

分析过程如下:

  1. 如果是 if 表达,肯定有一个跳转语句,语句有两部分组成ifnode和跳转标签IFLabel:TR(ifnode) + TR("IFEnd");
  2. ifnode由两部分组成,括号表达式和块表达式:TR(parent_expr) + TR(Block_expr);
  3. parent_expr:TR(Number1) + TR(Opt) + TR(Number2)。由于在汇编中两个操作符必须先压栈,然后调用操作符。所有表达式的过程如下:
  4. parent_expr:TR(Number1) + TR(Number2) + TR(Opt)。现在例子中的数据为TR(1) + TR(2) + TR("<")。
  5. 1和2是操作数需要压栈:TR("ldc.i4 1") + TR("ldc.i4 2") + TR("bgt IFLabel")。这一步表示对两个操作数压栈,然后进行比较:如果number1 > number2,则不执行Block_expr,直接跳转到ifnode的结尾,也就是IFLabel。
  6. 对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