ENSAMBLADOR TBIL Para facilitar el desarrollo y la modificación del programa IL, se ha escrito un ensamblador en TINY BASIC. Este ensamblador acepta los mnemónicos del lenguaje ensamblador IL y genera un código objeto hexadecimal apto para cargarse en memoria. Es un ensamblador de dos pasos: en el primero construye la tabla de símbolos y en el segundo genera el código objeto hexadecimal completo. Dado que TINY BASIC no admite cadenas ni matrices, el archivo fuente y la tabla de símbolos se manipulan mediante la función USR para invocar las subrutinas estándar del lenguaje máquina y así cargar y almacenar bytes en memoria. Lamentablemente, esto es muy lento, por lo que también se utiliza una tercera subrutina, que carga dos bytes, para agilizar el proceso. Los comentarios en el código fuente del ensamblador indican cómo se puede codificar dicha rutina. El ensamblador aún está limitado por el cálculo y se espera que tarde varias horas en cada paso. Esto se considera aceptable solo debido a la poca necesidad de ensamblar el código IL. El ensamblador acepta entrada libre con dos tipos de líneas fuente: líneas de comentario y líneas de instrucción del programa. Cada línea, de cualquier tipo, debe comenzar con un número de línea. En realidad, esto es una improvisación para convencer a TINY BASIC de que lea la línea fuente con un comando INPUT, y el número no tiene importancia para el ensamblador, salvo que es cero en la última línea del programa. Las líneas de comentario se indican al ensamblador mediante un punto después del número de línea. No se procesan más. Las líneas de instrucción pueden comenzar con una etiqueta o no. Una etiqueta se indica con dos puntos iniciales (que no forman parte de la etiqueta), seguidos de una letra y hasta tres letras o dígitos más, y termina con un espacio en blanco. El campo siguiente a la etiqueta, o el primer campo de una línea sin etiqueta, es el mnemónico de la instrucción. Este es uno de los códigos de dos letras (o de una letra en el caso de J) definidos anteriormente. Las instrucciones que requieren operandos deben ir seguidas de al menos un espacio en blanco y, a continuación, el operando en el formato correcto. Los saltos y las bifurcaciones aceptan una referencia de etiqueta; las bifurcaciones también aceptan el símbolo "*" para indicar una bifurcación de parada por error. La instrucción SX requiere un solo dígito octal (1-7). Las instrucciones LB y LN deben ir seguidas de un número decimal. Este número es procesado por el comando BASIC INPUT, que acepta expresiones e ignora los espacios en blanco, por lo que se debe tener cuidado con lo que se permite después del número. En particular, no puede ir seguido de más dígitos decimales ni de los caracteres + - * o /. El número debe comenzar con un dígito. Las instrucciones BC y PC van seguidas de una cadena (después de la etiqueta en el caso de BC). La cadena se encierra entre un par de delimitadores que pueden ser cualquier carácter que no sea un espacio en blanco, excepto el circunflejo ASCII (hexadecimal 5E, que a veces se imprime como una flecha hacia arriba). A cualquier carácter dentro de la cadena seguido de un circunflejo se le resta un hexadecimal 40 de su código, lo que permite generar cadenas con caracteres de control. El último carácter de la cadena tiene el bit más significativo establecido en uno en el código objeto. Todo lo que aparece en la línea de código fuente después de los operandos, si lo hay, es tratado por el ensamblador como comentarios. El funcionamiento del ensamblador está determinado por las restricciones impuestas por TINY BASIC. Las líneas de código fuente no deben tener más de 60 caracteres aproximadamente para dejar espacio en la pila de expresiones. Cada línea de código fuente debe terminar en un control DC3 (X-OFF) a menos que se utilice otro control de lectura, ya que se requieren varias decenas de segundos para procesar cada línea. El programa se carga y se inicia con un comando RUN. Solicitará las direcciones de las rutinas de carga y almacenamiento de bytes, que deben escribirse en decimal. También solicitará la dirección de memoria donde se cargará el programa. Esta dirección solo se utiliza para generar la salida del contador de ubicación y no afecta la generación de código. Una de las primeras acciones del ensamblador es buscar la tabla mnemotécnica, que se encuentra incrustada en las líneas de pseudocomentarios cerca del inicio del ensamblador. Estas se identifican con un asterisco inicial en la línea, aunque la búsqueda se centra en la línea número 3. La tabla de símbolos también se inicializa vacía. Cada línea del programa ensamblado contendrá la dirección de memoria hexadecimal, el código objeto hexadecimal que se cargará en esa dirección, un punto y coma que marca el final del código máquina y, a continuación, la siguiente línea fuente. Observe que la línea fuente se repite a medida que se lee (esto lo realizan las rutinas de E/S), por lo que el código ensamblado para esa línea se encuentra al principio de la siguiente. Si el archivo fuente contiene un carácter de salto de línea después de cada retorno de carro, el código objeto aparecerá en la misma línea del listado, pero en realidad lo sigue en el archivo de salida. En el caso de los códigos de operación LN, PC y BC, que generan más de dos bytes de código, se utilizará una segunda línea para el código objeto sobrante. El listado generado para el eje 1 se verá muy similar al del Paso 2, excepto que parte del código objeto estará incompleto. Los errores de ensamblador que no provoquen un fallo en el programa se identificarán mediante una indicación de dos letras entre dos asteriscos. A continuación, se presenta un resumen de los errores reconocidos y marcados por este ensamblador: *DL* Etiqueta duplicada (sólo Paso 1) *IE* mnemónico no identificable *OP* Operando formado Incorrectamente *US* Símbolo indefinido en salto o rama *LE* Fin prematuro de línea Algunos errores del programa fuente serán detectados por el intérprete de TINY BASIC y detendrán el ensamblador. Estos errores son catastróficos, ya que no solo se aborta el ensamblador, sino que TINY carga el resto del archivo fuente en memoria a través del ensamblador como si fuera un programa BASIC, destruyendo así la integridad del ensamblador. Los errores catastróficos son: Líneas sin un nombre de línea Líneas Excesivamente largas Expresión inválida como operando de LN o LB Desborde de tabla de símbolos Se espera que esta versión del ensamblador se ejecute en algo menos de 8K bytes de memoria, dependiendo de cuántas líneas de comentario y espacios en blanco se eliminen. En términos operativos, el programa es bastante directo, con pocos detalles técnicos. El ensamblador construye la tabla de símbolos robando espacio de la pila GOSUB. Por cada etiqueta que se añade a la tabla, se ejecutan tres GOSUB no devueltos, liberando seis bytes. Los símbolos con menos de 4 caracteres se rellenan con espacios. La misma rutina de búsqueda en la tabla de símbolos se utiliza tanto para la definición (para comprobar si hay duplicados) como para la referencia. La búsqueda en la tabla se realiza con los comandos USR de recuperación de memoria. La búsqueda en la tabla de códigos de operación se realiza de forma similar. Los códigos hexadecimales nunca se convierten a binario, sino que una subrutina especial selecciona la instrucción de impresión de dígitos adecuada basándose en el valor ASCII de los códigos. En los pocos casos en que el operando está incrustado en el código de operación, los bits adicionales se añaden antes de la salida. El tipo de instrucción (es decir, el tipo de operandos aceptados para la instrucción en particular) se determina por su posición en la tabla: la primera posición es SX; las dos siguientes son saltos; las cinco siguientes son bifurcaciones, seguidas de los códigos de operación de cadena (nótese la superposición). Los códigos de operación de byte y número literales son finalmente seguidos por todos los genéricos (sin operando). El ensamblador sabe cuántos códigos de operación hay y deja de buscar cuando se alcanza este número, en lugar de buscar un indicador de fin de tabla. La tabla se divide en varias líneas de TINY BASIC; los límites de línea se alinean con las posiciones de los mnemónicos en la tabla, por lo que representan códigos de operación que nunca coinciden (el mnemónico sería CR-NUL). El funcionamiento del resto del ensamblador es bastante evidente y no requiere mayor explicación.