$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