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.