Эмиссия газов от очистных сооружений канализации: В последние годы внимание мирового сообщества сосредоточено на экологических проблемах...
Типы сооружений для обработки осадков: Септиками называются сооружения, в которых одновременно происходят осветление сточной жидкости...
Топ:
Основы обеспечения единства измерений: Обеспечение единства измерений - деятельность метрологических служб, направленная на достижение...
Устройство и оснащение процедурного кабинета: Решающая роль в обеспечении правильного лечения пациентов отводится процедурной медсестре...
Эволюция кровеносной системы позвоночных животных: Биологическая эволюция – необратимый процесс исторического развития живой природы...
Интересное:
Отражение на счетах бухгалтерского учета процесса приобретения: Процесс заготовления представляет систему экономических событий, включающих приобретение организацией у поставщиков сырья...
Принципы управления денежными потоками: одним из методов контроля за состоянием денежной наличности является...
Как мы говорим и как мы слушаем: общение можно сравнить с огромным зонтиком, под которым скрыто все...
Дисциплины:
2020-04-01 | 129 |
5.00
из
|
Заказать работу |
|
|
Содержание
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 указывает на правило(левую часть), выполняющееся первым.
Секция правил содержит грамматические правила:
Каждое правило состоит из слева лежащего символа (нетерминального), разделенного ':' и одним или несколькими возможными правилами, разделенными '|' и завершенными ';':
|
Правило справа может быть пустым
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 - Не является автором материалов. Исключительное право сохранено за автором текста.
Если вы не хотите, чтобы данный материал был у нас на сайте, перейдите по ссылке: Нарушение авторских прав. Мы поможем в написании вашей работы!