Documentos de Académico
Documentos de Profesional
Documentos de Cultura
9 Control II - Procedimientos y Ambientes
9 Control II - Procedimientos y Ambientes
// C++
void c( int& x, int& y ) // Especificación
{
int t = x; // Cuerpo
x = y; // Cuerpo
y = t; // Cuerpo
}
En algunos lenguajes y en algunas situaciones, puede separarse una especificación de procedimiento de su cuerpo, en
el caso de que la especificación deba estar disponible por adelantado:
Nótese como esta especificación no requiere que estén especificados los nombres de los parámetros.
En C++ esta clase de especificación se conoce como una declaración, mientras que la definición completa se llama
definición.
Se llama o activa un procedimiento al enunciar su nombre, junto con los argumentos de la llamada, que corresponden a
sus parámetros:
intSwap( a, b );
Una llamada a un procedimiento transfiere el control al principio del procedimiento llamado (el llamado). Cuando la
ejecución llega al final del cuerpo (o algún enunciado de tipo return), el control es devuelto al llamador.
Algunos lenguajes de programación pueden hacer la distinción entre procedimiento y funciones.
Un procedimiento se comunica con el resto del programa a través de sus parámetros y también a través de sus
referencias no locales, esto es, referencias a variables declaradas fuera de su propio cuerpo.
A:
{
int x, y;
... Registro de la activación de A
x = y * 10; x
y
B:
{
Registro de la activación de B
int i = x / 2;
i
}
}
int x;
void B( void )
{
int i = x / 2;
}
Entorno global
void A( void ) x
{
int x, y; Registro de la activación de A
... x
x = y * 10; y
B();
Registro de la activación de B
}
i
main()
{
A();
return 0;
}
Bajo la regla de alcance léxica, la x en B es la x global del programa. Por lo tanto, la activación de B debe retener
información con respecto al ambiente global.
Esto es debido a que el ambiente global es el ambiente definidor de B, en tanto que al registro de activación de A se le
conoce como ambiente invocador de B.
Para bloques que no sean procedimientos, al ambiente definidor es igual al ambiente invocador.
El método de comunicación de un procedimiento con su ambiente invocador es a través de sus parámetros.
Para escribir esta función en forma cerrada, tendríamos que incluir la operación en la lista de parámetros:
Si optamos por no hacer esto, entonces la semántica de esta función solamente puede determinarse con relación al
ambiente que la rodea y el código de esta función junto con una representación de su ambiente de definición se llama
cerradura (también llamada clausura léxica o closures), porque puede ser utilizado para resolver todas las referencias no
locales excepcionales con relación al cuerpo de la función.
Sin embargo, las asignaciones directas a los parámetros no cambia el argumento fuera del parámetro.
C C++ Pascal
void inc( int* x ) void inc( int& x ) procedure inc( var x: integer );
{ { begin
( *x )++; x++; x:= x + 1;
} } end
Después de la llamada a inc el valor del argumento aumenta en 1, de manera que ha ocurrido un efecto colateral.
Es posible el alias múltiple.
Un problema adicional que debe ser resuelto en un lenguaje con paso por referencia es la respuesta del lenguaje a los
argumentos de referencia que no son variables.
a tiene el valor 3 después de que p es llamado en el caso de que se utilice el paso por referencia, en tanto que a tiene el
valor 2 si se utiliza el paso por valor-resultado.
Los problemas en este mecanismo, son el orden en el que los resultados se copian de regreso a los argumentos y si las
ubicaciones de los argumentos se calculan solamente a la entrada y se almacenan o son recalculados a la salida.
int i;
int a[ 10 ];
main()
{
i = 1;
a[ 1 ] = 1;
a[ 2 ] = 2;
p( a[ i ] );
return 0;
}
Cuando se llame al procedimiento con la sentencia Una_Prueba(5 + P, 48, Q), se evalúan las expresiones 5 + P y 48
(sólo se permiten expresiones en el modo in), después se asignan a los parámetros formales A y B, que se comportan
como constantes. A continuación, se asigna el valor A + B a la variable formal C. Obsérvese que especificando el modo
out no se puede conocer el valor del parámetro real Q. En este caso, el parámetro formal C es una nueva variable cuyo
valor se asignará al parámetro real Q cuando finalice el procedimiento. Si se hubiera querido obtener el valor de Q,
además de poder modificarlo, se debería haber empleado C: in out Integer.
Área COMMON
Registro de activación
de programa principal
Registro de la
activación de S1
Registro de la
activación de S2
…
enlace de
control
dirección
de retorno
parámetros
pasados
variables
locales
temporales
main()
{
q(); Dirección de crecimiento de la pila
...
}
void p( int y )
{
int i = x;
char c;
...
}
void q( int a )
{
int x;
...
p( 1 );
}
main()
{
q( 2 );
return 0;
}
En el caso de las referencias no locales, por ejemplo la referencia x a en p. Si el lenguaje no permite anidar
procedimientos (C, Fortran), todas las referencias no locales por fuera de un procedimiento son realmente globales y se
asignan estáticamente.
Sin embargo, si el lenguaje permite anidar procedimientos (Pascal, Ada, Modula 2), las referencias no locales ahora
pueden ser variables locales en el alcance de procedimiento que lo rodea:
procedure q is
x: integer;
procedure p( y: integer ) is
i: integer := x;
begin
...
end p;
procedure r is
x: float;
begin
p( 1 );
...
end r;
begin
r;
end q;
En el ejemplo anterior, para encontrar la referencia no local a la x de q desde el interior de p, se podría seguir el enlace
de control hasta el registro de activación de r, pero con ello encontraríamos la x local de r, logrando un alcance dinámico
en vez de un alcance léxico.
Para lograr el alcance léxico, un procedimiento es que p mantenga un enlace a su ambiente léxico o de definición.
A este enlace se le conoce como enlace de acceso o enlace estático. Ahora cada registro de activación necesita de un
nuevo campo, e campo del enlace de acceso.