Veamos la forma del árbol en una sentencia de retorno:
pl@nereida:~/Lbook/code/Simple-Types/script$ perl -wd usetypes.pl prueba16.c 2 main::(usetypes.pl:5): my $filename = shift || die "Usage:\n$0 file.c\n"; DB<1> f Types.eyp 1 2 3 4 5 6 7 #line 8 "Types.eyp" 8 9: use strict; 10: use Carp; DB<2> c 598 1 int f() { 2 int a[30]; 3 4 return a; 5 } Simple::Types::compile(Types.eyp:598): 598: set_types($t); # Init basic types DB<3> insert_method(qw{PROGRAM FUNCTION}, 'footnote', sub {}) DB<4> p $t->str PROGRAM(FUNCTION[f](RETURN(VAR(TERMINAL[a:4]))))
pl@nereida:~/doc/casiano/PLBOOK/PLBOOK/code/Simple-Types/lib/Simple$ \ sed -ne '267,282p' Trans.trg | cat -n 1 returntype: RETURN($ch) 2 => { 3 my $rt = $RETURN->{t}; 4 5 $ch = char2int($RETURN, 0) if $rt == $INT; 6 $ch = int2char($RETURN, 0) if $rt == $CHAR; 7 8 type_error("Type error in return statement", $ch->line) 9 unless ($rt == $ch->{t}); 10 11 # $RETURN->{t} has already the correct type 12 13 $RETURN->type(ref($RETURN).ref($rt)); 14 15 return 1;
El análisis de ámbito de las sentencias de retorno se hizo de forma ligeramente
distinta al resto. El siguiente fragmento de código figura en la subrutina compile
justo despueés del resto del análisis de ámbito::
pl@nereida:~/doc/casiano/PLBOOK/PLBOOK/code/Simple-Types/lib/Simple$ \ sed -ne '585,595p' Types.eyp | cat -n 1 # Scope Analysis: Return-Function 2 our $retscope; # retscope: /FUNCTION|RETURN/ 3 my @returns = $retscope->m($t); 4 for (@returns) { 5 my $node = $_->node; 6 if (ref($node) eq 'RETURN') { 7 my $function = $_->father->node; 8 $node->{function} = $function; 9 $node->{t} = $function->{t}->child(1); 10 } 11 }
pl@nereida:~/Lbook/code/Simple-Types/script$ usetypes.pl prueba16.c 2 1 int f() { 2 int a[30]; 3 4 return a; 5 } Type Error at line 4: Type error in return statement
El retorno vacío por parte de una función no se considera un error en C
:
pl@nereida:~/Lbook/code/Simple-Types/script$ usetypes.pl prueba26.c 2 | head -12 1 int f() { 2 int a[30]; 3 4 return; 5 } PROGRAM^{0}( FUNCTION[f]^{1}( EMPTYRETURN ) ) # PROGRAM ---------------------------
Véase la conducta de gcc
ante el mismo programa:
pl@nereida:~/Lbook/code/Simple-Types/script$ gcc -c prueba26.c pl@nereida:~/Lbook/code/Simple-Types/script$ ls -ltr | tail -1 -rw-r--r-- 1 pl users 690 2008-01-10 13:32 prueba26.o
En esta sección seguiremos una aproximación diferente. En este caso queremos maximizar nuestro conocimiento
Para comprobar la correción del tipo del valor retornado
vamos a usar el método m
.
La razón para hacerlo es familiarizarle con el uso de
m
.
Usaremos una transformación
árbol bind_ret2function
a la que llamaremos (línea 33) desde compile
después de haber verificado el resto de la comprobación de tipos (línea 30).
Podemos postponer este análisis ya que el padre de
un nodo RETURN
es un nodo FUNCTION
y por tanto
no hay nodos cuya comprobación de tipos dependa de
la computación de tipo de un nodo RETURN
.
nereida:~/doc/casiano/PLBOOK/PLBOOK/code/Simple-Types/lib/Simple> \ sed -ne '519,554p' Types.eyp | cat -n 1 sub compile { 2 my($self)=shift; 3 .. .......................................... 29 30 $t->bud(@typecheck); 31 32 our $bind_ret2function; 33 my @FUNCTIONS = $bind_ret2function->m($t); 34 35 return $t; 36 }
bind_ret2function
realiza la comprobación de
tipos en los siguientes pasos:
RETURN
en la función.
Recuerde que Parse::Eyapp::Node::m retorna nodos
Match y que los nodos del AST se obtienen usando el método
node sobre el nodo Match (línea 5)
RETURN
encontrados (línea 8)
RETURN
encontrado:
function
del nodo la función
que le anida (línea 15)
$exp->{t}
) no coincide con el declarado
en la función ($return_type
) (líneas 21-22)
RETURN
a RETURNINT
o RETURNCHAR
según sea el tipo retornado.
Al igual que en las asignaciones eliminamos la sobrecarga semántica
del nodo acercándonos a niveles mas bajos de programación.
Sigue el código.
La línea 1 muestra una simple expresión regular árbol
que casa con aquellas sentencias RETURN
en las que se ha explicitado
una expresión de retorno y que es usada por bind_ret2function
.
nereida:~/doc/casiano/PLBOOK/PLBOOK/code/Simple-Types/lib/Simple> \ sed -ne '196,225p' Trans.trg | cat -n 1 /* TIMTOWTDI when MOPping */ 2 return: RETURN(.) 3 bind_ret2function: FUNCTION 4 => { 5 my @RETURNS = $return->m($FUNCTION); 6 @RETURNS = map { $_->node } @RETURNS; 7 8 # Set "returns" attribute for the FUNCTION node 9 $FUNCTION->{returns} = \@RETURNS; 10 11 my $exp; 12 my $return_type = $FUNCTION->{t}->child(1); 13 for (@RETURNS) { 14 15 # Set "function" attribute for each RETURN node 16 $_->{function} = $FUNCTION; 17 18 #always char-int conversion 19 $exp = char2int($_, 0) if $return_type == $INT; 20 $exp = int2char($_, 0) if $return_type == $CHAR; 21 22 type_error("Returned type does not match function declaration", 23 $_->line) 24 unless $exp->{t} == $return_type; 25 $_->type("RETURN".ref($return_type)); 26 27 } 28 29 return 1; 30 }
Obsérvese que la solución no optimiza la homogeneidad ni la generalidad
ni el mantenimiento. Por ello, en condiciones normales de construcción de
un compilador - como es el caso de la práctica
13.16 -
es aconsejable abordar el análisis de tipos de la sentencia RETURN
con
la misma aproximación seguida para el resto de los nodos.