Harbour es un lenguaje de programación informática que se utiliza principalmente para crear programas de bases de datos y de negocios. Es una versión modernizada, de código abierto y multiplataforma del antiguo sistema Clipper , que a su vez se desarrolló a partir del mercado de bases de datos dBase de los años 1980 y 1990.
El código Harbour utiliza las mismas bases de datos y se puede compilar bajo una amplia variedad de plataformas, incluyendo Microsoft Windows , Linux , variantes de Unix , varios descendientes de BSD , Mac OS X , MINIX 3 , Windows CE , Pocket PC , Symbian , iOS , Android , QNX , VxWorks , OS/2 (incluyendo eComStation y ArcaOS ), [1] BeOS / Haiku , AIX y MS-DOS .
La idea de un compilador Clipper de software libre ha estado dando vueltas durante mucho tiempo y el tema ha surgido a menudo en las discusiones sobre comp.lang.clipper. Antonio Linares fundó el proyecto Harbour y la implementación comenzó en marzo de 1999. El nombre "Harbour" fue propuesto por Linares, es un juego de palabras con Clipper como tipo de barco. Harbour es un sinónimo de puerto (donde atracan los barcos), y Harbour es un puerto del lenguaje Clipper.
En 2009, el puerto fue remodelado sustancialmente, principalmente por Viktor Szakáts y Przemyslaw Czerpak.
Harbour extiende el enfoque de los controladores de bases de datos reemplazables (RDD) de Clipper. Ofrece múltiples RDD como DBF , DBFNTX, DBFCDX, DBFDBT y DBFFPT. En Harbour, se pueden usar múltiples RDD en una sola aplicación y se pueden definir nuevos RDD lógicos combinando otros RDD. La arquitectura RDD permite la herencia, de modo que un RDD determinado puede extender la funcionalidad de otros RDD existentes. Los RDD de terceros, como RDDSQL, RDDSIX, RMDBFCDX, Advantage Database Server y Mediator, ejemplifican algunas de las características de la arquitectura RDD. La implementación de DBFNTX tiene casi la misma funcionalidad de DBFCDX y RDDSIX. NETIO y LetoDB [2] proporcionan acceso remoto a través del protocolo TCP .
Harbour también ofrece soporte ODBC mediante una sintaxis OOP y soporte ADO mediante OLE . MySQL , PostgreSQL , SQLite , Firebird y Oracle son ejemplos de bases de datos a las que Harbour puede conectarse.
Las tecnologías xBase suelen confundirse con el software RDBMS . Si bien esto es cierto, xBase es más que un simple sistema de base de datos, ya que al mismo tiempo los lenguajes xBase que utilizan únicamente DBF no pueden proporcionar el concepto completo de un RDBMS real.
Harbour tiene como objetivo ser escrito una vez y compilado en cualquier lugar . Como el mismo compilador está disponible para todos los sistemas operativos anteriores, no hay necesidad de volver a codificar para producir productos idénticos para diferentes plataformas, excepto cuando se utilizan características dependientes del sistema operativo. La compilación cruzada es compatible con MinGW . En Microsoft Windows, Harbour es más estable pero menos documentado que Clipper, pero tiene capacidad multiplataforma y es más transparente, permite una mayor personalización y puede ejecutarse desde una unidad flash USB.
En Linux y Windows Mobile, el código fuente de Clipper se puede compilar con Harbour con muy pocas adaptaciones. La mayoría del software escrito originalmente para ejecutarse en Xbase++, FlagShip, FoxPro, xHarbour y otros dialectos se puede compilar con Harbor con algunas adaptaciones. A partir de 2010 se han hecho muchos esfuerzos para facilitar la transición desde otros dialectos de xBase .
Harbour puede utilizar los siguientes compiladores de C, entre otros: GCC , MinGW , Clang , ICC , Microsoft Visual C++ (6.0+), Borland C++ , Watcom C , Pelles C y Sun Studio .
Harbour puede utilizar múltiples emulaciones de terminal gráfica, incluidos controladores de consola y consolas/GUI híbridas, como GTWvt y GTWvg.
Harbour admite GUI externas, gratuitas (por ejemplo, HBQt, HWGui, Mini-GUI (última versión basada en Qt y QtContribs [3] ) y comerciales (por ejemplo, FiveWin, Xailer). HBQt es una biblioteca que proporciona enlaces a Qt. La aplicación HBIDE es una muestra del potencial de HBQt.
Harbour es 100% compatible con Clipper [4] y admite muchas extensiones de sintaxis de lenguaje, incluidas bibliotecas de tiempo de ejecución muy extendidas como OLE , Blat, OpenSSL , Free Image, GD , hbtip, hbtpathy, PCRE , hbmzip ( zlib ), hbbz2 ( bzip2 ), cURL , Cairo , su propia implementación de CA-Tools, bibliotecas NanFor actualizadas y muchas otras. Harbour tiene una comunidad de desarrollo activa y un amplio soporte de terceros.
Cualquier lenguaje xBase ofrece una forma muy productiva de crear aplicaciones comerciales y de uso intensivo de datos. Harbour no es una excepción.
Una de las características más potentes de los lenguajes xBase es el operador de macro '&'. La implementación de Harbour del operador de macro permite la compilación en tiempo de ejecución de cualquier expresión de Harbour válida. Dicha expresión compilada se puede utilizar como VALOR, es decir, el lado derecho de una asignación (valor r) o se puede utilizar para resolver el lado izquierdo (valor l) de una asignación, es decir, variables privadas o públicas, o un campo de base de datos.
Además, el operador macro puede compilar y ejecutar llamadas de función, completar asignaciones o incluso listas de argumentos, y el resultado puede usarse para resolver cualquiera de los contextos anteriores en la aplicación compilada.
El último compilador de macros puede compilar cualquier código Harbour válido, incluido el código por proceso, antes de la compilación.
Sintaxis:
&(... )
Se compilará el valor de texto de la expresión '...' y el valor resultante de la ejecución del código compilado es el resultado.
&Algún ID
es la forma abreviada de &(SomeId).
&SomeId.postfix
es la forma corta de &(SomeId + "postfix").
La programación en un estilo OOP es un tema más amplio que una biblioteca específica o una interfaz específica, pero la programación OOP es algo que muchos programadores de Clipper han llegado a esperar. CA-Clipper 5.2 y especialmente 5.3 agregaron una serie de clases base y una sintaxis OOP correspondiente. Bibliotecas como Class(y), FieWin, Clip4Win y Top Class brindan funcionalidad OOP adicional.
Harbour tiene extensiones OOP con soporte completo para clases, incluida la herencia, basadas en la sintaxis Class(y). La sintaxis OOP en Harbour es muy similar a la de las bibliotecas de clases Clipper anteriores, por lo que debería ser posible mantener el código Clipper heredado con cambios mínimos.
Harbour, como todos los lenguajes xBase, no distingue entre mayúsculas y minúsculas y, opcionalmente, puede aceptar palabras clave escritas solo con sus primeros cuatro caracteres.
Harbour tiene seis tipos escalares: Nil , String , Date , Logical , Numeric , Pointer y cuatro tipos complejos: Array , Object , CodeBlock y Hash . Un escalar contiene un único valor, como una cadena, un valor numérico o una referencia a cualquier otro tipo. Los arrays son listas ordenadas de escalares o tipos complejos, indexados por número, comenzando en 1. Los hashes, o arrays asociativos , son colecciones desordenadas de valores de cualquier tipo indexados por su clave asociada, que puede ser de cualquier tipo escalar o complejo.
Representación literal (estática) de tipos escalares:
NIL
"hello", 'hello', [hello]
0d20100405
.T., .F.
1, 1.1, −1, 0xFF
Los tipos complejos también pueden representarse como valores literales:
{ "String", 1, { "Nested Array" }, .T., FunctionCall(), @FunctionPointer() }
{ |Arg1, ArgN| Arg1 := ArgN + OuterVar + FunctionCall() }
{ "Name" => "John", 1 => "Numeric key", "Name2" => { "Nested" => "Hash" } }
Los hashes pueden utilizar cualquier tipo, incluidos otros hashes, como clave para cualquier elemento. Los hashes y las matrices pueden contener cualquier tipo como valor de cualquier miembro, incluidas las matrices anidadas y los hashes.
Los bloques de código pueden tener referencias a variables del procedimiento/función>método en el que se definieron. Dichos bloques de código pueden devolverse como un valor o por medio de un argumento pasado POR REFERENCIA ; en tal caso, el bloque de código "sobrevivirá" a la rutina en la que se definió y cualquier variable a la que haga referencia será una variable SEPARADA .
Las variables independientes mantendrán su valor mientras exista un bloque de código que las haga referencia. Dichos valores se compartirán con cualquier otro bloque de código que pueda tener acceso a esas mismas variables. Si el bloque de código no sobrevivió a la rutina que lo contenía y se evaluará durante la vida útil de la rutina en la que está definido, los cambios en sus variables independientes mediante su evaluación se reflejarán en su rutina principal.
Los bloques de código se pueden evaluar cualquier cantidad de veces, mediante la función Eval( BlockExp ) .
Se pueden asignar todos los tipos a las variables con nombre. Los identificadores de las variables con nombre tienen entre 1 y 63 caracteres ASCII, comienzan con [A-Z|_]
y constan de los caracteres [A-Z|0–9|_]
hasta un máximo de 63 caracteres. Las variables con nombre no distinguen entre mayúsculas y minúsculas.
Las variables tienen uno de los siguientes alcances:
LOCAL y STATIC se resuelven en tiempo de compilación y, por lo tanto, son mucho más rápidas que las variables PRIVATE y PUBLIC , que son entidades dinámicas a las que se accede mediante una tabla de símbolos en tiempo de ejecución . Por esta misma razón, las variables LOCAL y STATIC no se exponen al compilador de macros y cualquier código de macro que intente hacer referencia a ellas generará un error en tiempo de ejecución.
Debido a la naturaleza dinámica de las variables PRIVADAS y PÚBLICAS , se pueden crear y destruir en tiempo de ejecución y se puede acceder a ellas y modificarlas por medio de macros en tiempo de ejecución o mediante bloques de código creados sobre la marcha.
Las estructuras de control básicas incluyen todas las estructuras de control estándar de dBase y Clipper , así como otras adicionales inspiradas en los lenguajes de programación C o Java :
[HACER] MIENTRAS CondiciónExp ... [BUCLE] [SALIDA]FIN[HACER]
PARA Var := InitExp A EndExp [PASO StepExp ] ... [BUCLE] [SALIDA]PRÓXIMO
PARA CADA Var EN CollectionExp ... [ Var :__enumIndex()] [BUCLE] [SALIDA]PRÓXIMO
[]
indican sintaxis opcional.En la instrucción FOR , la expresión de asignación se evalúa antes de la primera iteración del bucle. La expresión TO se evalúa y se compara con el valor de la variable de control antes de cada iteración, y el bucle finaliza si se evalúa como un valor numérico mayor que el valor numérico de la variable de control. La expresión STEP opcional se evalúa después de cada iteración, antes de decidir si se debe realizar la siguiente iteración.
En FOR EACH , la variable Var tendrá el valor (escalar o complejo) del elemento respectivo en el valor de la colección. La expresión de la colección puede ser una matriz (de cualquier tipo o combinación de tipos), una tabla hash o un tipo de objeto.
SI CondExp ... [SI NO] CondExp ...[DEMÁS] ...FIN[SI]
... representa 0 o más declaraciones .
Las expresiones de condición deben evaluarse como un valor LÓGICO .
Harbour admite una construcción SWITCH inspirada en la implementación C de switch().
INTERRUPTOR SwitchExp CASO LiteralExp ... [SALIDA][CASO LiteralExp ] ... [SALIDA][DE LO CONTRARIO] ...FIN[CAMBIAR]
COMENZAR SECUENCIA ... [ROMPER] [Romper( [ Exp ] )]RECUPERAR [USANDO Var ] ...FIN[SECUENCIA]
o:
COMENZAR SECUENCIA ... [ROMPER] [Romper()]FIN[SECUENCIA]
La estructura BEGIN SEQUENCE permite la interrupción sin problemas de cualquier secuencia, incluso cuando se cruzan procedimientos o funciones anidados. Esto significa que un procedimiento o función llamado puede emitir una sentencia BREAK o una expresión Break() para forzar el despliegue de cualquier procedimiento o función anidados, hasta llegar a la primera estructura BEGIN SEQUENCE externa, ya sea después de su sentencia END respectiva o de una cláusula RECOVER si está presente. La sentencia Break puede pasar opcionalmente cualquier tipo de expresión, que puede ser aceptada por la sentencia RECOVER para permitir un manejo posterior de la recuperación.
Además, el objeto de error de Harbour admite las propiedades canDefault , canRetry y canSubstitute , lo que permite a los controladores de errores realizar algunos preparativos y luego solicitar una operación de reintento , una reanudación o devolver un valor para reemplazar la expresión que activa la condición de error.
Alternativamente, las declaraciones TRY [CATCH] [FINALLY] están disponibles en la biblioteca xhb y funcionan como la construcción SEQUENCE.
[ESTÁTICO] PROCEDIMIENTO SomeProcedureName [ESTÁTICO] PROCEDIMIENTO SomeProcedureName ()[ESTÁTICO] PROCEDIMIENTO SomeProcedureName ( Param1 [, ParamsN ] )
PROCEDIMIENTO DE INICIO SomeProcedureName PROCEDIMIENTO DE SALIDA SomeProcedureName
[ESTÁTICA] FUNCIÓN SomeProcedureName [ESTÁTICA] FUNCIÓN SomeProcedureName ()[ESTÁTICA] FUNCIÓN SomeProcedureName ( Param1 [, ParamsN ] )
Los procedimientos y funciones en Harbour se pueden especificar con las palabras clave PROCEDURE
, o FUNCTION
. Las reglas de denominación son las mismas que las de las variables (hasta 63 caracteres sin distinción entre mayúsculas y minúsculas). Tanto los procedimientos como las funciones se pueden calificar con el calificador de ámbito STATIC para restringir su uso al ámbito del módulo en el que se definan.
Los calificadores opcionales INIT o EXIT marcarán el procedimiento que se invocará automáticamente justo antes de llamar al procedimiento de inicio de la aplicación o justo después de salir de la aplicación, respectivamente. Los parámetros que se pasan a un procedimiento o función aparecen en la subrutina como variables locales y pueden aceptar cualquier tipo, incluidas las referencias.
Los cambios en las variables de argumento no se reflejan en las respectivas variables pasadas por el procedimiento/función/método de llamada a menos que se pasen explícitamente POR REFERENCIA utilizando el prefijo @ .
PROCEDIMIENTO no tiene valor de retorno y si se utiliza en un contexto de Expresión producirá un valor NIL .
FUNCTION puede devolver cualquier tipo mediante la declaración RETURN, en cualquier parte del cuerpo de su definición.
A continuación se muestra un ejemplo de definición de procedimiento y una llamada de función:
x := Cubo( 2 ) FUNCIÓN Cubo(n) DEVUELVE n ** 3
El programa típico " hola mundo " sería:
? "¡Hola Mundo!"
O:
QOut ( "¡Hola, mundo!" )
O:
Alerta ( "¡Hola, mundo!" )
O bien, encerrado en un procedimiento explícito:
PROCEDIMIENTO Main() ? "¡Hola Mundo!" DEVOLVER
Procedimiento principal:
#include "hbclass.ch" PROCEDIMIENTO Main() Persona LOCAL CLS oPersona := Pers en ():New( "Dave" ) oPersona :Ojos := "Inválido" oPersona :Ojos := "Azul" Alerta (oPerson:Describe()) DEVOLVER
Definición de clase:
CREAR CLASE Persona VAR Nombre INIT "" MÉTODO Nuevo( cNombre ) MÉTODO Describe() ACCESO Ojos EN LÍNEA ::pvtEyes ASIGNAR Ojos( x ) INLINE iif( HB_ISSTRING( x ) .AND. x $ "Azul,Marrón,Verde", ::pvtOjos := x, Alerta( "Valor no válido" ) ) PROTEGIDO: VAR pvtOjos FIN DE CLASE // Ejemplo de definición de método normal MÉTODO Nuevo( cNombre ) CLASE Persona ::Nombre := cNombre REGRESO Yo MÉTODO Describe() CLASE Persona cDescripción LOCAL SI Vacío(::Nombre) cDescription := "No tengo nombre todavía." DEMÁS cDescription := "Mi nombre es: " + ::Nombre + ";" FINALIZAR SI SI ! Vacío(:Ojos) cDescription += "el color de mis ojos es: " + ::Ojos FINALIZAR SI DEVOLVER cDescripción
Todas las herramientas son multiplataforma.
Actualmente, el desarrollo de Harbour está a cargo de Viktor Szakáts en colaboración con Przemysław Czerpak, quien también contribuye con muchos componentes del lenguaje principal y componentes complementarios. HBIDE y algunos otros componentes, especialmente HBQt, son desarrollados por Pritpal Bedi. Otros miembros de la comunidad de desarrollo envían cambios al repositorio de código fuente de GitHub . [5] A partir de 2015, el desarrollo de Harbour es activo y dinámico.
xHarbour es una bifurcación [6] del proyecto Harbour anterior. xHarbour adopta un enfoque más agresivo para implementar nuevas características en el lenguaje, mientras que Harbour es más conservador en su enfoque, apuntando primero a una réplica exacta del comportamiento de Clipper y luego implementando nuevas características y extensiones como una consideración secundaria. También debe tenerse en cuenta que Harbour es compatible con una amplia variedad de sistemas operativos , mientras que xHarbour solo es compatible con MS Windows y Linux de 32 bits.
Los desarrolladores de Harbour han intentado documentar todo el comportamiento oculto en el lenguaje Clipper y probar el código compilado con Harbour junto con el mismo código compilado con Clipper para mantener la compatibilidad.
Los desarrolladores de Harbour rechazan explícitamente las extensiones del lenguaje que podrían afectar la compatibilidad con Clipper. Estos rechazos se suavizaron recientemente, ya que la nueva arquitectura de Harbour permite extensiones fuera del compilador principal.
Se puede encontrar una comparación detallada entre las extensiones implementadas en Harbour y xHarbour en el repositorio de origen del proyecto en GitHub. [7]