04 abril 2008

Un compilador sencillo paso a paso (6 - Nuevas órdenes)

Sigamos ampliando nuestro compilador elemental. Nos queda mucho por hacer. Algunas cosas serán relativamente trabajosas, como declarar y usar variables, o más todavía cuando queramos crear procedimientos, pero algún otro detalle es sencillo, como seguir añadiendo nuevas órdenes simples.

Comenzaremos por ahí: vamos a añadir tres órdenes nuevas, que permitan cambiar el modo de pantalla, el color del texto y el color de fondo.


  • La orden de cambiar un modo de pantalla será "CpcMode", que recibirá un único parámetro: el número de modo (0 para 20 columnas y 16 colores, 1 para 40 columnas y 4 colores, 2 para 80 columnas y 2 colores). Le pondremos el prefijo "Cpc" por eso de que es una orden "casi exclusiva de los CPC", mientras que las anteriores (cls, locate, writechar) tendrían sentido en casi cualquier sistema informático.


  • Las órdenes de cambiar color, como también existirán para casi cualquier sistema, no tendrán el prefijo "cpc", y seguirán la nomenclatura que se usaba en el Basic de estos equipos: PEN para cambiar el color de escritura (pluma) y PAPER para el color de fondo (papel).



Así, al generador de código (uPachiG) bastaría con añadirle las correspondientes llamadas a rutinas del firmware:


(* Generar codigo para CPCMODE *)
procedure genCPCMODE(modo: byte);
begin
writeln( ficheroDestino, lineaActual,' DATA 3E,',
hexStr(modo,2), ': '' LD A, ',modo );
lineaActual := lineaActual + 10;
writeln( ficheroDestino, lineaActual,' DATA CD,0E,BC: '' CALL &BC0E - SET MODE' );
lineaActual := lineaActual + 10;
longitudTotal := longitudTotal + 5;
end;

(* Generar codigo para PAPER *)
procedure genPAPER(color: byte);
begin
writeln( ficheroDestino, lineaActual,' DATA 3E,',
hexStr(color,2), ': '' LD A, ', color);
lineaActual := lineaActual + 10;
writeln( ficheroDestino, lineaActual,' DATA CD,96,BB: '' CALL &BB96 - SET PAPER' );
lineaActual := lineaActual + 10;
longitudTotal := longitudTotal + 5;
end;

(* Generar codigo para PEN *)
procedure genPEN(color: byte);
begin
writeln( ficheroDestino, lineaActual,' DATA 3E,',
hexStr(color,2), ': '' LD A, ', color);
lineaActual := lineaActual + 10;
writeln( ficheroDestino, lineaActual,' DATA CD,90,BB: '' CALL &BB90 - SET PEN' );
lineaActual := lineaActual + 10;
longitudTotal := longitudTotal + 5;
end;




En el analizador sintáctico, los cambios son pequeños también. Aun así, podemos aprovechar para hacerlo un poco más modular: los detalles del análisis no deberían estar todos dentro del procedimiento "analizarCualquierOrden", sino que éste debería delegar en otros, así:


procedure analizarCualquierOrden;
begin
orden := upcase(obtenerIdentificador);
if orden = 'CLS' then
begin
analizarCLS;
end
else
if orden = 'CPCMODE' then
begin
analizarCPCMODE;
end
else

[...]

procedure analizarCLS;
begin
leerSimbolo(';');
genCLS;
end;

procedure analizarCPCMODE;
begin
leerSimbolo('(');
val(obtenerEntero,x,codError);
leerSimbolo(')');
leerSimbolo(';');
genCPCMODE(x);
end;

procedure analizarPAPER;
begin
leerSimbolo('(');
val(obtenerEntero,x,codError);
leerSimbolo(')');
leerSimbolo(';');
genPAPER(x);
end;



Como siempre, para más detalles, todo el código está en la página del proyecto en Google Code:

http://code.google.com/p/cpcpachi/