Создание компилятора языка для .NET Framework - Ориентация на платформу .NET Framework

ОГЛАВЛЕНИЕ

Ориентация на платформу .NET Framework

Прежде чем переходить к разделу, выполняющему создание кода, мне следует сперва остановиться и рассказать о моей цели. So here I will describe the compiler services that the .NET CLR provides, including the stack-based virtual machine, the type system, and the libraries used for .NET assembly creation. Я также кратко коснусь средств, необходимых для обнаружение и диагностики ошибок в выводе компилятора.
CLR – это виртуальная машина, то есть программа, имитирующая компьютерную систему. Как все компьютеры, CLR располагает набором низкоуровневых операций, которые она может выполнять, набором служб памяти и языком сборки для определения выполняемых программ. CLR использует абстрактную структуру данных на основе стеков для моделирования исполнения кода, а также язык сборки, именуемый промежуточным языком (Intermediate Language – IL), для определения операций, которые можно выполнять на стеке.

При исполнении компьютерной программы, определенной в IL, CLR просто имитирует операции, указанные для стека, перемещая и выталкивая данные, для выполнения инструкцией. Предположим, нужно сложить два числа, используя IL. Код для выполнения сложения 10 + 20 выглядит так:

  ldc.i4    10    
  ldc.i4    20    
  add        

Первая строка (ldc.i4 10) помещает целое число 10 на стек. Затем вторая строка (ldc.i4 20) помещает целое число 20 на стек. Третья строка (add) выталкивает два целых числа со стека, складывает их и помещает результат обратно на стек.

Имитация машины стека осуществляется путем перевода IL и семантики стека в машинный язык базового процессора, либо во время выполнения, с помощью компиляции непосредственно перед выполнением (just-in-time – JIT), либо заранее, посредством таких служб, как генератор машинных образов (Ngen).

Существует множество доступных инструкций IL для создания собственных программ – от базовой арифметики, до контроля потока, до различных соглашений о вызовах. Подробности о всех инструкциях IL можно найти в Разделе III спецификаций ассоциации European Computer Manufacturers Association (ECMA) (доступном на msdn2.microsoft.com/aa569283).

Абстрактный стек CLR выполняет операции не только на целых числах. Он обладает богатой системой типов, включая строки, целые числа, логические типы, плавающие типы, дублеры, итд. Чтобы мой язык мог безопасно работать на CLR и взаимодействовать с другими совместимыми с .NET языками, я включил часть системы типов CLR в мою собственную программу. Если конкретно, то язык Good for Nothing определяет два типа – числа и строки, для которых я устанавливаю соответствие с System.Int32 и System.String.

Компилятор Good for Nothing использует компонент библиотеки базовых классов (Base Class Library – BCL), именуемый System.Reflection.Emit для работы с созданием кода IL, а также созданием и упаковкой сборок .NET. Это низкоуровневая библиотека, предоставляющая лишь насущно необходимое в виде простых абстракций создания кода, сверх языка IL. Эта библиотека также используется в других известных API-интерфейсах BCL, включая System.Xml.XmlSerializer.

Высокоуровневые классы, необходимые для создания сборки .NET (показанные на рис. 8) в некотором роде следуют шаблонам программ-компоновщиков с API-интерфейсом компоновщика для каждой логической абстракции метаданных .NET metadata. Класс AssemblyBuilder используется для создания файла PE и устанавливает необходимые элементы метаданных сборки .NET, подобно манифесту. Класс ModuleBuilder используется для создания модулей внутри сборки. TypeBuilder используется для создания типов с связанных с ними метаданных. MethodBuilder и LocalBuilder занимаются, соотвественно, добавлением методов к типам и локальных переменных к методам. Класс ILGenerator используется для создания кода IL для методов, используя класс OpCodes, являющийся большой нумерацией, содержащей все возможные инструкции IL. Все эти классы Reflection.Emit используются в генераторе кода Good for Nothing.

 

Рис. 8 Библиотеки Reflection.Emit, используемые для создания сборки .NET