Capítulo 8. Intérpretes
Los intérpretes realizan normalmente dos operaciones:
- Traducen el código fuente a un formato interno (esta operación no es
estrictamente indispensable).
- Ejecutan o interpretan el programa traducido al formato interno.
El formato interno podría ser simplemente el resultado del análisis
morfológico, o llevar realizada cierta dosis de análisis sintáctico/semántico,
como la traducción a notación polaca inversa o a cuádruplas. La primera parte
del intérprete se llama a veces "el compilador", aunque el código interno que
genera no es el lenguaje de la máquina, ni siquiera lenguaje simbólico, ni
tampoco un lenguaje de alto nivel.
En el lenguaje JAVA, las dos partes se han separado por completo, y tenemos
el compilador de JAVA, que traduce los fuentes a
bytecode, y el intérprete de JAVA, que en realidad
interpreta bytecode.
Lenguajes interpretativos
Algunos lenguajes no pueden compilarse por completo al lenguaje de la
máquina por uno de los motivos siguientes:
- Porque contienen operadores que precisan de la presencia del intérprete,
como aquéllos que ejecutan en tiempo de ejecución cadenas de caracteres que
representan instrucciones del lenguaje fuente (APL, LISP, Prolog, Smalltalk).
- Porque han eliminado totalmente la declaración de las variables, de tal
modo que una variable tiene siempre el tipo del último valor que se le asignó
(APL, LISP, Smalltalk).
- Porque se ha eliminado la gestión dinámica de la memoria, confiándole al
intérprete la eliminación automática de la memoria no utilizada (APL, JAVA,
LISP, Smalltalk).
- Porque la presencia del intérprete durante la ejecución es necesaria por
razones de seguridad o de independencia de la máquina (JAVA).
Entre los lenguajes interpretativos destacan APL, JAVA, LISP, Prolog, Rexx,
Smalltalk y SNOBOL.
Ventajas de un intérprete
- Flexibilidad: permite realizar acciones complejas, imposibles o muy
difíciles con un compilador, como las siguientes:
- Ejecución de cadenas de caracteres mediante operadores como "execute",
"interprete" o "evalquote".
- Modificar sobre la marcha el significado de los símbolos e incluso
prescindir por completo de las declaraciones.
- Obtener un ligamiento dinámico completo en los sistemas
orientados a objetos.
- Simplificar la gestión de memoria en los programas fuente.
- Facilidad de depuración de programas: la interpretación puede
interrumpirse en cualquier momento para examinar o modificar los valores de
las variables o la situación en la ejecución. La tabla de símbolos está
disponible. Se pueden corregir los errores y continuar. Trazas y paradas
programadas. Saltos en el programa. Abandonos de subrutinas.
- Rapidez en el desarrollo.
Desventajas de un intérprete
- Velocidad: usualmente un orden de magnitud menor que la de un programa
compilado.
- Tamaño del programa objeto, que exige añadir el intérprete al programa
propiamente dicho.
Uso de los intérpretes
Los intérpretes se usan principalmente:
- Para el desarrollo de prototipos.
- Para la enseñanza.
- Cuando el lenguaje tiene características que exigen un intérprete (Lisp,
APL, REXX, Smalltalk, Prolog).
- Cuando el lenguaje dispone de operadores muy potentes, lo que significa
que la mayor parte del tiempo los programas están ejecutando código rápido
prefabricado, más que los programas fuente del programador (APL, SNOBOL).
- Para obtener independencia de la máquina (JAVA).
- Para aumentar la seguridad (JAVA).
Generación de código en un intérprete
- La gestión de registros durante la ejecución es innecesaria. El propio
intérprete la realiza.
- Las conversiones de tipo pueden aplazarse. Esto puede tener ventajas e
inconvenientes, y normalmente habrá que buscar un equilibrio entre la
ocupación de memoria y el tiempo de ejecución.
- Durante el análisis sintáctico, la información semántica asociada a los
operandos de las expresiones suele generarse sobre plataformas de
operandos, es decir, vectores de estructuras que contienen toda la
información asociada al operando izquierdo, el operando derecho y el resultado
de la operación.
Tipos de estructura de intérpretes
- Algunos intérpretes utilizan una tabla de símbolos de tamaño fijo, cuyos
elementos apuntan directamente a la memoria asignada a las variables.
- Otros tienen tablas de símbolos cuyo tamaño puede modificarse de forma
dinámica.
- En algunos, la tabla de símbolos no apunta directamente a la memoria
asignada a las variables, sino que lo hace a través de una tabla de
referencias intermedia, que lleva la cuenta del número de punteros que apuntan
en un momento dado al objeto de que se trate. Esto simplifica la recolección
de desechos y la gestión de la memoria, a costa de aumentar el tiempo de
acceso a las variables, pues hay que atravesar un direccionamiento indirecto
más.