viernes, 25 de marzo de 2011

Histroria del lenguaje de Pascal

Colegio de ciencias y Humanidades Plantel Sur




Cibernetica y computación


Tema:Historia del lenguaje de pascal


Alumno: Medina Reyes Osvaldo


Grupo:671


Introduccion

Historia de pascal

El nombre es un homenaje a Blaise Pascal, creador de la "máquina aritmética" y gran matemático del siglo XVII. Y supongo que Niklaus Wirth, de la Escuela Politécnica de Zurich, creador del lenguaje Pascal, fue quien lo decidió, e impulsó su entrada en universidades y grandes empresas.

Es un lenguaje moderno, si se le compara con otros, pues se conocen sus inicios en el 1966, bajo la denominación de ALGOL W, pues partió para la creación del ALGOL 60, y su comienzo fue un ordenador de Control Data, con un procesador programado también en Pascal.

¿Que es Pascal?

El lenguaje de programación en Pascal, es un lenguaje de alto nivel, y de proposito general, lo cual quiere decir que se puede utilizar para cualquier tipo de propósitos.El lenguaje de programación en Pascal se considera un lenguaje estructurado, sencillo y practico para todos aquellos usuarios que se inician en el mundo de la programación, ya que fue creado con fines de aprendizaje.

Al ser un Pascal lenguaje estructurado, sirve de base para cualquier otro lenguaje de alto nivel, por estas caracteristicas es utilizado en las universidades e institutos de educacion para inicializar a los futuros ingenieros en sistemas o informatica.

El lenguaje de programación Pascal, es idoneo en el estudio y definicion de las estrucuras de datos, su facil definicion lo hace manejable para un programador novato.

Con la programación en Pascal, se pueden realizar desde programas formales, rutinas, utilitarios, hasta cualquier clase de video juegos.

Programación en Pascal es un lenguaje de sintaxis sencilla, muy estructurado y que comprueba exhaustivamente todo tipo de datos.

El mejor de los propósitos de programación en Pascal es que enseña buenas formas de programación, con lo cual se utiliza mucho en la enseñanza, por todos los motivos nominados anteriormente, por su sencillez, su estructuración y su facilidad de lectura y entendimiento.

Existen varios dialectos locales de programación en Pascal, entre ellas el Turbo Pascal, el cual acepta intrucciones de Pascal.

En 1971 se publicó oficialmente en el Acta Informática bajo el título "La programación en lenguaje Pascal", si traduzco correctamente "The programming language Pascal". Y cuatro años más tarde volvió a publicarse la mayor parte del código en el mismo Acta. Era la versión estándar y precisaba ordenadores potentes (teniendo en cuenta las fechas de las que hablamos), pero hubo rápidas ampliaciones o mejor dicho, derivaciones, concretamente la UCSD Pascal desarrollada por Kenneth Bowles que elimina parte del código original para que pueda ejecutarse en ordenadores más pequeños. La otra que surgió por aquellos años lo hizo de la mano de Apple, por supuesto con el interface gráfico que siempre ha caracterizado a sus ordenadores, y diseñada exclusivamente para ellos. No creo que ni siquiera se pensase entonces en entornos gráficos por los fabricantes de software de cualquier otra empresa.

Aquellos que manejen hoy en día Pascal, o que han seguido su rumbo, conocen perfectamente lo que es básico en el lenguaje. En todos estos años la sintaxis básica no ha cambiado. Lo que hoy conocemos como un "procedimiento" o bloque independiente de código, se llamaba de la misma forma cuando se creó. Veamos como es así:

- La estructura, que es la parte que más se ha modificado, porque es una necesidad dado que hoy Pascal es un lenguaje orientado a objetos, básicamente contiene los mismos bloques: uno de cabecera donde se declaran variables y constantes, tipos (mandatos "Type", no confundir con tipos de datos), procedimientos, funciones, y poco más. Y ha continuación de ello lo que es el programa o contenido del procedimiento en sí, que igual que hoy se divide entre el "Begin" y el "End."

- Los operadores, salvo error, son los mismos. Pero difiere en algo en cuanto a tipos de datos definidos por el lenguaje, ese apartado se ha ido enriqueciendo en las sucesivas modificaciones, aunque básicamente sean igualmente numéricos, booleanos y de caracteres, y además permite la creación de los que no vienen predefinidos.

- Así que acepta la definición de datos. El más llamativo es el "Real", ya que en origen solo contiene valores enteros. Y además otros que estamos utilizando ahora mismo:
1. Enumerados o tipo escalar que pueden definirse exactamente igual que hoy.
2. Los tipos estructurados, como son los "Registros" (tan arraigados y potentes en varios lenguajes además de Pascal, como en lenguaje C), así podemos escribir:

NombreDelRegistro = Record
Declaración de elementos del registro.

3. Conjuntos. De la misma forma utilizando la cláusula "Set of".

4. La capacidad de los punteros en el Pascal de sus primeros tiempos, se ha perdido dada la tendencia de los programadores de sistemas a ocultar herramientas de gran potencia.







- En cuanto a estructuras tiene las condicionales "If" y "Case" que son las que se manejan en estos momentos





- En iteraciones o bucles o estructuras repetitivas (la definición a gusto de cada cual) tiene las tres que usamos: "While", "For" y "Repeat".
- La recursividad se puede utilizar de forma habitual, es una posibilidad mas del lenguaje.
- El paso de parámetros a procedimientos y funciones es muy similar, aceptando el de "valor" y el de "referencia"
- El manejo de ficheros, aún con muchas instrucciones iguales, incluso pienso que la mayoría, sí que varía, pero es muy lógico, los archivos se han modificado en unos casos, son nuevos en otros.

Y aunque la esencia del lenguaje sea la misma, como creo que se ha podido ver, otros aspectos ha sufrido fuertes modificaciones. Así aparece el Turbo Pascal, el Object Pascal (Pascal dirigido a objetos), el actual de fuentes abiertas o Free Pascal, y por último y entiendo que el más potente, el que toma como base el lenguaje y lo convierte en una RAD, que es Delphi, de la empresa Borland.


Lenguajes
de
programación



Una declaración de procedimiento en Pascal tiene la forma siguiente:
procedure ()

begin

end;

Este formato es muy similar al utilizado en Algol, e incluso las reglas de entorno son
las mismas (es decir, son también estáticas).
Pascal, sin embargo, añade una restricción adicional relacionada con el orden de las
declaraciones: los nombres deben asociarse antes de usarse, para permitir la
compilación en un solo paso.

Esto tiene dos problemas:
1) Los métodos de programación estructurada motivan a los programadores a
organizar sus programas de “arriba hacia abajo” (top-down). Es decir, los
procedimientos superiores se definen primero y luego los inferiores, que son a
los que éstos invocan, se definen después.
Debe resultar por tanto muy evidente que este esquema de programación es
exactamente lo contrario de lo que requiere Pascal. En contraste, el lenguaje C sí
tiene una estructura de “arriba hacia abajo”.
2) Adicionalmente, los procedimientos mutuamente recursivos no pueden
definirse antes de ser invocados. Este es un problema más serio y requirió que el
comité de estandarización de Pascal optara por agregar una declaración llamada
“forward” para resolverlo.

procedure Q ( . . . ); forward;
procedure P ( . . . );
begin
:
Q( . . . );
:
end;
procedure Q;
begin
:
P( . . . );
:
end;


La mayor parte de los dialectos de Pascal requieren que las declaraciones en un
procedimiento o en un programa se encuentren en un cierto orden: etiquetas,
constantes, tipos, variables y subprogramas.
Esto suena razonable pero podría resultar inconveniente en programas más grandes,
puesto que impide al programador agrupar las declaraciones relacionadas de
constantes, tipos, variables y subprogramas.
Este problema ha sido resuelto mediante el mecanismo de encapsulamiento que
proporcionan los lenguajes de cuarta generación.

Pascal elimina el bloque usado en Algol, y lo mantiene sólo para las sentencias
compuestas. Es importante recordar que la diferencia es que un bloque puede
contener declaraciones locales y sentencias, mientras que una sentencia compuesta
contiene sólo sentencias.
Con esta decisión, el almacenamiento en Pascal puede compartirse sólo entre
procedimientos disjuntos, complicando el uso eficiente de memoria.


Estructuras de Control


Pascal tiene más estructuras de control que Algol, pero éstas son más simples.
Todas sus estructuras de control tienen un punto de entrada desde la sentencia
previa y un punto de salida hacia la sentencia siguiente
El ejemplo clásico es la sentencia if-then-else, la cual es exactamente igual a la de
ALGOL.
Esta propiedad de contar con un solo punto de entrada y un solo punto de salida
simplifica los programas al satisfacer el Principio Estructural (la estructura estática
del programa corresponde en una manera simple con su estructura dinámica)
Pascal cuenta con una sentencia GOTO, aunque rara vez se necesita debido a la
riqueza de sus estructuras de control


Una observación importante acerca del GOTO en Pascal es que, al igual que en
ALGOL, se permiten las transferencias no locales, con todas las ineficiencias
asociadas a ellas en lo que a la implementación se refiere
Al igual que la mayoría de los descendientes de ALGOL, Pascal tiene
procedimientos totalmente recursivo.


La sintaxis para un ciclo for en Pascal es:
for := to|downto do

¿Qué problemas le ve al ciclo for


Los incrementos o decrementos sólo se pueden hacer
a pasos unitarios.
Este constructor debería permitir el uso de incrementos no unitarios (por
ejemplo, fracciones decimales), puesto que el diseño del lenguaje no se
complicaria mucho más con esta modificación, y el constructor se haría mucho
más poderoso para el programador.

El ciclo for es un iterador definido, es decir una estructura que itera durante un
número definido (predecible) de veces.
Pascal proporciona dos iteradores indefinidos:

while do
repeat until
El primero es un ciclo con la decisión al principio y el segundo es un ciclo con la
decisión al final.13

Pascal no proporciona un iterador para tomar decisiones en medio, así que tiene que
usarse GOTO para este tipo de ciclos:
while true do
begin
. . . primera mitad del ciclo . . .
if then goto 99;
. . . segunda mitad del ciclo . . .
end;
99:14


¿Puede eliminarse el GOTO si se incluye un ciclo con la decisión en medio?
Algunos lenguajes modernos como Ada proporcionan un iterador indefinido con la
decisión en medio, haciendo innecesario el uso del GOTO.

Sentencia para Casos


La sentencia para casos con etiquetas es una contribución importante de Pascal y
fue diseñada por C.A.R. Hoare.


Sintaxis:
case of
: begin . . . . . . end;
: begin . . . . . . end;
.
.
.
: begin . . . . . . end
end

Esta sentencia proporciona un mecanismo seguro que está auto-documentado (sigue
el Principio de Etiquetamiento). Es decir, no depende del programador el
documentar adecuadamente cada uno de los casos posibles.
La sentencia para casos también es muy eficiente, porque el compilador puede
determinar el tipo de expresión de selección de casos que necesita y, por tanto, los
valores posibles que dicha expresión puede tener.

Mecanismos de
paso de parámetros



Pascal eliminó el paso de parámetros por nombre y sólo permite el paso por valor y
el paso por referencia. Sin embargo, en este caso, el programador debe especificar
qué mecanismo utilizar, en vez de hacer que el compilador use siempre el mismo
(como en FORTRAN).
El paso por valor y el paso por referencia son mecanismos mejor conocidos y los
programadores pueden lidiar con ellos de manera más fácil que con el paso por
nombre.19

El único problema con estos 2 mecanismos de paso de parámetros es que en algunos
casos los programadores podrían pasar algo por referencia simplemente porque es
más eficiente (en términos de uso de memoria), poniendo en peligro la seguridad de
sus programas y causando confusión entre otras personas que lean este código.
La raíz de este problema es que dos cuestiones ortogonales están siendo
confundidas:
1) La decisión de si un parámetro debe ser usado para entrada o para salida.
2) La decisión de si debe copiarse su valor o pasarse la dirección de su valor.

Lenguajes modernos como Ada han separado mejor estas decisiones al usar un
mecanismo de paso de parámetros que se deriva del “paso por constante”, que es un
modo que se incluía en el reporte original de Pascal en vez del paso por valor.
Un parámetro pasado por constante es considerado como una constante dentro del
cuerpo del procedimiento invocado; por lo tanto, no es legal usar ese parámetro
como el destino de una asignación.
También es ilegal usar este parámetro en cualquier otro contexto donde funja como
destino, tal y como un parámetro de invocación pasado por referencia. Por lo tanto,
el compilador protege la seguridad de los parámetros pasados por constante.

Puesto que el compilador previene que un parámetro pasado por constante sea
alterado, el compilador puede elegir si pasa el valor del parámetro o su dirección (lo
que resulte más eficiente).
Por ejemplo, para valores pequeños podría simplemente copiar el valor, mientras
que para valores grandes (p.ej., arreglos), podría pasar un apuntador a la estructura
correspondiente.
Esto ahorra tiempo y espacio y no introduce ningún peligro puesto que el
compilador impide las asignaciones a constantes.
¿Por qué se eliminó entonces el paso por constante de Pascal? Probablemente
debido a que Pascal permite ciertas formas limitadas de “aliasing” a través del uso de
variables globales.

type vector = array [1..100] of real;
var A : vector;
procedure P (x : vector);
begin
writeln(x[1]);
A[1]:=0;
writeln(x[1]);
end;
begin
P(A)
end.


En este ejemplo, ‘x’ y ‘A’ son ambos alias del mismo arreglo. Puesto que ‘x’ se pasa
por constante, el compilador puede elegir pasar la dirección de ‘A’ a P. Sin embargo,
si efectuamos la asignación a A[1] dentro de P, el valor del arreglo se alterará.
En consecuencia, los resultados producidos por los 2 writeln(x[1]) podrían ser
diferentes, a pesar de que ‘x’ nunca se accesó directamente.

Parámetros Procedurales


Para restaurar algo de la flexibilidad perdida al omitir el paso de parámetros por
nombre, Pascal permite que se pasen procedimientos y funciones como argumentos.
En el Reporte Revisado de Pascal, los procedimientos o funciones pueden pasarse
simplemente definiéndolos como parámetros, pero sin necesidad de especificar sus
propios parámetros

Ejemplo:
procedure difsq (function f:real, x:real) : real;
begin
difsq := f(x*x) - f(-x*x)
end;
Esto introduce un error muy serio de seguridad en Pascal, puesto que es
prácticamente imposible detectar cualquier uso erróneo del procedimiento pasado
como parámetro.

Por esta razón, el Pascal estándar requiere que los programadores especifiquen los
parámetros de un procedimiento que se pasa como parámetro.
Ejemplo:
procedure difsq (function f(y:real):real, x:real): real;
begin
difsq := f(x*x) - f(-x*x)
end;

Esto permite al compilador hacer un chequeo completo de tipos, preservando el
chequeo fuerte de tipos. Sin embargo, también incrementa la complejidad del
lenguaje, y parece implicar que los procedimientos son ciudadanos de primera clase
en Pascal (y no lo son).
Si se usan procedimientos como parámetros, probablemente deba esperarse que uno
sea capaz de usarlos en declaraciones de variables.
Sin embargo, de ser así, el lenguaje tendría que definir el significado de variables
procedurales, arreglos de procedimientos, funciones con valores procedurales,
archivos de procedimientos, etc.

Hay muchas cuestiones complejas de diseño involucradas en estos conceptos. Por lo
tanto, probablemente los procedimientos no debieran ser considerados ciudadanos
de primera clase en un lenguaje estructurado (como el caso de Pascal).
El problema es que si los procedimientos pasan a ser ciudadanos de segunda clase, se
introduce una excepción al lenguaje y, en consecuencia, éste se torna más complejo.

Implementación de los Lenguajes Estructurados

Los registros de activación, como su nombre lo indica, llevan el registro del estado
de activación de un procedimiento.
Para saber el estado de activación de un procedimiento, necesitamos saber lo
siguiente:
1) El código o algoritmo, que forma el cuerpo del procedimiento.
2) El lugar en ese código donde se está ejecutando esta activación del
procedimiento.
3) Los valores de todas las variables visibles a esta activación.
Puesto que el código o algoritmo no cambia durante la ejecución del procedimiento,
no se almacena en el registro de activación.

Sin embargo, los otros dos elementos (puntos 2 y 3 de los antes mencionados) deben
almacenarse porque pueden cambiar entre instancias de la ejecución de un
procedimiento.
Esto significa que tenemos que dividir la representación del estado de un
procedimiento en dos partes:
1) Una parte fija del programa.
2) Una parte variable del registro de activación.

Un registro de activación tiene también dos partes:
1) La parte de la instrucción (IP), que designa la instrucción actual que está
siendo (o por ser) ejecutada en esta activación del procedimiento.
2) La parte del ambiente (EP), que define el contexto a usarse para esta
activación del procedimiento.
La parte del ambiente consiste a su vez de otras 2 partes:
1) El contexto local (asociaciones locales; p.ej., variables locales)
2) El contexto no local (asociaciones no locales; p.ej., variables globales o el
ambiente anterior).
Toda variable es local a algún procedimiento. Por lo tanto, toda variable puede
encontrarse en el registro de activación de algún procedimiento.

Para proporcionar acceso a las variables no locales de un procedimiento, es
necesario proporcionar acceso a los registros de activación de los procedimiento
para los cuales dichas variables son locales.
La forma más simple de hacer esto es manteniendo un apuntador al registro de
activación del procedimiento que rodea el actual. Esto implica que necesitamos una
liga desde cada contorno al que rodee a éste.
Juntas, estas ligas forman una cadena que nos lleva del registro de activación activo
en ese momento (el cual contiene la EP) al más exterior (o activación global). A esta
liga se le llama “liga estática” (y a la cadena, “cadena estática”), porque refleja la
estructura estática del programa, o sea, la forma en la que se anidan los
procedimientos.

El registro del apuntador del ambiente (EP) apunta hacia el registro de activación
del contexto activo en ese momento. De tal forma, diremos que éste es el registro
de activación “actual”.
El registro del Apuntador de la Pila (SP) apunta siempre a la parte superior de la pila
del sistema. Llamaremos “lugar de control” a la pareja formada por los registros IPEP, porque ellos dos definen la instrucción y el contexto que controla a la
computadora.


Para accesar una variable, necesitamos dos pasos:
1) Recorrer la cadena estática en tiempo de ejecución tantas ligas como nos
indique la distancia estática que haya entre nuestra posición actual y el registro
de activación en el que reside la variable deseada.
2) La dirección de la variable se obtiene sumando el desplazamiento (offset) fijo
de la variable con respecto a la dirección obtenida en el paso anterior. Este
“desplazamiento” es también una constante calculada por el compilador


Los elementos que necesitan almacenarse en un registro de activación para un
lenguaje estructurado que permite recursividad son los siguientes:
1) Los parámetros y las variables locales.
2) La liga estática (proporciona acceso al entorno circundante (no local)).
3) La dirección de continuación de ejecución del procedimiento o función.
4) La liga dinámica (nos permite restaurar el estado del invocador al salir de un
procedimiento), la cual apunta hacia el registro de activación del invocador de
esta activación de este procedimiento.
Necesitamos tanto la liga estática como la dinámica,ya que una nos llevará al
ambiente en el cual se definió un procedimiento/función (hay que recordar que la
mayoría de los lenguajes estructurados usan reglas de entorno estáticas) y la otra nos
llevará al procedimiento que nos invocó.



Costos de la Implementación
de una Cadena Estática


Accesar una variable: sd+1 referencias de memoria.
Primero, necesitamos atravesar la cadena estática tantas veces como registros de
activación (RAs) nos indique “sd” (la distancia estática). De esta manera
llegaremos al RA actual que contiene el ambiente de la variable deseada.
Posteriormente, agregamos el desplazamiento a ese valor para localizar la
posición precisa de la variable dentro de su registro de activación
correspondiente. Esto requiere una referencia adicional de memoria.

Invocación de un procedimiento: sd+3 referencias de memoria.
Se necesita una referencia para almacenar el IP (Apuntador de Instrucción) del
invocador, sd referencias para atravesar la cadena estática y 2 referencias para
establecer las ligas estática y dinámica.
Nótese que en este caso estamos ignorando el tiempo requerido para almacenar los
parámetros pasados al procedimiento.


Retorno de un Procedimiento: 2 referencias de memoria.
Se requiere una referencia para reinstalar el contexto del invocador (siguiendo la
Liga Dinámica). La otra referencia se usa para continuar la ejecución (usando el
IP) a partir del punto donde nos quedamos en el ambiente anterior.

Pasar un procedimiento como parámetro: sd+2 referencias de memoria.
Se requieren sd referencias para accesar el ambiente de definición del
procedimiento pasado como parámetro, y 2 más para almacenar el EP
(apuntador de ambiente) y el IP (apuntador de instrucción).
Invocación a un procedimiento definido como parámetro: 5 referencias de memoria.
Una se requiere para almacenar el IP, una para fijar la Liga Dinámica, una para
establecer la liga estática, una para instalar el RA del invocado y una más para
entrar al ambiente del invocado.

Goto: sd referencias de memoria.
Tenemos que llegar al ambiente donde se ha declarado la etiqueta, y eso podría
significar atravesar una larga porción de la cadena estática.
Esa es la razón por la que se debe evitar al máximo el uso de goto’s no locales en los
lenguajes estructurados, puesto que son muy costosos desde el punto de vista de la
implementación.

¿Por qué resulta difícil regresar un procedimiento en un lenguaje estructurado?
Porque tendríamos que mantener el RA de un procedimiento aún después de
que hubiese terminado de ejecutarse (normalmente el RA de un procedimiento
se remueve de la pila una vez que concluye su ejecución).
Por lo tanto, el uso de una pila de registros de activación no funcionará en este caso
y se requiere de otro tipo de implementación. Esa es la razón por la que los lenguajes
funcionales usan un esquema distinto de manejo de memoria (la recolección de
basura).

Método de los “Displays”


Podemos usar un enfoque alternativo en el cual se emplea un arreglo que contiene
apuntadores a todos los contextos accesibles utilizados. A este arreglo se le
denomina “display”, y el nombre se hace extensivo para el método también.
Si D es el arreglo, entonces “D[i]” es un apuntador al registro de activación del
ambiente en el nivel de anidamiento estático “i”.
Advierta que no se requiere el registro EP, puesto que el compilador sabe a qué nivel
se ejecutará cada sentencia.
Tampoco hay necesidad de la Liga Estática, puesto que el “display” realiza esta
función.

Acceso a una variable: 2 referencias de memoria.
Con este método, podemos accesar una variable usando sólo 2 referencias de
memoria sin importar dónde se encuentre la variable.
Esto es porque sólo necesitamos una referencia para obtener el RA apropiado y
luego otra más para localizar a la variable dentro del RA correspondiente.
En algunas implementaciones, el “display” se almacena en registros de alta velocidad,
lo que significa que sólo se requiere una referencia de memoria.

Invocación a un Procedimiento: 6 referencias de memoria.
Cuando invocamos un procedimiento, podríamos potencialmente perder el
contenido del “display” en el nivel actual de anidamiento, o a un nivel inferior al
actual.
Puesto que no queremos perder esta información, porque la necesitaremos para
reactivar el “display” una vez que termine de ejecutarse el procedimiento, entonces
necesitamos almacenarla.
Normalmente, se reserva espacio dentro del RA para poder contar con esta
información cuando regresemos de la invocación a un procedimiento.
Además de esta información, necesitamos almacenar los parámetros, la dirección de
retorno (donde continuará la ejecución en el segmento de código donde está el
invocador) y la liga dinámica del procedimiento.


Por lo tanto, necesitamos 6 referencias de memoria: una para almacenar la dirección
de retorno, una para almacenar el elemento del “display”, una para almacenar la liga
dinámica, una para instalar el nuevo RA, una para reservar espacio para el RA del
invocado y una más para entrar al procedimiento invocado. Nótese que no se está
incluyendo el tiempo requerido para transmitir los parámetros.

Regreso de un Procedimiento: 5 referencias de memoria.
Regresar de un procedimiento simplemente invierte las operaciones de la
invocación a un procedimiento. Necesitamos seguir la Liga Dinámica para ver
quién llamó a este procedimiento.
Se requieren 2 referencias de memoria puesto que primero debe usarse el display
para obtener el RA adecuado y se requiere una referencia más para poder seguir la
Liga Dinámica.
El siguiente paso es remover el RA del procedimiento invocado de la pila (una
referencia de memoria). Luego, restauramos el “display” de forma que apunte hacia
el RA del invocador (una referencia más de memoria). Finalmente, continuamos la
ejecución del invocador (una referencia de memoria).

Comparación de Enfoques


Realmente es relativo el poder determinar cuál de los dos enfoques es mejor. Esto
realmente depende de la frecuencia relativa (en tiempo de ejecución) con que se
efectúan invocaciones a procedimientos y accesos a variables, así como también
de la distancia estática promedio de cada una de éstos.

Puesto que la mayoría de los programas realizan más accesos a variables que
invocaciones a procedimientos, suele preferirse el método de los “displays” al de la
cadena estática.
Sin embargo, es importante aclarar que estos dos métodos no son los únicos que
existen. Hay otros, como la “asociación superficial” (shallow binding), que también
es usada comúnmente para implementar lenguajes estructurados.

Bloques


ALGOL y Pascal tienen otro constructor que define entornos: el bloque.
Recordemos que los bloques son similares a los procedimientos, pero no toman
parámetros y tienen una definición más simple. Resulta muy fácil implementar
bloques usando cualquiera de las dos técnicas antes descritas.
Usando la cadena estática, podemos implementar la entrada a un bloque igual que la
entrada a un procedimiento. Esto significa que tenemos que crear un registro de
activación para el bloque en el momento de entrar a él.

Sin embargo, sólo necesitamos almacenar la siguiente información:
-Variables locales
-Dirección de continuación
-Liga Estática
No podemos tener parámetros para los bloques, de forma que no necesitamos
reservar espacio para ellos. Tampoco se necesita la Liga Dinámica porque los
contextos estáticos y dinámicos previos de un bloque son siempre los mismos.

Hay que recordar que los bloques no tienen nombre (son anónimos) y por lo tanto,
pueden ser activados sólo en un contexto (aquél en el cual están textualmente
anidados). Por lo tanto, para un bloque, el ambiente de definición y el ambiente de
activación son los mismos.
Necesitamos almacenar la dirección de continuación, porque un bloque puede
invocar a un procedimiento, y necesitamos espacio para almacenar su estado de
ejecución.
Una vez que el bloque termina, su RA es removido de la pila, tal y como en el caso
de los procedimientos.
Sin embargo, en este caso no tenemos que saltar hacia otro lado, puesto que la
dirección de continuación siempre es la que sigue inmediatamente a la finalización
del bloque.

Usando “displays”, pueden implementarse los bloques de manera similar. Primero
reservamos espacio para el RA de un bloque en el momento de entrar a él y
colocamos el “display” correspondiente apuntando hacia su ambiente de
anidamiento estático.
El contenido previo del “display” en esa posición tiene que almacenarse en el RA del
bloque. Esto requiere 3 referencias de memoria (para actualizar el “display”).
La salida de un bloque es todavía más simple. Todo lo que se requiere es borrar el
RA del bloque y restaurar el “display”. Sólo se requieren 2 referencias de memoria
para esto.

No hay comentarios:

Publicar un comentario