Harbour (язык программирования)

Материал из Национальной библиотеки им. Н. Э. Баумана
Последнее изменение этой страницы: 20:15, 1 июня 2016.
Harbour Project
Парадигма императивный, структурированный, объектно-ориентированный
Спроектировано Antonio Linares
Первый   появившийся 1986
Печать дисциплины необязательная неявная, динамическая, защищённая, частично строгая
Лицензия Open source GPL-совместимая
Расширение файла .prg, .ch, .hbs, .dbf
Портал: http://www.harbour-project.org/
Диалект
Clipper, Xbase++, Flagship, FoxPro, xHarbour
Под влиянием
dBase, Clipper
Влияние
xHarbour

Harbour - это современный язык программирования, в первую очередь используемый для создания баз данных и бизнес программ. Это модернизированная, свободная, кроссплатфоменная версия старой и, в значительной степени предназначенной, только для DOS системы Clipper, которая в свою очередь разработана из dBase 1980-х и 90-х годов.

Harbour код, используя одни и те же базы данных может быть компилирован под широкий спектр платформ, включая DOS, Microsoft Windows, Linux, Unix, некоторые BSD потомки, Mac OS X, MINIX 3, Windows CE, Pocket PC, Symbian, iOS, Android, QNX, VxWorks, OS/2/eComStation, BeOS/Haiku, AIX.

История

Идея свободного компилятора Clipper напрашивалась в течении долгого времени, и эта тема часто возникала в ходе обсуждения на comp.lang.clipper. Реализация проекта началась после того, как Антонио Линарес основал Harbour. Начиная с 1999 Harbour являлся свободной реализацией Clipper. В 2001 году появилось коммерческое ответвление под названием xHarbour.

В 2009 году Harbour был глубоко переработан международным сообществом разработчиков под руководством Виктора Сакаца (венг. Viktor Szakáts) и Пшемыслава Черпака (польск. Przemysław Czerpak), по состоянию на настоящее время ведётся активное развитие и разработка, имеются как международное, так и языково-ориентированные (русский, испанский, португальский, итальянский и пр. языки) комьюнити разработчиков и пользователей.

Особенности

  • Компилятор с поддержкой всех основных платформ.
  • Является свободным программным обеспечением.
  • Совместимость с компиляторами Clipper.
  • Динамически создаваемые и автоматически освобождаемые переменные, массивы, составные структуры данных, которые, по сути, являются массивами.
  • Макро-оператор, который позволяет производить компиляцию во время исполнения для любых выражений Harbour.
  • Harbour может использовать следующие C компиляторы, среди которых: GCC, MinGW, Clang, ICC, Microsoft Visual C++ (6.0+), Borland C++, Watcom C, Pelles C и Sun Studio.
  • Harbour поддерживает внешние GUI.

Встроенные типы данных

В Harbour есть 6 скалярных типов данных:

  • ничто Nil
  • строка String
  • дата Date
  • логический Logical
  • число Number
  • указатель Pointer

И 4 составных типа:

  • массив Array
  • объект Object
  • блок кода CodeBlock
  • хэш Hash

Массивы — это упорядоченные списки скалярных или составных значений (то есть элементом массива может быть в том числе и другой массив, а его элементом — другой и т. п.), индексированный по номеру, начиная с 1 (а не с 0, как в некоторых других языках). Хэш-таблицы, или ассоциативные массивы — неупорядоченные собрания значений любых типов, индексируемые по ключу, связанному с каждым значением, который может быть любого скалярного или составного типа. В хэш-таблицах в качестве ключа для любого элемента может использоваться значение любого типа, включая другую хэш-таблицу. Хэш-таблицы и массивы могут содержать в качестве значения любого элемента значение любого типа, в том числе вложенные массивы и хэш-таблицы. Блоки кода могут содержать ссылки на переменные процедуры, функции или метода, в котором определен блок кода. Такие блоки кода могут возвращаться в виде значения или в аргументе, передаваемом по ссылке; в этом случае блок кода «переживёт» подпрограмму, в которой он определён, и все переменные, на которые он ссылается, будут «отсоединенными (detached)» переменными.

Переменные

Именованная переменная может быть любого типа. Имя переменной должно иметь длину от 1 до 63 символов, начинаться с [A-Z|_] и далее состоять из символов [A-Z|0–9|_]. Именованные переменные чувствительны к регистру.

Переменные имеют одну их следующих областей видимости:

  • LOCAL: Видима только в подпрограмме, в которой она была определена. Значение теряется при выходе из подпрограммы.
  • STATIC: Видима только в подпрограмме, в которой она была определена. Значение сохраняется в течение последующих вызовов процедуры. Если статическая переменная объявлена до любой процедуры / функции / метода, то она будет видна в любой подпрограмме в рамках того же файла с исходным кодом. Она будет поддерживать свою жизнь на протяжении всего срока выполнения приложения.
  • PRIVATE: Видима в пределах подпрограммы в которой она определена и в пределах всех подпрограмм, вызываемых из этой подпрограммы.
  • PUBLIC: Видима всеми подпрограммами в приложении.

Управляющие конструкции

Циклы

В языке Harbour есть три основных типа циклов.

 [DO] WHILE ''ConditionExp''
    ''...''
    [LOOP]
    [EXIT]
 END[DO]
 FOR ''Var'' := ''InitExp'' TO ''EndExp'' [STEP ''StepExp'']
    ''...''
    [LOOP]
    [EXIT]
 NEXT
 FOR EACH ''Var'' IN ''CollectionExp''
    ''...''
    [''Var'':__enumIndex()]
    [LOOP]
    [EXIT]
 NEXT

В условии цикла FOR выражение присваивания вычисляется до первой итерации. Выражение TO вычисляется и сравнивается со значением контрольной переменной до каждой итерации и цикл прерывается, если вычисленное числовое значение больше контрольной переменной. Опциональное выражение STEP вычисляется после каждой итерации, перед принятием решения о выполнении следующей итерации.

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

Условный оператор

 IF ''CondExp''
    ''...''
 [ELSEIF] ''CondExp''
    ''...''
 [ELSE]
    ''...''
 END[IF]

Выражение условия вычисляется до значения логического типа.

Конструкция SWITCH

Harbour поддерживает конструкцию SWITCH перенятую из Си реализации конструкции switch().

 SWITCH ''SwitchExp''
 CASE ''LiteralExp''
    ''...''
    [EXIT]
 [CASE ''LiteralExp'']
    ''...''
    [EXIT]
 [OTHERWISE]
    ''...''
 END[SWITCH]

Выражение LiteralExp должно быть вычисляемым во время компиляции и может включать операторы, которые состоят из статических значений времени компиляции. Опциональное выражение EXIT эквивалентно выражению break из C и, если это выражение присутствует, то выполнение конструкции SWITCH завершится, когда будет достигнуто выражение EXIT, в противном случае выполнение продолжится с первого оператора после следующего выражения CASE.

Процедуры/Функции

Процедуры и функции в Harbour могут быть объявлены с помощью ключевых слов PROCEDURE или FUNCTION. Правила именования такие же, как и для переменных (до 63 символов, не чувствительно к регистру). И процедуры и функции могут быть квалифицированы ключевым словом STATIC, для ограничения пространства их использования до модуля в котором они были определены.

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

 [STATIC] PROCEDURE ''SomeProcedureName''
 [STATIC] PROCEDURE ''SomeProcedureName''()
 [STATIC] PROCEDURE ''SomeProcedureName''( ''Param1'' [, ''ParamsN''] )

 INIT PROCEDURE ''SomeProcedureName''
 EXIT PROCEDURE ''SomeProcedureName''

 [STATIC] FUNCTION ''SomeProcedureName''
 [STATIC] FUNCTION ''SomeProcedureName''()
 [STATIC] FUNCTION ''SomeProcedureName''( ''Param1'' [, ''ParamsN''] )

Макро-оператор (компилятор времени выполнения)

Одна из наиболее мощных возможностей xBase-языков — это Макро-оператор '&'. Реализация макро-оператора в Harbour позволяет создавать любое допустимое в Harbour выражение прямо во время выполнения программы (компиляция времени выполнения). Такое скомпилированное выражение может быть использовано как значение, то есть в правой части операции присваивания (rvalue), но также — что более интересно — и как левая часть операции присваивания (lvalue), то есть как PRIVATE или PUBLIC переменная, или как поле (FIELD) базы данных.

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

Последний макро-компилятор может компилировать любой допустимый в Harbour код, включая код для препроцессора, обрабатываемый до компиляции.

Синтаксис макро-оператора:

  &( ... )

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

  &SomeId

это более короткая форма макро-оператора &(SomeId).

  &SomeId.postfix

это более короткая форма макро-оператора &(SomeId + «postfix»).

Объектно ориентированное программирование

В Harbour есть расширения, базирующиеся на синтаксисе CLASSy, для ООП-программирования с полной поддержкой классов, включая наследование. ООП-синтаксис в Harbour практически одинаков с тем, что ранее использовался в библиотеках классов для Clipper, в т. ч. вполне возможно без особых переделок использовать «унаследованный» Clipper-код.

Для создания и тестирования простого класса достаточно написать:

#include "hbclass.ch"
FUNCTION Main
Local obj := myFirstClass():New(3)   ? obj:x       
   ?
RETURN NilCLASS myFirstClass
   VAR   x
   METHOD New( n )   INLINE ( ::x := n, Self )
ENDCLASS

Примеры кода

Программа "hello world" на языке Harbour будет выглядеть так:

  ? "Hello, world!"

или так:

  QOut( "Hello, world!" )

или так:

  Alert( "Hello, world!" )

Или внутри процедуры:

 PROCEDURE Main()

    ? "Hello, world!"

    RETURN

Простая ООП программа:

#include "hbclass.ch"
FUNCTION Main
   Local obj1, obj2   obj1 := mySecondClass():New( 10,"Alex" )
   ? "Всего объектов mySecondClass:", mySecondClass():nKolObj
   obj2 := mySecondClass():New( 11,"Mike" )
   ? "Всего объектов mySecondClass:", mySecondClass():nKolObj
   ? obj1:x, obj2:x
   ? 
RETURN NilCLASS myFirstClass
   VAR   x
   METHOD New( n )   INLINE ( ::x := n, Self )
ENDCLASSCLASS mySecondClass  FROM myFirstClass
HIDDEN:
   VAR   cStringSEXPORTED:
   CLASS VAR  nKolObj     INIT 0
   VAR        cString1    INIT "Sample"
   METHOD New( n, s )
ENDCLASSMETHOD New( n, s ) CLASS mySecondClass   Super:New( n )
   ::nKolObj ++
   ::cStringS := s
RETURN Self

В данной программе два класса: myFirstClass и mySecondClass. При этом mySecondClass это наследник класса myFirstClass. Две переменные nKolObj и cString1 принимают начальные значение при определении класса. Они будут доступны для любых новых объектов этого класса. Метод New класса mySecondClass описывается отдельно с помощью конструкции METHOD <methodName> CLASS <className>. В этом методе Super:New(n) используется для вызова идентичного метода из класса предка для инициализации переменных объекта, унаследованных от этого предка. Переменная cStringS класса mySecondClass имеет атрибут HIDDEN (т.е. доступна только из методов класса), а остальные переменные и метод New помечены как EXPORTED (т.е. доступны везде). CLASS VAR nKolObj класса mySecondClass это переменная, которая принадлежит не объекту, а целому классу, в данной программе она используется как счетчик объектов класса.

Ссылки

  1. Harbour home page
  2. Extensive Harbour documentation
  3. Harbour for beginners

Автор статьи: Фадеев П.В.