Forth es un lenguaje de programación orientado a pilas y un entorno de desarrollo integrado interactivo diseñado por Charles H. "Chuck" Moore y utilizado por primera vez por otros programadores en 1970. Aunque no es un acrónimo , el nombre del lenguaje en sus primeros años se escribía a menudo con todas las letras mayúsculas como FORTH . Las implementaciones FORTH-79 y FORTH-83, que no fueron escritas por Moore, se convirtieron en estándares de facto , y se publicó un estándar técnico oficial del lenguaje en 1994 como ANS Forth. Existió una amplia gama de derivados de Forth antes y después de ANS Forth. La implementación de software libre y de código abierto Gforth se mantiene activamente, al igual que varios sistemas con soporte comercial .
Forth combina típicamente un compilador con un shell de comandos integrado, [a] donde el usuario interactúa a través de subrutinas llamadas palabras . Las palabras se pueden definir, probar, redefinir y depurar sin tener que volver a compilar o reiniciar todo el programa. Todos los elementos sintácticos, incluidas las variables, los operadores y el flujo de control, se definen como palabras. Se utiliza una pila para pasar parámetros entre palabras, lo que da lugar a un estilo de notación polaca inversa .
Durante gran parte de la existencia de Forth, la técnica estándar era compilar en código enhebrado , que se puede interpretar más rápido que el código de bytes . Uno de los primeros beneficios de Forth fue el tamaño: un entorno de desarrollo completo (incluidos el compilador, el editor y los programas de usuario) podía caber en la memoria de un sistema de 8 bits o similarmente limitado. Ya no está limitado por el espacio, existen implementaciones modernas que generan código de máquina optimizado como otros compiladores de lenguajes. La relativa simplicidad de crear un sistema Forth básico ha dado lugar a muchas variantes personales y propietarias, como el Forth personalizado utilizado para implementar el exitoso videojuego de 1986 Starflight de Electronic Arts . [1]
Forth se utiliza en el cargador de arranque Open Firmware , en aplicaciones de vuelos espaciales [2] como la nave espacial Philae , [3] [4] y en otros sistemas integrados que implican interacción con hardware.
Moore desarrolló una serie de microprocesadores para ejecutar directamente código compilado similar al de Forth y experimentó con lenguajes más pequeños basados en conceptos de Forth, incluidos cmForth y colorForth . La mayoría de estos lenguajes fueron diseñados para respaldar los propios proyectos de Moore, como el diseño de chips.
Forth tiene un nicho en aplicaciones astronómicas y espaciales [5] , así como una trayectoria en sistemas integrados . Las ROM de arranque de Open Firmware utilizadas por Apple , IBM , Sun y OLPC XO-1 contienen un entorno Forth.
Forth se ha utilizado a menudo para desarrollar nuevo hardware. Forth fue el primer software residente en el nuevo chip Intel 8086 en 1978, y MacFORTH fue el primer sistema de desarrollo residente para Macintosh 128K en 1984. [6]
Atari, Inc. utilizó una elaborada demostración animada escrita en Forth para mostrar las capacidades de las computadoras Atari de 8 bits en los grandes almacenes. [7] Electronic Arts publicó varios videojuegos en la década de 1980 que fueron escritos en Forth, incluidos Worms? (1983), [8] Adventure Construction Set (1984), [9] Amnesia (1986), [10] Starflight (1986), [1] y Lords of Conquest (1986). El juego de codificación de robots ChipWits (1984) fue escrito en MacFORTH. [11]
RapidFile (1986) de Ashton-Tate , un programa de base de datos de archivos planos, y VP-Planner [12] de Paperback Software International (1983), un programa de hoja de cálculo que compite con Lotus 1-2-3 , fueron escritos en Forth.
El Canon Cat (1987) utiliza Forth para la programación de su sistema.
Rockwell produjo microcomputadoras de un solo chip con núcleos Forth residentes: el R65F11 y el R65F12. ASYST fue una expansión de Forth para medición y control en PC. [13]
El lenguaje de programación Forth se utilizó en la producción de Star Wars: Episodio IV – Una nueva esperanza . [ cita requerida ] En concreto, se utilizó para controlar el sistema de control de movimiento Dystraflex, creado por John Dykstra y su equipo en Industrial Light & Magic . Este sistema fue fundamental para crear los movimientos de cámara complejos y precisos necesarios para las escenas de batalla espacial y las secuencias de carrera por las trincheras en la Estrella de la Muerte .
El sistema Dystraflex permitió programar con antelación los movimientos de cámara, que luego podían repetirse exactamente en varias tomas. Esto fue crucial para combinar imágenes en vivo con tomas de modelos y otros efectos visuales. Se eligió Forth por su eficiencia y su capacidad para manejar el procesamiento en tiempo real necesario para estas complejas tareas.
Forth evolucionó a partir del sistema de programación personal de Charles H. Moore , que había estado en continuo desarrollo desde 1968. [6] [14] Forth fue expuesto por primera vez a otros programadores a principios de la década de 1970, comenzando con Elizabeth Rather en el Observatorio Nacional de Radioastronomía de los Estados Unidos (NRAO). [6] Después de su trabajo en NRAO, Charles Moore y Elizabeth Rather formaron FORTH, Inc. en 1973, refinando y portando los sistemas Forth a docenas de otras plataformas en la siguiente década.
Moore vio a Forth como un sucesor de los lenguajes de programación de tercera generación de compilación-enlace-go , o software para hardware de "cuarta generación". Recuerda cómo se acuñó el nombre: [15]
En Mohasco ["a finales de los años 60"] también trabajé directamente en un IBM 1130 conectado a una pantalla gráfica IBM 2250. El 1130 era un ordenador muy importante: tenía el primer disco de cartucho, así como un lector de tarjetas, un perforador de tarjetas (como respaldo del disco) y una máquina de escribir de consola. El 1130 permitía al programador, por primera vez, controlar totalmente el ordenador de forma interactiva.
FORTH apareció por primera vez como entidad en ese 1130. Se llamaba FORTH, una abreviatura de cinco letras de FOURTH, que significa lenguaje informático de cuarta generación. Tal vez recuerden que esa era la época de los ordenadores de tercera generación y yo iba a dar un salto adelante. Pero como FORTH funcionaba en el 1130 (que solo permitía identificadores de cinco caracteres), el nombre se acortó.
microFORTH de FORTH, Inc. fue desarrollado para los microprocesadores Intel 8080 , Motorola 6800 , Zilog Z80 y RCA 1802 , a partir de 1976. MicroFORTH fue utilizado posteriormente por aficionados para generar sistemas Forth para otras arquitecturas, como el 6502 en 1978. El Forth Interest Group se formó en 1978. [16] Promovió y distribuyó su propia versión del lenguaje, FIG-Forth, para la mayoría de las marcas de ordenadores domésticos.
Forth fue popular a principios de los años 1980, [17] porque se adaptaba bien a la memoria limitada de los microordenadores . La facilidad de implementación del lenguaje dio lugar a muchas implementaciones. [18] El ordenador doméstico Jupiter ACE tiene Forth en su sistema operativo residente en ROM . Insoft GraFORTH es una versión de Forth con extensiones gráficas para Apple II. [19]
La práctica común se codificó en las normas de facto FORTH-79 [20] y FORTH-83 [21] en los años 1979 y 1983, respectivamente. Estas normas fueron unificadas por ANSI en 1994, comúnmente conocidas como ANS Forth. [22] [23]
A partir de 2018, se recuperó la fuente de la versión 1130 original de FORTH y ahora se está actualizando para ejecutarse en un sistema 1130 restaurado o emulado. [24]
Forth enfatiza el uso de funciones pequeñas y simples llamadas palabras . Las palabras para tareas más grandes requieren muchas palabras más pequeñas, cada una de las cuales realiza una subtarea distinta. Un programa Forth grande es una jerarquía de palabras. Estas palabras, al ser módulos distintos que se comunican implícitamente a través de un mecanismo de pila, pueden ser prototipadas, construidas y probadas de forma independiente. El nivel más alto del código Forth puede parecerse a una descripción en inglés de la aplicación. Forth ha sido llamado un lenguaje de metaaplicación : un lenguaje que puede usarse para crear lenguajes orientados a problemas . [25]
Forth se basa en el uso explícito de una pila de datos y la notación polaca inversa , que se utiliza habitualmente en las calculadoras de Hewlett-Packard . En RPN, el operador se coloca después de sus operandos, a diferencia de la notación infija más común , en la que el operador se coloca entre sus operandos. La notación postfija hace que el lenguaje sea más fácil de analizar y extender; la flexibilidad de Forth hace que una gramática BNF estática sea inapropiada, y no tiene un compilador monolítico. Extender el compilador solo requiere escribir una nueva palabra, en lugar de modificar una gramática y cambiar la implementación subyacente.
Usando RPN, se puede obtener el resultado de la expresión matemática (25 * 10 + 50)
de esta manera:
25 10 * 50 + CR . 300 ok
Primero se colocan los números 25 y 10 en la pila.
La palabra *
toma los dos números superiores de la pila, los multiplica y vuelve a colocar el producto en la pila.
Luego se coloca el número 50 en la pila.
La palabra +
suma los dos valores superiores, empujando la suma. CR
( retorno de carro ) inicia la salida en una nueva línea. Finalmente, .
imprime el resultado. Como todo se ha completado correctamente, el sistema Forth imprime OK
. [26]
Incluso las características estructurales de Forth se basan en pilas. Por ejemplo:
: PISO5 ( n -- n' ) DUP 6 < SI ELIMINAR 5 DE LO CONTRARIO 1 - ENTONCES ;
Los dos puntos indican el comienzo de una nueva definición, en este caso una nueva palabra (nuevamente, palabra es el término utilizado para una subrutina) llamada FLOOR5
. El texto entre paréntesis es un comentario que advierte que esta palabra espera un número en la pila y devolverá un número posiblemente modificado (en la pila).
La subrutina utiliza los siguientes comandos: DUP
duplica el número en la pila; 6
coloca un 6 en la parte superior de la pila; <
compara los dos números superiores en la pila (6 y la DUP
entrada ed) y los reemplaza con un valor verdadero o falso; IF
toma un valor verdadero o falso y elige ejecutar comandos inmediatamente después de él o saltar al ELSE
; DROP
descarta el valor en la pila; 5
coloca un 5 en la parte superior de la pila; y THEN
finaliza el condicional.
La FLOOR5
palabra es equivalente a esta función escrita en el lenguaje de programación C utilizando el operador condicional '?:'
int piso5 ( int v ) { devolver ( v < 6 ) ? 5 : ( v - 1 ); }
Esta función se escribe de forma más sucinta como:
: PISO5 ( n -- n' ) 1- 5 MÁXIMO ;
Esto se puede ejecutar de la siguiente manera:
1 PISO 5 CR . 5 ok 8 PISO 5 CR . 7 ok
Primero, se introduce un número (1 u 8) en la pila, FLOOR5
se llama a , que extrae el número nuevamente y coloca el resultado. CR
Mueve la salida a una nueva línea (nuevamente, esto solo está aquí para facilitar la lectura). Finalmente, una llamada a .
extrae el resultado y lo imprime.
La gramática de Forth no tiene una especificación oficial, sino que está definida por un algoritmo simple. El intérprete lee una línea de entrada desde el dispositivo de entrada del usuario, que luego es analizada en busca de una palabra usando espacios como delimitador ; algunos sistemas reconocen caracteres de espacio en blanco adicionales . Cuando el intérprete encuentra una palabra, la busca en el diccionario . Si la encuentra, el intérprete ejecuta el código asociado con la palabra y luego vuelve a analizar el resto del flujo de entrada. Si no se encuentra la palabra, se supone que es un número y se intenta convertirla en un número y colocarla en la pila; si tiene éxito, el intérprete continúa analizando el flujo de entrada. De lo contrario, si tanto la búsqueda como la conversión del número fallan, el intérprete imprime la palabra seguida de un mensaje de error que indica que no se reconoce la palabra, vacía el flujo de entrada y espera una nueva entrada del usuario. [27]
La definición de una palabra nueva comienza con la palabra :
(dos puntos) y termina con la palabra ;
(punto y coma). Por ejemplo,
: XDUP1 + . . ;
compilará la palabra X
y hará que el nombre se pueda encontrar en el diccionario. Cuando se ejecuta escribiendo 10 X
en la consola, se imprimirá 11 10
. [28]
La mayoría de los sistemas Forth incluyen un ensamblador para escribir palabras utilizando las funciones del procesador. Los ensambladores Forth suelen utilizar una sintaxis polaca inversa en la que los parámetros de una instrucción preceden a la instrucción. Un ensamblador polaco inverso típico prepara los operandos en la pila y el mnemónico copia la instrucción completa en la memoria como último paso. Un ensamblador Forth es por naturaleza un ensamblador de macros, de modo que es fácil definir un alias para los registros según su función en el sistema Forth: por ejemplo, "dsp" para el registro utilizado como puntero de la pila de datos. [29]
La mayoría de los sistemas Forth funcionan con un sistema operativo anfitrión, como Microsoft Windows , Linux o una versión de Unix , y utilizan el sistema de archivos del sistema operativo anfitrión para los archivos de origen y de datos; el estándar ANSI Forth describe las palabras utilizadas para E/S. Todos los sistemas Forth modernos utilizan archivos de texto normales para el código fuente, incluso si están integrados. Un sistema integrado con un compilador residente obtiene su código fuente a través de una línea serial.
Los sistemas Forth clásicos tradicionalmente no utilizan ni sistema operativo ni sistema de archivos . En lugar de almacenar el código en archivos, el código fuente se almacena en bloques de disco escritos en direcciones de disco físicas. La palabra BLOCK
se utiliza para traducir el número de un bloque de espacio en disco de 1K en la dirección de un búfer que contiene los datos, que es administrado automáticamente por el sistema Forth. El uso de bloques se ha vuelto poco común desde mediados de la década de 1990. En un sistema alojado, esos bloques también se asignan en un archivo normal en cualquier caso.
La multitarea , más comúnmente la programación round-robin cooperativa , está normalmente disponible (aunque las palabras y el soporte de multitarea no están cubiertos por el estándar ANSI Forth). La palabra se utiliza para guardar el contexto de ejecución de la tarea actual, para localizar la siguiente tarea y restaurar su contexto de ejecución. Cada tarea tiene sus propias pilas, copias privadas de algunas variables de control y un área de borrador. El intercambio de tareas es simple y eficiente; como resultado, los multitareas Forth están disponibles incluso en microcontroladores muy simples , como Intel 8051 , Atmel AVR y TI MSP430 . [30]PAUSE
Otras funciones no estándar incluyen un mecanismo para emitir llamadas al sistema operativo anfitrión o a los sistemas de ventanas , y muchas proporcionan extensiones que emplean la programación proporcionada por el sistema operativo. Por lo general, tienen un conjunto de palabras más grande y diferente de la palabra independiente de Forth PAUSE
para la creación, suspensión, destrucción y modificación de la prioridad de las tareas.
Un sistema Forth con todas las funciones y todo el código fuente se compilará a sí mismo, una técnica que los programadores Forth suelen denominar metacompilación o autoalojamiento (aunque el término no coincide exactamente con la metacompilación tal como se define normalmente). El método habitual consiste en redefinir el puñado de palabras que colocan los bits compilados en la memoria. Las palabras del compilador utilizan versiones con nombres especiales de fetch y store que pueden redirigirse a un área de búfer en la memoria. El área de búfer simula o accede a un área de memoria que comienza en una dirección diferente a la del búfer de código. Dichos compiladores definen palabras para acceder tanto a la memoria de la computadora de destino como a la memoria de la computadora anfitriona (que compila). [31]
Después de que las operaciones de búsqueda y almacenamiento se redefinen para el espacio de código, el compilador, el ensamblador, etc. se vuelven a compilar utilizando las nuevas definiciones de búsqueda y almacenamiento. Esto reutiliza de manera efectiva todo el código del compilador y el intérprete. Luego, se compila el código del sistema Forth, pero esta versión se almacena en el búfer. El búfer en memoria se escribe en el disco y se proporcionan formas de cargarlo temporalmente en la memoria para realizar pruebas. Cuando la nueva versión parece funcionar, se escribe sobre la versión anterior.
Existen numerosas variaciones de estos compiladores para diferentes entornos. Para sistemas integrados , el código puede escribirse en otro ordenador, una técnica conocida como compilación cruzada , a través de un puerto serie o incluso de un único bit TTL , mientras se mantienen los nombres de las palabras y otras partes no ejecutables del diccionario en el ordenador compilador original. Las definiciones mínimas para un compilador Forth de este tipo son las palabras que obtienen y almacenan un byte, y la palabra que ordena que se ejecute una palabra Forth. A menudo, la parte que más tiempo lleva escribir un puerto remoto es construir el programa inicial para implementar la obtención, el almacenamiento y la ejecución, pero muchos microprocesadores modernos tienen funciones de depuración integradas (como el Motorola CPU32 ) que eliminan esta tarea. [32]
La estructura de datos básica de Forth es el "diccionario", que asigna "palabras" a código ejecutable o estructuras de datos con nombre. El diccionario se presenta en la memoria como un árbol de listas enlazadas con enlaces que proceden de la última palabra definida (la más reciente) a la más antigua, hasta que se encuentra un valor centinela , normalmente un puntero NULL. Un cambio de contexto hace que una búsqueda de lista comience en una hoja diferente. Una búsqueda de lista enlazada continúa a medida que la rama se fusiona con el tronco principal que conduce finalmente de vuelta al centinela, la raíz. Puede haber varios diccionarios. En casos raros, como la metacompilación, un diccionario puede estar aislado y ser autónomo. El efecto se asemeja al de anidar espacios de nombres y puede sobrecargar palabras clave según el contexto.
Una palabra definida generalmente consta de una cabeza y un cuerpo , donde la cabeza consta del campo de nombre (NF) y el campo de enlace (LF), y el cuerpo consta del campo de código (CF) y el campo de parámetro (PF).
El encabezado y el cuerpo de una entrada de diccionario se tratan por separado porque pueden no ser contiguos. Por ejemplo, cuando se vuelve a compilar un programa Forth para una nueva plataforma, el encabezado puede permanecer en la computadora que compila, mientras que el cuerpo va a la nueva plataforma. En algunos entornos (como los sistemas integrados ), los encabezados ocupan memoria innecesariamente. Sin embargo, algunos compiladores cruzados pueden colocar los encabezados en el destino si se espera que el propio destino admita un Forth interactivo. [33]
El formato exacto de una entrada de diccionario no está prescrito y las implementaciones varían.
El compilador en sí no es un programa monolítico. Consta de palabras Forth visibles para el sistema y utilizables por un programador. Esto permite que un programador cambie las palabras del compilador para fines especiales.
El indicador "tiempo de compilación" en el campo de nombre se establece para palabras con comportamiento de "tiempo de compilación". La mayoría de las palabras simples ejecutan el mismo código ya sea que se escriban en una línea de comandos o se incorporen al código. Al compilarlas, el compilador simplemente coloca el código o un puntero enhebrado en la palabra. [28]
Los ejemplos clásicos de palabras de tiempo de compilación son las estructuras de control como IF
y WHILE
. Casi todas las estructuras de control de Forth y casi todos sus compiladores se implementan como palabras de tiempo de compilación. Aparte de algunas palabras de flujo de control que rara vez se usan y que solo se encuentran en unas pocas implementaciones, como la palabra de retorno condicional ?EXIT
utilizada en preForth de Ulrich Hoffmann, [34] [35] todas las palabras de flujo de control de Forth se ejecutan durante la compilación para compilar varias combinaciones de palabras primitivas junto con sus direcciones de rama. Por ejemplo, IF
y WHILE
, y las palabras que coinciden con ellas, configuran BRANCH
(rama incondicional) y ?BRANCH
(extraer un valor de la pila y ramificar si es falso). Las palabras de flujo de control de bucle contado funcionan de manera similar, pero configuran combinaciones de palabras primitivas que funcionan con un contador, y así sucesivamente. Durante la compilación, la pila de datos se utiliza para soportar el balanceo de la estructura de control, el anidamiento y el parcheo posterior de las direcciones de rama. El fragmento:
... DUP 6 < SI DROP 5 SI NO 1 - ENTONCES ...
a menudo se compilaría en la siguiente secuencia dentro de una definición:
... DUP LIT 6 < ?RAMA 5 GOTA LIT 5 RAMA 3 LIT 1 - ...
Los números que siguen BRANCH
representan direcciones de salto relativas. LIT
es la palabra primitiva para insertar un número "literal" en la pila de datos. (Se compilaría un código más rápido y más corto utilizando punteros a constantes en lugar de LIT
datos integrados, si alguno de los números involucrados se hubiera definido por separado como constantes. Se producirían cambios similares si se utilizaran otras palabras en lugar de constantes, y así sucesivamente).
La palabra :
(dos puntos) analiza un nombre como parámetro, crea una entrada de diccionario (una definición de dos puntos ) y entra en estado de compilación. El intérprete continúa leyendo palabras delimitadas por espacios desde el dispositivo de entrada del usuario. Si se encuentra una palabra, el intérprete ejecuta la semántica de compilación asociada con la palabra, en lugar de la semántica de interpretación . La semántica de compilación predeterminada de una palabra consiste en agregar su semántica de interpretación a la definición actual. [28]
La palabra ;
(punto y coma) finaliza la definición actual y vuelve al estado de interpretación. Es un ejemplo de una palabra cuya semántica de compilación difiere de la predeterminada. La semántica de interpretación de ;
(punto y coma), la mayoría de las palabras de flujo de control y varias otras palabras no están definidas en ANS Forth, lo que significa que solo se deben usar dentro de las definiciones y no en la línea de comandos interactiva. [28]
El estado del intérprete se puede cambiar manualmente con las palabras [
(corchete izquierdo) y ]
(corchete derecho) que ingresan al estado de interpretación o al estado de compilación, respectivamente. Estas palabras se pueden usar con la palabra LITERAL
para calcular un valor durante una compilación e insertar el valor calculado en la definición de dos puntos actual. LITERAL
tiene la semántica de compilación para tomar un objeto de la pila de datos y agregar semántica a la definición de dos puntos actual para colocar ese objeto en la pila de datos.
En ANS Forth, el estado actual del intérprete se puede leer desde el indicador STATE
que contiene el valor verdadero cuando está en estado de compilación y falso en caso contrario. Esto permite la implementación de las llamadas palabras inteligentes con un comportamiento que cambia según el estado actual del intérprete.
La palabra IMMEDIATE
marca la definición de dos puntos más reciente como una palabra inmediata , reemplazando efectivamente su semántica de compilación con su semántica de interpretación. [36] Las palabras inmediatas normalmente se ejecutan durante la compilación, no se compilan, pero el programador puede anular esto en cualquier estado. ;
es un ejemplo de una palabra inmediata. En ANS Forth, la palabra POSTPONE
toma un nombre como parámetro y agrega la semántica de compilación de la palabra nombrada a la definición actual incluso si la palabra fue marcada como inmediata. Forth-83 definió palabras separadas COMPILE
y [COMPILE]
para forzar la compilación de palabras no inmediatas e inmediatas, respectivamente.
En lugar de reservar espacio para un indicador Inmediato en cada definición, algunas implementaciones de Forth utilizan un Diccionario Inmediato que se verifica primero en modo de compilación.
En ANS Forth, las palabras sin nombre se pueden definir con la palabra :NONAME
que compila las siguientes palabras hasta la siguiente ;
(punto y coma) y deja un token de ejecución en la pila de datos. El token de ejecución proporciona un identificador opaco para la semántica compilada, similar a los punteros de función del lenguaje de programación C.
Los tokens de ejecución se pueden almacenar en variables. La palabra EXECUTE
toma un token de ejecución de la pila de datos y ejecuta la semántica asociada. La palabra COMPILE,
(compilación-coma) toma un token de ejecución de la pila de datos y agrega la semántica asociada a la definición actual.
La palabra '
(tick) toma el nombre de una palabra como parámetro y devuelve el token de ejecución asociado con esa palabra en la pila de datos. En estado de interpretación, ' RANDOM-WORD EXECUTE
es equivalente a RANDOM-WORD
. [37]
Las palabras :
(dos puntos), POSTPONE
, '
(tilde) son ejemplos de palabras que se analizan sintácticamente y que toman sus argumentos del dispositivo de entrada del usuario en lugar de la pila de datos. Otro ejemplo es la palabra (
(paréntesis) que lee e ignora las siguientes palabras hasta el siguiente paréntesis derecho inclusive y se utiliza para colocar comentarios en una definición de dos puntos. De manera similar, la palabra \
(barra invertida) se utiliza para comentarios que continúan hasta el final de la línea actual. Para que se analicen correctamente, (
(paréntesis) y \
(barra invertida) deben estar separadas por un espacio en blanco del siguiente texto del comentario.
En la mayoría de los sistemas Forth, el cuerpo de una definición de código consiste en lenguaje de máquina o alguna forma de código enhebrado . El Forth original, que sigue el estándar informal FIG (Forth Interest Group), es un TIL (lenguaje interpretativo enhebrado). Esto también se llama código enhebrado indirecto, pero los Forth enhebrados directos y enhebrados por subrutina también se han vuelto populares en los tiempos modernos. Los Forth modernos más rápidos, como SwiftForth, VFX Forth e iForth, compilan Forth a código de máquina nativo.
Cuando una palabra es una variable u otro objeto de datos, el CF apunta al código de tiempo de ejecución asociado con la palabra definitoria que la creó. Una palabra definitoria tiene un "comportamiento definitorio" característico (crear una entrada de diccionario y posiblemente asignar e inicializar espacio de datos) y también especifica el comportamiento de una instancia de la clase de palabras construidas por esta palabra definitoria. Algunos ejemplos incluyen:
VARIABLE
VARIABLE
devuelve su dirección en la pila.CONSTANT
CONSTANT
). El comportamiento de la instancia devuelve el valor.CREATE
Forth también ofrece una función mediante la cual un programador puede definir nuevas palabras de definición específicas de la aplicación, especificando tanto un comportamiento de definición personalizado como un comportamiento de instancia. Algunos ejemplos incluyen buffers circulares, bits con nombre en un puerto de E/S y matrices indexadas automáticamente.
Los objetos de datos definidos por estas y otras palabras similares tienen un alcance global. La función proporcionada por las variables locales en otros lenguajes la proporciona la pila de datos en Forth (aunque Forth también tiene variables locales reales). El estilo de programación de Forth utiliza muy pocos objetos de datos con nombre en comparación con otros lenguajes; normalmente, dichos objetos de datos se utilizan para contener datos que son utilizados por varias palabras o tareas (en una implementación multitarea). [38]
Forth no exige coherencia en el uso del tipo de datos ; es responsabilidad del programador utilizar operadores apropiados para obtener y almacenar valores o realizar otras operaciones con los datos.
: HOLA (--) CR ." ¡Hola, mundo! " ;
Hola <cr>¡Hola Mundo!
La palabra CR
(Carriage Return) hace que la salida siguiente CR
se muestre en una nueva línea. La palabra de análisis ."
(dot-quote) lee una cadena delimitada por comillas dobles y agrega código a la definición actual para que la cadena analizada se muestre al ejecutarse. El carácter de espacio que separa la palabra ."
de la cadena Hello, World!
no se incluye como parte de la cadena. Es necesario para que el analizador la reconozca ."
como una palabra Forth.
Un sistema Forth estándar también es un intérprete y se puede obtener el mismo resultado escribiendo el siguiente fragmento de código en la consola Forth:
CR . (¡Hola, mundo!)
.(
(dot-paren) es una palabra inmediata que analiza una cadena delimitada por paréntesis y la muestra. Al igual que con la palabra, ."
el carácter de espacio .(
que separa Hello, World!
no forma parte de la cadena.
La palabra CR
va antes del texto que se va a imprimir. Por convención, el intérprete de Forth no comienza la salida en una nueva línea. También por convención, el intérprete espera la entrada al final de la línea anterior, después de un ok
mensaje de solicitud. No hay una acción de "vaciado del búfer" implícita en Forth CR
, como ocurre a veces en otros lenguajes de programación.
Aquí está la definición de una palabra EMIT-Q
que cuando se ejecuta emite el carácter único Q
:
: EMIT-Q 81 (el valor ASCII para el carácter 'Q') EMIT ;
Esta definición se escribió para utilizar el valor ASCII del Q
carácter (81) directamente. El texto entre paréntesis es un comentario y el compilador lo ignora. La palabra EMIT
toma un valor de la pila de datos y muestra el carácter correspondiente.
La siguiente redefinición de EMIT-Q
utiliza las palabras [
(corchete izquierdo), ]
(corchete derecho) CHAR
y LITERAL
para cambiar temporalmente al estado de intérprete, calcular el valor ASCII del Q
carácter, volver al estado de compilación y agregar el valor calculado a la definición de dos puntos actual:
: EMITIR-Q [ CHAR Q ] LITERAL EMITIR ;
La palabra que se analiza CHAR
toma una palabra delimitada por espacios como parámetro y coloca el valor de su primer carácter en la pila de datos. La palabra [CHAR]
es una versión inmediata de CHAR
. Si se utiliza [CHAR]
, la definición de ejemplo de EMIT-Q
podría reescribirse de la siguiente manera:
: EMIT-Q [CHAR] Q EMIT ; \ Emite el carácter único 'Q'
Esta definición se utiliza \
(barra invertida) para el comentario descriptivo.
Tanto CHAR
y [CHAR]
están predefinidos en ANS Forth. Si se usaran IMMEDIATE
y POSTPONE
, [CHAR]
se podrían haber definido de la siguiente manera:
: [CHAR] CHAR POSPONE LITERAL ; INMEDIATO
En 1987, Ron Rivest desarrolló el sistema de cifrado RC4 para RSA Data Security, Inc. Su descripción es la siguiente:
Tenemos una matriz de 256 bytes, todos diferentes. Cada vez que se utiliza la matriz, cambia intercambiando dos bytes. Los intercambios están controlados por los contadores i y j , cada uno inicialmente 0. Para obtener una nueva i , agregue 1. Para obtener una nueva j , agregue el byte de la matriz en la nueva i . Intercambie los bytes de la matriz en i y j . El código es el byte de la matriz en la suma de los bytes de la matriz en i y j . Esto se XOR con un byte del texto sin formato para cifrar, o el texto cifrado para descifrar. La matriz se inicializa primero estableciéndola en 0 a 255. Luego, recorra usando i y j , obteniendo la nueva j agregando el byte de la matriz en i y un byte de clave, e intercambiando los bytes de la matriz en i y j . Finalmente, i y j se establecen en 0. Todas las adiciones son módulo 256.
La siguiente versión de Standard Forth utiliza únicamente palabras Core y Core Extension.
valor 0 ii valor 0 jj valor 0 KeyAddr valor 0 KeyLen crear SArray 256 asignación \ matriz de estado de 256 bytes : KeyArray KeyLen mod KeyAddr ; : obtener_byte + c@ ; : establecer_byte + c! ; : como_byte 255 y ; : restablecer_ij 0 A ii 0 A jj ; : i_actualizar 1 + como_byte A ii ; : j_actualizar ii SArray obtener_byte + como_byte A jj ; : intercambiar_s_ij jj SArray obtener_byte ii SArray obtener_byte jj SArray establecer_byte ii SArray establecer_byte ; : rc4_init ( KeyAddr KeyLen -- ) 256 min TO KeyLen TO KeyAddr 256 0 HACER i i SArray establecer_byte BUCLE restablecer_ij COMENZAR ii KeyArray obtener_byte jj + j_update swap_s_ij ii 255 < MIENTRAS ii i_update REPETIR restablecer_ij ; : rc4_byte ii i_update jj j_update swap_s_ij ii SArray obtener_byte jj SArray obtener_byte + as_byte SArray obtener_byte xor ;
Esta es una forma de probar el código:
hex crear AKey 61 c, 8 A c, 63 c, D2 c, FB c, : prueba cr 0 DO rc4_byte . LOOP cr ; AKey 5 rc4_init 2 C F9 4 C EE DC 5 prueba \ la salida debe ser: F1 38 29 C9 DE
Debido a que Forth es fácil de implementar y no tiene una implementación de referencia estándar, existen numerosas versiones del lenguaje. Además de admitir las variedades estándar de sistemas informáticos de escritorio ( POSIX , Microsoft Windows , macOS ), muchos de estos sistemas Forth también están destinados a una variedad de sistemas integrados . A continuación, se enumeran algunos de los sistemas que cumplen con el estándar ANS Forth de 1994.
En resumen, hay tres tipos de variables: Las variables del sistema contienen valores utilizados por todo el sistema Forth. Las variables de usuario contienen valores que son únicos para cada tarea, aunque las definiciones pueden ser utilizadas por todas las tareas del sistema. Las variables regulares pueden ser accesibles ya sea para todo el sistema o dentro de una sola tarea solamente, dependiendo de si están definidas dentro
o dentro de una tarea privada.
OPERATOR