Harbour (programming language)

From Bauman National Library
This page was last modified on 1 June 2016, at 17:15.
Harbour Project
Paradigm imperative, structured, object oriented
Designed by Antonio Linares
First appeared 1986
Typing discipline Dynamic, protected, partially strict
License Open source GPL-compatible
Filename extensions .prg, .ch, .hbs, .dbf
Website http://www.harbour-project.org/
Dialects
Clipper, Xbase++, Flagship, FoxPro, xHarbour
Influenced by
dBase, Clipper
Influenced
xHarbour

Harbour - a modern programming language that was created as Clipper language compiler programming (a variant of xBase) developed as free software. His initial goal was to support all statements and extensions of the most popular version of the compiler, Clipper 5.2. Harbour is also a cross-platform compiler can compile for and run on DOS (MS-DOS, DR-DOS, etc.), Microsoft Windows, OS / 2, GNU / Linux, several Unix variants, several descendants of BSD, Mac OS X, MINIX 3, Windows CE, Pocket PC, Symbian, iPhone OS, QNX, VxWorks, OS / 2 BeOS / Haiku, AIX using the same source files and database code.

History

The idea of a free software compiler Clipper had been around for a long time and was often debated in comp.lang.clipper. The project was initiated by Antonio Linares, creator of the FiveWin library, and was quickly seconded by other figures of development in Clipper. Several of the houses that develop libraries for Clipper supported the project, supporting it in its products. Harbour name is a pun on the type Clipper ships that arrived at a port, the port being Clipper Harbour.

Harbour in 2009 was redesigned substantially, especially by Viktor Szakáts and Przemyslaw Czerpak.

Features

  • It is a compiler with support for all major platforms.
  • The open source Harbour license.
  • Compatible with Clipper compilers.
  • Dynamically created and automatically released variables, arrays, complex data structures, which, in fact, are arrays.
  • Macro Operator allows for runtime compilation of any valid Harbour expression.
  • Harbour can use the following C compilers, among others: GCC, MinGW, Clang, ICC, Microsoft Visual C++ (6.0+), Borland C++, Watcom C, Pelles C and Sun Studio.
  • Harbour supports external GUIs.

Built-in data types

Harbour has 6 scalar types :

  • Nil
  • String
  • Date
  • Logical
  • Number
  • Pointer

And 4 complex types:

  • Array
  • Object
  • CodeBlock
  • Hash

Arrays are ordered lists of scalars or complex types, indexed by number, starting at 1. Hashes, or associative arrays, are unordered collections of any type values indexed by their associated key, which may be of any scalar or complex type. Hashes may use any type including other Hashes as the Key for any element. Hashes and Arrays may contain any type as the Value of any member. Codeblocks may have references to Variables of the Procedure/Function/Method in which it was defined.

Variables

All types can be assigned to named variables. Named variable identifiers are 1 to 63 characters long, start with [A-Z|_] and further consist of the characters [A-Z|0–9|_] up to a maximum of 63 characters. Named variables are not case sensitive. Variables have one of the following scopes:

  • LOCAL: Visible only within the routine which declared it. Value is lost upon exit of the routine.
  • STATIC: Visible only within the routine which declared it. Value is preserved for subsequent invocations of the routine. If a STATIC variable is declared before any Procedure/Function/Method is defined, it has a MODULE scope, and is visible within any routine defined within that same source file, it will maintain its life for the duration of the application lifetime.
  • PRIVATE: Visible within the routine which declared it, and all routines called by that routine.
  • PUBLIC: Visible by all routines in the same application.

Control structures

Loops

There are three types of loops in Harbour.

In the FOR statement, the assignment expression is evaluated prior to the first loop iteration. The TO expression is evaluated and compared against the value of the control variable, prior to each iteration, and the loop is terminated if it evaluates to a numeric value greater than the numeric value of the control variable. The optional STEP expression is evaluated after each iteration, prior to deciding whether to perform the next iteration.

In FOR EACH, the Var variable will have the value (scalar, or complex) of the respective element in the collection value. The collection expression, may be an Array (of any type or combinations of types), an Hash Table, or an Object type.

 [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

IF statements

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

The condition expression(s) has to evaluate to a LOGICAL value.

SWITCH statements

Harbour supports a SWITCH construct inspired by the C implementation of switch().

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

The LiteralExp must be a compiled time resolvable numeric expression, and may involve operators, as long as such operators involve compile time static value. The EXIT optional statement is the equivalent of the C statement break, and if present, execution of the SWITCH structure will end when the EXIT statement is reached, otherwise it will continue with the first statement below the next CASE statement (fall through).

Procedures/Functions

Procedures/Functions in Harbour can be specified with the keywords PROCEDURE, or FUNCTION. Naming rules are same as those for Variables (up to 63 characters non-case sensitive). Both Procedures and Functions may be qualified by the scope qualifier STATIC to restrict their usage to the scope of the module where defined.

The INIT or EXIT optional qualifiers, will flag the procedure to be automatically invoked just before calling the application startup procedure, or just after quitting the application, respectively. Parameters passed to a procedure/function appear in the subroutine as local variables, and may accept any type, including references.

 [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''] )

Macro Operator (runtime compiler)

One of the most powerful features of xBase languages is the Macro Operator '&'. Harbour's implementation of the Macro Operator allows for runtime compilation of any valid Harbour expression. Such a compiled expression may be used as a VALUE, i.e. the right side of an assignment (rvalue), but more interestingly, such a compiled expression may be used to resolve the left side (lvalue) of an assignment, i.e. PRIVATE, or PUBLIC variables, or a database FIELD.

Additionally, the Macro Operator may compile and execute function calls, complete assignments, or even list of arguments, and the result of the macro may be used to resolve any of the above contexts in the compiled application. In other words, any Harbour application may be extended and modified at runtime to compile and execute additional code on-demand.

Latest Macro compiler can compile any valid Harbour code including code to pre-process before compile.

Syntax:

  &( ... )

The text value of the expression '...' will be compiled, and the value resulting from the execution of the compiled code is the result.

  &SomeId

is the short form for &( SomeId ).

  &SomeId.postfix

is the short form of &( SomeId + "postfix" ).

Object Oriented Programming

Harbour has OOP extensions with full support for classes including inheritance, based on Class(y) syntax. OOP syntax in Harbour is very similar to that of earlier Clipper class libraries so it should be possible to maintain legacy Clipper code with minimal changes.

To create and test a simple class it is enough to write:

#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

Code examples

The typical "hello world" program would be:

  ? "Hello, world!"

Or:

  QOut( "Hello, world!" )

Or:

  Alert( "Hello, world!" )

Or, enclosed in an explicit procedure:

 PROCEDURE Main()

    ? "Hello, world!"

    RETURN

The simple OOP program:

#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

We have two classes, myFirstClass and mySecondClass, and the mySecondClass is the heir of myFirstClass. Two variables, nKolObj and cString1, in the declaration of a class the initial values are assigned, they will stay for any new object of the class. The method New of the class mySecondClass is described separately with the help of METHOD <methodName> CLASS <className>. In this method Super:New(n) is used to call an identically named method of the parent class to initialize the object's variables inherited from a parent. mySecondClass variable cStringS has the attribute (scope) HIDDEN (i.e., it is only available from methods of the class), and the rest of the variables and the method of New marked as EXPORTED (i.e., accessible from everywhere). In the mySecondClass the CLASS VAR nKolObj appeared - variable, which belongs not to the object, but to the whole class, here it is used as a counter of objects of this class.

References

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

The article is written by Fadeev P.V.