NOTAS DE IMPLEMENTACIÓN 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.