.NET编译之语法解析
13 Feb 2012你首先看见的是对当前方法的IL声明,其中包括方法的名字,返回类型、参数列表以及附着于该方法的其他修饰关键词(static/shared、public、virtual等等)。对象构造器则被赋给一个特殊的名字:.ctor。
在IL中,方法参数按照它们在参数列表中的位置依次被引用。如果方法是静态或共享方法,那么参数0则是参数列表中的第1个参数。而对实例方法来说,参数0则是指向该方法所在类的实例的指针(Me或者this)。方法中的所有局部变量都在.locals标记的段落中以同样的方式声明。
在声明所有的局部变量以后,程序的实际正文才开始。每条IL指令,或opcode都可以根据你的喜好以一个IL_ 标记作为代码行开头。我们接下来再了解些更重要的IL指令。
变量用法
以LD开头的指令把变量从内存装载到堆栈供其操作。装载指令有若干条,每一条装载指令都操作特定类型的变量。以下就是其中的一些装载指令:
LDC把一个数字常数装入堆栈。这条指令有两个修饰词。第一个是类型标识符,第二个是实际的数值。
LDLOC把一个局部变量装入堆栈。另外还有一条LDLOCA指令把一个局部变量的地址(而非变量的内容)装入堆栈。变量由它们在.locals节的位置标识。这些指令装载位置4及以后位置使用不同的语法,但是索引号会出现在指令中。
LDARG装载成员的一个参数,而LDARGA指令则装载参数的地址。变量由它们在.locals节中的位置标识。这些指令装载位置4及以后位置使用不同的语法,但是索引号仍然出现在指令中。
LDELEM把数组元素装入堆栈而且通常先于表示这个索引的其他装载语句之前使用。
LDLEN把一个数组的长度装入堆栈。
LDFLD和LDSFLD把类域(成员变量)和静态类域装入堆栈。域由一个全名识别。
每一条装载指令都有对应的一条存储指令,后者以ST开头,负责把一个条目存入内存。例如,STLOC就负责把堆栈最顶端的条目存入一个局部变量。存储指令指定变量的句法规则通常和它们对应的装载指令类似。
比较操作
如果你不能比较两个值而且根据其比较结果做出决定,那么许多问题都无法用任何程序语言来解决。IL有一套比较操作符,它们都以C字母开头,比较堆栈中的值。通常,如果比较结果为真则会把1推入堆栈否则就推入0。
大多数这类指令都很容易由它们的名字区分出来。例如,CEQ比较两个值是否相等,而CGT则确定堆栈最顶端的值是否比第二个最顶端值更大。 CLT类同于CGT,不过执行的是小于比较操作。
Goto
通常,在对两个值进行比较之后会根据比较的结果结果实施一些操作。IL分支指令(以BR开头)根据堆栈最顶端的条目中的内容跳到其他指令。BRTRUE 和BRFALSE弹出堆栈最顶端的条目,然后根据该项为真(1)还是为假(0)而分别跳到指定的代码行。如果没有执行指令跳跃则继续执行下一条指令。另外还有一个无条件分支操作符BR,它总是跳到指定的代码行。
你会发现分支操作就好像源代码中的if语句以及显式执行的Goto操作。IL中的分支命令同样具有高级流程控制结构的对等体,比如:if, case, while, for等等。
创造新对象和调用其他代码
CALL和CALLVIRT指令调用其他方法和函数。CALL通常表示被调用的方法是静态的或共享的,而CALLVIRT则用于实例方法。就两种指令来说,方法的名字都会在指令中包括。被送到方法的任何参数都会被弹出堆栈而且要在方法被调用之前装载。
因为创建一个新对象需要调用构造器,所以IL的对象创建也类似于其他的方法调用。参数首先被装载到堆栈,然后执行NEWOBJ指令,它调用对象的构造器同时把对象的索引放回堆栈。指令中得有对象的名字。
**
下边的是一点简短的代码和对应的IL
using System.Collections.Generic;
using System.Linq;
using System.Text;namespace test1
{
class Program
{
static void Main(string[] args)
{
StringBuilder z=new StringBuilder(“zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz”,20);
int zz = 11;
double x = 12;
Console.WriteLine(z);
Console.Write(zz);
Console.Write(x);
for (int i = ; i < 10;i++ )
{ x.ToString(); }
Console.Write(x);
Console.ReadLine();
}
}
}</p>
IL
{
.entrypoint
// 代码大小 91 (0x5b)
.maxstack 3
.locals init ([] class [mscorlib]System.Text.StringBuilder z,
[1] int32 zz,
[2] float64 x,
[3] int32 i,
[4] bool CS$4$0000)
IL_0000: nop
IL_0001: ldstr “zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz”
IL_0006: ldc.i4.s 20
IL_0008: newobj instance void [mscorlib]System.Text.StringBuilder::.ctor(string,
int32)
IL_000d: stloc.
IL_000e: ldc.i4.s 11
IL_0010: stloc.1
IL_0011: ldc.r8 12.
IL_001a: stloc.2
IL_001b: ldloc.
IL_001c: call void [mscorlib]System.Console::WriteLine(object)
IL_0021: nop
IL_0022: ldloc.1
IL_0023: call void [mscorlib]System.Console::Write(int32)
IL_0028: nop
IL_0029: ldloc.2
IL_002a: call void [mscorlib]System.Console::Write(float64)
IL_002f: nop
IL_0030: ldc.i4.
IL_0031: stloc.3
IL_0032: br.s IL_0042
IL_0034: nop
IL_0035: ldloca.s x
IL_0037: call instance string [mscorlib]System.Double::ToString()
IL_003c: pop
IL_003d: nop
IL_003e: ldloc.3
IL_003f: ldc.i4.1
IL_0040: add
IL_0041: stloc.3
IL_0042: ldloc.3
IL_0043: ldc.i4.s 10
IL_0045: clt
IL_0047: stloc.s CS$4$0000
IL_0049: ldloc.s CS$4$0000
IL_004b: brtrue.s IL_0034
IL_004d: ldloc.2
IL_004e: call void [mscorlib]System.Console::Write(float64)
IL_0053: nop
IL_0054: call string [mscorlib]System.Console::ReadLine()
IL_0059: pop
IL_005a: ret
} // end of method Program::Main
转载请注明:于哲的博客 » .NET编译之语法解析