您的位置:首页 > 编程语言

开发自己的编程语言(五)—— CIL中间代码的生成

2014-01-13 15:36 423 查看
    在编译原理中,最难的步骤应该是代码的优化。只有通过不停的优化代码才能得到更好的性能,而性能又是商业编译器的重要指标。这一切就注定了码优化是一个没有止境的过程。但是对于不争早夕的初级语言来说,这一步骤就显得可有可无,因为有足够的时间让我去等待一个结果的出现。就像我花了很长很长的时间去等待斐波那契第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 1
ldc.i4 2
bgt IFEnd
ldc.i4 100
call 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 1
ldc.i4 2
bgt IfEnd1
ldc.i4 1
call void [mscorlib]System.Console::WriteLine(int32)
br ElseEnd1
IfEnd1:
ldc.i4 2
ldc.i4 3
bgt IfEnd2
ldc.i4 3
call void [mscorlib]System.Console::WriteLine(int32)
br ElseEnd2
IfEnd2:
ldc.i4 4
call void [mscorlib]System.Console::WriteLine(int32)
ElseEnd2:
ElseEnd1:

目前还只有实现上述简单的代码,如果其他代码有bug,请关注后期修改。

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  编译器 中间语言 CIL