Основные сведения из баз данных — КиберПедия 

Эмиссия газов от очистных сооружений канализации: В последние годы внимание мирового сообщества сосредоточено на экологических проблемах...

Типы сооружений для обработки осадков: Септиками называются сооружения, в которых одновременно происходят осветление сточной жидкости...

Основные сведения из баз данных

2020-04-01 129
Основные сведения из баз данных 0.00 из 5.00 0 оценок
Заказать работу

Содержание

 

1. Введение

2. Основные сведения из баз данных

· основные определения и классификация

· типы пользователей к БД

· механизм транзакций и курсоров

3. Основные сведения из Berkeley DB

4. Основные сведения по программной системе         генерации языков программирования YAPP

5. Структура разрабатываемой программы

· Ядро, включающее в себя библиотеку классов и все необходимые для работы стаба инструменты

· Лексический анализатор, его структура

· Синтаксический анализатор, его структура

· Семантика, генерация С++ стабов (автоматически сгенерированный программный код)

6. Пример работы программы

7. Заключение

8. Список используемой литературы

9. Приложения


Введение

 

В современном информационном мире, пожалуй, нет места, где бы не использовались информационные хранилища данных – базы данных. Они нужны во всех отраслях информационного хозяйства, в них хранится информация про курсы валют, бронирование авиабилетов, координаты спутника и т. д. Естественно, доступ к таким данным может осуществляться в режиме реального времени, следовательно время, скорость реакции программной системы - это один из самых существенных критериев.

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

1. Реляционная модель является универсальной, то есть с ее помощью в принципе можно реализовать любую схему данных.

2. Реляционная модель имеет под собой математический аппарат реляционной алгебры, она более формализована, нежели остальные модели.

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

Однако за универсальность нужно платить. И одним из слабых мест у реляционных СУБД является скорость выполнения запроса! Конечно, создаются интеллектуальные препроцессоры, оптимизирующие запрос, а также время его выполнения (так, например, такой есть в InterBase, Oracle, Informix), но проблема заключается в самой модели. Были проведены эксперименты, в ходе которых работа с навигационно-сетевой СУБД(Berkeley DB) была эффективней на порядок, чем с реляционной СУБД(Informix).

Таким образом, сетевые СУБД работают быстрей, однако они более запутанней, их семантика более сложная, чем реляционная, практически недоступная для понимания конечного пользователя. Интерфейс к такой базе данных обычно является низкоуровневым. Возникает вопрос, а нельзя ли как-нибудь поднять уровень абстракции, сделать интерфейс к ней более понятным и простым для программиста. Это послужило основой для данной работы.

Итак, постановка задачи:

Сформировать транслятор генерации объектно-ориентированного интерфейса на С++ для работы с низкоуровневой СУБД BerkeleyDB по заданной пользователем схеме данных.


Пользователи системы баз данных

Здесь под пользователем СУБД будем понимать субъект (пользователь, программист, прикладная программа), взаимодействующий с каким-нибудь интерфейсом к ней. Пользователей можно разбить на несколько категорий:

Первая – системные, отвечающие за программирование, например оболочек для базы. У нас это субъект, который формирует стабы по заданной схеме хранения данных.

Вторая - прикладные, отвечающие за написание прикладных программ, использующих базу данных(эту оболочку).

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

Основные сведения по программной системе генерации языков программирования YAPP

YAPP представляет собой  программную систему с использованием Perl для генерации и использования синтаксических анализаторов LALR. Фактически это коллекция модулей расширения, написанных на Perl, совместимая с форматом YACC и позволяющих генерировать perl-код.

Пользователь  формирует файл с грамматикой, описывающей некоторый желаемый язык. Этот файл подается на вход к yapp

yapp grammar_file.yp

На выходе получаем perl-модуль, выполняющий синтаксический анализатор языка, описываемого пользователем. То есть, фактически, yapp и генерирует синтаксические анализаторы.

Чтобы подключить синтаксический анализатор, пользователь должен подготовить уже своими силами лексический анализатор и использовать примерно такой код:

use MyParser; $parser=new MyParser(); $value=$parser->YYParse(yylex => \&lexer_sub, yyerror => \&error_sub);

Файл грамматики

1) Комментарии бывают в стиле Perl # или в стиле С //, /* */.

2) Признаки литералов и строк.

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

Синтаксис нетерминальных символов и символьных лексем: [A-Za-z][A-Za-z0-9_]*.

Запрещено использование название «error» для литералов.

Структура его выглядит следующим образом (очень похожа на yacc, фактически является ее подмножеством)

Файл состоит из трех секций, разделенных %%:

заголовок %% секция правил %% нижняя секция

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

Она содержит также декларации приоритета, представленных%left, %right и %nonassoc(определяющ. ассоциативность).

%start указывает на правило(левую часть), выполняющееся первым.

Секция правил содержит грамматические правила:

Каждое правило состоит из слева лежащего символа (нетерминального), разделенного ':' и одним или несколькими возможными правилами, разделенными '|' и завершенными ';':

exp: exp '+' exp   | exp '-' exp  ;

Правило справа может быть пустым

input: #empty   | input line  ;

Для задания явного приоритета в случае неоднозначности следует использовать директиву %prec, дающую правилу высокий приоритет.

exp: '-' exp %prec NEG { -$_[1] }   | exp '+' exp  { $_[1] + $_[3] }   | NUM  ;Примечательно, что YAPP позволяет встраивать в синтаксический анализатор семантику. Это организуется путем добавления в конце правила конструкций {…}, ограничивающих Perl-команды. Они встраиваются в синтаксический анализатор и выполняются после применения анализатором этого правила. Такой код может возвращать некоторую величину, используемую в определении следующего правила по дереву.Переменные $_[1], $_[n] являются параметрами и хранят значения разобранного правила. Нижняя секция может содержать корректный Perl-код, встраиваемый в конце сформированного синтаксического анализатора. Там можно указать лексер, процедуру анализа ошибок.

Библиотека классов

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

· Транзакции

· Исключения

· Базовые записи

· Таблицы

· Базы данных

· Курсоры

Базовые записи

Базовая запись – это элементарная единица хранения в таблице. Описание ее класса:

//! базовый класс для записей с vtable pointer

class hbObj{

   Dbt dbt;

protected:

   void dbtInit(uint s,void* d)

           {

                   dbt.set_flags(DB_DBT_USERMEM);

                   dbt.set_ulen(s);

                   dbt.set_size(s);

                   dbt.set_data(d);

           }

public:

   operator Dbt*(){return &dbt;}

   void* getData(void) {return dbt.get_data();};

   uint getSize(void) {return dbt.get_size();};

 

   hbObj()                            {}

  virtual ~hbObj()                   {}

};

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

//! реальный класс, который приводится к Dbt

 

template <class A> class hbRec:public hbObj

{

   A data;

public:

   A* getPnt(void)    { return &data;} // если в в A массив то можно переопределить операцию & для А

   hbRec()                            { memset(&data,0,sizeof(A));dbtInit(sizeof(A),&data);}

   hbRec(const hbRec<A>& a):data(a.data) { dbtInit(sizeof(A),&data);}

   hbRec(const A& a) :data(a)   { dbtInit(sizeof(A),&data);}

   void SetData(const A& a)        { data = a;dbtInit(sizeof(A),&data);}

   virtual ~hbRec()                   {}

};

 

Таблицы

Диаграмма отношений существующих таблиц приведена ниже:

По аналогии с записями существует базовый класс таблиц hbBasetbl, который поддерживает работу со всеми стандартными типами таблиц (Hash, Btree, Queue). Фактически ее тип является ее состоянием и определяется в момент открытия.

class hbBasetbl

{

   // нужен для того чтобы set_flags вызывалась ровно один раз

   uint Set_flg_Counter;

   ushort state;

   // флаг, показывающ. открыта ли сама таблица, необходим для экстр. закрытия в случае некоректного

// открытия

   bool tableopen;

   hbInit ini;

protected:

   uint recsize;

   uint keysize; // только для DB_HASH

   Db *table;

   virtual void UsrOpen(hbTxn *tx,FileConf& conf,bool openidx,hbInitRt* irt = 0,u_int32_t op_flags = 0);

   virtual void UsrClose();

   void SetRecSize(uint recsize1){recsize = recsize1;}

   void SetKeySize(uint keysize1){keysize = keysize1;}

   uint GetType() {return ini.type;}

   bool IsDup() {return (ini.st_flags & DB_DUP | ini.st_flags & DB_DUPSORT)>0;}

 public:

   hbEnv& env;

   operator Db*(){return table;}

   Db* operator ->(){return table;}

   const char* GetDbName(){return ini.dbname;}

 

   hbBasetbl(hbEnv& e,hbInit&);

   virtual ~hbBasetbl(){ if(state) Close();}

 

   void Open(hbTxn *tx,FileConf& conf,bool openidx,hbInitRt* irt = 0,u_int32_t op_flags = 0);

   void Close();

       

   virtual void Create(hbTxn *tx,FileConf& conf,hbInitRt* irt = 0,u_int32_t op_flags = 0);

 

   virtual int Get(hbTxn *tx,hbObj *key,hbObj *val,u_int32_t flags=0); // в стиле С (без исключений)

   virtual int Pget(hbTxn *tx,hbObj *fkey,hbObj *pkey,                     // в стиле С (без исключений)    

                           hbObj *val, u_int32_t flags=0);

   virtual int Del(hbTxn *tx,hbObj *key,u_int32_t flags=0);      // в стиле С (без исключений)

 

   virtual int tGet(hbTxn *tx,hbObj *key,hbObj *val,u_int32_t flags=0);         // в стиле С++

   virtual int tPget(hbTxn *tx,hbObj *fkey,hbObj *pkey, hbObj *val, u_int32_t flags=0); // в стиле С++

   virtual int tDel(hbTxn *tx,hbObj *key,u_int32_t flags=0);                  // в стиле С++

   virtual int Put(hbTxn *tx,hbObj *key,hbObj *val,u_int32_t flags=0);

   bool IsOpen(){return state;}

};

 

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

Этот класс является базовым, и совсем неудобен для работы, если эта таблица является индексированной (то есть имеет индексы – другие индексные таблицы). Необходим еще один класс, который будет обобщением понятия индексируемой таблицы и являться контейнером для таких индексных таблиц. Этот класс представлен ниже.

class hbPTable:public hbBasetbl{

   void ErrorClose();

   void eee();

   void FixIdx(uint bulk_ret_buffer_size,int i,FileConf& conf);

void FixIdxForQueue(uint bulk_ret_buffer_size,int i,FileConf& conf);

void FixIdxForHash(uint bulk_ret_buffer_size,int i,FileConf& conf);

void CheckMainToIdx(uint bulk_ret_buffer_size,bool fix,FileConf& conf);

void CheckMainToIdxForQueue(uint bulk_ret_buffer_size,bool fix,FileConf& conf);

void CheckMainToIdxForHash(uint bulk_ret_buffer_size,bool fix,FileConf& conf);

void CheckIdxToMain(uint bulk_ret_buffer_size,bool fix,FileConf& conf);

void CheckIdxToMainForQueue(uint bulk_ret_buffer_size,bool fix,FileConf& conf);

void CheckIdxToMainForHash(uint bulk_ret_buffer_size,bool fix,FileConf& conf);

inline void ExportForQueue(uint bulk_ret_buffer_size,FILE* f, hbTxn* tx);

   inline void ExportForHash(uint bulk_ret_buffer_size,FILE* f, hbTxn* tx);

   inline void Import3(Dbt* key,Dbt* data);

   inline void Import2(char* buf);

   inline void Import1(FILE* f,char*& buf1,uint&);

           inline void CheckForRefForQueue(uint bulk_ret_buffer_size);

           inline void CheckForRefForHash(uint bulk_ret_buffer_size);

           inline uint GetMaxRefRecBuf();

protected:

   int sz;

   IdxItem *idx;

   RefItems ref;

   virtual void UsrOpen(hbTxn *tx,FileConf& conf,bool openidx,hbInitRt* irt = 0,u_int32_t flags = 0);

   virtual void UsrClose();

   inline virtual void ExportDBTemplate(FILE*,const char*,const char*) = 0;

   inline virtual void ImportDBTemplate(  char* buf1,

                                                   uint       buf1len,

                                                   char* buf2,

                                                   uint       buf2len,

                                                   hbObj*&    Key,

                                                   hbObj*&    Val) = 0;

public:

   //! конструктор принимает массив инициализаторов (в тч индексов)

   hbPTable(hbEnv& env,hbInit& ini1);

   virtual ~hbPTable();

 

   // проверка индексной целостности

   void CheckIdx(uint bulk_ret_buffer_size,bool fix);

 

   // проверка ссылочной целостности

   void CheckForRef(uint bulk_ret_buffer_size);

 

   void Export(uint bulk_ret_buffer_size,FILE* f, hbTxn* tx);

   void Import(FILE* f,char*& buf,uint&);

 

   virtual int Pget(hbTxn *tx,int n,hbObj *fkey, hbObj* pkey, hbObj *val, u_int32_t flags=0)

                                           {return idx[n].table.Pget(tx,fkey,pkey,val,flags);}

   hbBasetbl& GetIdx(int n)

                                           {return idx[n].table;}

   inline uint GetIdxCount()      {return sz;}

   inline uint GetRecSize()       {return recsize;}

 

};

Как видим, этот класс расширяет старый интерфейс путем введения утилитарных методов экспорта, импорта, различного рода проверок и операциями с индексными таблицами. Однако этот класс также не удобен в работе, так как не знает ничего о типах структур и ее характеристиках. Введение этих типов как параметров шаблона позволило бы очень упростить работу с интерфейсом индексируемой таблицы (но не расширить!). Результат приведен ниже:

template<class Key,class Val> class hbTable:public hbPTable

{

public:

   //! конструктор принимает массив инициализаторов (в тч индексов)

   hbTable(hbEnv& e,hbInit& ini1):hbPTable(e,ini1) {SetRecSize(sizeof(Val));SetKeySize(sizeof(Key));}

//SetRecSize use by QUEUE only

   virtual ~hbTable()         {}

 

   // более продвинутые функции

   int Get(const bexcp& excp, hbTxn *tx,const Key &key,Val *val, u_int32_t flags=0)

                                   {

                                                   Get(excp,tx,(Key*)&key,val,flags);

                                   }

 

   int Pget(const bexcp& excp, hbTxn *tx,int n,hbObj *fkey,Key *pkey, Val *val,u_int32_t flags=0)

                                   {

                                           MTRY

                                                   hbRec<Key> k;

                                                   hbRec<Val> v;

                                                   int z=Pget(tx,n,fkey,&k,&v,flags);

                                                  *pkey= *(k.getPnt());

                                                   *val= *(v.getPnt());

                                                   return z;

                                           CATCH_hbExcp

                                   }

   int Del(const bexcp& excp, hbTxn *tx, const Key &key,u_int32_t flags=0)

                                   {

                                                   Del(excp,tx,(Key*)&key,flags);

                                   }

   int tGet(const bexcp& excp, hbTxn *tx, Key *key,Val *val, u_int32_t flags=0)

                                   {

                                           MTRY

                                                   hbRec<Key> k(*key);

                                                   hbRec<Val> v;

                                                   int z = tGet(tx,&k,&v,flags);

                                                   *val= *(v.getPnt());

                                                   return z;

                                           CATCH_hbExcp

                                   }

   int Put(const bexcp& excp, hbTxn *tx,const Key &key, const Val &val, u_int32_t flags=0)

                                   {

                                                   Put(excp,tx,(Key*)&key,(Val*)&val,flags);

                                   }

   uint Append(const bexcp& excp, hbTxn *tx, Val *val)

                                   {

                                           MTRY

                                                   if(GetType()!= DB_QUEUE) return 0;

                                                   hbRec<uint> k;

                                                   hbRec<Val> v(*val);

                                                   hbBasetbl::Put(tx,&k,&v,DB_APPEND);

                                                   return (uint&)*(k.getPnt());

                                           CATCH_hbExcp

                                   }

   uint Append(const bexcp& excp, hbTxn *tx,const Val &val)

                                   {

                                                   return Append(excp,tx,(Val*)&val);

                                   }

};

Этот параметризированный класс на самом деле только переопределил сигнатуры методов более удобными и работающими с пользовательскими типами данных.

Транзакции

Класс транзакций имеет следующий вид:

class hbTxn{

   hbEnv& Env;

   bexcp excp1;

   hbTxn* parent;

   DbTxn* Txn;

   void SetFlags(){}

   hbTxn(const hbTxn& Txn1):Env(Txn1.Env){} //copy constr

   hbTxn& operator=(const hbTxn&){return *this;} //:=

public:

   operator DbTxn*()                                  {return Txn;};

 hbTxn(const bexcp& excp, hbEnv& env1,ullong flags = 0,hbTxn* parent1 = 0); // младшие 32 бита это //обычн. беркл. флаги 33 бит отвечает за немедленный старт транзакции сразу же после создания

   hbTxn(const bexcp& excp, hbTxn* parent1,ullong flags = 0); 

               // --- " ---

   ~hbTxn();

   bool HaveParentTxn()                               {return parent!=0;}

   void Start(const bexcp& excp, ulong flags = 0);

   void Commit(const bexcp& excp, ulong flags = 0);

   void RollBack(const bexcp& excp);

   //void RollBack();

};

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

try

{

    hbTxn tx(excp, parent_tx);

    // операции с базой

    tx.Commit();

}

catch(…){}
Как видим, первое - не надо заботиться об удалении объекта транзакции (при любой ситуации), второе – в случае исключения Rollback() вызовется автоматически в деструкторе этого объекта.

 

Транслятор

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

Файл грамматики приведен ниже:

%%

 

#-------------------------------------------------------

#------ COMMENTS --------------------------------------

#-------------------------------------------------------

 

#id        идентификатор

#string       строковый литерал или идентификатор

#num       чиловой литерал

#float     литерал числа с плавающей точкой

#char      символьный литерал

#rawcode::= любая последователность кода между '{*' и '*}'

 

file:      'end'                                              {tblproc::Finish();}

       | filetext 'end'                                     {tblproc::Finish();}

;

 

filetext:  item

       | item filetext

;

 

item:      optionblock

       | idxblock

       | structblock

       | enumblock

       | codeblock

       | tableblock

;

 

literal:   string                                             {[$_[1],0]}

       | num                                                {[$_[1],1]}

       | float                                              {[$_[1],2]}

       | char                                               {[$_[1],3]}

;

 

#---------------------------------------------------------

optionblock: 'option' '{' oplist '}' ';'

                {tblproc::OptBlockPrint('',$_[3]);}

       | 'option' opitem ';'  

                            {tblproc::OptBlockPrint('',[$_[2]]);}

       | 'option' id '{' oplist '}' ';'   

                {tblproc::OptBlockPrint($_[2],$_[4]);}

       | 'option' id opitem ';'   

                       {tblproc::OptBlockPrint($_[2],[$_[3]]);}

;

 

oplist:

           opitem ';'                                         {[$_[1]]}

       | opitem ';' oplist                                  {push @{$_[3]}, $_[1]; $_[3]}

;

 

opitem:    id '=' literal   

                                 {[$_[1],@{$_[3]}[0],0,@{$_[3]}[1]]}

       | id '=' id                                          {[$_[1],$_[3],1,'']}

;

#---------------------------------------------------------

idxblock:  'idx' id idxitem ';'

                              {tblproc::IdxBlockPrint($_[2],[$_[3]]);}

      | 'idx' id '{' idxitemlist '}' ';' 

                {tblproc::IdxBlockPrint($_[2],$_[4]);}

;

 

idxitemlist: idxitem ';'                                        {[$_[1]]}

       | idxitem ';' idxitemlist                            {unshift @{$_[3]},$_[1]; $_[3]}

;

idxitem:   idxmod1 id '(' flist1 ')' 

                        {[0,$_[1],$_[2],$_[4],'']}

       | idxmod1 id '(' flist1 ')' '{*' rawcode '*}' 

      {[0,$_[1],$_[2],$_[4],$_[7]]}

       | idxmod2 id '(' flist2 ')'                          {[1,$_[1],$_[2],$_[4],'']}

       | idxmod2 id '(' flist2 ')' '{*' rawcode '*}'

       {[1,$_[1],$_[2],$_[4],$_[7]]}

;

 

idxmod1:   '.!'

       | ':!'

       | '%!'

;

 

idxmod2:   '.'

       | ':'

       | '%'

;

 

flist1:    id                                                 {[[$_[1],'']]}

       | id ',' flist1                                      {unshift

@{$_[3]},[$_[1],''];$_[3]}

;

 

flist2:    idxmod3 id                                         {[[$_[2],$_[1]]]}

       | idxmod3 id ',' flist2                              {unshift

@{$_[4]},[$_[2],$_[1]];$_[4]}

;

 

idxmod3:   '+'

       | '-'

          | '^'

;

 

#---------------------------------------------------------

codeblock: code 'decl' '{*' rawcode '*}'

                     {tblproc::CodeBlockPrint('hh', \$_[4],0);}

       | code 'tab' '{*' rawcode '*}'

                       {tblproc::CodeBlockPrint('tab', \$_[4],0);}

       | code 'def' '{*' rawcode '*}'

                      {tblproc::CodeBlockPrint('cc', \$_[4],0);}

       | code 'def' 'top' '{*' rawcode '*}'

               {tblproc::CodeBlockPrint('cc', \$_[5],1);}

       | code '{*' rawcode '*}' 

                           {tblproc::CodeBlockPrint('all', \$_[3],0);}

;

 

#---------------------------------------------------------

enumblock: 'enum' id '{' enumlist '}' ';' 

                   {tblproc::EnumBlockPrint($_[2],$_[4]);}

       | 'enum' id ';'

                                     {tblproc::EnumBlockPrint($_[2],[]);}

;

enumlist:  enumitem                                           {[$_[1]]}

       | enumitem ',' enumlist                              {unshift @{$_[3]}, $_[1]; $_[3]}

;

enumitem:  id                                                 {[$_[1],'']}

       | id '=' num                                         {[$_[1],$_[3]]}

;

 

#---------------------------------------------------------

 

structblock: 'struct' id '{' structlist '}' ';'

               {tblproc::StructBlockPrint($_[2],$_[4]);}

;

 

structlist: structitem                                         {[$_[1]]}

       | structitem structlist                              {unshift @{$_[2]}, $_[1]; $_[2]}

;

 

structitem: id pnlistid ';'   

                               {[$_[1],@{$_[2]}[0],@{$_[2]}[1]]}

;

 

#---------------------------------------------------------

tableblock: tableforward  

                  {tblproc::TableBlockPrint(@{$_[1]}[0],'',[],[]);}

       | tablehead ';' 

                            {tblproc::TableBlockPrint(@{$_[1]}[0],@{$_[1]}[1],@{$_[1]}[2], []);}

       | tablehead tail ';' 

                               {tblproc::TableBlockPrint(@{$_[1]}[0],@{$_[1]}[1],@{$_[1]}[2], $_[2]);}

;

 

tail:      idxtailitem                                        {$_[1]}

       | idxtailitem tail                                {unshift @{$_[2]},$_[1];$_[2]}

       | optiontailitem

       | optiontailitem tail

;

 

tableforward: 'table' id ';'                                     {[$_[2]]}

;

 

tablehead: 'table' memmodifid '{' memberlist '}'

             {[@{$_[2]}[0],@{$_[2]}[1],$_[4]]}

;

 

memmodifid: id                                                 {[$_[1],'']}

       | memmodificator id                                  {[$_[2],'$']}

;

 

memberlist: memberitem                                         {[$_[1]]}

       | memberitem memberlist                              {unshift @{$_[2]}, $_[1]; $_[2]}

;

memberitem: id pnlistid ';' 

                                 {[$_[1],@{$_[2]}[0],@{$_[2]}[1],[]]}

       | id pnlistid modificator1 ';' 

                    {[$_[1],@{$_[2]}[0],@{$_[2]}[1],$_[3]]}

;

 

modificator1: idxmodificator                                     {[$_[1], '']}

#      | idxmodificator memmodificator                      {[$_[1], '$','']}

       | idxmodificator '{*' rawcode '*}'                   {[$_[1], $_[3]]}

#      | idxmodificator memmodificator '{*' rawcode '*}'    {[$_[1], '$', $_[4]]}

;

 

pnlistid:  pnlist id                                          {[$_[1], $_[2]]}

       | id                                                 {[[], $_[1]]}

;

 

pnlist:    pointer                                            {[$_[1],'']}

       | pointer array                                      {[$_[1],$_[2]]}

       | array                                              {['',$_[1]]}

;

 

pointer:   '+'

       | '-'

       | '*'

;

 

array:     '[' id ']'                                         {$_[2]}

       | '[' num ']'                                        {$_[2]}

;

 

idxmodificator: '.!'

       | ':!'

       | '%!'

       | '.+'

       | ':+'

       | '%+'

       | '.-'

       | ':-'

       | '%-'

       | '.^'

       | ':^'

       | '%^'

;

 

memmodificator: '$'

;

 

idxtailitem: 'idx' idxitem                                        {[$_[2]]}

       | 'idx' '{' idxitemlist '}'                          {$_[3]}

;

 

optiontailitem: 'option' '{' oplist '}'

       | 'option' opitem

;

#---------------------------------------------------------

%%

use tblproc;

 

 

Основными компонентами этой грамматики являются:

· option   – элемент языка, определяющий настройки к конкретной таблице.

· Idx блок – это блок, определяющий параметры индексной таблицы.

· Table блок - блок, определяющий таблицу, ее записи и индексы.

· Struct блок - блок, аналогичен table, с той разницей, генерирует только определения структур записей без определения самой таблицы.

· Enum блок – определение С++ енумераторов, используемых в определении таблицы.

· Code блок – блок сырого С++ кода встраимого непосредственного в результирующий файл.

Транслятор состоит из 3 основных частей лексики, семантики и пускового модуля, написанных на языке Perl.

Лексический анализатор создан с учетом этой грамматики и имеет следующий интерфейс.

Prepare(array of lines); // normal result ==0

token Next();

Он поддерживает также препроцессирование на уровне вложений include.

Семантический анализатор состоит из API, вызываемых как обработчики событий (для интерфейса yapp указываются в определении грамматики).

Пусковой модуль является оболочкой для запуска синтаксического анализатора, с разбором входных параметров

Формат:

   1)HibaseCompiler.pl [-f имя файла] [-p путь к hibase] [-d каталог, куда помещ. сген стаб]

   2)program | HibaseCompiler.pl [-p путь к hibase] [-d каталог,куда помещ. сген стаб].

 

Пример работы программы

 

В качестве примера  расмотрим следующее определение базы данных

Tables. def

code def top

{*

#include <stdio.h>

#include <stdlib.h>

#include <pthread.h>

#include <db_cxx.h>

 

#include "../hblib/consts.hh"

#include "../hblib/ll.hh"

#include "../hblib/utils.hh"

#include "../hblib/hdb.hh"

 

#include "tbmain.hh"

#include "dbmain.hh"

*}

 

option

{

file = "main";

namespace = "hb";

};

 

 table supplier

 {

char [12]name.!; // key uh; //unq,hash

char [40]desc;

 };

 

 table thing

 {

    supplier+ tsupplier;                    // внешняя ссылка

char [12]name.!; // key uh; //unq,hash

char [40]desc;

 };

end

 

В результате работы транслятора  получаем 3 файла: файл описания структур записей таблиц, файл определения самих таблиц и базы и файл ее реализации:

Hbmain.hh

 

namespace hb{

using namespace hb;

class mainEnv;

 

struct supplierKey

{

   db_recno_t key;

 

inline void Export(FILE* f);

inline void Import(char*,uint);

supplierKey(const db_recno_t& key_temp);

supplierKey(){}

}__attribute__ ((packed));

struct supplierVal

{

   char name[12];

   char desc[40];

 

inline void Export(FILE* f);

inline void Import(char*,uint);

supplierVal(char* name_temp,char* desc_temp);

supplierVal(){}

}__attribute__ ((packed));

class qsupplier: public hbTable<supplierKey,supplierVal>{

mainEnv& menv;

public:

qsupplier(mainEnv&);

inline void RefInit();

static void GetRef_supplier(uint, char*,char*, db_recno_t*&, uint&);

    static int qsupplier::idx_name(Db *db,const Dbt* pk,const Dbt* pv,Dbt* fv);

};

struct isupplier_name

{

   char name[12];

    char* Getname(){return name;}

   isupplier_name(char* name_temp);

}__attribute__ ((packed));

 

//------------------------------------------------------------------------------

 

struct thingKey

{

   db_recno_t key;

 

inline void Export(FILE* f);

inline void Import(char*,uint);

thingKey(const db_recno_t& key_temp);

thingKey(){}

}__attribute__ ((packed));

struct thingVal

{

   db_recno_t tsupplier;

   char name[12];

   char desc[40];

 

inline void Export(FILE* f);

inline void Import(char*,uint);

thingVal(const db_recno_t& tsupplier_temp,char* name_temp,char* desc_temp);

thingVal(){}

}__attribute__ ((packed));

 

 

class qthing: public hbTable<thingKey,thingVal>{

mainEnv& menv;

public:

qthing(mainEnv&);

inline void RefInit();

static void GetRef_thing(uint, char*,char*, db_recno_t*&, uint&);

    static int qthing::idx_name(Db *db,const Dbt* pk,const Dbt* pv,Dbt* fv);

};

struct ithing_name

{

   char name[12];

    char* Getname(){return name;}

   ithing_name(char* name_temp);

}__attribute__ ((packed));

 

//------------------------------------------------------------------------------

};

 

Dbmain.hh

 

namespace hb{

using namespace hb;

enum idxNames{

   dbn_supplier_name = 0, dbn_thing_name = 0};

class mainEnv;

class mainEnv:public hbEnv{

public:

   mainEnv(const char*,ushort flt = LL_DEBUG, Log* LogObj1 = 0);

   qsupplier&         tsupplier;

   qthing&    tthing;

};

};

 

Dbmain.cc

 

#include <stdio.h>

#include <stdlib.h>

#include <pthread.h>

#include <db_cxx.h>

 

#include "../hblib/consts.hh"

#include "../hblib/ll.hh"

#include "../hblib/utils.hh"

#include "../hblib/hdb.hh"

 

#include "tbmain.hh"

#include "dbmain.hh"

 

//#include <stdio.h>

//#include <stdlib.h>

//#include <time.h>

//#include <string.h>

//#include <stdarg.h>

//#include <pthread.h>

//#include <unistd.h>

//#include <dirent.h>

//#include <ctype.h>

//#include <sys/types.h>

 

//#include "../hibase/consts.hh"

//#include "../hibase/ll.hh"

 

//#include "../hibase/hdb.hh"

 

//#include "myconst.hh"

//#include "dbmain.hh"

namespace hb{};

using namespace hb;

namespace hb{};

using namespace hb;

#define NUMDB 2

enum maindbNames{

dbnsupplier = 0,dbnthing};

static hbInit tblIndexes[]={

{ "supplier::name","supplier.i","name",DB_HASH,0,0,0,&qsupplier::idx_name, 0, 0 },

{ "thing::name","thing.i","name",DB_HASH,0,0,0,&qthing::idx_name, 0, 0 }

};

static hbInit tblInits[]={

{"supplier","supplier.q",0,DB_QUEUE,0,1, tblIndexes + 0, 0, &qsupplier::GetRef_supplier, 0},

{"thing","thing.q",0,DB_QUEUE,0,1, tblIndexes + 1, 0, &qthing::GetRef_thing, 1}

};

envInit mainEnvInit={

NUMDB,

 "$Id: tblproc.pm,v 1.35 2004/01/10 23:57:48 bora Exp $"

};

 

 

qsupplier::qsupplier(mainEnv& env): hbTable<supplierKey,supplierVal>(env,tblInits[dbnsupplier]), menv(env)

{}

 

void qsupplier::RefInit()

{

 

}

 

void qsupplier::GetRef_supplier(uint num, char* key,char* val, db_recno_t*& refs, uint& ref_count)

{

   supplierKey *key1 = (supplierKey*)key;

   supplierVal *val1 = (supplierVal*)val;

 

}

void supplierKey::Export(FILE* f)

{

   fprintf(f,"%d",key);

}

void supplierKey::Import(char* buf, uint len)

{

   int j,num, i = 0;

   char temp;

   {j = i;for(;i<len;i++)if(buf[i]==',' || buf[i]=='}')break;}

           temp = buf[i];buf[i] = '\0';sscanf(buf+j,"%d",&key);

           buf[i] = temp;

   i++;

}

supplierKey::supplierKey(const db_recno_t& key_temp)

{

   memset(this,0,sizeof(*this));

   key = key_temp;

}

void supplierVal::Export(FILE* f)

{

   fprintf(f,"{");

   CharArrInToStr(f,name,12);

   fprintf(f,"}");

   fprintf(f,",");

   fprintf(f,"{");

   CharArrInToStr(f,desc,40);

   fprintf(f,"}");

}

void supplierVal::Import(char* buf, uint len)

{

   int j,num, i = 0;

   char temp;

 

if(buf[i++]!='{')

   throw hbExcp(3,LL_CRITICAL,0,"Ошибка импорта: +указатель на таблицу = 0.");

j = i;

for(;i<len;i++)

{

   if (buf[i] == '}' && buf[i-1]!='\\')

       break;

}

   StrToCharArr(buf+j,i-j,name,12);

   i+= 2;

 

if(buf[i++]!='{')

   throw hbExcp(3,LL_CRITICAL,0,"Ошибка импорта: +указатель на таблицу = 0.");

j = i;

for(;i<len;i++)

{

   if (buf[i] == '}' && buf[i-1]!='\\')

       break;

}

   StrToCharArr(buf+j,i-j,desc,40);

   i+= 2;

}

supplierVal::supplierVal(char* name_temp,char* desc_temp)

{

   memset(this,0,sizeof(*this));

   strncpy(name,name_temp, sizeof(name));

   strncpy(desc,desc_temp, sizeof(desc));

}

 

 

isupplier_name::isupplier_name(char* name_temp)

{

   memcpy(name,name_temp,sizeof(name));

}

 

int qsupplier::idx_name(Db *db,const Dbt* pk,const Dbt* pv,Dbt* fv)

{

   supplierVal *v= (supplierVal*)(pv->get_data());

 

fv->set_data(v->name);

fv->set_size(sizeof(isupplier_name));

return 0;

}

 

//------------------------------------------------------------------------------

 

qthing::qthing(mainEnv& env): hbTable<thingKey,thingVal>(env,tblInits[dbnthing]), menv(env)

{}

 

void qthing::RefInit()

{

   ref.reftables[0].type      = '+';

   ref.reftables[0].reftable  = &menv.tsupplier;

 

}

 

void qthing::GetRef_thing(uint num, char* key,char* val, db_recno_t*& refs, uint& ref_count)

{

   thingKey *key1 = (thingKey*)key;

   thingVal *val1 = (thingVal*)val;

   if(num==0)

   {

           refs = &val1->tsupplier; ref_count = 1;

   }

 

}

void thingKey::Export(FILE* f)

{

   fprintf(f,"%d",key);

}

void thingKey::Import(char* buf, uint len)

{

   int j,num, i = 0;

   char temp;

   {j = i;for(;i<len;i++)if(buf[i]==',' || buf[i]=='}')break;}

           temp = buf[i];buf[i] = '\0';sscanf(buf+j,"%d",&key);

           buf[i] = temp;

   i++;

}

thingKey::thingKey(const db_recno_t& key_temp)

{

   memset(this,0,sizeof(*this));

   key = key_temp;

}

void thingVal::Export(FILE* f)

{

   fprintf(f,"%d",tsupplier);

   fprintf(f,",");

   fprintf(f,"{");

   CharArrInToStr(f,name,12);

   fprintf(f,"}");

   fprintf(f,",");

   fprintf(f,"{");

   CharArrInToStr(f,desc,40);

   fprintf(f,"}");

}

void thingVal::Import(char* buf, uint len)

{

   int j,num, i = 0;

   char temp;

   {j = i;for(;i<len;i++)if(buf[i]==',' || buf[i]=='}')break;}

           temp = buf[i];buf[i] = '\0';sscanf(buf+j,"%d",&tsupplier);

           buf[i] = temp;

   if(tsupplier == 0) throw hbExcp(3,LL_CRITICAL,0," Ошибка импорта: +указатель на таблицу = 0. ");

   i++;

 

if(buf[i++]!='{')

   throw hbExcp(3,LL_CRITICAL,0," Ошибка импорта: не могу распарсить строку.");

j = i;

for(;i<len;i++)

{

   if (buf[i] == '}' && buf[i-1]!='\\')

       break;

}

   StrToCharArr(buf+j,i-j,name,12);

   i+= 2;

 

if(buf[i++]!='{')

   throw hbExcp(3,LL_CRITICAL,0," Ошибка импорта: не могу распарсить строку. ");

 j = i;

for(;i<len;i++)

{

   if (buf[i] == '}' && buf[i-1]!='\\')

       break;

}

   StrToCharArr(buf+j,i-j,desc,40);

   i+= 2;

}

thingVal::thingVal(const db_recno_t& tsupplier_temp,char* name_temp,char* desc_temp)

{

   memset(this,0,sizeof(*this));

   tsupplier = tsupplier_temp;

   strncpy(name,name_temp, sizeof(name));

   strncpy(desc,desc_temp, sizeof(desc));

}

 

ithing_name::ithing_name(char* name_temp)

{

   memcpy(name,name_temp,sizeof(name));

}

 

int qthing::idx_name(Db *db,const Dbt* pk,const Dbt* pv,Dbt* fv)

{

   thingVal *v= (thingVal*)(pv->get_data());

 

fv->set_data(v->name);

fv->set_size(sizeof(ithing_name));

return 0;

}

 

//------------------------------------------------------------------------------

mainEnv::mainEnv(const char *path,ushort flt, Log* LogObj1):hbEnv(path,mainEnvInit,flt,LogObj1),

tsupplier(* (new qsupplier(*this))),

tthing(* (new qthing(*this)))

{

   dbs[dbnsupplier]            = &tsupplier;tsupplier.RefInit();

   dbs[dbnthing]       = &tthing;tthing.RefInit();

 

}

 

Файл пример описан так

int main(void)

{

mainEnv env ("./DataBase/");

//создаем базу, то есть формируем необходимые файлы для всех таблиц

env.Init(bexcp(16,"main","example.cc",3,LL_DEBUG));

env.Close(bexcp(16,"main","example.cc",3,LL_DEBUG));

env.ImportDB(bexcp(16,"main","example.cc",3,LL_DEBUG),"./Export1.ex");

env.ExportDB(bexcp(16,"main","example.cc",3,LL_DEBUG),"./Export.ex");

// проверяем на индексную целостность

env.CheckForIdx(bexcp(16,"main","example.cc",3,LL_DEBUG));

// проверяем на ссылочную целостность

env.CheckForRef(bexcp(16,"main","example.cc",3,LL_DEBU


Поделиться с друзьями:

История развития хранилищ для нефти: Первые склады нефти появились в XVII веке. Они представляли собой землянные ямы-амбара глубиной 4…5 м...

Типы сооружений для обработки осадков: Септиками называются сооружения, в которых одновременно происходят осветление сточной жидкости...

Своеобразие русской архитектуры: Основной материал – дерево – быстрота постройки, но недолговечность и необходимость деления...

Таксономические единицы (категории) растений: Каждая система классификации состоит из определённых соподчиненных друг другу...



© cyberpedia.su 2017-2024 - Не является автором материалов. Исключительное право сохранено за автором текста.
Если вы не хотите, чтобы данный материал был у нас на сайте, перейдите по ссылке: Нарушение авторских прав. Мы поможем в написании вашей работы!

0.963 с.