УДК 004.4&#39

advertisement
УДК 004.4’422. Технологии Microsoft в теории и практике
программирования. Программные проекты и системы
ОСОБЕННОСТИ РАЗРАБОТКИ КОМПИЛЯТОРА
ЯЗЫКА OBJECT PASCAL ДЛЯ ПЛАТФОРМЫ .NET
Бондарев И.В. магистр, Университет Bayreuth(Германия); Иванов С.О.
магистр ЮФУ; Михалкович С.С. доцент, к.ф-м.н ЮФУ;
Ткачук А.В. аспирант ЮФУ.
В данной работе описаны
проблемы, возникшие при создании
компилятора языка Object Pascal под платформу .NET, а также
представлены пути их решения.
Среди особенностей и концепций .NET, повлиявших в наибольшей
степени на разработку компилятора, следует выделить: 1) генерацию IL
кода с последующей JIT-компиляций на этапе выполнения, вследствие
чего отпадает необходимость в проведении машинно-зависимых
оптимизаций на этапе генерации кода; 2) возможность использования
общей библиотеки классов – FCL; 3) сборку мусора; 4) ссылочную модель
объектов; 5) все типы – классы; 6) объектную ориентированность IL кода.
Разрабатываемый компилятор PascalABC.NET [1,2] представляет собой
компилятор языка программирования Object Pascal, дополненный рядом
современных возможностей. По дизайну язык PascalABC.NET наиболее
близок к Delphi Object Pascal и Chrome [3]. Язык PascalABC.NET содержит
все основные элементы современных языков программирования: модули,
классы, перегрузку операций, интерфейсы, исключения, обобщенные
классы (шаблоны). Объектная модель PascalABC.NET – ссылочная, как и в
платформе .NET. При компиляции используется трехзвенная генерация
кода (текст программы – синтаксическое дерево – семантическое дерево –
IL-код). Для генерации IL кода использован System.Reflection.Emit[1].
Далее речь пойдет о том, какие конструкциях языка легко ложились на
платформу .NET, какие конструкции порождали трудности реализации
(вложенные процедуры, типизированные файлы, множества), а также о
том, какие конструкции не были реализованы и по какой причине
(бестиповые параметры, полноценные указатели, открытые массивы).
Некоторые конструкции языка соответствуют идеологии платформы и
легко проецируются в конструкции IL. К таковым относятся операторы
ветвления, цикла, перехода, исключения, числовые типы и операции с
ними, а также классы и интерфейсы.
Строковый тип претерпел ряд изменений. В .NET строки
представляются типом System.String и индексируются с 0. Для
совместимости с Object Pascal строки в компиляторе PascalABC.NET
также представлены типом System.String, но для строк был добавлен
изменяемый индексатор (s[i]:=’c’), а также директива компилятора,
которая переключает индексацию срок с 1 на 0 (по умолчанию строки
индексируются с единицы).
В PascalABC.NET введена перегрузка операций. Перегрузка операций
для типа T, являющегося классом или записью, осуществляется при
помощи статического метода со специальным именем operator@, где @ знак операции, например: function T.operator+(left, right: T): T; static;
Перевод ряда других конструкций языка в .NET не так очевиден. Так
например, в .NET отсутствует сущность, эквивалентная модулю (Unit)
языка Object Pascal. Для каждого модуля языка Object Pascal заводятся два
пространства имен (для секций интерфейса и реализации). В каждом
пространстве имен генерируется специальный класс, куда помещаются
глобальные подпрограммы и переменные модуля в качестве статических
членов. Объявленные пользователем типы попадают в соответствующее
пространство имен, сгенерированное для данного модуля.
Особые сложности вызвало проектирование в .NET вложенных
подпрограмм. Это связано с тем, что возможность создания вложенных
подпрограмм отсутствует в IL-коде. При разработке компилятора
PascalABC.NET было принято решение переводить в IL-код каждую из
таких подпрограмм при помощи создания вложенных классов (в IL-коде
вложенные классы разрешены). Каждой подпрограмме, содержащей
вложенные подпрограммы, ставится в соответствие класс. Входные
параметры этой подпрограммы и ее локальные переменные становятся
полями этого класса. Благодаря этому вложенные подпрограммы,
переведенные во вложенные классы, получают доступ к переменным
объемлющих подпрограмм.
Вследствие необходимости доступа к пространствам имен,
существующих на момент компиляции сборок, была обобщена
конструкция подключения внешних модулей uses. Она применяется не
только для подключения написанного на языке Object Pascal модуля, но и
при использовании пространства имен какой-либо сборки (uses
System.Windows.Forms). При этом имя, указанное в конструкции uses,
трактуется сначала как имя модуля, а если он отсутствует, как
пространство имен .NET.
Тип множеств (set of T) в языке PascalABC.NET был существенно
расширен: базовый тип T множества может быть любым (например,
возможно объявить set of string или set of Person). Множества реализованы
на базе хеш-таблицы, которая позволяет хранить элементы любого типа.
В компиляторе реализованы типизированные файлы (file of T, в
Delphi.NET они отсутствуют). В качестве типа элементов в
типизированном файле не могут фигурировать указатели, ссылочные типы
(в частности, строки), а также тип записи, содержащий ссылочные поля
или указатели.
Почти весь код, реализующий множества и типизированные файлы,
написан на самом языке PascalABC.NET и содержится в системном модуле
PABCSystem, автоматически подключаемом к остальным модулям.
Компилятор делает лишь некоторые проверки, например, ограничения на
тип элементов для типизированных файлов.
Конструкторы в Object Pascal, в отличие от платформы .NET,
наследуются. Для решения этой проблемы компилятор генерирует
унаследованные конструкторы, если пользователь не определил ни одного
своего. При этом в определенных пользователем конструкторах первой
строкой кода должен быть вызов конструктора предка (если это не так,
компилятор попытается сгенерировать вызов конструктора предка по
умолчанию). Конструктор по умолчанию добавляется ко всем классам,
написанным на PascalABC.NET (если у класса-предка есть конструктор по
умолчанию). Все конструкторы должны иметь имя Create – так обходится
проблема их перевода в «безымянные» конструкторы платформы .NET.
Аналогичное решение принято в компиляторе Chrome [3].
Далее
излагаются
некоторые
дополнительные
возможности,
добавленные в язык, а также введенные в язык ограничения.
Переменные можно описывать прямо в блоке операторов.
Добавленный в язык цикл foreach позволяет перебрать элементы
динамических массивов, размерных массивов, строк, множеств, а также
элементы типов, реализующих интерфейс System.Collections.IEnumerable.
Как и в платформе .NET, разрешено объявлять методы в записях; кроме
того, записи могут реализовывать интерфейсы. Записи представляют
собой размерные типы и проецируются на value-типы (System.ValueType).
В PascalABC.NET указатели делятся на типизированные (содержат
адрес ячейки памяти некоторого типа) и бестиповые (содержат адрес, не
связанный с данными какого-либо определенного типа). Так как в
платформе .NET работает автоматическая сборка мусора, это накладывает
некоторые ограничения на использование указателей: базовый тип
типизированного указателя не должен быть ссылочным или содержать
ссылочные типы на каком-то уровне (например, запрещены указатели на
записи, у которых одно из полей имеет ссылочный тип). Данное
ограничение связано с тем, что сборщик мусора может передвигать
динамическую память в непредсказуемый момент. Также из-за этого
ограничения в языке PascalABC.NET отсутствуют бестиповые параметры
подпрограмм (var a) и ряд связанных с ними стандартных подпрограмм.
Все классы в PascalABC.NET являются наследниками System.Object.
Благодаря сборке мусора необходимость в деструкторах отпадает, они
оставлены для совместимости в виде обычных процедур. При
необходимости пользователь может сам перегрузить процедуру Finalize,
которую вызовет сборщик мусора перед освобождением памяти, занятой
данным объектом.
Для динамических массивов (array of T) принята структурная
эквивалентность типов, поэтому открытые массивы не включены в язык.
Процедурные переменные в языке PascalABC.NET проецируются на
делегаты. К процедурным переменным применимы операции += -=, что
позволяет добавлять к процедурной переменной несколько подпрограмм с
совместимым прототипом (внешних подпрограмм или методов)
В PascalABC.NET помимо процедуры new выделения памяти под
указатель (new(p)) присутствует операция new для конструирования
объекта. Синтаксис операции new идентичен синтаксису этой операции в
языках C# и Chrome (ident := new type_name(params)) и является
альтернативой традиционному вызову конструктора (Delphi). Введение
операции new помогло использовать имена обобщенных классов (generics)
в вызове конструктора, оставив грамматику языка контекстно-свободной.
В языке PascalABC.NET имеется как доступ ко всем стандартным
generic-типам платформы .NET (таким, как List<T>, Dictionary<T, Q>), так
и возможность создания своих generic-типов. Для создания своих genericтипов был разработан простой синтаксис, аналогичный Chrome [3].
Проблемы при создании обобщенных классов были обусловлены
неочевидным способом генерации generic-типов в библиотеке
Reflection.Emit. Например, при создании инстанции существующего
шаблона от не полностью переведенных в IL-код параметров-классов
следует
вызывать
TypeBuilder.GetConstructor
(generic_instance,
construcor_definition_reference)
вместо
очевидного
метода
generic_instance.GetConstructor (параметры конструктора).
Для системы программирования PascalABC.NET разработана
компактная и простая в использовании оболочка, обладающая при этом
всеми наиболее часто используемыми программистом функциями, такими
как: отладчик, система intellisense, навигация по исходному коду,
перенаправление ввода/вывода в специальное окно.
Последняя версия компилятора PascalABC.NET и описание языка
доступно на сайте проекта [2].
1.
2.
3.
Водолазов Н.Н., Михалкович С.С., Ткачук А.В. Архитектура
компилятора PascalABC.NET. Труды IV Всероссийской научнотехнической конференции «Технологии Microsoft в теории и практике
программирования». 2007 г., с 181-182.
Сайт проекта PаscalABC.NET – http://pascalabc.net
Сайт компилятора Chrome – http://remobjects.com/chrome/
АННОТАЦИЯ
В данной работе описаны типичные проблемы, возникшие при создании
компилятора языка Object Pascal под платформу .NET, а также
представлены пути их решения. Перевод в IL байт-код некоторых
конструкций языка Pascal затруднителен. Вложенные подпрограммы,
отсутствующие в платформе, моделируются при помощи вложенных
классов. Строки проецируются на тип System.String, но являются
изменяемыми. Смоделированы размерные массивы Object Pascal.
Множества в PascalABC.NET могут быть построены на базе любого типа.
Разработчикам компилятора PascalABC.NET удалось также реализовать
типизированные файлы и обобщенные типы (generics), что не было
сделано в среде программирования Delphi.NET.
тезисамы на английском языке в объеме 1/4 страницы,
включая заголовок и сведения об авторах.
Download