The website "dmilvdv.narod.ru." is not registered with uCoz.
If you are absolutely sure your website must be here,
please contact our Support Team.
If you were searching for something on the Internet and ended up here, try again:

About uCoz web-service

Community

Legal information

7.2 Разработка

7.2 Разработка

Предыдущая  Содержание  Следующая V*D*V

Давайте сделаем несколько выводов из эксперимента препроцессирования Point. Мы начали с довольно простого, строчно-ориентированного описания класса:

 

строки для интерфейса                      // произвольные

%prot

строки для представления

 

% метакласс[: метасупер] класс: супер {    // заголовок

    ...                                    // компоненты объектов

%                                          // статически компонуемые

    тип имя ([const] _self, ...);

    ...

%-                                         // динамически компонуемые

    тип имя ([const] _self, ...);

    ...

%}

 

Единственная трудность состоит в том, что нам надо распутать списки параметров и разделить информацию о типе и об имени в каждой декларации. Дешёвое решение состоит в том, чтобы потребовать, чтобы const предшествовал типу, если таковой имеется, и чтобы тип предшествовал имени (* При необходимости это всегда может быть организовано с помощью typedef.). Также распознаются следующие особые случаи:

 

_self

цель сообщения в текущем классе

_name

другой объект в текущем классе

class @ name

объект в другом классе

 

Всем им может предшествовать const. Объекты в текущем классе разыменовываются после импортирования.

Именем файла для описания класса является имя класса с последующим .d, поэтому ooc может найти описания суперклассов. Мы не должны сильно беспокоиться о метаклассе: либо класс имеет тот же самый метакласс, как и его суперкласс, либо класс имеет новый метакласс и суперкласс этого метакласса является метаклассом суперкласса класса. В любом случае, если мы прочитаем описание суперкласса, то получим достаточно информации, чтобы справиться с метаклассом.

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

 

$ ooc Point -h > Point.h # файл интерфейса

$ ooc Point -r > Point.r # файл представления

 

Файл реализации является более трудным. ooc должен как-то узнать о телах методов и должны или нет параметры быть проверены и импортированы. Если мы добавим тела методов в файл описания класса, мы сохраним всё вместе, но потребуется гораздо больше обработки: во время каждого запуска ooc должен загрузить файлы описаний классов обратно в корневой класс, тем не менее, тела методов интересны только в самом внешнем файле описания. Кроме того, реализации изменятся скорее, чем интерфейсы; если тела методов сохраняются с описанием класса, make будет заново создавать интерфейсные файлы каждый раз, когда мы меняем тело метода, и это, вероятно, приведёт к большому количеству ненужных перекомпиляций. (* yacc имеет аналогичную проблему с файлом заголовка y.tab.h. Стандартным подходом является дублирование этого файла, переписывание копии только если она является новой, и использование этой копии в правилах makefile. См. [K&P84].)

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

 

$ ooc Point -dc > skeleton # начало реализации

 

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

ooc должен быть инструментом разработки и сопровождения. Если мы изменим заголовок метода в описании класса, очень разумно ожидать, что ooc распространит это изменение по всем файлам реализации. Используя вариант со скелетом мы сможем лишь создавать новый скелет и вручную редактировать всё вместе — не очень приятная перспектива!

Если мы не хотим сохранять тела методов в описании класса, и если мы требуем, чтобы ooc менял существующий файл реализации, мы приходим к проектированию ooc как препроцессора. Вот типичный вызов:

 

$ ooc Point Point.dc > Point.c # работа препроцессора

 

ooc загружает описание класса для Point, а затем читает файл реализации Point.dc и записывает препроцессированную версию этого файла в поток стандартного вывода. Мы можем даже совместить это с подходом скелета, описанного выше, до тех пор, пока мы создаём скелет с командами препроцессора, а не как неизменяемый файл C.

 

Предыдущая  Содержание  Следующая