Использование компилятора Delphi (dcc32.exe) в прикладных программах

Delphi (хотя можно использовать любой другой быстрый и качественный компилятор для любого другого подходящего языка). Далее я рассмотрю этапы, которые нужно сделать, чтобы воплотить замыслы технолога. Конкретности реализации демонстрируется на примере небольшой библиотеки, которую прилагаю к статье (называется она DccUsing) и крошечного проекта под незатейливым именем DccExamples. 1. Генерация кода На основе исходного представления, которое формулирует технолог, нужно сгенерировать код для компиляции. Исходное представление может быть любым, в простейшем случае - это обычный текст. В процессе генерации кода наибольшее внимание нужно уделить диагностике ошибок. То есть, ошибки желательно выявить во время генерации кода и генерировать уже синтаксически правильный код. Для этого можно использовать любые доступные методы, вплоть до синтаксических анализаторов с рекурсивным спуском - такие анализаторы достаточно просты и описаны во многих книгах, например у Бьерна Страуструпа в "Язык программирования C++" (Третье издание). Если есть возможность, то желательно контролировать также семантическую правильность. Далее я буду рассматривать только те моменты, которые являются общими для всех задач без учета их специфики. Генерировать исходный текст можно любым способом, например, просто посылая строки текста в файл. Более удобный способ, как мне кажется, это направление текста в строко-ориентированный поток. Такой поток предоставляет дополнительное удобство при диагностике ошибок. Библиотека DccUsing содержит два потоковых класса: TFileCompileOut и TStringCompileOut, которые порождаются от TCompileOut. Классы очень просты, их реализацию можно посмотреть в исходном файле библиотеки, поэтому я дам только обзор. Базовый класс имеет методы:

public
 procedure IncLevel;
 procedure DecLevel;
 procedure AddSpace;
 procedure AddLine(const aLine: String);
 procedure AddLines(const aLines: array of String);
 procedure AddFile(const aFileName: String);
 procedure AddLineTemplate(const aLine: String;
  const aArgs: array of String);
 procedure AddLinesTemplate(const aLines, aArgs: array of String);
 procedure AddFileTemplate(const aFileName: String;
  const aArgs: array of String);
 procedure AddPoint(aPoint: Integer);
 function FindPoint(aLine: Integer): Integer;
 property Level: Integer read FLevel;
 property LinesCount: Integer read FLinesCount;

Первые три метода позволяют управлять форматированием кода. Хотя форматирование совсем не обязательно (код никто не читает), но дает удобства при отладке, а, кроме того, мне нравится, когда программа выглядит эстетично. IncLevel увеличивает отступ текста, DecLevel уменьшает, а AddSpace добавляет в поток пустую строку. Два следующих метода добавляют в поток соответственно строку и массив строк, а метод AddFile - весь указанный файл. Свойства позволяют узнать текущий уровень отступа и текущее число строк в потоке. Назначение методов AddPoint и FindPoint будет объяснено в разделе диагностики ошибок.
Методы AddLineTemplate, AddLinesTemplate и AddFileTemplate более сложны, чем предыдущие методы, представляют собой простые макропроцессоры и позволяют параметризовать генерируемый текст. Параметризующие аргументы - это массив строк, которые заменяют метасимволы в исходном тексте шаблона. Метасимволы выглядят так: {{X}}, где Х - это порядковый номер аргумента, начиная от 1. Макроподстановка производится без всякого учета лексики. Поэтому можно параметризовать все что угодно - идентификаторы, строки, комментарии, операторы и т.д. Например, если шаблон текста таков:

const

 tFunc: array[0..5] of String = (

  'function {{1}}.SortProc{{2}}(const a1, a2: {{2}}): Integer;',

  'begin',

  ' if a2 > a1 then result := 1',

  ' else if a2 = a1 then result := 0',

  ' else result := -1;',

  'end;'

 );

то при использовании
c.AddLinesTemplate(tFunc,['TTestClass1','Integer']);

мы получим такой результат:

function TTestClass1.SortProcInteger(const a1, a2: Integer): Integer;

begin

 if  a2 > a1 then result := 1

 else if a2 = a1 then result := 0

 else  result := -1;

end;

а при использовании

c.AddLinesTemplate(tFunc,['TTestClass2','String']);

такой:
function TTestClass2.SortProcString(const a1, a2: String): Integer;

begin

 if  a2 > a1 then result := 1

 else if a2 = a1 then result := 0

 else  result := -1;

end;

Наследуемые классы переопределяют абстрактную процедуру записи строки в поток и имеют специфические методы. Класс TFileCompileOut специализируется на построчном выводе в файл:

public

 constructor Create(const aFileName: String);

 destructor Destroy; override;

 property  FileName: String read FFileName;

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

Проверка
Антиспам проверка
Image CAPTCHA
...