XHarbour
xHarbour is a free multi-platform extended Clipper compiler, offering multiple graphic terminals, including console drivers, GUIs, and hybrid console/GUIs. xHarbour is backward-compatible with Clipper and supports many language syntax extensions, greatly extended run-time libraries, and extensive third party support.
Like most dynamic languages, xHarbour is also available as a scripting language utilizing an interpreter written in the xHarbour language.
The xHarbour Usenet newsgroup is an active community for discussing xHarbour related questions.
Built-in data types
xHarbour has 6 scalar types : Nil, String, Date, Logical, Number, Pointer, and 4 complex types: Array, Object, CodeBlock, and Hash. A scalar holds a single value, such as a string, number, or reference to any other type. 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.Literal representation of scalar types:
- Nil: NIL
- String: "hello", 'hello', , or E"hello\n"
- Date: ctod
- Logical: .T.,.F.
- Number: 1, 1.1, -1, 0xFF
- Array:
- CodeBlock:
- Hash:
Codeblocks may have references to Variables of the Procedure/Function>method in which it was defined. Such Codeblocks may be returned as a value, or by means of an argument passed BY REFERENCE, in such case the Codeblock will "outlive" the routine in which it was defined, and any variables it references, will be a DETACHED variable.
Detached variables will maintain their value for as long as a Codeblock referencing them still exists. Such values will be shared with any other Codeblock which may have access to those same variables. If the Codeblock did not outlive its containing routine, and will be evaluated within the lifetime of the routine in which it is defined, changes to its Detached Variables by means of its evaluation, will be reflected back at its parent routine.
Codeblocks can be evaluated any number of times, by means of the Eval function.
Variables
All types can be assigned to named variables. Named variable identifiers are 1 to 63 characters long, start with and further consist of the characters 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.
- GLOBAL Visible within any routine defined in the same source module where the GLOBAL variable is declared, as well as any routine of any other source module, which explicitly declares it, by means of the GLOBAL EXTERNAL declaration. Both GLOBAL and GLOBAL EXTERNAL declarations must be declared before any Procedure/Function/Method is defined.
- PRIVATE: Visible within the routine which declared it, and all routines called by that routine.
- PUBLIC: Visible by all routines in the same application.
Due to the dynamic nature of PRIVATE and PUBLIC variables, they can be created and destroyed at runtime, can be accessed and modified by means of runtime macros, and can be accessed and modified by Codeblocks created on the fly.
Control structures
The basic control structures include all of the standard dBase, and Clipper control structures as well as additional ones inspired by the C or Java programming languages:Loops
WHILE ConditionExp...
END
FOR Var := InitExp TO EndExp
...
NEXT
FOR EACH Var IN CollectionExp
...
NEXT
- The ... is a sequence of one of more xHarbour statements, and square bracketes denote optional syntax.
- The HB_EnumIndex may be optionally used to retrieve the current iteration index.
- The LOOP statement restarts the current iteration of the enclosing loop structure, and if the enclosing loop is a FOR or FOR EACH loop, it increases the iterator, moving to the next iteration of the loop.
- The EXIT statement immediately terminates execution of the enclosing loop structure.
- The NEXT statement closes the control structure and moves to the next iteration of loop structure.
In FOR EACH, the Var variable will have the value of the respective element in the collection value. The collection expression, may be an Array, an Hash Table, or an Object type.
IF statements
IF CondExp...
CondExp
...
...
END
... represents 0 or more statement.
The condition expression has to evaluate to a LOGICAL value.
DO CASE statements
DO CASECASE CondExp
...
...
...
END
Above construct is logically equivalent to:
IF CondExp
...
ELSEIF CondExp
...
...
...
END
SWITCH statements
xHarbour supports a SWITCH construct inspired by the C implementation of switch.SWITCH SwitchExp
CASE LiteralExp
...
...
...
END
- 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.
BEGIN SEQUENCE statements
...
RECOVER
...
END
or:
BEGIN SEQUENCE
...
END
The BEGIN SEQUENCE structure allows for a well behaved abortion of any sequence, even when crossing nested procedures/functions. This means that a called procedure/function, may issue a BREAK statement, or a Break expression, to force unfolding of any nested procedure/functions, all the way back to the first outer BEGIN SEQUENCE structure, either after its respective END statement, or a RECOVER clause if present. The Break statement may optionally pass any type of expression, which may be accepted by the RECOVER statement to allow further recovery handing.
Additionally the xHarbour Error Object supports canDefault, canRetry and canSubstitute properties, which allows error handlers to perform some preparations, and then request a Retry Operation, a Resume, or return a Value to replace the expression triggering the error condition.
TRY CATCH FINALLY statements
TRY...
CATCH
...
END
TRY
...
CATCH
...
FINALLY
...
END
or:
TRY
...
FINALLY
...
END
The TRY construct is very similar to the BEGIN SEQUENCE construct, except it automatically integrates error handling, so that any error will be intercepted, and recovered by means of the CATCH statement or forwarded to an outer CATCH handler otherwise. The FINALLY section is guaranteed to be executed before the TRY or CATCH sections forward flow control by means of RETURN, BREAK, or THROW.
Procedures/Functions
PROCEDURE SomeProcedureNamePROCEDURE SomeProcedureName
PROCEDURE SomeProcedureName
INIT PROCEDURE SomeProcedureName
EXIT PROCEDURE SomeProcedureName
FUNCTION SomeProcedureName
FUNCTION SomeProcedureName
FUNCTION SomeProcedureName
Procedures/Functions in xHarbour can be specified with the keywords
PROCEDURE
, or FUNCTION
. Naming rules are same as those for Variables. 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.
Changes to argument variables are not reflected in respective variables passed by the calling procedure/function/method unless explicitly passed BY REFERENCE using the @ prefix.
PROCEDURE have no return value, and if used in an Expression context will produce a NIL value.
FUNCTION may return any type by means of the RETURN statement, anywhere in the body of its definition.
An example procedure definition and a function call follows:
x := Cube
FUNCTION Cube
RETURN n ** 3
Database support
xHarbour extends the Clipper Replaceable Database Drivers approach. It offers multiple RDDs such as DBF, DBFNTX, DBFCDX, DBFDBT, and DBFFPT. In xHarbour multiple RDDs can be used in a single application, and new logical RDDs can be defined from combination of other RDD. The RDD architecture allows for inheritance, so that a given RDD may extend the functionality of other existing RDD. 3rd party RDDs, like RDDSQL, RDDSIX, RMDBFCDX, Advantage Database Server, and Mediator exemplify some of the RDD architecture features.xHarbour also offers ODBC support by means of an OOP syntax, and ADO support by means of OLE.
Macro Operator (runtime compiler)
One of the most powerful features of the xBase languages is the MACRO Operator '&'. xHarbour’s implementation of the Macro Operator allows for runtime compilation of any valid xHarbour expression. Such compiled expression may be used as a VALUE, i.e. the right side of an Assignment, but such compiled expression may be used to resolve the LEFT side of an assignment, i.e. PRIVATE, or PUBLIC variables, or 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. IOW, any xHarbour application may be extended, and/or modified in runtime, to compile and execute additional code on demand.
The xHarbour implementation of this feature is so complete that the xHarbour interpreter, xbScript, uses it heavily, to compile xHarbour scripts.
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.postfix
is the short form of &.
Example code
Hello, world!
The typical "hello world" program would be:? "Hello, world!"
Or:
QOut
Or:
Alert
Or, enclosed in an explicit procedure:
PROCEDURE Main
? "Hello, world!"
RETURN
OOP
#include "hbclass.ch"
PROCEDURE Main
LOCAl oPerson := Person
oPerson:Eyes := "Invalid"
oPerson:Eyes := "Blue"
Alert
RETURN
CLASS Person
DATA Name INIT ""
METHOD New CONSTRUCTOR
ACCESS Eyes INLINE ::pvtEyes
ASSIGN Eyes INLINE IIF 'C'.AND. x IN "Blue,Brown,Green", ::pvtEyes := x, Alert
// Sample of IN-LINE Method definition
INLINE METHOD Describe
LOCAL cDescription
IF Empty
cDescription := "I have no name yet."
ELSE
cDescription := "My name is: " + ::Name + ";"
ENDIF
IF ! Empty
cDescription += "my eyes' color is: " + ::Eyes
ENDIF
ENDMETHOD
PRIVATE:
DATA pvtEyes
ENDCLASS
// Sample of normal Method definition.
METHOD New CLASS Person
::Name := cName
RETURN Self
Scripting
xHarbour is also available as an interpreted language in few flavors of scripting engines.- Stand alone Interpreter: Portable, self-contained, interpreter xBaseScript.
- ActiveScript: Microsoft ActiveScript compliant OLE DLL, which supports xHarbour scripting in:
- * Windows Script Host.
- * Internet Explorer, HTML client side scripting.
- * IIS, and any other ASP compliant server.