La comprobación de tipos en una llamada a función conlleva los siguientes pasos:
int a[10][20]
y int b[5][20]
se considerarán compatibles
pero int c[10][10]
y int d[10][20]
no.
La siguiente sesión con el depurador ilustra la forma del árbol de análisis en las llamadas:
pl@nereida:~/Lbook/code/Simple-Types/script$ perl -wd usetypes.pl prueba23.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(char a[10], int b) { 2 return a[5]; 3 } 4 5 int h(int x) { 6 return x*2; 7 } 8 9 int g() { 10 char x[5]; 11 int y[19][30]; 12 f(x,h(y[1][1])); 13 } Simple::Types::compile(Types.eyp:598): 598: set_types($t); # Init basic typesEjecutamos hasta la línea 598, justo después de terminar el análisis de ámbito y antes de comenzar con la fase de comprobación de tipos.
A continuación mostramos una versión compacta del árbol. Para ello suprimimos
la salida de notas a pie de página ''vaciando'' el método footnotes
:
DB<3> insert_method(qw{PROGRAM FUNCTION}, 'footnote', sub {}) # Avoid footnotes DB<4> p $t->str PROGRAM( FUNCTION[f](RETURN(VARARRAY(TERMINAL[a:2],INDEXSPEC(INUM(TERMINAL[5:2]))))), FUNCTION[h](RETURN(TIMES(VAR(TERMINAL[x:6]),INUM(TERMINAL[2:6])))), FUNCTION[g]( FUNCTIONCALL( TERMINAL[f:12], ARGLIST( VAR(TERMINAL[x:12]), FUNCTIONCALL( TERMINAL[h:12], ARGLIST(VARARRAY(TERMINAL[y:12],INDEXSPEC(INUM(TERMINAL[1:12]),INUM(TERMINAL[1:12])))) ))))) DB<6> p $t->descendant(".2.0")->str FUNCTIONCALL( TERMINAL[f:12], ARGLIST( VAR(TERMINAL[x:12]), FUNCTIONCALL( TERMINAL[h:12], ARGLIST(VARARRAY(TERMINAL[y:12],INDEXSPEC(INUM(TERMINAL[1:12]),INUM(TERMINAL[1:12]))))))) DB<7> p $t->descendant(".2.0")->{t}->str F(X_2(A_10(CHAR),INT),INT)
La sesión ilustra como la función insert_method
puede ser utilizada para
introducir métodos en las clases influyendo en la presentación del árbol. Veamos un
segundo ejemplo en el que eliminamos la presentación de la información
asociada con los nodos:
DB<8> insert_method(qw{FUNCTION TERMINAL}, 'info', sub {}) DB<9> x $t->str 0 'PROGRAM( FUNCTION(RETURN(VARARRAY(TERMINAL,INDEXSPEC(INUM(TERMINAL))))), FUNCTION(RETURN(TIMES(VAR(TERMINAL),INUM(TERMINAL)))), FUNCTION( FUNCTIONCALL(TERMINAL,ARGLIST(VAR(TERMINAL),i FUNCTIONCALL( TERMINAL, ARGLIST(VARARRAY(TERMINAL,INDEXSPEC(INUM(TERMINAL),INUM(TERMINAL)))))))))'
Sigue el código de comprobación de tipos de las llamadas:
pl@nereida:~/doc/casiano/PLBOOK/PLBOOK/code/Simple-Types/lib/Simple$ \ sed -ne '/^func/,234p' Trans.trg | cat -n 1 functioncall: FUNCTIONCALL($f, ARGLIST) 2 => { 3 # Before type checking attribute "t" has the declaration of $f 4 my $ftype = $FUNCTIONCALL->{t}; 5 6 type_error(" Variable '".$f->value."' was not declared as function", $f->line) 7 unless $ftype->isa("F"); 8 9 my @partypes = $ftype->child(0)->children; 10 11 my @args = $ARGLIST->children; # actual arguments 12 my $numargs = @args; # Number of actual arguments 13 my $numpar = @partypes; # Number of declared parameters 14 15 # Check number of args 16 type_error("Function '".$f->value."' called with $numargs args expected $numpar",$f->line) 17 if ($numargs != $numpar); 18 19 # Check type compatibility between args 20 # Do type cohercion if needed 21 for (0..$#args) { 22 my $pt = shift @partypes; 23 my $ch = $ARGLIST->child($_); 24 $ch = char2int($ARGLIST, $_) if $pt == $INT; 25 $ch = int2char($ARGLIST, $_) if $pt == $CHAR; 26 27 my $cht = $ch->{t}; 28 unless (array_compatible($cht, $pt)) { 29 type_error( 30 "Type of argument " .($_+1)." in call to " .$f->value." differs from expected", 31 $f->line 32 ) 33 } 34 } 35 36 # Now attribute "t" has the type of the node 37 $FUNCTIONCALL->{t} = $ftype->child(1); 38 return 1; 39 }
La función array_compatible
sigue la costumbre C
de
considerar compatibles arrays que difieren en la primera dimensión.
Véase la conducta de gcc
al respecto:
pl@nereida:~/Lbook/code/Simple-Types/script$ cat -n ArrayChecking.c 1 #include <stdio.h> 2 3 void f(int a[3][3]) { 4 a[1][2] = 5; 5 } 6 7 main() { 8 int b[2][3]; 9 f(b); 10 printf("%d\n",b[1][2]); 11 } pl@nereida:~/Lbook/code/Simple-Types/script$ gcc ArrayChecking.c pl@nereida:~/Lbook/code/Simple-Types/script$ a.out 5
Recordemos el código de la función array_compatible
:
pl@nereida:~/doc/casiano/PLBOOK/PLBOOK/code/Simple-Types/lib/Simple$ sed -ne '96,124p' Trans.trg | cat -n 1 { # support for arrays 2 3 sub compute_dimensionality { .. ....................................................... 14 } 15 16 sub is_array { .. .................................... 20 } 21 22 sub array_compatible { 23 my ($a1, $a2) = @_; 24 25 return 1 if $a1 == $a2; 26 # int a[10][20] and int b[5][20] are considered compatibles 27 return (is_array($a1) && is_array($a2) && ($a1->child(0) == $a2->child(0))); 28 } 29 }
pl@nereida:~/Lbook/code/Simple-Types/script$ usetypes.pl prueba07.c 2 1 int a,b,e[10][20]; 2 3 g() {} 4 5 int f(char c) { 6 char d; 7 c = 'X'; 8 g(e[d], 'A'+c); 9 if (c > 0) { 10 int d; 11 d = a + b; 12 } 13 c = d * 2; 14 return c; 15 } 16 Type Error at line 8: Function 'g' called with 2 args expected 0
pl@nereida:~/Lbook/code/Simple-Types/script$ usetypes.pl prueba22.c 2 1 int f(char a[10], int b) { 2 return a[5]; 3 } 4 5 int h(int x) { 6 return x*2; 7 } 8 9 int g() { 10 char x[5]; 11 int y[19][30]; 12 f(x,h(y)); 13 } Type Error at line 12: Type of argument 1 in call to h differs from expected