Apuntes sobre Beta BASIC 4.0+D
Descripción del contenido de la página
Relación de características destacadas, limitaciones, fallos y trucos de Beta BASIC 4.0+D (para ZX Spectrum 128 con interfaz +D).
La versión 4.0+D del lenguaje es una variante de la versión 4.0, específica para la interfaz de disco Plus D (o su antecesora DISCiPLE); había variantes de la versión 4.0 para varias unidades de disco. A su vez, la versión 4.0 del lenguaje es la adaptación de la versión 3.0 para aprovechar las ventajas de la ZX Spectrum 128 respecto al modelo anterior: disco RAM y chip de sonido.
Toda la documentación de la versión 3.0 es válida para la 4.0 salvo casos excepcionales. De hecho la documentación de la versión 4.0 solo se ocupa de los comandos y funciones nuevos o ampliados, y remite al manual de la 3.0 para el resto.
Características destacadas
Las mejoras que Beta BASIC 4.0+D ofrece sobre Sinclair BASIC son muchas y muy importantes. No es un conjunto de extensiones para el lenguaje original de la ZX Spectrum, como ha habido varios, sino un BASIC nuevo que por restricciones de espacio utiliza parte de las rutinas de la ROM.
Listo a continuación, divididas en secciones, algunas de las características que me parecen más destacadas.
Programación estructurada
- Procedimientos (
DEF PROC
yEND PROC
) con variables locales (LOCAL
). Los parámetros pueden pasarse opcionalmente por referencia (REF
) y pueden omitirse si se les especifican valores predeterminados (DEFAULT
); también pueden ser una lista de longitud variable (DATA
eITEM()
). - Estructura
ELSE
para los condicionales. - Estructura para bucles (
DO
yLOOP
), con dos tipos de condición de terminación (WHILE
yUNTIL
) que pueden estar tanto al inicio como al final de la estructura (¡o en ambos lugares o en ninguno!), y con posibles salidas interiores (EXIT IF
). - Estructura
ON
para ejecutar comandos o hacer saltos en función de un valor.
Edición de programas
- Edición directa de líneas escribiendo su número precedido de un cero.
- Editor de línea mejorado (quizá más eficaz incluso que el editor de pantalla completa de la ZX Spectrum 128).
- Herramientas de edición: búsqueda de textos, procedimientos y variables (
REF
yLIST REF
). - Listado alfabético de variables numéricas, de cadena o ambas, con sus valores (
LIST VAL
,LIST VAL$
yLIST DATA
); también por impresora, conLLIST
. - Listado de procedimientos individuales (
LIST PROC
yLLIST PROC
). - Sustitución de textos y valores (
ALTER
). - Partición (
<>
) y unión (JOIN
) de líneas. - Comando
RENUM
para renumerar números de línea, con todas las opciones; permite hacer copias de bloques (conRENUM*
). - Comando
DELETE
para borrar zonas del programa. - Atajos de teclado (
DEF KEY
) asignables a cualquier texto, incluidos comandos del lenguaje.
Velocidad
- Mayor velocidad de ejecución gracias a que el sistema usa direcciones de memoria para el control de flujo en lugar de números de línea.
- Mayor velocidad de algunas funciones ya existentes o alternativas (gráficas, trigonométricas, aleatorias...)
Datos
- Comando
SORT
para ordenar matrices o cadenas de texto. - Creación y manipulación de matrices directamente en el disco RAM.
- Comando
SORT!
para ordenar matrices directamente el disco RAM. - Formato compacto de datos opcional en líneas
DATA
(conLINE
). - Función
ITEM()
para conocer anticipadamente el tipo del próximo dato disponible en líneasDATA
. - Funciones
CHAR$()
,NUMBER()
yFP$()
para convertir números en cadenas y viceversa. - Funciones
DEC()
yHEX$()
para convertir números de base hexadecimal a decimal y viceversa; funciónBIN$
para convertir números decimales en binarios. - Comandos para mover (
JOIN
) o copiar (COPY
) partes de una cadena de texto en otra, o elementos de una matriz en otra. - Comando
DELETE
para eliminar partes de una cadena de texto o elementos de una matriz. - Función
INSTRING()
para hacer búsquedas dentro de una cadena de texto. - Función
INARRAY()
para hacer búsquedas dentro de una matriz. - Función
LENGTH()
para conocer el tamaño de una matriz; o la dirección de una matriz, o de una cadena de texto. - Función
MEMORY$()
para manipular cualquier zona de la memoria como una cadena de texto. - Función
SHIFT$()
para hacer cambios de formato en cadenas de texto. - Función
USING$()
y modo de impresiónUSING
para formatear números.
Gráficos
- Comando
GET
para tomar cualquier zona de la pantalla como un gráfico reutilizable, con o sin información de color. - Comando
PLOT
extendido para situar textos y gráficos de cualquier tamaño en coordenadas de pixeles. - Comandos
ROLL
ySCROLL
para mover zonas de pantalla. - Comando
WINDOW
para definir ventanas. - Comando
CSIZE
para usar diferentes tamaños de letra. - Comando
FILL
para rellenar zonas, con colores o gráficos; funciónFILLED()
para conocer el número de puntos de la zona rellenada. - El origen de las coordenadas gráficas es configurable (con las variables
xos
yyos
). - Comando
OVER
ampliado con el modo 2 (equivalente a realizar unOR
con los pixeles).
Otras mejoras
- Control de errores (
ON ERROR
). - Depuración de programas (
TRACE
). - Asignación de varias variables con un solo
LET
, más rápido y económico. - Comando
KEYIN
para ejecutar comandos en cadenas de texto o incluso reescribir el programa desde dentro. - 29 nuevas funciones muy útiles.
Funciones
Beta BASIC ofrece la posibilidad de definir procedimientos, pero no funciones propiamente dichas. Es una de sus limitaciones.
El programador tiene dos opciones:
- Crear funciones con el mismo y limitado comando
DEF FN
de Sinclair BASIC, funciones que sólo permiten cálculos de una línea y cuyo nombre sólo puede constar de una letra. - Crear seudo-funciones con procedimientos que devuelvan el cálculo en una variable global o en un parámetro pasado por referencia.
Esto no es todo. Beta BASIC usa 29 de las 52 funciones disponibles en Sinclair BASIC para definir sus propias funciones con nombres largos nuevos, de forma casi trasparente. ¿Cómo lo hace? Por una parte, las definiciones de estas funciones (con el citado comando DEF FN
) están escondidas en la línea 0 del programa (que el editor mantiene invisible) y contienen, camufladas, las llamadas al código máquina correspondiente en cada caso; por otra parte, el editor reconoce estas funciones tanto con su nuevo nombre largo como con su nombre original corto (en este caso las funciones numéricas son reconocidas al teclear el paréntesis de apertura; las funciones de cadena son reconocidas al teclear el símbolo del dólar). En los listados en pantalla o impresora, así como en la línea de edición, siempre se mostrará el nombre largo.
La siguiente tabla muestra una fila por cada una de las funciones que el programador puede definir en Sinclair BASIC. Las que ya están definidas por Beta BASIC 4.0 (29, dos más que en Beta BASIC 3.0) muestran sus parámetros y, en la segunda celda, el nombre largo alternativo; las restantes (23) están disponibles para el programador.
Nombre original | Nombre largo |
---|---|
FN A$() | |
FN A(N,N) |
AND(N,N) |
FN B$(N) |
BIN$(N) |
FN B() | |
FN C$(N) |
CHAR$(N) |
FN C(N) |
COSE(N) |
FN D$() | |
FN D(T$) |
DEC(T$) |
FN E$() | |
FN E(N) |
EOF(N) |
FN F$(N,N) |
FP$(N,N) |
FN F() |
FILLED() |
FN G$() | |
FN G() | |
FN H$(N) |
HEX$(N) |
FN H() | |
FN I$() | |
FN I(N,T$,T$) |
INSTRING(N,T$,T$) |
FN J$() | |
FN J() | |
FN K$(N,N) |
SCRN$(N,N) |
FN K() | |
FN L$() | |
FN L(N,N$) |
LENGTH(N,N$) |
FN M$() |
MEMORY$() |
FN M() |
MEM() |
FN N$() | |
FN N(T$) |
NUMBER(T$) |
FN O$() | |
FN O(N,N) |
OR(N,N) |
FN P$() | |
FN P(N) |
DPEEK(N) |
FN Q$() | |
FN Q() | |
FN R$() | |
FN R(N) |
RNDM(N) |
FN T$(N,T$) |
STRING$(N,T$) |
FN S(N) |
SINE(N) |
FN T$() |
TIME$() |
FN T() |
ITEM() |
FN U$(T$,N) |
USING$(T$,N) |
FN U(M$,T$) |
INM(M$,T$) |
FN V$() | |
FN V(N,N) |
MOD(N,N) |
FN W$() | |
FN W() | |
FN X$() |
MDP$() |
FN X(N,N) |
XOR(N,N) |
FN Y$() |
CAT$() |
FN Y() | |
FN Z$(N,T$) |
SHIFT$(N,T$) |
FN Z() |
Parámetros utilizados:
- N: número.
- T$: cadena de texto.
- N$: cadena de texto con el nombre de una matriz de cualquier tipo.
- M$: matriz de cadenas de texto.
Limitaciones
Algunas de las limitaciones de Beta BASIC 4.0 son lamentables porque el desarrollo de programas sería mucho más fácil sin ellas; otras limitaciones son de poca importancia. Pero en conjunto todas las limitaciones están compensadas más que sobradamente por las muchas e importantes ventajas del lenguaje.
- No permite nombres largos de variables de cadena ni de matrices; la conservación de esta incómoda limitación original de Sinclair BASIC la justificó Andy Wright, el autor de Beta BASIC, por la complejidad que habría supuesto reescribir las partes de la ROM involucradas y la consiguiente reducción de la memoria disponible para los programas.
- No permite definir funciones de forma análoga a los procedimientos. El programador debe usar el limitado sistema de definición de funciones original de Sinclair BASIC, o bien procedimientos que devuelvan los cálculos en variables globales o en parámetros pasados por referencia.
- No permite usar las dos líneas inferiores de la pantalla como parte de las ventanas.
- No permite utilizar los nuevos comandos gráficos
SCROLL
yROLL
en las dos líneas inferiores de la pantalla. - Borra las dos líneas inferiores de la pantalla cuando es borrada alguna ventana.
- La estructura
IF
, a pesar de la nueva incorporación deELSE
, sigue limitada a una línea. Recuerdo que el autor, en algún número de Beta BASIC Newsletter, mencionó que el código deEND IF
está sin terminar en el programa. - Las referencias a elementos de matrices creadas en el disco RAM deben estar en la primera posición de las expresiones. Esta limitación es debida al evaluador de expresiones original de Sinclair BASIC.
- La longitud de línea en la impresión de listados (con
POKE 57500,n
, según indica la página 94 del manual de Beta BASIC 3.0) no funciona para valores mayores de 80 (equivalen a 80). Esto impide sacar listados en ficheros (desde un emulador) sin que se corten las líneas y haya que reconstruirlas después. - El comando
DELETE
no puede usarse para eliminar elementos de matrices en el disco RAM. Es una funcionalidad que el programador no contempló, pero si se intenta no se obtiene un mensaje de error sintáctico sino el bloqueo o reinicio del sistema. - No permite usar la función
LENGTH()
con matrices creadas en el disco RAM. - No permite ampliar (con
JOIN
oCOPY
) las matrices creadas en el disco RAM. - La sintaxis para las matrices locales no es homogénea: las matrices numéricas deben indicarse expresamente, con paréntesis (ejemplo:
LOCAL m()
), pero las variables y matrices de texto comparten la misma notación, que por tanto afecta a ambas (LOCAL a$
define como local tanto la variableA$
como la matrizA$
). - El nuevo comando
GET
no permite guardar los gráficos directamente en matrices en el disco RAM, lo que sería utilísimo para evitar usar variables intermedias. Si el programa es largo y el gráfico es grande, probablemente no haya memoria para hacer la operación. Por suerte, y paradójicamente, su compañeroPLOT
sí permite poner en pantalla gráficos guardados en matrices en el disco RAM, aunque copia todo su contenido a la zona de variables, lo que significa que el problema de la escasez de memoria sigue existiendo. - No permite ordenar matrices numéricas en el disco RAM. La alternativa es usar matrices textuales y guardar los números codificados como cadenas de texto con las funciones
CHAR$
,FP$
yUSING$
.
Fallos
Todo programa complejo tiene fallos. En los números del boletín Beta BASIC Newsletter el autor del lenguaje fue proponiendo soluciones para algunos fallos que los usuarios fueron describiendo. Este apartado mostrará los fallos que he descubierto yo y que no están mencionados en la citada documentación:
Comando DELETE
Una de los usos del comando DELETE
es borrar elementos de matrices, pero si lo usamos, análogamente a otros comandos, con la sintaxis para acceder a las matrices creadas en el disco RAM (DELETE!
), provocamos un cuelgue del sistema en lugar de un error sintáctico, que sería lo adecuado pues es una funcionalidad no implementada.
Función STRING$()
Cuando la función STRING$()
es anidada, muchas veces el resultado es diferente de lo esperado. Aún no he averiguado por qué no siempre ocurre.
Ejemplos:
PRINT STRING$(5,STRING$(2,"X"))
imprime 4 «X» en lugar de 10.PRINT STRING$(2,STRING$(5,"X"))
imprime 25 «X» en lugar de 10.LET A$=STRING$(5,"X"):PRINT STRING$(2,A$)
imprime correctamente 10 «X».LET A$=STRING$(2,"X"):PRINT STRING$(5,A$)
imprime correctamente 10 «X».
Para mostrar este fallo escribí el programa stringBug.
Comandos de G+DOS y Beta DOS tras ELSE
Los comandos de la unidad de disco no son aceptados tras la nueva palabra clase ELSE
; es necesario separarlos por medio del signo de dos puntos.
La siguiente línea es aceptada, porque CAT!
es un comando del disco RAM:
10 IF 1 THEN PRINT:ELSE CAT!
Pero estas otras no son aceptadas, porque CAT 1
es comando del G+DOS original de la interfaz +D, y CAT
es la versión abreviada de Beta DOS:
10 IF 1 THEN PRINT:ELSE CAT 1
20 IF 1 THEN PRINT:ELSE CAT
La solución es separar ELSE
en estos casos:
10 IF 1 THEN PRINT:ELSE:CAT 1
20 IF 1 THEN PRINT:ELSE:CAT
Lo he probado con varios comandos de disco y ocurre lo mismo, pero con Beta DOS; no lo he probado con G+DOS.