IMPORTANTE: El texto original lo empecé a escribir en https://sites.google.com/site/plus3code/home/manuales-plus3code/estilo como una colección de apuntes variopintos sobre el uso y funcionamiento del intérprete de BASIC del +3 y trucos habituales usados en el BASIC del Spectrum. Aunque el texto es básicamente el mismo, he intentado ampliarlo y reorganizarlo.
Esto cambió con los modelos +128, lanzados en España en 1985, en los que pasaban a incorporarse más programas y opciones en el firmware. El +128 británico (1986) presentaba por primera vez el conocido sistema de menús que continuaría empleando Amstrad en sus modelos y que a todo el mundo le resulta familiar.
Terminología del Manual
A pesar de ser un interface no muy elaborado visualmente, de acuerdo con la terminología empleada en el Manual del +3 podemos diferenciar una serie de elementos:
menú de presentación:
Los ordenadores de las series ZX (ZX80, ZX81, ZX Spectrum) no ofrecen en su conjunto un interface de usuario particularmente complejo. En los modelos iniciales del Spectrum, producidos y comercializados por la compañía británica Sinclair Research Ldt. a partir de 1982, el usuario interactuaba única y directamente con un intérprete del lenguaje de programación BASIC residente en la ROM de la máquina; este intérprete presenta un dialecto particular del BASIC, habitualmente nombrado como "Sinclair BASIC".
-----
menús de edición:
-----
barras de información:
-----
Estos elementos se encuentran en el sistema básico y tienen una serie de características concretables que pasamos a describir.
La pantalla desde BASIC
Como recordatorio: la pantalla del Spectrum tiene 255 x 192 píxeles, y 32 columnas x 24 filas de texto.
Desde BASIC, las 22 primeras filas y las 2 últimas tienen un tratamiento diferente, al estar estas dos últimas reservadas para los mensajes del intérprete. Las 22 primeras pueden ser impresas con PRINT AT 0,0 para la línea 1 hasta PRINT AT 21,0 para la línea 22, mientras que a las dos últimas se suele acceder a través de PRINT #1 o INPUT. Estrictamente hablando, el intérprete soporta hasta PRINT AT 22,0, pero para poder usarlo hay que pokear una variable del sistema (ver más adelante) llamada DL_SZ que contiene el número de líneas (incluida una en blanco) de que consta la pantalla inferior. Puede ser pokeada de esta manera (la información la saqué de un estupendo artículo de F. León en El Trastero del Spectrum):
1 POKE 23659,0 2 PRINT AT 22,0; "Linea 23" 3 POKE 23659, 2
No se puede hacer lo mismo sin embargo con la última línea. Por otra parte, la memoria de pantalla divide la imagen en tres áreas rectangulares: superior, centro e inferior:
Los UDG ocupan 168 bytes y normalmente se encuentran a partir de la posición 65368 de memoria. Los UDG son un elemento característico de nuestro sistema, que también podemos encontrar muchísimas veces bajo su nombre traducido: GDU (Gráficos Definibles por el Usuario, véase el Capítulo 8, Sección 14 del Manual del Usuario). En modo 48K, el +3 cuenta con 21 GDU, en modo 128K tiene 19 GDU; a cambio cuenta con los comandos PLAY y SPECTRUM, que ocupan el lugar de los 2 GDU extra que hay en el modo 48K.
Atajos y trucos del editor BASIC
(Fuente: aquí) El editor de +3BASIC tiene algunos trucos para mover el cursor por el listado con el que estemos trabajando:
Simb + i –> Mueve el cursor 10 lineas abajo
Extra + j –> Borra desde el cursor hasta fin de linea
GRAPH (Simb + 9) –> Cambia a modo gráfico
GRAPH (Simb + 9) + w –> Va al inicio del listado
GRAPH (Simb + 9) + v –> Va al fin del listado
GRAPH (Simb + 9) + x –> Va a final de linea
GRAPH (Simb + 9) + y –> Va a inicio de linea
GRAPH (Simb + 9) + z –> Cambia el modo de pantalla (editor/pantalla)
Extra + w –> Borra desde el cursor hasta fin / Cambia modo normal
Puntos interesantes del intérprete
(Fuentes varias: p.ej. aquí y aquí) El intérprete proporciona algunas sorpresas interesantes a través del analizador sintáctico de expresiones entre paréntesis. El manual documenta el uso de ( TO ) con variables tipo string, pero se deja mucho en el tintero sobre el resto de combinaciones y posibilidades, con el empleo de operadores booleanos y los operadores lógicos AND, OR, NOT, etc. Algunos ejemplos:
LET y=(5 AND x=0)
es exactamente lo mismo que IF x=0 THEN LET y=5 ELSE IF x<>0 THEN LET y=0
y que LET y=(5 AND NOT x)
lo que también puede ser escrito como: LET y = 0 : IF a = 0 THEN LET y = 5
LET y=(5 OR NOT x)
es exactamente lo mismo que IF x=0 THEN LET y=1 ELSE IF x<>0 THEN LET y=5
y que LET y=(5 OR x=0)
y así etc. Los valores 0 y 1 marcados en rojo y verde no los hemos introducido nosotros, son el resultado de la evaluación de la expresión.
Veamos otro ejemplo con el siguiente mini-programa, con solo dos líneas (30-40) queda resuelto el control en cuatro direcciones de un carácter en pantalla:
10 LET x=5 : LET y=5
20 PRINT AT x, y; "O" : LET ax=x : LET ay=y
30 LET y=y+(INKEY$="p" AND y<21)-(INKEY$="o" AND y>0)
40 LET x=x+(INKEY$="a" AND x<31)-(INKEY$="q" AND x>0)
50 IF (ax=x AND ay=y) THEN GO TO 30
60 PRINT AT ax, ay; " " : GO TO 20
El intérprete está lleno de posibilidades a explotar y aun muchísimos años después de la retirada comercial del Spectrum se siguen descubriendo nuevos y sorprendentes trucos. En 2011 por ejemplo se descubrió que era posible copiar desde el editor BASIC bloques de datos de una parte a otra de la memoria sin recurrir al ensamblador y al código máquina, simplemente "hackeando" algunas variables del sistema:
10 DIM s$(6912):
DEF FN p(a) = PEEK a+256*PEEK (a+1):
DEF FN l(v) = v-256*FN h(v):
DEF FN h(v) = INT (v/256):
LET udg = FN p(23675)
20 LET df = 16384:
LET dl = 6912:
LET defadd = 23563
30 FOR a = udg TO udg+8:
READ v:
POKE a,v:
NEXT a:
DATA 65,36,14,0,FN l(df),FN h(df),FN l(dl),FN h(dl),41
35 PRINT #0; "load a SCREEN$ then press ""j"""
.
. <---AQUI METERIAMOS UN LOAD "" SCREEN$
.
36 IF INKEY$ <> "j" THEN
PAUSE 0:
GO TO 36
40 POKE defadd,FN l(udg):
POKE defadd+1,FN h(udg):
LET s$ = a$:
POKE defadd,0:
POKE defadd+1,0
50 CLS :
PRINT #0; "press ""j"" again"
51 IF INKEY$ <> "j" THEN
PAUSE 0:
GO TO 51
60 POKE defadd,FN l(udg):
POKE defadd+1,FN h(udg):
LET a$ = s$:
POKE defadd,0:
POKE defadd+1,0:
PAUSE 0
Reconfiguración del editor (POKEs)
POKE 23609, x ==> Cambia la duración del sonido del teclado (al teclear).
POKE 23611,205 ==> Permite 21 UGD en 128k, sin afectar a PLAY y SPECTRUM. La dirección 23611 corresponde con la variable del sistema FLAGS e inicialmente contiene el valor 211.
POKE 23613, 4 : POKE 23614, 61 ==> RESET si se para el programa por un error (anti-BREAK).
POKE 23658,8 ==> Pone el teclado en mayúsculas.
POKE 23692, 255 ==> anti-mensaje "SCROLL?", ej.:
10 FOR n = 0 TO 10000
20 PRINT n : POKE 23692, 255
30 NEXT n
Otras consideraciones a la hora de programar en Sinclair BASIC
Más memoria:
Como norma general, convertir todas las CIFRAS en VAL"CIFRAS"
Más velocidad:
GO TO y GO SUB buscan el número de línea desde el principio del listado, lo mismo para funciones FN y bucles FOR/NEXT. Las sentencias y operadores que más tiempo consumen: IF y * (multiplicación)
Funciones (FN):
(Fuente: aquí) Implementación de ON x GO TO/GO SUB, ej.:
1000 INPUT "Introduzca opcion 1-3 "; h
1010 GO SUB FN o(h, "1500,1600,1700")
1500 REM "ON 1"
1510 RETURN
1600 REM "ON 2"
1610 RETURN
1700 REM "ON 3"
1710 RETURN
.....
9990 DEF FN o(n, a$) = VAL a$((n-1)*5+1 TO (n-1)*5+4)
VAL$:
(Fuente: aquí) La función VAL$ es una de las grandes desconocidas cuyos potenciales usos son en general ignorados. Como ejemplo:
10 LET a$="""El ""+b$+"" se fue hace ""+c$" 20 LET b$="gato" 30 LET c$="rato" 40 PRINT VAL$ a$
50 LET b$="diplodocus"
60 PRINT VAL$ a$
Otra forma de hacer esto (probablemente la más habitual), es a través de funciones FN:
10 DEF FN a$(b$)="El "+b$+" se fue hace "+c$
20 LET b$="gato"
30 LET c$="rato"
40 PRINT FN a$(b$) 50 LET b$="dromedario"
60 PRINT FN a$(b$)
Convenciones sobre las extensiones en el nombre de los ficheros de disco con +3DOS
No existen estándares formales establecidos al respecto. Es relativamente habitual encontrar alguna de las siguientes extensiones:
*.BAS
*.BIN
_.PAN
_.SCR
*.TAS
*.UDG
_.FNT
_.CHR
*.PAS
*.ASM
Con todo, es orientativo.
Estas tres partes están en la memoria a partir de la dirección 16384. Cada franja ocupa 2048 bytes (en total 6144) y después de las tres, a partir de 22528, hay 768 bytes más con los atributos (color, brillo, etc) de la pantalla. En total 6912 bytes. Cada una de estas franjas puede ser salvada y cargada como imagen SCREEN$ de manera independiente (sin los atributos), al estar situadas una detrás de otra en memoria. Esto lo podemos hacer sencillamente con:
- Parte superior. SAVE "nombre" CODE 16384, 2048
- Parte central. SAVE "nombre" CODE 18432, 2048
- Parte inferior. SAVE "nombre" CODE 20480, 2048
- Atributos. SAVE "nombre" CODE 22528,768
Que es en conjunto como hacer SAVE "nombre" CODE 16384,6912 para salvar toda la pantalla (o SAVE "nombre" SCREEN$). Cada una de estas sub-pantallas de 2K puede ser cargada empleando LOAD "nombre" CODE o LOAD "nombre" SCREEN$, para sus posiciones originales. También podemos forzarlas a otra posición en la pantalla a través de CODE (LOAD "" CODE posición).
Organización de la memoria
Dada la naturaleza del sistema operativo, conocer la manera en la que está distribuida la memoria puede ser siempre del máximo interés:
Esto que vemos a la izquierda viene a ser una esquema aproximado de la memoria RAM de nuestro +3 en tiempo de ejecución desde Sinclair BASIC, esto es, arrancamos el ordenador desde 0, metemos un listado BASIC y tecleamos RUN desde el editor +3BASIC, sin tocar CM ni nada. Cuando el sistema hace uso de +3DOS por ejemplo, la memoria cambia (la ROM paginada es la ROM2, que contiene el DOS, la parte superior que en la imagen se ve como RAM0, se pagina a RAM7, etc.). Mientras estamos editando el código fuente, la ROM paginada es la ROM0 (que contiene el editor) y la ROM1 (que contiene el programa que chequea la sintaxis del código introducido). Los bloques de memoria RAM1, RAM3, RAM4 y RAM6 son usados normalmente como caché del disco y para el disco RAM (el disco M). Así, el esquema mostrado, como se ha dicho, responde al estado de la máquina ejecutando código BASIC, sin estar realizando operaciones con ficheros. Podemos desde BASIC alterar el mapeado de la RAM, tal como recoge el Manual del +3: "CLEAR 49151 traslada todo BASIC a posiciones inferiores a las que contienen el sistema de paginación de RAM. Con la orden POKE 23388, 16+n (donde n es un número del 0 al 7) podemos hacer que el ordenador seleccione la página n de la RAM. Entonces podremos usar PEEK y POKE como de costumbre para inspeccionar y modificar la página en cuestión. Tenga en cuenta que las páginas adicionales normalmente son utilizadas por el sistema de disco y por el editor, de modo que se debe reinicializar el ordenador después de experimentar con la memoria." (Capítulo 8: Guía de programación en +3 BASIC. Sección 24: La memoria, página 199 de la versión española).
Resumiendo y rememorando: aunque no tiene necesariamente por qué ser así y puede ser modificado por software el mapeado de la memoria, en la configuración inicial en BASIC, tras los primeros 16K, que por defecto están ocupados por ROM, se sitúan tres bloques consecutivos de RAM también paginada. En los Spectrum +3/+2A, la RAM4, RAM5, RAM6 y RAM7 son memoria contenida (contended memory). Esto se refiere a ciertos tiempos de ciclos de máquina y puede afectar a la programación y ejecución de CM, porque en los modelos de Spectrum anterior, este tipo de memoria estaba en otra posiciones.
Como ya se dijo antes, en la dirección 16384 empieza la memoria de la pantalla, coincidiendo con el fin de la ROM y el inicio de la RAM.
Lo que en el esquema se ve como "SYSTEM VARIABLES" se refiere por una parte a las variables del sistema, un conjunto de posiciones en memoria referidas al editor BASIC y a la configuración del intérprete y del sistema operativo, y también al resto de datos que hay en esa zona, como información de los canales (pantalla, teclado, impresora), buffers y etc., hasta el inicio de PROG, que marca el inicio del área destinada al código fuente BASIC del usuario.
A partir de aquí, hasta RAMTOP, hay varios bloques de información (no representados gráficamente en el esquema), referidos al listado que en ese momento esté siendo editado: el listado del código fuente en sí, las variables, matrices, etc. y su contenido se almacenan de acuerdo con un orden y formato determinado en estos bloques, y a continuación tenemos el espacio todavía sobrante hasta llegar a la RAMTOP, luego sigue el bloque de datos de los 18 UDG y por fin la P_RAMPT, el límite físico de la memoria del ordenador.