мая 10, 2010

Собственный препроцессор (aka dpp)

Все больше и больше утыкаюсь в ограничения возможностей Free Pascal'я. Сегодня решил начать осуществлять свою давнюю задумку - препроцессор.

Итак, в чем заключается задумка. Есть файлы, написанные на моем расширенном паскале, имеют расширение dpp. Препроцессор просматривает папки, ищет такие файлы, и на их основе генерирует pas-файлы, которые уже можно просто скомпилировать free pascal'ем.

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

Сделано это странное ограничение для того, чтобы компилятор Free Pascal когда сообщал об ошибках, указывал бы номера строки и столбца ошибки совпадающие с соответствующими строками и столбцами в dpp-файла.

Моя утилитка dpp будет open source и ей сможет пользоваться любой желающий.

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

1) Событийную систему. К сожалению, мне не удалось на чистом fpc написать красиво отправку сообщения, поэтому ввожу такую конструкцию
#(5, 3, 'hello', Obj)-> Notifier
Она отправляет сообщение в Notifier с параметрами 5, 3, 'hello', Obj.

2) Автоматические создание и освобождение классов. Две конструкции

#autoclass(FMyClass: TMyClass) TMyExtendedClass.Create('hello')
Описывается внутри описания класса. Создает у класса поле FMyClass, которое будет автоматически создаваться во всех конструкторах вызовом TMyExtendedClass.Create('hello') и автоматически освобождаться в каждом деструкторе. По сути, время жизни поля привязывается к времени жизни хозяина - частоиспользуемая схема.

#stackclass(MyClass: TMyClass) TMyExtendedClass.Create('hello', Param1)
Описывается внутри описания метода. Автоматически создает в начале метода, автоматически уничтожает в конце

3) Система сериализации классов (для генерации кода по загрузке/сохранению). Тут немного сложнее, основные конструкции примерно такие:

#streaminterface
#streamimplementation(TMyClass)
Создает все необходимые функции по сохранению/загрузке класса TMyClass

#streamfield(FImportantValue: Integer)
Создает поле у класса, которое необходимо сохранять

4) Продвинутое RTTI.
#RTTIclass(MyRTTIVar) from TMyClass
Записывает в MyRTTIVar RTTI-информацию о классе TMyClass

5) Вставка в код название текущего файла/текущего метода/содержимого текущей строки/номера текущей строки. Очень удобно для логов.
#currentfilename_______________
#currentmethodname_____________
#currentline___________________
#currentlinenumber_____________

6) Собственно, печать в лог с указанием всей нужной инфы из пункта 5
#log 'error ' + IntToStr(ErrorId) + '!'

Пока что готов только пункт 1 :)


Комментариев нет:

Отправить комментарий

Постоянные читатели

Обо мне

Моя фотография
Мой e-mail: vitek_03(at)mail(dot)ru