Si soy informático hoy en día, es porque cuando era pequeño empecé con un Sinclair ZX Spectrum + 128k, una variante del Sinclair Spectrum + fabricada en España por Investrónica.
Fue con el Sinclair BASIC con el que empecé a programar, principalmente juegos, tanto aventuras conversacionales como arcades (me temo que estos eran aún de peor calidad... mi única defensa es que por entonces era un preadolescente).
Para mi, como es lógico, todo aquello que era soportado por Sinclair BASIC era "lo normal", como es lógico. De hecho, yo iba a clases de informática (con Amstrad PC-1512, lo que tenían en el colegio), con GW-BASIC. Por cierto, si quieres "jugar" con GW-BASIC, aparte de compilarlo (Microsoft ha publicado el código fuente de GW-BASIC), puedes hacerlo en este intérprete on-line de GW-BASIC, o bajarte QB64, un intérprete compatible con QBasic.
Decía que para mi, lo que soportaba Sinclair BASIC era lo normal. Así que me sorprendí cuando mi profesor de entonces me explicó las limitaciones de las cadenas de caracteres en GW-BASIC: es decir, con una longitud máxima de 255 caracteres (pues cada cadena de caracteres podía llegar a ocupar un bloque de 256 bytes), utilizando para la longitud real de la misma el primero de ellos.
Le respondí algo así como "no lo entiendo, en mi Spectrum puedo tener cadenas de caracteres de la longitud que quiera, hasta agotar la memoria". Solo recuerdo que sacudió la cabeza, incrédulo. Pero es verdad. Es verdad, ¿no? A ver, el Spectrum 128k incorporaba en ROM un editor de texto. ¿Dónde se guardaba el texto que incluyeras en el editor? Pues en una cadena de caracteres. La que tú quisieras. De hecho, para invocar el editor, solo tenías que introducir el siguiente comando interactivo:
edit t$
Y, tras salir del editor de texto, tenías el contenido tecleado en t$. Así de simple. Una cadena de caracteres era una estructura de datos en sí misma. Algo que en C podrías hacer de la siguiente forma:
typedef struct _text {
size_t num_lines;
char * lines[];
} Text;
Es verdad que en C podrías tener todo el texto en una cadena de caracteres, aunque sería inmanejable (también era poco manejable en Sinclair BASIC, aunque ya hablaremos de eso). En Pascal, por ejemplo, no queda más remedio que utilizar una estructura de este tipo con el soporte estándar de cadenas de caracteres.
type Text = record
num_lines: integer;
lines: array of string;
end;
Pero volvamos a Sinclair BASIC. ¿Realmente podemos tener cualquier número de caracteres en su interior? Parece que sí. Utilizando un programa en Sinclair BASIC:
10 cls
20 print "Cadenas"
30 let a$ = ""
40 if ( len a$ / 100 ) - int( len a$ / 100) goto 70
50 let a$ = a$ + "+"
60 print at 10, 5; "Ahora len a$ es: "; len a$
70 goto 40
Lo que hace el programa es ir publicando el tamaño de la variable tras cada adición de un carácter '+' a la misma (podría ser cualquiera, un espacio, una letra...). El programa debería ejecutarse hasta dar un error de memoria. Hasta el límte de cadenas de caracteres en Sinclair BASIC, o bien hasta el tamaño de la memoria libre para BASIC, unos 40K.
El resultado de la ejecución es la siguiente:
Así, el resultado es que... una cadena es capaz de albergar 13781 caracteres. Esto lo sabemos porque las variables mantienen sus valores aún cuando la ejecución se interrumpe. La siguiente instrucción, como puede esperarse, nos da el dato requerido.
print len a$
Pues parece que no se puede llegar a ocupar toda la memoria, no... quizás tenga que ver con la forma de guardar los caracteres. En caso de que se guarde en formato **Pascal**, entonces la longitud debe estar almacenada en más de 1 byte. En caso de ser 2 bytes (16 bits), nos permitiría tener hasta 32768 caracteres. Está claro que no es este el límite al que estamos llegando. ¿Qué sucede entonces?
En el ZX Spectrum BASIC no tenemos una función free()
, pero aunque no esté disponible como un comando de BASIC, sí está disponible como una rutina en la ROM, en la dirección 7962: 65546-usr 7962
. En realidad calcula el espacio ocupado. Si quitamos ese espacio del total absoluto que puede direccionar el Z80, 64K (65536), tendremos el espacio libre. El resultado de este cálculo es 27531, casi 27K libres. Así, no es cierto estrictamente que no haya más memoria, el límite tiene que venir de otro lugar. De hecho, podemos visualizar el contenido de la cadena, editar el programa... El Spectrum sigue funcionando perfectamente.
print 65536 - usr 7962
Si ejecutamos este código justo tras encender el Spectrum, el resultado sería 41469, alrededor de 40K (el BASIC del Spectrum es terriblemente lento, aunque por otra parte es de los que deja mucho espacio libre de RAM para programas, en lugar de, por ejemplo, Microsoft BASIC).
Si sumamos los 13781 bytes que ocupa la cadena (unos 13K), con el espacio libre reportado por la rutina de la ROM (27531), el resultado es 41312. Hay una diferencia de 157 bytes, que debemos atribuir a las estructuras de datos que mantiene el intérprete de Sinclair BASIC, pero aproximadamente tenemos el valor inicial.
Si consultamos el desensamblado de la ROM del Speccy, lo cierto es que la rutina que responde a la función len
, por ejemplo, en len a$
, hace uso de la función STK_FETCH, que recupera un parámetro cualquiera. Este parámetro puede ser un número (el Spectrum por defecto utiliza números reales, para los que aparentemente usa 5 bytes, o una cadena de caracteres, para los que utiliza cuatro: 2 para la dirección de memoria en la que reside la cadena de caracteres, y 2 para el tamaño de la cadena.
Esto nos refuerza en el sentido de que el límite en cuanto a la estructura de datos que se mantiene para cada cadena de caracteres es de 32768 o 32K. En cualquier caso, 13K de texto pueden parecer poca cosa hoy en día, pero dado que cada byte es exactamente un carácter, en realidad estamos hablando de, potencialmente, 31 páginas.
Llegados a este punto, debemos asumir que la infraestructura del intérprete de BASIC para las cadenas de caracteres es la que realmente impone este límite, que parece un tanto artificial. Desafortunadamente, no he encontrado ninguna referencia donde se trate en profundidad cómo funcionan las interioridades de Sinclair BASIC, o en específico, su manejo de cadenas de caracteres.
Por cierto, ¿conoces ese deprimente dicho de que está todo inventado? Pues el slicing ya existía en Sinclair BASIC para cadenas y matrices. Sinceramente, no recordaba que esto se pudiera hacer.
10 let a$ = "Eh hola ZX Spectrum"
20 print a$
30 let a$(1 to 4) = " M"
40 print a$
Este programa visualiza lo siguiente:
Eh hola ZX Spectrum
Mola ZX Spectrum
En la línea 30, cuando el índice es 1, se puede omitir (sí, como en Python), dejándolo en let a$(to 4) = " M"
.
Top comments (0)