

$tree = Syntax::Analysis::parser; ... # otras fases ########code generation local $target = ""; # target code $tree->translate; ...
en la cadena $target dejamos el código emitido.
Cada método visita los hijos, traduciéndolos y añadiendo
el código que fuera necesario para la traducción del nodo.
sub PROGRAM::translate {
my $tree = shift;
$target .= "DATA ". $data."\n" if $data;
$tree->STS->translate;
}
Traducir la lista de sentencias es concatenar la traducción de cada una de las sentencias en la lista:
sub STATEMENTS::translate {
my $statements = shift;
my @statements = @{$statements};
for my $s (@statements) {
$s->translate;
}
}
Si suponemos que disponemos en el ensamblador de nuestra máquina
objeto de instrucciones PRINT_INT y PRINT_STR
que imprimen el contenido
de la expresión que esta en la cima de la pila, la traducción será:
sub PRINT::translate {
my $self = shift;
$self->EXPRESSION->translate;
if ($self->EXPRESSION->TYPE == $int_type) { emit "PRINT_INT\n"; }
else {emit "PRINT_STR\n"; }
}
Asi, si la sentencia era P c, donde c es del tipo cadena,
se debería eventualmente llamar al método de traducción del identificador:
sub ID::translate {
my $self = shift;
my $id = $self->VAL;
my $type = Semantic::Analysis::get_type($id);
if ($type == $int_type) {
emit "LOAD ".$symbol_table{$id}->{ADDRESS}."\n";
}
else {
emit "LOAD_STRING ".$symbol_table{$id}->{ADDRESS}."\n";
}
}
la función emit simplemente concatena el código
producido a la salida:
sub emit { $target .= shift; }
Para la traducción de una sentencia de asignación
supondremos de la existencia de isntrucciones STORE_INT
y STORE_STRING. La instrucción STORE_STRING asume
que en la cima de la pila están la dirección y la cadena a almacenar.
sub ASSIGN::translate {
my $self = shift;
$self->RIGHT->translate;
my $id = $self->LEFT;
$id->translate;
my $type = Semantic::Analysis::get_type($id->VAL);
if ($type == $int_type) {
emit "STORE_INT\n";
}
else {
emit "STORE_STRING\n";
}
}
Si se está traduciendo una sentencia como a = "hola",
se acabará llamando al método
de traducción asociado con la clase STR
el cual actúa empujando la dirección y la longitud de la cadena en
la pila:
sub STR::translate {
my $self = shift;
emit "PUSHSTR ".$self->OFFSET." ".$self->LENGTH."\n";
}
Así la traducción de este fuente:
$ cat test06.tutu string a; a = "hola"; p a
es:
$ ./main.pl test06.tutu test06.ok $ cat test06.ok DATA 2, hola PUSHSTR 2 4 PUSHADDR 0 STORE_STRING LOAD_STRING 0 PRINT_STR
El resto de los métodos de traducción es similar:
sub LEFTVALUE::translate {
my $id = shift ->VAL;
emit "PUSHADDR ".$symbol_table{$id}->{ADDRESS}."\n";
}
sub NUM::translate {
my $self = shift;
emit "PUSH ".$self->VAL."\n";
}
sub PLUS::translate {
my $self = shift;
$self->LEFT->translate;
$self->RIGHT->translate;
emit "PLUS\n";
}
sub TIMES::translate {
my $self = shift;
$self->LEFT->translate;
$self->RIGHT->translate;
emit "MULT\n";
}
Veamos un ejemplo. Dado el código fuente:
$ cat test02.tutu int a,b; string c; a = 2+3; b = 3*4; c = "hola"; p c; c = "mundo"; p c; p 9+2; p a+1; p b+1el código generado es:
$ ./main.pl test02.tutu test02.ok $ cat test02.ok DATA 4, holamundo PUSH 5 PUSHADDR 0 STORE_INT PUSH 12 PUSHADDR 1 STORE_INT PUSHSTR 4 4 PUSHADDR 2 STORE_STRING LOAD_STRING 2 PRINT_STR PUSHSTR 8 5 PUSHADDR 2 STORE_STRING LOAD_STRING 2 PRINT_STR PUSH 11 PRINT_INT LOAD 0 INC PRINT_INT LOAD 1 INC PRINT_INT

