Palabras para ampliar Ace Forth
Descripción del contenido de la página
Palabras para ampliar el lenguaje Ace Forth de la computadora Jupiter Ace.
Mi artículo Palabras para ampliar Abersoft Forth no podía quedar sin esta continuación sobre Ace Forth. Ace Forth es la versión de Forth de la Jupiter Ace, una pequeña pero extraordinaria computadora de 1982 que no tuvo demasiada suerte en su tiempo. El motivo principal por el que es una máquina especial es que lleva incorporado el lenguaje de programación Forth, en lugar del omnipresente BASIC.
Ace Forth tiene algunas características muy interesantes, diseñadas para adaptar el sistema a una computadora que no podía guardar los códigos fuente de los programas en memoria. Pero las limitaciones de memoria (menos de 1 KiB de memoria útil en la versión base de 3 KiB) hicieron que no pudieran ir incluidas de serie en Ace Forth algunas palabras interesantes.
El estupendo manual de la Jupiter Ace (el mejor manual de computadora que jamás he leído, escrito por Steven Vickers, el autor de la máquina, quien fuera autor también del manual de la ZX Spectrum) incluye definiciones de palabras útiles para ampliar las capacidades de la Ace y facilitar la escritura de programas.
En esta página iré recopilando definiciones que no estén en el manual, algunas escritas por mí y otras encontradas en diversas fuentes.
Compilación
compile
y [compile]
Estas dos palabras son clásicas, y habituales en todos los sistemas Forth anteriores al estándar ANS Forth de 1994 (que las mantuvo por compatibilidad pero las sustituyó por postpone
). Sin embargo no están presentes en Ace Forth.
Encontré una posible definición de compile
y [compile]
en el foro de Jupiter Ace Resource Site:
: compile ( -- ) begin find dup dup 0= if drop retype then until , ;
: [compile] ( <word > -- ) compile ; immediate
state
Ace Forth carece de la variable state
, cuyo contenido indica si el sistema se haya en modo de compilación o de interpretación.
Sin embargo la variable del sistema llamada FLAGS indica eso mismo con su sexto bitio. Su dirección en el mapa de memoria de la Jupiter Ace es 15422 en decimal y 3C3E en hexadecimal. Esto me permitió definir las siguientes palabras, que proporcionan la misma funcionalidad de state
:
15422 constant FLAGS
: compiling? FLAGS c@ 64 and ;
: interpreting? compiling? 0= ;
Cadenas de texto
Una palabra importante de la que carece Ace Forth es s"
, que compila una cadena de texto en la definición de una palabra; en tiempo de ejecución la devuelve, según el sistema Forth de que se trate, bien con su dirección de inicio y su longitud, bien como una cadena contada, esto es, con la dirección de su longitud.
Afortunadamente la palabra compiler
permite crearla. Aunque el manual no da ejemplos, compiler
permite crear palabras con zonas de datos de longitud variable cuando recibe -1 en lugar de una longitud concreta. Reproduzco a continuación el código original de s"
publicado en el foro de Jupiter Ace Resource Site, con un formateo más claro y los comentarios traducidos:
-1 compiler s"
ascii " word count
dup 1+ , ( guarda el tamaño del campo de parámetros )
dup c, ( guarda la longitud de la cadena )
0 do
dup i + c@ c, ( guarda los caracteres de la cadena )
loop
drop
runs>
2+ ( dirección de la longitud de la cadena )
;
A primeros de marzo de 2009 me puse a trabajar en una versión de la palabra evaluate
para Ace Forth, pero antes necesitaba una versión mejorada de s"
, con un funcionamiento igual al que tiene en ANS Forth: que devuelva la cadena como su dirección y su longitud, y que funcione tanto en modo de compilación como de interpretación.
Tras un rato de trabajo y varios intentos, lo conseguí. Incluso aproveché para escribir también c"
, que hace lo mismo pero devuelve cadenas contadas. A continuación muestro el código, con todas las palabras necesarias para su compilación:
: ( ascii ) word drop ; immediate
: \ 0 word drop ; immediate
15422 constant FLAGS
: compiling? FLAGS c@ 64 and ;
: count ( a1 -- a2 u ) dup 1+ swap c@ ;
: bounds ( a1 u -- a2 a3 ) over + swap ;
: cmove ( a0 a1 u -- ) bounds do dup c@ i c! 1+ loop drop ;
: compile ( -- ) begin find dup dup 0= if drop retype then until , ;
: [compile] ( <word > -- ) compile ; immediate
: (") ( <string"> -- )
ascii " word count
dup 1+ , \ store the size of the parameter field
dup c, \ store the string length
bounds do i c@ c, loop \ store the chars
;
-1 compiler [c"] ( <string"> -- )
(")
runs> ( -- a )
2+
;
-1 compiler [s"] ( <string"> -- )
(")
runs> ( -- a u )
2+ count
;
: (c") ( <string"> -- a )
ascii " word dup c@ 1+
pad swap cmove pad
;
: (s") ( <string"> -- a u )
(c") count
;
: c" ( <string"> -- a )
compiling? if [compile] [c"] else (c") then
; immediate
: s" ( <string"> -- a u )
compiling? if [compile] [s"] else (s") then
; immediate
Publiqué mi propuesta para C"
y S"
en el foro de la Jupiter Ace.
Comentarios
Paréntesis
Ace Forth usa el paréntesis para marcar los comentarios, como es la costumbre de Forth, pero con dos peculiaridades: en modo de interpretación no lo acepta; y en modo de compilación guarda el comentario en el diccionario.
Este peculiar comportamiento se debe a que el código fuente no se conserva, sino que lo que se guarda en cinta de casete es el diccionario compilado, pero las palabras compiladas pueden editarse con edit
(que las descompila en el momento), incluidos los comentarios.
Sin embargo, cuando me propuse escribir algún programa para la Jupiter Ace con un editor externo para después «alimentar» con el fichero de texto la entrada de una versión modificada por mí del emulador xAce, necesitaba añadir comentarios al código fuera de la definición de las palabras, es decir, en modo de interpretación.
Lo primero que se me ocurrió fue esto (para lo que necesitaba la definición de [compile]
y de interpreting?
mencionadas anteriormente), pero no funcionó como yo esperaba:
: (() ascii ) word drop ;
: ( interpreting? if ()) else [compile] ( then ; immediate
La nueva palabra (
funcionará ahora en modo de interpretación, pero no en modo de compilación: en lugar de ejecutar (
, la compilará. En teoría debería funcionar.
Decidí simplificar. Bastaba redefinir (
por completo y olvidar su definición original, pues en todo caso no necesitaba guardar los comentarios en el diccionario:
: ( ascii ) word drop ; immediate
Ahora sí funciona bien en ambos modos: descarta el comentario. Sin embargo sigue teniendo un fallo: sólo busca el paréntesis de cierre en la línea actual de entrada. Si no lo encuentra, hará lo mismo que si lo hubiera encontrado. Esto no es un grave inconveniente, pero impide escribir comentarios de varias líneas.
Para permitir comentarios de varias líneas escribí la definición así:
: ( begin ascii ) word c@ 31 = while retype repeat ; immediate
Efectivamente, ahora el sistema aceptaba comentarios de varias líneas, tanto en modo de interpretación como de compilación.
Barra invertida
La mayoría de los sistemas Forth incluyen la palabra \
para incluir comentarios de final de línea. Esta es mi definición para Ace Forth:
: \ 0 word drop ; immediate
Gráficos
Leer un carácter escrito en la pantalla
Abersoft Forth dispone de la palabra SCREEN
para leer el código de un carácter que ha sido escrito en la pantalla. Es el equivalente de la instrucción homónima de Sinclair BASIC.
La organización de la pantalla de la Jupiter Ace es mucho más sencilla que la de la ZX Spectrum: Mientras ésta guarda en la memoria de pantalla, para cada carácter mostrado, los ocho octetos que constituyen su gráfico, aquélla sólo guarda el código del carácter. Gracias a ello definir la palabra screen
en Ace Forth es muy sencillo: Sólo hace falta la dirección inicial de la memoria de pantalla y añadirle lo que corresponda en función de las coordenadas:
: screen ( y x -- c ) swap 32 * + 8192 + c@ ;
O bien, un poco más rápido pero con un orden de parámetros diferente al habitual en ZX Spectrum:
: screen ( x y -- c ) 32 * + 8192 * c@ ;