Разработка компиляторов

       

Генерация кода: условный оператор


Далее мы генерируем условный оператор, исключение и завершаем цикл:

Label Next = il.DefineLabel(); il.Emit (OpCodes.Ldloc, var_i); il.Emit (OpCodes.Ldc_I4, 10); il.Emit (OpCodes.Bne_Un_S, Next);

Type[] no_types = new Type [0]; il.Emit (OpCodes.Newobj, typeof (System.Exception).GetConstructor (no_types)); il.ThrowException (typeof (System.Exception)); il.MarkLabel (Next);

il.Emit (OpCodes.Ldloc, var_i); Type [] arg = new Type [1]; arg [0] = typeof (int); MethodInfo writeLine = typeof(System.Console).GetMethod ("WriteLine", arg); il.EmitCall (OpCodes.Call, writeLine, null); ...

Теперь нам необходимо оттранслировать условный оператор. Так как никаких if'ов в ассемблере MSIL нет (кроме условных переходов), то необходимо предварительно преобразовать этот оператор к следующей форме: if (i!=10) goto Next , где Next - это специальная метка, расположенная после ветки then условного оператора.

Label Next = il.DefineLabel(); il.Emit (OpCodes.Ldloc, var_i); il.Emit (OpCodes.Ldc_I4, 10); il.Emit (OpCodes.Bne_Un_S, Next);

Затем мы создаем новый экземпляр System.Exception: метод GetConstructor по массиву, содержащему типы параметров конструктора, находит в типе соответствующий конструктор. В нашем случае аргументов у конструктора нет, поэтому массив пуст. После этих действий можно спокойно поставить метку Next:

Type[] no_types = new Type [0]; il.Emit (OpCodes.Newobj, typeof (System.Exception).GetConstructor (no_types)); il.ThrowException (typeof (System.Exception)); il.MarkLabel (Next);

Далее генерируется вывод значения переменной i на консоль. Процесс мало отличается от генерации создания нового объекта, за исключением того, что мы вызываем не конструктор, а метод, и, следовательно, должны задать его имя:

il.Emit (OpCodes.Ldloc, var_i); Type[] arg = new Type [1]; arg [0] = typeof (int); MethodInfo writeLine = typeof (System.Console).GetMethod ("WriteLine", arg); il.EmitCall (OpCodes.Call, writeLine, null);

il.Emit (OpCodes.Ldloc, var_i); // i = i + 1; il.Emit (OpCodes.Ldc_I4_1); il.Emit (OpCodes.Add); il.Emit (OpCodes.Stloc, var_i);

Наконец, генерируется переход к следующей итерации цикла ( goto Start):

il.Emit (OpCodes.Br, Start);



Содержание раздела