El intérprete TINY BASIC fue diseñado por Dennis Allison como un
analizador sintáctico de descenso recursivo. Parte de la elegante
simplicidad de este diseño se perdió al añadirle sintaxis más compleja,
pero la forma básica se conserva. El intérprete de lenguaje (IL) es
especialmente adecuado para el análisis sintáctico de descenso recursivo
de TINY BASIC debido a la naturaleza recursiva general de sus
procedimientos y a la simplicidad de los tokens TINY BASIC. El lenguaje
IL está optimizado para la interpretación de TINY. La experiencia ha
demostrado que la dificultad de añadir nuevas funciones al lenguaje es
desproporcionada con respecto a la naturaleza de estas. Normalmente es
necesario añadir subrutinas de lenguaje máquina adicionales para
soportar las nuevas funciones. A menudo, la dificultad supera las
ventajas.
Consideremos, por ejemplo, la aritmética de punto flotante. Esta es una
adición solicitada con frecuencia. Sin embargo, para implementar el
punto flotante, se deben superar los siguientes problemas:
1. Tamaño de la variable. Si bien 16 bits no permiten números muy
grandes, son adecuados para enteros pequeños, como los necesarios para
juegos y aplicaciones de control industrial, los dos entornos para los
que TINY es más adecuado. Sin embargo, los números de punto flotante
significativos no caben en menos de 20 bits, y 32 bits es un límite
inferior mucho más razonable. 26 variables de cuatro bytes cada una
equivalen a 104 bytes, un tamaño no demasiado grande para aprovechar el
direccionamiento de la página 00. Sin rehacer todo el intérprete de ML,
sería necesario colocar dos bytes donde se encuentran las variables y
los otros dos en el espacio entre 00C8 y 00FB. La pila de expresiones
puede resultar demasiado pequeña para expresiones muy complejas de
variables de punto flotante de longitud doble. Esto tendería a limitar
el tamaño permitido de las líneas de entrada, que comparten el mismo
espacio de trabajo con la pila de expresiones.
2. Rutinas de manejo de números. No solo sería necesario reescribir las
rutinas aritméticas que controlan los códigos de operación AD, SU, MP y
DV, sino también modificar todos los demás códigos de operación que
trabajan con números en la pila. De lo contrario, el programa podría
tener dificultades para ejecutar un GOSUB en la línea 1.23E2. Quizás una
alternativa más sencilla sería conservar los códigos de operación
existentes y añadir las rutinas de punto flotante en los huecos del
conjunto de instrucciones de IL, incluyendo una para fijar un número de
punto flotante, así como la carga y el almacenamiento de variables, y
las conversiones de impresión y constantes. Es posible que no haya
suficientes códigos de operación sin usar para realizar esto sin
sacrificar las funciones existentes.
3. El código de evaluación de expresiones en el intérprete de IL
necesitaría una revisión para distinguir entre los requisitos de enteros
y de punto flotante, y para seleccionar los códigos de operación
adecuados.
En resumen, añadir operaciones de punto flotante a TINY es probablemente
factible, aunque no fácil.
Por otro lado, las operaciones con cadenas o matrices probablemente no
sean prácticas dentro de los límites del sistema actual. Si bien todas
las variables en TINY están predefinidas, las matrices y las cadenas de
longitud variable requerirían rutinas de asignación y desasignación de
memoria, punteros de dirección y tablas de dimensiones. Es concebible
que este espacio se tome de la memoria no utilizada del programa de
usuario, ya sea al final del programa (modificando el puntero en
0024-0025 hexadecimal) o debajo de la pila GOSUB (modificando el puntero
en 0022-0023 hexadecimal). En este último caso, el asignador de memoria
necesitaría mover la pila y también modificar el puntero de pila y el
contenido de 0026-0027 hexadecimal. Lograr que el sistema sea
invulnerable a errores de programación sería extremadamente difícil. Las
mejoras que podrían ser considerablemente más sencillas y que quizás
deberían considerarse primero son una función AND lógica (como
intrínseca) o la indirección de datos del tipo utilizado en NIBL.
Añadir una función intrínseca consiste principalmente en reconocer el
nombre de la función dentro del procedimiento de análisis FACTor, llamar
a EXPR para evaluar cada argumento y, a continuación, realizar la
evaluación. En el caso de una función AND lógica, se necesitaría una
rutina de lenguaje máquina para la evaluación. Esto puede implementarse
de dos maneras: el código de operación US existente puede incorporarse a
la evaluación, donde el intérprete de IL sabe dónde se encuentra la
subrutina; o bien, puede definirse un nuevo código de operación. La
siguiente secuencia ilustra la técnica anterior (suponiendo que el
código AND en lenguaje máquina se encuentra en la ubicación 0003):
:F20 BC F30 "AND(" RECONOCE NOMBRE FUNCION
LN 3 DIRECCION DE CARGA PARA USR
JS EXPR OBTIENE PRIMER ARGUMENTO
JS ARG OBTIENE SEGUNDO ARGUMENTO
BC * ")" DEBE SER PARENTESIS ABIERTA
US VE A HACERLO
RT RETORNA A TERM.
:F30 ... (DESCANSA DE LO HECHO)
El operador de indirección "@" podría manejarse de manera similar:
:STMT BC TLET "LET@" EVALUA ALMACEN INDIRECTO
LN 280 SI, PONE DIRECCION POKE
JS EXPR OBTIENE DIRECCION
BC * "=" SGTE DEBE SER IGUAL
JS EXPR OBTIENE VALOR
BE * ESO DEBE SER FIN DE LINEA
US ALMACENA EL BYTE BAJO
SP LIMPIA EL STACK
NX FINALIZA LA DECLARACION
:TLET BC GOTO "LET" ...ETC.
La indirección en la búsqueda también es sencilla:
:F40 BC F5 "@" ES INDIRECTA?
LN 276 SI, OBTIENE DIRECCION PEEK
JS EXPR OBTIENE DIRECCION DE BYTE
DS (DUMMY)
US VE A OBTENERLA
RT
:F5 BC ...ETC.
Al agregar subrutinas de ML, puede ser útil saber dónde encontrar
algunos de los punteros internos utilizados por TINY. El programa IL
generalmente se ubica al final del código ML. Su dirección se almacena
en los dos bytes que preceden al código de Inicio en Frío. En otras
palabras, para encontrar la dirección base de IL (o cambiarla), siga el
JMP en hexadecimal 0100-0103 y busque dos bytes antes de su destino.
Esta es la única copia de la dirección, y los cambios aquí afectan a
todo el intérprete.
Las primeras instrucciones de la rutina de Inicio en Frío definen los
límites inferiores del espacio de usuario, por lo que, si es necesario
agregar código, se puede modificar para dejar espacio.
La tabla de direcciones de códigos de operación se ubica cerca del
inicio del intérprete ML (justo después de las rutinas PEEK y POKE). Las
primeras seis direcciones seleccionan las instrucciones de bifurcación.
La mayoría de los códigos de operación no utilizados saltan a la misma
dirección. Cada rutina de servicio de código de operación se codifica
como una subrutina.
Aquí se definen algunas de las ubicaciones de memoria de la página 00
que podrían ser de interés (todas las direcciones están en hexadecimal):
0020-0021 Inicio del espacio de programa de usuario
0022-0023 Fin del espacio de programa de usuario
0024-0025 Fin del programa BASIC, se añade SPARE
0026-0027 Principio de la pila BASIC
0028-0029 Número de línea BASIC actual
002A-002B Contador de programa IL
002C-002D Puntero BASIC
002E-002F Puntero guardado
0030-007F Línea de entrada y pila de expresiones
0080-0081 Semilla de número aleatorio
0082-00B5 Variables
00BF Contador de columna de salida y modo de cinta
Otros parámetros importantes tales como la bandera de modo RUN, el
puntero de la pila de operandos, y el puntero de fin de línea de entrada
se colocan en locaciones distintas, dependiendo de las versiones.
LISTADO DE ENSAMBLADOR DE TINY BASIC
El siguiente es un listado en ensamblador de la versión distribuida
actual de TINY BASIC.