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 los enlaces que proceden de la última palabra definida (la más reciente) a la más antigua, hasta que se encuentra un valor centinela, generalmente un puntero NULO. 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 eventualmente regresa al centinela, la raíz.Puede haber varios diccionarios. En casos raros, como la metacompilación, un diccionario puede estar aislado e independiente.El efecto se asemeja al de anidar espacios de nombres y puede sobrecargar palabras clave dependiendo del contexto.
Una palabra definida generalmente consiste en la cabeza y el cuerpo con la cabeza que consiste en el campo de nombre (NF) y el campo de enlace (LF), y el cuerpo que consiste en el campo de código (CF) y el campo de parámetro (PF).
La cabeza y el cuerpo de una entrada de diccionario se tratan por separado porque pueden no ser contiguos. Por ejemplo, cuando un programa Forth se recompila para una nueva plataforma, la cabeza puede permanecer en la computadora de compilación, mientras que el cuerpo va a la nueva plataforma. En algunos entornos (como los sistemas embebidos), los cabezales ocupan memoria innecesariamente. Sin embargo, algunos compiladores cruzados pueden poner cabezas en el objetivo si se espera que el objetivo en sí soporte un Forth interactivo.
Entrada de diccionarios Edit
El formato exacto de una entrada de diccionario no está prescrito, y las implementaciones varían. Sin embargo, ciertos componentes casi siempre están presentes, aunque el tamaño y el orden exactos pueden variar. Descrito como una estructura, una entrada de diccionario podría verse de esta manera:
structure byte: flag \ 3bit flags + length of word's name char-array: name \ name's runtime length isn't known at compile time address: previous \ link field, backward ptr to previous word address: codeword \ ptr to the code to execute this word any-array: parameterfield \ unknown length of data, words, or opcodes end-structure forthword
El campo nombre comienza con un prefijo que indica la longitud del nombre de la palabra (normalmente hasta 32 bytes), y varios bits para las banderas. La representación de caracteres del nombre de la palabra sigue al prefijo. Dependiendo de la implementación particular de Forth, puede haber uno o más bytes NUL (‘\0’) para alineación.
El campo de enlace contiene un puntero a la palabra previamente definida. El puntero puede ser un desplazamiento relativo o una dirección absoluta que apunta al siguiente hermano mayor.
El puntero del campo de código será la dirección de la palabra que ejecutará el código o los datos en el campo de parámetros o el comienzo del código de máquina que el procesador ejecutará directamente. Para las palabras definidas por dos puntos, el puntero del campo de código apunta a la palabra que guardará el puntero de instrucción (IP) actual en la pila de retorno y cargará la IP con la nueva dirección desde la que continuar la ejecución de las palabras. Esto es lo mismo que las instrucciones de llamada/devolución de un procesador.
Estructura del compiladoreditar
El compilador en sí no es un programa monolítico. Consiste en palabras Forth visibles para el sistema y utilizables por un programador. Esto permite a un programador cambiar las palabras del compilador para propósitos especiales.
El indicador » tiempo de compilación «en el campo nombre se establece para palabras con comportamiento» tiempo de compilación». La mayoría de las palabras simples ejecutan el mismo código, ya sea que estén escritas en una línea de comandos o incrustadas en código. Al compilar estos, el compilador simplemente coloca código o un puntero enhebrado a la palabra.
Los ejemplos clásicos de palabras en tiempo de compilación son las estructuras de control como IF
y WHILE
. Casi todas las estructuras de control de Forth y casi todo su compilador se implementan como palabras en tiempo de compilación. Aparte de algunas palabras de flujo de control raramente usadas que solo se encuentran en unas pocas implementaciones, como un retorno condicional, 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 los de, configurar BRANCH
(bifurcación incondicional) y ?BRANCH
(pop un valor de la pila, y la rama de si es falso). Las palabras de flujo de control de bucle contado funcionan de manera similar, pero configura 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 equilibrio de la estructura de control, el anidamiento y el retaguardia de las direcciones de rama. El fragmento de código:
... DUP 6 < IF DROP 5 ELSE 1 - THEN ...
iba a ser compilado con la siguiente secuencia en el interior de una definición:
... DUP LIT 6 < ?BRANCH 5 DROP LIT 5 BRANCH 3 LIT 1 - ...
Los números después de BRANCH
representan relativa saltar direcciones. LIT
es la palabra primitiva para insertar un número «literal» en la pila de datos.
Estado de compilación e interpretacióneditar
La palabra :
(dos puntos) analiza un nombre como parámetro, crea una entrada de diccionario (una definición de dos puntos) e ingresa el 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 a la palabra, en lugar de la semántica de interpretación. La semántica de compilación predeterminada de una palabra consiste en añadir su semántica de interpretación a la definición actual.
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 deben usarse dentro de las definiciones y no en la línea de comandos interactiva.
El estado del intérprete se puede cambiar manualmente con las palabras (entre corchetes a la derecha) que ingresan el estado de interpretación o el 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 compilación semántica para tomar un objeto de la pila de datos y para añadir semántica a la actual colon definición para colocar el objeto en la pila de datos.
En adelante, el estado actual del intérprete se puede leer desde la bandera STATE
que contiene el valor true cuando está en estado de compilación y false de lo contrario. Esto permite la implementación de las llamadas palabras inteligentes de estado con un comportamiento que cambia de acuerdo con el estado actual del intérprete.
Palabras inmediataseditar
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. Las palabras inmediatas son normalmente ejecutadas durante la compilación, no compiladas, pero esto puede ser anulado por el programador en cualquier estado. ;
es un ejemplo de 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 se marcó inmediata. Forth-83 define palabras separadas COMPILE
y para forzar la compilación de palabras no inmediatas e inmediatas, respectivamente.
Palabras sin nombre y tokens de ejecución Edit
En adelante, las palabras sin nombre se pueden definir con la palabra :NONAME
que compila las siguientes palabras hasta el 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 realiza la semántica asociada. La palabra COMPILE,
(coma de compilación) toma un token de ejecución de la pila de datos y añade 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 a esa palabra en la pila de datos. En el estado de interpretación, ' RANDOM-WORD EXECUTE
es equivalente a RANDOM-WORD
.
Edit
Las palabras :
(dos puntos), POSTPONE
'
(tick) son ejemplos de análisis de palabras 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 e incluyendo el siguiente paréntesis derecho y se usa para colocar comentarios en una definición de dos puntos. De manera similar, la palabra \
(barra invertida) se usa para comentarios que continúan hasta el final de la línea actual. Para analizarlo correctamente, (
(paréntesis) y \
(barra invertida) deben estar separados por espacios en blanco del siguiente texto de comentario.
Estructura de codeEdit
En la mayoría de los sistemas Forth, el cuerpo de una definición de código consiste en lenguaje máquina o alguna forma de código enhebrado. El Forth original que sigue el estándar informal FIG (Grupo de Interés Forth), es un TIL (Lenguaje Interpretativo Enhebrado). Esto también se llama código de rosca indirecta, pero los fuertes de rosca directa y 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 en código de máquina nativo.
Objetos de datosEditar
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 definidora que la creó. Una palabra definidora tiene un «comportamiento definitorio» característico (crear una entrada de diccionario más posiblemente asignar e inicializar el espacio de datos) y también especifica el comportamiento de una instancia de la clase de palabras construidas por esta palabra definitoria. Los ejemplos incluyen:
VARIABLE
Nombra una ubicación de memoria de una celda no inicializada. El comportamiento de instancia de unVARIABLE
devuelve su dirección en la pila.CONSTANT
Nombres de un valor (especificado como argumento aCONSTANT
). Comportamiento de instancia devuelve el valor.CREATE
Nombra una ubicación; el espacio se puede asignar en esta ubicación, o se puede configurar para que contenga una cadena u otro valor inicializado. Comportamiento de instancia devuelve la dirección del comienzo de este espacio.
Forth también proporciona una facilidad mediante la cual un programador puede definir nuevas palabras definidoras específicas de la aplicación, especificando tanto un comportamiento de definición personalizado como un comportamiento de instancia. Algunos ejemplos incluyen búferes circulares, bits con nombre en un puerto de E/S y matrices indexadas automáticamente.
Los objetos de datos definidos por estas palabras y similares son de alcance global. La función proporcionada por variables locales en otros idiomas es proporcionada por la pila de datos en Forth (aunque Forth también tiene variables locales reales). El estilo de programación Forth utiliza muy pocos objetos de datos con nombre en comparación con otros lenguajes; por lo general, estos objetos de datos se utilizan para contener datos que son utilizados por un número de palabras o tareas (en una implementación multitarea).
Forth no impone la consistencia del uso de los tipos de datos; es responsabilidad del programador usar operadores apropiados para obtener y almacenar valores o realizar otras operaciones en los datos.