This is a mirror of official site: http://jasper-net.blogspot.com/

Mono.Cecil: делаем свой «компилятор»

| Thursday, December 2, 2010
Одной из самых роскошных тем для программистов, балующихся изобретением велосипедов, является написание собственных языков, интерпретаторов и компиляторов. Действительно, программа, способная создавать или исполнять другие программы, инстинктивно вселяет благоговейный трепет в сердца кодеров — потому что сложно, объемно, но безумно увлекательно.

Большинство начинают с собственных интерпретаторов, которые представляют собой в общем виде огромный свитч команд в цикле. Интересно, вольготно, но муторно и весьма медленно. Хочется чего-то более шустрого, чтобы JIT'ить умело и, желательно, само следило за памятью.

Отличным решением данной проблемы является выбор .NET в качестве целевой платформы. Оставим лексический разбор на следующий раз, а сегодня давайте попробуем сделать простейшую программу, которая создает работающий исполняемый экзешник:

greeter1.png

Программа будет требовать имя, и выводить в консоли Hello, %username%.

Для создания экзешника существует много способов, например:
Трансляция в C#-код и вызов csc.exe: просто, но неспортивно
Генерация IL-кода в текстовой форме и компиляция ilasm.exe: неудобно по причине необходимости писать руками огромный манифест
Генерация сборки напрямую с помощью Reflection или Cecil

Как раз последний вариант я и выбрал. К сожалению, я не знаю, в чем для данной задачи Cecil превосходит Reflection, но мне попался пример именно на Cecil, поэтому именно его я и разберу.

Mono.Cecil — это библиотека, позволяющая работать со сборкой как с массивом байтов. C ее помощью можно как создавать свои собственные сборки, так и ковыряться и модифицировать уже существующие. Она предоставляет широкий спектр классов, которыми (обычно) удобно пользоваться.

Предмет беседы

Вот, собственно, готовый код (без описания класса, формы и всего прочего, кроме собственно метода-генератора):

using Mono.Cecil;
using Mono.Cecil.Cil;

public void Compile(string str)
{
 // создаем библиотеку и задаем ее название, версию и тип: консольное приложение
 var name = new AssemblyNameDefinition("SuperGreeterBinary", new Version(1, 0, 0, 0));
 var asm = AssemblyDefinition.CreateAssembly(name, "greeter.exe", ModuleKind.Console);

 // импортируем в библиотеку типы string и void
 asm.MainModule.Import(typeof(String));
 var void_import = asm.MainModule.Import(typeof(void));

 // создаем метод Main, статический, приватный, возвращающий void
 var method = new MethodDefinition("Main", MethodAttributes.Static | MethodAttributes.Private | MethodAttributes.HideBySig, void_import);


Read more: Habrahabr.ru

Posted via email from .NET Info

0 comments: