

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 types
Ejecutamos 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

