Harbour — новое лицо xBase family

в 16:48, , рубрики: dbms, open source, байт-код, компилятор, Компиляторы, кроссплатформенная разработка, Программирование, СУБД, метки: , , , , ,

Для справки: xBase — семейство систем программирования, СУБД, берущих начало с dBase (1980 г.). Их объединяет общий язык программирования ( естественно, с вариациями, присущими конкретной реализации ) и встроенные в этот язык средства доступа к реляционным базам данных формата DBF. Собственно, dBase начинался как СУБД с языком, предназначеннным для обслуживания баз данных. Это процедурный язык программирования, он относится к группе интерпретируемых языков и обладает многими, если не всеми, их родовыми чертами, такими, например, как динамическая типизация.

Clipper, непосредственный предшественник Harbour, был создан в 1985 г. с целью повышения производительности dBase III. Для этого исходный код программы преобразовывался на стадии компиляции в байт-код, который встраивался в исполнямый файл вместе с виртуальной машиной, предназначенной для исполнения этого байт-кода. Таким образом, Clipper давал на выходе автономный exe файл, не требующий для своего запуска и выполнения внешнего интерпретатора, как в случае dBase или FoxBase ( другой популярный xBase продукт ).

В конце 80-х и начале 90-х Clipper был очень популярен, он был одним из основных средств программирования для приложений, связанных с использованием баз данных, в первую очередь бухгалтерских, управленческих, банковских. Язык модернизировался от версии к версии, добавлялись новые подсистемы. Среди последних особенно следует отметить Extend System и RDD. Extend System (система расширения) предназначена для связи с модулями, написанными на С — вызов функций, передача параметров, получение возвращаемых значений. RDD — Replaceable Database Drivers (заменяемые драйверы баз данных) — технология, которая позволяла, прилинковав взамен стандартной другую, специальную библиотеку, работать с БД другого типа, не изменив ни строчки кода. Именно так Clipper-приложения работали, например, с Novell'овским Btrieve (если кто помнит, была такая клиент-серверная не SQL СУБД).

XBase системы всегда воспринимались как предназначенные, в первую очередь, для работы с базами данных и, возможно поэтому, с ростом популярности SQL стали выходить из тренда. И если с Fox'ом все было более-менее благополучно — купившая его Microsoft сделала на его основе популярный продукт Visual Foxpro, который еще несколько лет назад (в 2006, согласно Википедии), был на почетном 12-м месте в списке TIOBE, то у Clipper дела были куда хуже. Computer Associates, которая владела им с начала 90-х, сделала ставку на другие продукты. Clipper же остался в стороне от магистрального пути, назревшие проблемы не решались, а в 1997 году Computer Associates объявила о закрытии дальнейшей его разработки, оставив пишущих на нем программистов наедине с 16-разрядной, рассчитанной на применение в среде MS-DOS системой программирования.

Многие из тех, кто задумывался о своем будущем, мигрировали на другие платформы, но остались и те, кто считал, что достоинства Clipper, будучи реализованы в современной среде программирования, будут востребованы и дальше. Были созданы несколько таких реализаций (xBase++, Clip, Harbour), об одной из которых, наиболее успешной на этот день я и поведу речь — прошу простить меня за такое длинное, но, на мой взгляд, необходимое вступление.

Итак, Harbour. Проект стартовал в 1999 году, официальный сайт — www.harbour-project.org. Текущая версия — 3.0 (stable), 3.2 (development).

Как и Clipper, Harbour транслирует исходный текст программы в байт-код, но, в отличие от своего предшественника, компилятор Harbour создает не объектные, а с файлы, которые потом надо «скормить» С компилятору. Например, вот такую простейшую функцию, выводящую приветствие на консоль:

Function Hello
   ? "Hello"
   Return Nil

он транслирует в (комментарии — мои):

// HB_FUNC определено как:
// #define HB_FUNC( funcname )        HB_EXTERN_C_ HB_EXPORT HARBOUR HB_FUN_##funcname ( void )

HB_FUNC( HELLO )
{
   // байт-код
   static const HB_BYTE pcode[] =
   {
      36,2,0,176,2,0,106,6,72,101,108,108,111,0,
      20,1,36,3,0,100,110,7
   };
   // Вызов виртуальной машины (далее - ВМ) для выполнения байт-кода
   hb_vmExecute( pcode, symbols );
}

Рассмотрим байт-код подробнее:

   static const HB_BYTE pcode[] =
   {
      36,2,0,                          // 36 - код, за которым следует номер строки 
                                       // исходного текста, в данном случае - 2
      176,2,0,                         // 176 - помещает символ на стек ВМ, имеется 
                                       // ввиду символ, представляющий функцию вывода
      106,6,'H','e','l','l','o','',  // 106 - помещает строку на стек ВМ
      20,1,                            // 20 - ВМ должна выполнить функцию и отбросить 
                                       // ее результат, 1 - количество параметров
      36,3,0,                          // 36 - код, за которым следует номер строки 
                                       // исходного текста, в данном случае - 3
      100,                             // 100 - помещает Nil на стек ВМ
      110,                             // 110 - ВМ должна вернуть значение с вершины стека
      7                                // 7 - ВМ должна завершить работу
   };

Ваш проект может включать исходники на Harbour (*.prg), на C, специальные объектные файлы и библиотеки. С код может быть встроен и в prg-файл, его надо заключить в #pragma BEGINDUMP#pragma ENDDUMP и, естественно, он должен соответствовать соглашениям EXTEND SYSTEM (я упоминал о ней, когда говорил о Clipper). Ниже — пример такого симбиоза:

Function Main
   ? Sinus( 30 ), Sinus( 60 )
   ?

   Return Nil

#pragma BEGINDUMP
#include <math.h>
#include "hbapi.h"
#include "hbapiitm.h"

#define PI 3.14159265
// Вычисляем синус угла, заданного в градусах

HB_FUNC( SINUS )
{
   // hb_parnd( n ) - функция EXTEND SYSTEM, принимает n-й переданный параметр
   //    как double из Harbour функции
   // hb_retnd( d ) - функция EXTEND SYSTEM, возвращает double значение d
   //    обратно в Harbour функцию

   hb_retnd( sin( hb_parnd( 1 ) * PI / 180 ) );
}
#pragma ENDDUMP

Я не случайно уделил столько внимания С в Harbour. Расширенная ( извините за невольную тавтологию ), по сравнению с Clipper, Extend System и Item API, предоставляющая доступ из С кода к внутренним структурам Harbour, его переменным, массивам, объектам позволяют говорить о симбиозе двух языков, я считаю это одной из важнейших особенностей Harbour. Благодаря этому Harbour уже «оброс» большим количеством модулей — оболочек к разнообразным продуктам, имеющим C API и список таких модулей, как open source, так и коммерческих, постоянно растет (в настоящее время подумываю об OpenCV). Конечно же, С используется в Harbour не только для создания оболочек к готовым продуктам, но и для самостоятельных разработок — новые RDD, GUI библиотеки и др. Иногда, в контексте некоторых приложений я рассматриваю Harbour как оболочку к С коду — для облегчения реализации пользовательского интерфейса, доступа к БД и пр.

Встроенный доступ к БД, эта родовая черта xBase, — еще одна тема, которой хочется уделить особое внимание. Это, действительно, очень удобно — иметь возможность, не используя внешние СУБД, с помощью только встроенных языковых средств производить все необходимые манипуляции с базами данных — создание, модификация, пополнение, редактирование, поиск. В случае, когда количество информации, хранящейся в БД, сравнительно невелико, использовать внешнюю СУБД представляется совершенно излишним, для таких приложений и MySQL выглядит монстром (а ведь некоторые даже MS SQL ставят) — xBase подход здесь выглядит наиболее адекватным решением. Впрочем, и для больших БД Harbour может применяться (и применяется) вполне успешно.

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

Function Test
   Local aStru := { {"FAMILY","C",16,0}, {"IMYA","C",16,0}, {"OTCHES","C",16,0}, ;
      {"TELEFON","C",10,0} }

   // Создаем таблицу БД mytable с ФИО и номерами телефона
   dbCreate( "mytable", aStru )

   // Открываем mytable
   USE mytable

   // Создаем индексы по фамилии и по телефону
   INDEX ON FAMILY TAG FAMILY
   INDEX ON TELEFON TAG TELEFON

   // Добавляем записи
   APPEND BLANK
   REPLACE FAMILY WITH "Иванов", IMYA WITH "Игорь", OTCHES WITH "Константинович", ;
      TELEFON WITH "9101682020"
   ...

   // Ищем запись по номеру телефона, используя индекс
   ordSetFocus( "TELEFON" )
   IF dbSeek( "9101682020" )
      // Если запись найдена, изменяем номер
      REPLACE TELEFON WITH "9102875555"
   ENDIF
   ...

   Return Nil

Средства доступа к БД не ограничиваются стандартными. Есть RDD, написанные для клиент-серверных СУБД, как основанных на DBF ( коммерческая Advantage Database Server от Sybase и open source LetoDb ), та и SQL. Есть модули, обеспечивающие доступ посредством ODBC и ADO, есть модули для MySQL, PostgreSQL, SQLite, использующие C API этих СУБД.

В Harbour получили дальнейшее развитие все особенности Clipper, сделавшие его языком высокого уровня, на котором удобно программировать — автоматическое выделение и освобождение памяти, сборщик мусора, так называемые raw arrays, возможность компилировать и исполнять в run-time, в динамике фрагменты кода. Добавлена полноценная реализация ООП. Препроцессор, сохранив всю мощь Clipper'овского, расширен за счет некоторых конструкций, взятых из С. Впрочем, не буду перечислять здесь все новшества, а просто сошлюсь на раздел моего сайта Harbour для начинающих.

Да, я, кажется, забыл сказать, что Harbour — кроссплатформенная система с открытыми исходниками. Он существует на 32- и 64-разрядных платформах, на Windows, Linux, Unix, Mac OS X, QNX, OS/2, вроде бы и на Android, и еще на чем-то, чего я не видел.

Буду рад, если эта статья вызовет интерес. В этом случае можно будет рассмотреть какие-то аспекты более подробно.

Автор: alkresin

Источник

Поделиться

* - обязательные к заполнению поля