Parser Generator
Инструментарий для построения компиляторов.
   

Главная

О сайте

Документация

Download

Ссылки

Библиография

О нас


Библиотека вспомогательных классов.

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

Управление памятью.

Управление памятью является важным и очень тонким вопросом при построение любой программной системы. При неправильном или неаккуратном использовании динамической памяти можно загубить огромную работу. Данная система активной использует динамическую память, поэтому сразу встал вопрос о том, как ее использовать.

Стандартная библиотека языка C++ предоставляет механизм "умных" (smart) указателей. При работе с кусками динамической памяти один из указателей назначается ответственным за выделенный участок и при своем удалении он должен освободить занимаемую память. Этот прием сильно облегчает работу, однако он не позволяет полностью положится на "умные" указатели. Причина в том, что в системе один объект может входить в множество различных контейнеров и вопрос о том кто из них является ответственным за удаление объекта является очень сложным.

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

Базовым классом для всех классов библиотеки является ref_obj. В каждом объекте этого класса хранится счетчик все указателей на этот объект. Каждый указатель, при создании, удалении, изменении своего значения уменьшает или увеличивает значение этого счетчика. Если при уменьшении счетчик обращается в ноль, значит на него больше никто не указывает и объект можно удалять из памяти. У этого подхода есть еще одно ограничение- нельзя использовать круговые (циклические) ссылки. Например, если два объекта хранят указатели друг на друга, значит значение их счетчиков никогда не обратиться в ноль, хотя снаружи, никто уже о них ничего не знает.

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

Ввод-вывод, сохранение состояния объектов.

Любая более или менее сложная система должна уметь сохранять и восстанавливать результаты своей работы. Для этого разрабатываются специальные форматы файлов или база данных. С появлением стандарта XML стало возможным намного упростить этот процесс. Самым простым способом сохранить данные, является хранение информации в базе данных, однако база данных очень "тяжеловесный" механизм. Даже самые простые из них "тянут" вместе с собой большие библиотеки доступа к информации. XML в этом смысле является более "изящным" решением. Несмотря на то, что библиотека XML тоже требует памяти, тем не менее эти затраты на уровне самых "легких" баз данных. К тому же XML стал стандартом, что обеспечивает переносимость на другие платформы и легкую интеграцию с другим программными средствами.

Для разбора XML документов была применена библиотека XERCES фирмы Apache Software. Эта фирма заслужила известность благодаря своим разработкам в области интернет проектов. XERCES является надежным и парсером XML, который соответствует стандартам консорциума W3C.

Однако мы не стали использовать XERCES напрямую, подразумевая, что впоследствии нами будет использован парсер, который мы создадим, с помощью своего средства. В качестве декораторов (оберток) используется несколько классов, которые предоставляет самую необходимую функциональность, для разбора XML документов, скрывая от остальных классов реализацию парсинга. В дальнейшем планируется подменить XERCES собственным парсером.

Почти все сохраняемые (persistent) объекты реализуют методы
void fromXML (string) и
void fromXMLNode (XMLNode)
Первый осуществляет разбор XML строки, получает соответствующую структуру данных (XMLNode), и передает ее второму методу, который осуществляет восстановление состояния объекта по этой структуре. Также почти все объекты реализуют метод
string toString(),
который возвращает XML строку, описывающую состояние объекта. Эту XML строку можно передать другому объекту этого класса на вход метода fromXML, получив, в результате, копию исходного объекта. Даже простое использование метода toString в целях отладки очень сильно облегчает восприятие программистом объекта, так как позволяет сразу увидеть его состояние.

Класс строки и класс variant

Программа предусматривает работу со строками. Необходимо выбрать из различных вариантов самый лучший, для нашего случая. Стандартные Си строки- самый простой вариант. Они не позволяет производить операции над строками, простой перегрузкой операторов, а нашей задачей являлось создать легкий в понимании код, поэтому мы решили обратить свое внимание на STL строки. Однако было принято решение перегрузить стандартный STL класс string введя в него дополнительную функциональность, которая позволила ему легко сочетаться с библиотекой разбора XML, а также добавили некоторые полезные методы (to_upper, to_lower, from_long...).

Другая проблема заключалась в хранении атрибутов термов и атрибутов узлов XML дерева. Хотелось достичь максимальной гибкости в работе и не просто хранить эти атрибуты в виде строк, а иметь способ работы с ними наподобие работы с переменными типа variant. Был написан класс variant для представления значений различных типов (string, long, boolean, char). Этот класс взял на себя задачу преобразования этих типов друг в друга (а также некоторые другие функции), что позволило сильно упростить код. Например стало возможным написать следующий код:
variant v;
v = "Year : ";
v += 2002; // v=" Year : 2002"
Классы string и variant тесно связаны между собой обеспечивая взаимную функциональность.


 
   
© С. Григорчук 2001, Содержание, дизайн

ukman@yandex.ru
Hosted by uCoz