Jupiter Ace Forth (Estructura Palabras)

Elurdio
Mensajes: 410
Registrado: 07 Dic 2021 21:33
Ubicación: Barcelona
Agradecido : 90 veces
Agradecimiento recibido: 84 veces

Jupiter Ace Forth (Estructura Palabras)

Mensajepor Elurdio » 08 Ene 2022 16:39

Necesito conocer al detalle la estructura de los diferentes tipos de palabras de usuario del Jupite Ace. He pensado en hacer un programa que, dada una palabra de usuario, me liste todas la palabras de usuario que la componen y en el orden adecuado (que no me liste primero una palabra que necesita a otra listada más adelante).

Ahora estoy estudiando las palabras tipo DEFINER. Ya pondré lo que averigüe.

De momento pongo estas tres del Jupiter Ace Archive (Tweeter):

Estas dos corresponden a la siguiente definición colon:

: STAR ASCII * EMIT ;

Word_map3.jpg
Word_map3.jpg (51.97 KiB) Visto 591 veces


Parameter_Field3.jpg
Parameter_Field3.jpg (43.57 KiB) Visto 591 veces


NOTA: Creo que la segunda (la del PF) está un poco mal.

Forth Vocabulary Structure2.jpg
Forth Vocabulary Structure2.jpg (131.25 KiB) Visto 780 veces


El primero es un excelente esquema gráfico de la estructura de la cabecera de cualquier palabra de usuario del Ace Forth (*) que está muy bien explicada en el manual del JA. En mi caso, dado el tipo de programas que hago últimamente, la utilizo constantemente.

La segunda, como luego explico, no se corresponde con la definición de STAR

En cuanto a la tercera, poco la uso, pues de momento, todo lo que hago presupone que solo hay el vocabulario por defecto (FORTH), ningún otro creado.

Veo algunos fallos en las dos primeras:

En la cabecera de STAR hay una flecha roja que sale del CFA y apunta la principio del PF, dando a entender que el valor almacenado en el CFA apunta al inicio del PF. Esto es cierto para muchas primitivas Forth y para las generadas con el assembler de Bolfield pero no para las definiciones Colon como STAR.

En el PF de STAR hay varios errores:
- Los 2 primeros bytes con H0EC3 son el contenido de CFA del Header (cabecera), no forman parte del PF. El PF empieza justo después.
- Los 2 primeros bytes del PF pone que es H1011 (Stack Word) cuando debería poner H104B (Stack Byte) que es el que realmente corresponde a ASCII.
- Después viene un byte con el código ascii en cuestión, H2A en este caso, no los dos bytes que pone (H0011).

Por lo visto se han equivocado y han hecho la estructura de la palabra:

: STAR 42 EMIT ; muy parecida, pues 42 es el código ascii de asterisco.

que correspondería al PF mostrado (salvo que 42 en hex es 2A y no 11)

(*) La cabecera de una palabra primitiva del Ace Forth es más corta, pues carece del LENGTH FIELD. La única excepción es la primitiva FORTH que tiene una cabecera completa.

Elurdio
Mensajes: 410
Registrado: 07 Dic 2021 21:33
Ubicación: Barcelona
Agradecido : 90 veces
Agradecimiento recibido: 84 veces

Re: Jupiter Ace Forth (Estructura Palabras)

Mensajepor Elurdio » 08 Ene 2022 23:44

A falta de hacer un esquema al estilo de los anteriores, pongo aquí lo que he averiguado de la estructura de una palabra tipo DEFINER:

Header (cabecera)
·
·
#1085 (CFA) DEFINER
---------------------------
aquí comienza el PF
---------------------------
2 bytes La dirección de memoria después de DOES> (apunta al principio de los 3 bytes CD F0 0F .... ver más abajo)
---------------------------
·
n bytes Palabras compiladas antes de DOES>
·
---------------------------
#10E8 Exit. Final de la sección de palabras compiladas antes de DOES>
---------------------------
2 bytes Un número negativo que sumado a esta dirección de memoria, da la dirección de memoria del byte justo antes del incio de la cabecera.
------------------------------------------Inicio sección después del DOES>---------------------------------
3 bytes CD F0 0F Código máquina de: CALL #0FF0. Coloca en la pila la dirección del PF de la palabra que ha llamado a ésta y ejecuta las palabras que siguen
---------------------------
·
n bytes Palabras compiladas antes de ;
·
---------------------------
#04B6 Exit. Fin de la palabra.
---------------------------

Elurdio
Mensajes: 410
Registrado: 07 Dic 2021 21:33
Ubicación: Barcelona
Agradecido : 90 veces
Agradecimiento recibido: 84 veces

Re: Jupiter Ace Forth (Estructura Palabras)

Mensajepor Elurdio » 09 Ene 2022 15:04

Código: Seleccionar todo

DEFINER Ejemplo estructura:

DEFINER 2CONSTANT
 SWAP , ,
DOES>
 2@
;

En este diccionario concreto empieza la cabecera en #41B2

-----------------------------------Inicio de la cabecera (Header)
-----------------------------------NF: Name Field (ASCII del último carácter + 128)
41B2   32        2
-----------
41B3   43        C
-----------
41B4   4F        O
-----------
41B5   4E        N
-----------
41B6   53        S
-----------
41B7   54        T
-----------
41B8   41        A
-----------
41B9   4E        N
-----------
41BA   D4        T+128 (T en vídeo Inverso)
-----------------------------------LF: Length Field
41BB   1A   
-----------      001A   Tamaño en bytes de la palabra desde aquí hasta final (header-NF+PF)
41BC   00   
-----------------------------------LFA: Link Field Address
41BD   9E   
-----------      419E   Dirección de memoria del NLF de la palabra anterior a ésta.
41BE   41   
-----------------------------------NLF: Name Length Field
41BF   09        2CONSTANT son 9 bytes (1 por caracter)
-----------------------------------CFA: Code Field Address
41C0   85   
-----------      1085   En esta dirección está la rutina que se ejecutará con una palabra tipo DEFINER
41C1   10   
-----------------------------------Inicio del Parameter Field (PF). 41C2 es el PFA (Parameter Field Address)
41C2   CE   
-----------      41CE   Dirección de inicio de la zona después del DOES> (ver más abajo)
41C3   41   
---------------------
41C4   85   
-----------      0885   CFA de la palabra SWAP
41C5   08   
---------------------
41C6   4E   
-----------      0F4E   CFA de la palabra ,
41C7   0F   
---------------------
41C8   4E   
-----------      0F4E   CFA de la palabra ,
41C9   0F   
---------------------
41CA   E8   
-----------      10E8   EXIT Fin de la sección antes de DOES>
41CB   10   
---------------------
41CC   E5   
-----------      FFE5   Número negativo (FFE5 = -27 decimal) que sumado a 41CD nos da 41B2 = Posición del
41CD   FF               primer caracter del nombre (el 2 de 2CONSTANT).
-----------------------------------DOES>----------------------------
41CE   CD   
-----------      CALL 0FF0
41CF   F0        Lamada a la rutina que coloca en la pila el PFA (Parameter Field Address) de la palabra que 
-----------        llama a 2CONSTANT y luego sigue ejecutanto el resto de este PF (sigue con 41D1 etc)
41D0   0F   
---------------------
41D1   54   
-----------      4154   CFA de la palabra 2@
41D2   41   
---------------------
41D3   B6   
-----------      04B6   EXIT Fin de la palabra
41D4   04   
-----------------------------------Fin del PF y de la palabra.

Elurdio
Mensajes: 410
Registrado: 07 Dic 2021 21:33
Ubicación: Barcelona
Agradecido : 90 veces
Agradecimiento recibido: 84 veces

Re: Jupiter Ace Forth (Estructura Palabras)

Mensajepor Elurdio » 10 Ene 2022 12:42

Palabra tipo COMPILER
Header (cabecera)
·
·
#1108 (CFA) COMPILER
-----------------------------Comienza PF
2 bytes La dirección del primer byte justo después de RUNS> (dondes está el #1142 ver más abajo)
---------
·
n bytes de Palabras Compiladas antes del RUNS>
·
---------
#1140 Exit. Fin de la sección antes del RUNS>
---------
1 byte Dos casos:
FF: El tamaño del Operand Field (OF) está en los 2 primeros bytes del mismo.
n: (menor que FF) el tamaño del OF es n.
---------
2 bytes Un número negativo que sumado a su dirección nos da dirección del byte justo antes del Header.
----------------------------Inicio sección después del RUNS>
#1142 CFA de la rutina que ejecuta esta seccón.
---------
·
n bytes de Palabras Compiladas antes del ;
·
---------
#04B6 Exit. Fin de la palabra.
---------

Elurdio
Mensajes: 410
Registrado: 07 Dic 2021 21:33
Ubicación: Barcelona
Agradecido : 90 veces
Agradecimiento recibido: 84 veces

Re: Jupiter Ace Forth (Estructura Palabras)

Mensajepor Elurdio » 10 Ene 2022 23:31

Otras estructuras

Las palabras definidas con palabras definidoras de usuario tienen como CFA la dirección del CALL 0FF0 de la palabra definidora con la que se definió.

Palabras definidoras primitivas:

CONSTANT el CFA de una constante apunta a #0FF5 donde hay una rutina que pone la word (la constante) del PF en la pila
VARIABLE el CFA de una variable apunta a #FF0 donde hay una rutina que pone la dirección de su PF en la pila.


Las compilaciones con palabras compiladoras de usuario compilan primero la dirección en que se encuentra el #1142 de la palabra compiladora y a continuación su Operand Field (OF).

Palabras compiladoras primitivas:

LITERAL
ASCII
."
(
IF THEN ELSE
BEGIN UNTIL
BEGIN WHILE REPEAT
DO LOOP +LOOP

Creo que están todas...

LITERAL
Compila #1011 seguidos de 2 bytes (una word) del OF. En #1011 está la rutina que pone la word que le sigue en la pila.

ASCII
Compila #104B seguidos de 1 byte del OF. En #104B está la rutina que pone el byte que le sigue en la pila

."
Compila #1396 seguido de 2 bytes con la longitud del texto. A continuación los caracteres que lo componen (1 byte por carácter)
En #1396 prepara y llama la rutina que imprime la cadena de caracteres

(
Compila #1379 seguido de 2 bytes con la longitud del comentario. A continuación los caracteres que lo componen (1 byte cada uno)

IF en un IF THEN
Compila #1283 seguido de 2 bytes con la distancia al byte después del THEN (compilado como #12A4)

IF en un IF ELSE THEN
Compila #1283 seguido de 2 bytes con la distancia al byte después del ELSE (compilado como #1271). A continuación del ELSE vienen
2 bytes con la distancia al byte después del THEN (compilado como #12A4).

BEGIN UNTIL
Compila #129F para el BEGIN y #128D para el UNTIL al que sigue su OF de 2 bytes con un número negativo que sumado la dirección del
byte alto de este número negativo nos da la dirección del primer byte después del BEGIN.

BEGIN WHILE REPEAT
Compila #129F para el BEGIN y #1288 para el WHILE seguido de su OF de 2 bytes con la distancia al byte después del REPEAT
compilado como #1276 seguido de su OF de 2 bytes con un número negativo que sumado a la dirección del High byte del mismo nos
da la dirección del byte pasado el BEGIN.

DO LOOP
Compila #1323 para el DO y #1332 para el LOOP seguido de 2 bytes con un número negativo que sumado a la dirección del Hight byte
del mismo nos da la dirección del byte después del DO.

DO +LOOP
Compila #1323 para el DO y #133C para el +LOOP seguido de 2 bytes con un número negativo que sumado a la dirección del Hight byte
del mismo nos da la dirección del byte después del DO.

-----------------------------------------

Creo que con esto ya tengo todo lo necesario para analizar la composición de cualquier palabra de usuario del JA
Espero no haberme equivocado ni dejado nada.

También útil:

Compilations Address que son final de palabra:

#04B6 Fin :
#10E8 Fin DOES>
#1140 Fin RUNS>

=====================================
Detección de una palabra definida con una Definidora:

Sea TEST una palabra definida con una palabra definidora (creada con DEFINER)

FIND TEST @ 4 - @ H. nos dará #10E8 que es igual para cualquier definidora

Como sacar el CFA de la definidora:

CFA @ 2- DUP @ + 1+ = dirección del primer carácter del nombre de la definidora. Entonces se busca hacia adelante hasta encontrar un carácter con ascii > 128. Entonces la dirección 6 bytes más adelante es la del CFA de la definidora.

==============================================
Detección de un CFA compilado que pertenece a una palabra COMPILER

El contenido de la dirección apuntada por CFA debe ser #1142

CFA @ = #1142

Detección del CFA de la COMPILER:

CFA 2- DUP @ + 1+ = dirección del primer carácter del nombre. Entonces se busca hacia adelante hasta encontrar un carácter con ascii > 128. Entonces la dirección 6 bytes más adelante es la del CFA de la COMPILER.

Elurdio
Mensajes: 410
Registrado: 07 Dic 2021 21:33
Ubicación: Barcelona
Agradecido : 90 veces
Agradecimiento recibido: 84 veces

Re: Jupiter Ace Forth (Estructura Palabras)

Mensajepor Elurdio » 06 Feb 2022 13:38

En el post anterior dije:

Creo que con esto ya tengo todo lo necesario para analizar la composición de cualquier palabra de usuario del JA
Espero no haberme equivocado ni dejado nada.


Pues me he dejado algo...

Haciendo pruebas de mi último programa (el extractor de diccionario) que utiliza una versión reducida del extractor de palabras, acabo de descubrir que me dejé un tipo de palabras por analizar: Los números en coma flotante.

NUMERO EN COMA FLOTANTE
Compila #1064 seguido de 4 bytes (una dword) del OF. En #1064 está la rutina que pone la dword que le sigue como número en coma flotante en la pila.

Tengo que arreglar el extractor de palabras y los programas que lo usan.

Elurdio
Mensajes: 410
Registrado: 07 Dic 2021 21:33
Ubicación: Barcelona
Agradecido : 90 veces
Agradecimiento recibido: 84 veces

Re: Jupiter Ace Forth (Estructura Palabras)

Mensajepor Elurdio » 01 Mar 2022 22:27

Estudiando más a fondo el ensamblador/desensamblador de Boldfield (ADB) me he encontrado con un nuevo tipo de palabra. Más que uno nuevo es una variante de la palabra primitiva que ADB genera normalmente (las primitivas de usuario). Pero hay que tenerlo en cuenta, pues si bien el extractor de palabras no se ve afectado, sí que provoca error en el extractor automático de fichero fuente. Tampoco se lista correctamente con WLIST

Cuando escribes código máquina con el ADB se acaba generando una palabra tipo primitiva: El CF apunta al PFA de la palabra. O sea, apunta al inicio del código máquina almacenado en el PF de la palabra:

Si generamos con ADB la palabra TEST su CF apunta al inicio de su PF, o sea, a su PFA (PF address)
Word_map_TEST - copia.jpg
Word_map_TEST - copia.jpg (53.3 KiB) Visto 500 veces

Pero si generamos una palabra con etiquetas absolutas sin haber definido un origen, se genera una palabra primitiva que contiene antes del código máquina en sí, una serie de datos necesarios para que se pueda "relocalizar" la palabra a un origen concreto (ver documentación del ADB). Entonces el CF ya no apunta al PFA, pues allí lo que hay es el inicio de los datos. El inicio del código máquina está más allá.

Hasta ahora mis programas detectaban las palabras primitivas de usuario comprobando que el CF = PFA
Ahora la cosa se complica un poco. El nuevo criterio es que el PFA =< CF =< Final de la palabra. En otras palabras, que el Code Field apunta a cualquier posición dentro del Parameter Field, no necesariamente la posición inicial.

Elurdio
Mensajes: 410
Registrado: 07 Dic 2021 21:33
Ubicación: Barcelona
Agradecido : 90 veces
Agradecimiento recibido: 84 veces

Re: Jupiter Ace Forth (Estructura Palabras)

Mensajepor Elurdio » 02 Ago 2022 16:49

Estructuras de las Palabras (I)

Voy a ver si "mastico" un poco toda la información que puse en los posts anteriores (y corrijo algunos errores).

Toda palabra del Ace Forth se compila en el diccionario con una Cabecera (Header) seguida de su Campo de Parámetros o PF (Parameter Field)

Word_map3.jpg
Word_map3.jpg (51.97 KiB) Visto 287 veces

Cabecera de una Palabra

La cabecera consta de cinco campos:

Name Field o Campo del Nombre: NF. (n bytes, con n=número de letras del nombre)
  • Contiene el nombre de la palabra guardando en cada byte el código ASCII de las letras que lo componen. Al código del último carácter se le ha sumado 128. Es por tanto una campo de tamaño variable.
  • El tamaño máximo del nombre es de 63 caracteres.
  • Los caracters permitidos tienen código 32 < ASCII < 128
Length Field o Campo Longitud: LF (2 bytes)
  • Contiene la longitud total de la palabra en bytes sin contar el tamaño del Name Field NF (Cabecera + PF - NF).
  • Se calcula cuando se añade la siguiente palabra al diccionario. Por tanto, la última palabra tiene este campo a cero.
LInk Field o Campo de Enlace: LkF (2 bytes)
  • Almacena la dirección de memoria del Campo de Longitud del Nombre NLF de la palabra anterior a ésta.
Name Length Field Campo Longitud del Nombre: NLF (1 byte)
  • Contiene la longitud en bytes (o caracteres) del Nombre de la palabra que ya sabemos que como máximo es 63 bytes.
  • Si la palabra es tipo Inmediata entonces se le suma 64 a la longitud del nombre.
Code Field Campo de Código: CF (2 bytes)
  • Contiene la dirección del Código Máquina que se ha de ejecutar cuando se ejecute esta palabra.


A las direcciones dónde empiezan diferentes campos se les asigna también una abreviatura:

NF  -> NFA   (Name Field Address)
LF -> LFA (Length Field Address)
LkF -> LkFA (Link Field Address)
NLF -> NLFA (Name Length Field Address)
CF -> CFA (Code Field Address)


La Cabecera de las palabras que vienen con el Ace Forth (las Primitivas) NO tienen Length Field

Aunque estrictamente hablando no son lo mismo el Campo que la dirección del Campo, muchas veces se usan indistintamente uno u otro término.

Así, diríamos que, para una determinada palabra, el Campo del Código o Code Field (un espacio de memoria de 2 bytes de tamaño) empieza en la dirección de memoria que llamamos Dirección del Campo del Código o Code Field Address CFA y contiene un número que es la dirección donde empieza el código máquina que hay que ejecutar cuando se ejecuta esta palabra.

En el caso del NFA es la dirección donde empieza la palabra y también la dirección dónde se almacena el código del primer carácter mientras el NF es el campo completo (el espacio que ocupan todos los caracteres del nombre).

En general, al contenido de un Campo o Field se le representa por la abreviatura del campo entre paréntesis. Así el contenido del CF es (CF) y a menudo incluso se representa (CFA).

Por ejemplo, en el gráfico de arriba, al espacio que representa el Link Field le ha llamado Link Field Address, cuando ésta en realidad es la dirección de memoria del primer byte de los dos que lo componen. Pero ya he dicho que a menudo se usan indistintamente uno u otro término.

En el caso del NF, (NF) sería el nombre en sí (el conjunto de los caracteres ASCII que lo componen con el último+64)

Ha de quedar claro que cuando usamos (CFA) está implícito que conocemos el tamaño en bytes del CF. Así (CFA) indica el valor de 2 bytes en memoria con la dirección de su primer byte almacenada en la dirección CFA. Y lo mismo para los demás Campos cada uno con su tamaño.

NOTA: En el gráfico hay una flecha roja que sale del CF y apunta al primer byte del PF. Esto es cierto en un tipo concreto de palabras. En general el CF apunta fuera de la definición de la palabra.

Elurdio
Mensajes: 410
Registrado: 07 Dic 2021 21:33
Ubicación: Barcelona
Agradecido : 90 veces
Agradecimiento recibido: 84 veces

Re: Jupiter Ace Forth (Estructura Palabras)

Mensajepor Elurdio » 02 Ago 2022 22:43

Estructura de las Palabras (II)

Campo de Parámetros o Parameter Field PF de una Palabra (I)

A continuación de la cabecera (justo después del CF) empieza el Paremeter Field PF de la palabra. Al igual que los campos de la cabecera, el PF tiene asociada su PFA o Parameter Field Address (dirección del campo de parámetros) que es la dirección de inicio del PF.

Si tenemos la dirección de cualquier campo podemos calcular la de cualquier otro sumando o restando los bytes que las separan.

Ej: Si conocemos el NLFA de una palabra, por lo dicho antes (ver dibujo post anterior) vemos que:

LFA = NLFA - 4
LkNA = NLFA - 2
CFA = NLFA + 1
PFA = NLFA + 3

Para averiguar el NFA usaremos el contenido de NLF que no es más que el tamaño del NF (si es mayor de 63 hay que restarle 64)

Supongamos que en nuestro caso (NLF) < 64
NFA = LFA - (NLF) = NLFA - 4 - (NLF) = NLFA - 4 - (NLFA)


Si lo que tenemos es el NFA para hallar los demás procedemos así:

Vamos mirando los valores de los bytes empezando en NFA. Cuando encontremos uno que contiene un valor mayor que 128 sabremos que es el último carácter del nombre. Sea ésta la dirección ADR:

LFA  = ADR + 1
LkNA = ADR + 3
etc.

Elurdio
Mensajes: 410
Registrado: 07 Dic 2021 21:33
Ubicación: Barcelona
Agradecido : 90 veces
Agradecimiento recibido: 84 veces

Re: Jupiter Ace Forth (Estructura Palabras)

Mensajepor Elurdio » 04 Ago 2022 11:18

Estructura de las Palabras (III)

Campo de Parámetros o Parameter Field PF de una Palabra (II)

Así como la estructura de la cabecera es igual para todas las palabras, en cambio la estructura del Paremeter Field o Campo de Parámetros depende del tipo de palabra. En Ace Forth podemos definir seis tipos de palabras:

CONSTANT
VARIABLE
CREATE
COLON
DEFINER
COMPILER


CONSTANT y VARIABLE: Su PF es de 2 bytes de longitud y contiene los 2 bytes que componen el número entero que almacenan. Primero está el Low byte seguido del Hight byte. Así, la PFA apunta al Low byte y PFA+1 apunta al High byte.

CONSTANT: (CF) = $0FF5 = 4085
VARIABLE: (CF) = $0FF0 = 4080


CREATE: Las palabras recién definidas con CREATE solo tienen Cabecera (Header). El tamaño del PF es 0 en este caso. Una vez creada, se le puede asignar al PF espacio y/o contenido con las palabras al uso C, y/o , y/o ALLOT. El Ace Forth "no entiende" el PF de una palabra tipo CREATE, por lo que no se puede usar ni LIST ni EDIT con ellas.

Cuando se ejecuta una palabra tipo CREATE lo único que hace es dejar en la pila su PFA.

CREATE: (CF) = $0FEC = 4076

COLON: Es el tipo de palabra básico del Ace Forth. El Parameter Field de una palabra tipo COLON (las que empiezan con ":") es una sucesión de "Compiled Words" CW o "Palabras Compiladas"

COLON: (CF) = $0EC3 = 3779

Una CW es el CFA de la palabra que representa seguido (opcionalmente) de uno o más bytes donde se almacenan datos. A este Campo para datos se les llama el "Operand Field" OF o "Campo de Datos"

CW = PFA+OF

.
El gráfico de la estructura del PF que puse al principio de este hilo y que saqué de la cuenta Twitter del JA Archive tiene muchos errores, por lo que usaremos otro que he hecho con mis "escasos" medios.

PF Esquema.jpg
PF Esquema.jpg (59.56 KiB) Visto 240 veces


Todos los números del esquema (excepto el 265 de la definición de TEST) están en Hexadecimal.
265 = $109 (un $ delante de un número indica que está en hexadecimal)

Vemos que en algunos casos uso CA en vez de CFA. CA es la Compilation Address o Dirección de Compilación y es lo mismo que un CFA pero yo lo uso en casos especiales:

El CFA lo uso cuando es el de la Cabecera (Header). Pero hay palabras (que ya veremos más adelante) que tienen dos CFAs porque en realidad, constan de dos palabras que comparten Cabecera. Cuando se compilan en una definición colocan el CFA de la segunda "palabra". En estos caso uso CA en vez de CFA

Recordemos que FIND pone en la pila el CFA del CF de la Cabecera de la palabra que le sigue:

Así, por ejemplo, si haces:

FIND LITERAL .

Imprime en pantalla el valor del CFA de LITERAL: 4012 = $1006 que como vemos NO coincide con el valor compilado en la definición de TEST que es $1011. Ya veremos luego que este valor es el CFA de la parte Runtime de LITERAL. Por eso uso CA en vez de CFA
El Runtime de LITERAL cuando se ejecuta, pone en la pila el número entero almacenado en su OF.

Si hacemos lo mismo con DUP:

FIND DUP .

Imprime en pantalla el valor del CFA de DUP: 2155 = $86B que coincide con el valor compilado. Por eso uso CFA

En el esquema, el conjunto formado por los 4 primeros bytes es el CW de LITERAL aplicado al 265: CA = CFA de la parte Runtime de LITERAL y 265 es el OF
Los demás CW son todos de 2 bytes, pues ninguno tiene un OF (Operand Field)

Elurdio
Mensajes: 410
Registrado: 07 Dic 2021 21:33
Ubicación: Barcelona
Agradecido : 90 veces
Agradecimiento recibido: 84 veces

Re: Jupiter Ace Forth (Estructura Palabras)

Mensajepor Elurdio » 04 Ago 2022 13:19

Estructura de las Palabras (IV)

Un dato a tener en cuenta es que el diccionario del Jupiter Ace sin ninguna palabra de usuario creada aún llega hasta la dirección de memoria 15440 ($3C50) que contiene el último byte de la palabra FORTH.

Luego podemos afirmar que cualquier CFA (o CA) menor que ese valor corresponde a una palabra Primitiva de Forth y cualquiera mayor a una palabra de Usuario.

Estructura de las palabras tipo DEFINER(I)

Este es quizás el tipo de palabra más complejo del Ace Forth. Repasemos primero su funcionamiento. Usaremos 2CONSTANT como ejemplo:
(Pongo la definición, pero lo que importa ahora es la idea, ya explicaré luego su funcionamiento interno detallado, tanto de 2CONSTANT como de 2@)

DEFINER 2CONSTANT
SWAP , ,
DOES>
2@
;

CONSTANT almacena un número entero y cuando se ejecuta nos lo pone en la pila.
2CONSTANT almacena dos números enteros y cuando se ejecuta nos los pone en la pila. El orden en que lo hace es:
  • Primero almacena el que está segundo en la pila
  • Luego almacena el que está primero en la pila
La palabra 2@ toma los números que se almacenaron y los devuelve a la pila. Es un definición COLON:

: 2@
DUP @ SWAP 2+ @
;

Si hacemos:

50 34 2CONSTANT SALDO

creamos la palabra SALDO que es una palabra tipo 2CONSTANT, por lo que almacenó dos números de la pila (50 y 34) cuando la creamos y cuando la ejecutemos nos devolverá los dos números a la pila.

Así vemos que 2CONSTANT (una palabra definida con DEFINER) es un generador (definidor) de un nuevo tipo de palabras, las palabras tipo 2CONSTANT.

Podemos generar otra más:

12 17 2CONSTANT HABER

etc.

Las palabras SALDO y HABER son ambas tipo 2CONSTANT.

Luego DEFINER nos permite crear nuevos tipos de palabras. Con DEFINER creamos la palabra que usaremos para definir palabras de su tipo.

DEFINER -> 2CONSTANT -> Palabras tipo 2CONSTANT (SALDO, HABER, ...)
DEFINER -> CARGADOR -> Palabras tipo CARGADOR (...)
etc.

Hay autores que ven en DEFINER el germen de lo que luego serían las CLASES en programación orientada a objetos (con DEFINER creo la CLASE 2CONSTANT con la que puedo crear los objetos SALDO, HABER, etc.)

Elurdio
Mensajes: 410
Registrado: 07 Dic 2021 21:33
Ubicación: Barcelona
Agradecido : 90 veces
Agradecimiento recibido: 84 veces

Re: Jupiter Ace Forth (Estructura Palabras)

Mensajepor Elurdio » 04 Ago 2022 16:16

Estructura de las Palabras (V)

Conitnuamos con DEFINER

Estructura de las palabras tipo DEFINER(II)

A las palabras creadas con DEFINER se les llama Palabras Definidoras de Usuario, como por ejemplo 2CONSTANT

Gracias a DEFINER podemos extender nuestra lista de 6 palabras definidoras (CONSTANT, VARIABLE, CREATE, etc.) con innumerables tipos más.

Seguimos con el ejemplo de 2CONSTANT:

Cuando definimos 2CONSTANT con DEFINER

DEFINER 2CONSTANT
SWAP , ,
DOES>
2@
;

Vemos que hay dos partes:
  • Lo que va entre el nombre y DOES>
  • Lo que va entre DOES> y el ;

Podemos considerar cada parte como una definición tipo COLON independientes entre sí. Dos palabras con una sola Cabecera. Llamaremos a la primera (antes de DOES>) la parte Definidora y a la segunda la parte Runtime

Cuando definimos una nueva palabra con una palabra Definidora de Usuario (una tipo DEFINER), lo primero que hace la tipo DEFINER es crear la Cabecera (Header) de la nueva palabra. Siguiendo con nuestro ejemplo:

50 34 2CONSTANT SALDO

2CONSTANT crea la Cabecera (Header) de SALDO como haría CREATE. El Parameter Field PF de SALDO lo creará la parte Definidora de 2CONSTANT

SWAP , ,

SWAP pone el 54 en el top de la pila y , (coma) lo compila el primero del PF. Queda el 34 que la segunda , (coma) lo compila a continuación del 54. Así el PF de SALDO son los dos número 54 y 34 almacenados en 4 bytes (2 bytes cada uno)

Ya tenemos SALDO. Si lo ejecutamos, SALDO, lo primero que hace es dejar en la pila su PFA (esto lo hace cualquier palabra creada con una palabra Definidora de Usuario). A continuación ejecuta el código que hay en la parte Runtime de 2CONSTANT:

2@

A su vez 2@ ejecuta su PF

DUP @ SWAP 2+ @

Tenemos en la pila el PFA de SALDO:

DUP lo duplica.
@ recupera su contenido (54) y lo pone en la pila.
SWAP coloca el PFA en el top de la pila.
2+ le suma 2 con lo que ahora apunta al tercer byte de los 4 que tiene el PF de SALDO.
@ recupera su contenido (34) y lo coloca en la pila.

Con lo que la pila queda { 54 34 }

Resumiendo:

Con DEFINER creamos palabras Definidoras de Usuario. Son nuevos tipos de palabras.
Con las palabras Definidoras de Usuario creamos palabras cuyo PF lo construye la parte Definidora de la palabra Definidora de Usuario
Cuando ejecutamos una palabra creada con una palabra Definidora de Usuario, primero deja su PFA en la pila y se ejecuta la parte Runtime de la palabra Definidora de Usuario con la que se creó.

DEFINER Nombre
parte Definidora
DOES>
parte Runtime
;

Elurdio
Mensajes: 410
Registrado: 07 Dic 2021 21:33
Ubicación: Barcelona
Agradecido : 90 veces
Agradecimiento recibido: 84 veces

Re: Jupiter Ace Forth (Estructura Palabras)

Mensajepor Elurdio » 04 Ago 2022 23:15

Estructura de las Palabras (VI)

Vamos ahora con la estructura de las palabras tipo DEFINER y las palabras definidas con ellas.

Estructura de las palabras tipo DEFINER(III)

Cuando creamos una palabra Definidora de Usuario con DEFINER:
  1. Se crea una Cabecera con el nombre suministrado
  2. DEFINER: (CF) = $1085 = 4229
  3. Al principio del PF se compila una dirección o Address (2 bytes) que apunta al primer byte después del CA de DOES>
  4. Se compilan los CW de las palabras que componen la parte Definidora
  5. Se compila el CA de DOES> (*)
  6. Se compila un número entero negativo al que llamo SHIFT (2 bytes) que sumado a la dirección (Address) que se compiló al principio del PF (punto 3) nos da la dirección de memoria del primer byte justo antes del NFA de la palabra (1 byte antes del inicio del nombre).
  7. Se compila la instrucción en código máquina: CALL $0FF0. Son tres bytes: $CD $F0 $0F
  8. Se compilan los CW de las palabras que componen la parte Runtime
  9. Se compila el CA de ; (**)
(*) Pongo CA de DOES> porque DOES> es una palabra tipo COMPILER (aunque con su propia estructura al ser una primitiva del Ace Forth). En este punto se compila el segundo CFA (el de su parte Runtime) de ahí que uso CA y no PFA. Ya lo veremos en detalle cuando estudiemos las tipo COMPILER
(**) De modo similar a DOES>, la palabra ; es una palabra tipo COMPILER... etc. De ahí que usemos CA en vez de PFA.

La estructura de las palabras creadas con una Definidora de Usuario es bastante sencilla:

  • El contenido de su CF es la dirección de memoria dónde empieza la instrucción en código máquina CALL $0FF0 en el PF de Definidora de Usuario que la creó (punto 7)
  • Su PF tiene la estructura que le dé la parte Definidora de la Definidora de Usuario que la creó

Sigamos con nuestro ejemplo:

DEFINER 2CONSTANT
SWAP , ,
DOES>
2@
;

Ahora creamos la palabra DATO con nuestra palabra Definidora de Usuario 2CONSTANT.
12 9 2CONSTANT DATO

Pues bien, todo lo dicho anteriormente se recoge a continuación en un esquema para nuestro ejemplo:
DEFINER -> 2CONSTANT -> DATO

Esquema Definer 4.jpg
Esquema Definer 4.jpg (99.63 KiB) Visto 61 veces


NOTAS del Esquema:

  • Todos los números están en Hexadecimal.
  • Cada casilla del esquema del PF son 2 bytes a excepción de la casilla con el CALL $0FF0 que ocupa 3 bytes.
  • No está el valor de Address pues depende de la posición que ocupe en el diccionario la palabra 2CONSTANT
    Tampoco he puesto el valor del CFA de 2@ porque también depende de su posición en el diccionario.
  • En cambio, el valor de SHIFT solo depende de la definición de 2CONSTANT por lo que es independiente de la posición que ocupe 2CONSTANT en el diccionario.
  • SHIFT = $FFE5 = -27

Elurdio
Mensajes: 410
Registrado: 07 Dic 2021 21:33
Ubicación: Barcelona
Agradecido : 90 veces
Agradecimiento recibido: 84 veces

Re: Jupiter Ace Forth (Estructura Palabras)

Mensajepor Elurdio » 05 Ago 2022 11:57

Estructura de las Palabras (VII)
Estructura de las palabras tipo DEFINER(IV)


Que el valor de SHIFT es -27 en 2CONSTANT es fácil de ver mirando el esquema gráfico:

El valor absoluto de SHIFT es el número de bytes que hay que restar a la dirección de su primer byte (que es precisamente Address(azul)) para obtener la dirección del primer byte antes del inicio de la cabecera de 2CONSTANT

Contemos:
En el PF de 2CONSTANT, antes de la dirección Address(azul) hay 5 casillas de 2 bytes cada una -> 5*2=10 bytes.
La Cabecera son 7 bytes de los 4 campos de tamaño fijo + 9 bytes del campo del nombre = 16 bytes.
Nos da un total 26 bytes hasta el primer carácter del nombre. Sumamos otro byte pues queremos que apunte un byte antes -> 27 bytes.

Una aplicación útil de conocer estas estructuras es, entre otras, ésta:

A partir del CFA de DATO ¿Cómo saber el CFA de la palabra Definidora de Usuario que la creó?

Vamos a verlo con 2CONSTANT->DATO como ejemplo, pero el método es de aplicación general.

  • Por el esquema vemos que la dirección de memoria almacenada en el CFA de DATO = (CFA) apunta al primer byte de la instrucción en código máquina CALL $0FF0
  • Si a esta dirección le restamos 2 obtenemos el valor de Address(azul):
    Address(azul) = (CFA) - 2
  • El contenido de Address(azul) es SHIFT:
    SHIFT = ( Address(azul) ) = ( (CFA) - 2 )
  • El esquema nos muestra que:
    Address(azul) + SHIFT + 1 = NFA = (CFA) - 2 + ( (CFA) - 2 ) + 1 =

O sea, conociendo el CFA de DATO vemos que el NFA (la dirección que apunta el inicio del Header de 2CONSTANT) es:
(CFA) - 2 + ( (CFA) - 2 ) + 1 

Que en Ace Forth se calcularía así:
CFA @ 2- DUP @ + 1+

Una vez tenemos el NFA sabiendo que el último carácter del nombre tiene 128 sumado, lo buscamos y sabemos que, por la estructura de la Cabecera de una palabra, el CFA de la definidora señala 6 bytes más adelante.

Este resultado es general, pues aunque hemos usado el ejemplo del esquema, todo lo dicho es independiente de la palabra en cuestión.

Otro cáculo útil: CFA -> Runtime

A partir del CFA de una palabra definidora de usuario podemos obtener fácilmente el valor del CFA de su Runtime (su CA)
CFA 2+ @ = CA

Elurdio
Mensajes: 410
Registrado: 07 Dic 2021 21:33
Ubicación: Barcelona
Agradecido : 90 veces
Agradecimiento recibido: 84 veces

Re: Jupiter Ace Forth (Estructura Palabras)

Mensajepor Elurdio » 05 Ago 2022 16:41

Estructura de las Palabras (VIII)
Estructura de las palabras tipo COMPILER(I)


Aunque a primera vista las palabras tipo COMPILER puedan parecer semejantes a las tipo DEFINER, son completamente diferentes. Eso sí, tienen ciertas similitudes estructurales.

Las palabras tipo COMPILER, al igual que las DEFINER, se componen de dos partes distintas. La que va entre el nombre y RUNS> y la que va entre éste y el ; (punto y coma) final.

n COMPILER Nombre
parte Compilante
RUNS>
parte Runtime
;

En el caso COMPILER la primera parte recibe el nombre de Compilante versus el caso DEFINER -> parte Definidora

La gran diferencia entre DEFINER y COMPILER :
  • DEFINER crea palabras se usarán para definir otras palabras.
  • COMPILER crea palabras que compilan información durante la compilación

Recordemos que durante la compilación de una definición, cada palabra que se encuentra tras el nombre se compila en el PF. Pero si la palabra que se encuentra es tipo COMPILER se ejecutará (pues es inmediata) lo que le permite compilar/hacer "cosas" durante la compilación.

En cambio, si creamos una palabra que, entre otras, contiene una palabra tipo DEFINER, cuando la entremos la tipo DEFINER se compilará como cualquier otra.

Veámoslo más claro con unos ejemplos genéricos:

Supongamos que tengo la palabra SOYCOMPI del tipo COMPILER y la palbra SOYDEFI del tipo DEFINER.

Si ahora defino la palabra TEST tipo COLON así:

: TEST DUP SOYDEFI + SOYCOMPI SWAP ;


El proceso sería:

  1. Se crea la cabecera de TEST
  2. Se compila DUP
  3. Se compila SOYDEFI
  4. Se compila +
  5. Se ejecuta SOYCOMPI
    • Primero compila el CFA de su Runtime
    • Luego se ejecuta su parte Compilante con lo que puede hacer de todo en medio de la compilación de TEST. Normalmente crea espacio para datos (compilar un OF) que necesitará cuando se ejecute su Runtime así como también hacer cálculos, etc.
  6. Se compila SWAP
  7. Se termina la compilación del PF de TEST

Queda patente en el ejemplo la gran diferencia entre SOYDEFI y SOYCOMPI

Elurdio
Mensajes: 410
Registrado: 07 Dic 2021 21:33
Ubicación: Barcelona
Agradecido : 90 veces
Agradecimiento recibido: 84 veces

Re: Jupiter Ace Forth (Estructura Palabras)

Mensajepor Elurdio » 05 Ago 2022 22:31

Estructura de las Palabras (IX)
Estructura de las palabras tipo COMPILER(II)


La característica principal de las palabras definidas con COMPILER es que son inmediatas. Y cuando se ejecutan estando el Ace Forth en modo Compilación, lo primero que hacen es compilar el CFA de su parte Runtime y a continuación ejecutan su parte Compilante. Esta parte Compilante normalmente añade un Operand Field OF a continuación del CFA del Runtime, aunque no necesariamente.

O sea, de modo parecido a lo que dijimos con DEFINER, las palabras tipo COMPILER se componen de una cabecera y dos palabras tipo COLON a las que hemos llamado parte Compilante la primera y parte Runtime la segunda.

El conjunto Cabecera + parte Compilante equivale a una palabra tipo COLON Inmediata. Su CFA es el que lleva la cabecera.

La parte Runtime equivale a otra palabra, y su cabecera solo tiene un Code Field que apunta a la rutina que se encarga de ejecutar el Runtime. Obviamente el CFA del CF del Runtime es diferente del de la Cabecera, pues ocupa una posición de memoria diferente.

Así tenemos que las palabras tipo COMPILER tienen una Cabecera y dos palabras cada una con sus propios CFA.

Yo, como notación en mis esquemas-dibujo, cuando se compila el CFA que se corresponde con el de la Cabecera pongo que compila su CFA y cuando compila el otro, pongo que compila su CA o Compilation Address para diferenciarlos.

Ace Forth tiene muchas primitivas que son palabras Compilantes, al estilo de las tipo COMPILER pero con una estructura propia. Eso sí, al igual que las COMPILER tienen dos CFAs diferentes: El de la parte Compilante que coincide con el CFA de la Cabecera y el de la parte Runtime que es diferente. Por tanto uso CA en los esquemas cuando compilan el CFA del Runtime. Son palabras tales como:

 DOES> RUNS> ; IF ELSE THEN BEGIN UNTIL ... etc.

Volviendo a las tipo COMPILER, cuando se ejecuta la parte Runtime antes que nada, deja en la pila la dirección del Operand Field OF que compiló la parte Compilante a continuación del CA del Runtime. Esta dirección la deja incluso si NO se compiló ningún OF, pues en este caso considera que sí lo compiló pero que consta de cero bytes.

Cuando se define una palabra tipo COMPILER espera en la pila un número con el tamaño del OF que va a crear. Si el tamaño no se conoce de antemano, entonces se pone un menos uno como tamaño y es la parte Compilante la que tiene que colocarlo como un entero de 2 bytes al principio de OF (estos 2 bytes no se cuentan al calcular el tamaño del OF)

Para ver la estructura de las palabras tipo COMPILER usaremos como ejemplo la palabra 2LITERAL que toma los dos primeros números de la pila y los compila en el diccionario como su OF. Cuando se ejecuta 2LITERAL repone en la pila los dos números que compiló en su OF durante la parte compilante.

4 COMPILER 2LITERAL
SWAP , ,
RUNS>
2@
;

Vemos que las partes Compilante y Runtime de 2LITERAL son idénticas a las Definidora y Runtime de 2CONSTANT.

Esto se debe a que 2LITERAL hace lo mismo que hacía 2CONSTANT. La diferencia radica en que 2CONSTANT creaba un nuevo tipo de palabra con la que creábamos otras palabra que compilan en sus propios PFs los números que le damos. Mientras que 2LITERAL los compila dentro del PF de la palabra que se está definiendo.

Luego usaremos 2LITERAL en la definición de TEST y veremos ambas estructuras.
: TEST [ 23 18 ] 2LITERAL + ;


Volver a “Jupiter Ace”

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 1 invitado