= Tabla de Símbolos =
Tabla de Símbolos:
Estructura utilizada por el compilador para almacenar información(atributos) asociada a los símbolos declarados en el programa en compilación.
Puede contener adicionalmente:
–símbolos temporales
–etiquetas
–símbolos predefinidos
•Conceptualmente: colección de registros
•Estructura fuertemente influenciada por aspectos sintácticos y semánticos del lenguaje: Código
•Los tipos disponibles en el lenguaje: determinan el CONTENIDO de la tabla.
•Las reglas de ámbito: determinan la visibilidad de los símbolos, e.g., el MECANISMO DE ACCESO a la tabla.
= Contenido de la tabla =
•Palabras reservadas:tienen un significado especial; NO pueden ser redefinidas.program beginend type vararrayif...
•Símbolos predefinidos: Tienen un significado especial, pero pueden ser redefinidos.
•Literales, constantes que denotan un valor
var a:
record
b,c : integer;
end;
•Símbolos generados por el compilador:
-Genera el símbolo noname1 para el tipo anónimo correspondiente al registro.
•Símbolos definidos por el programador.
–Variables: tipo, lugar en memoria, ¿valor? ¿referencias?.
–Tipos de datos : descripción.
–Procedimientos y funciones: dirección, parámetros, tipo de resultado.
–Parámetros: tipo de variable, clase de parámetro.
–Etiquetas: lugar en el programa.
El contenidos de las tablas de símbolos. Operaciones y organización. Atributos, lenguajes no estructurados y estructurados en bloques, representación OO de símbolos y tipos en compiladores de una pasada.
= Administración de la tabla de símbolos =
El análisis semántico conecta las definiciones de las variables con sus usos, checa que cada expresión tenga un tipo correcto y traduce la sintaxis abstracta a una representación mas simple para generar código maquina.
Esta fase es caracterizada por el mantener la tabla de símbolos, la cual mapea identificadores con sus tipos y localidades, también esta tabla puede ser llamada environment, donde cada variable local en un programa tiene un ámbito o scope dentro del cual es visible.
Un ambiente es un conjunto de atados denotados por à.
= Manejo de errores semánticos =
Cuando el checador de tipos detecta un error de tipos o un identificador no declarado, debe imprimir el mensaje de error y continuar.
Esto debido a que normalmente el programador prefiere que le describan todos los errores posibles del programa fuente.
Esto quiere decir, que si un error de tipos es encontrado, no debe producirse un programa objeto por parte del compilador.
Así, las siguientes fases no deben ejecutarse.
Hasta esta etapa (chequeo de tipos), la parte del compilador se conoce con el nombre de “front End”.
REGISTROS DE ACTIVACION
En casi cualquier LP, una función (método) puede tener variables locales que son creadas cuando se llama la función (al entrar a esta).
Diferentes invocaciones a la función pueden existir a la vez, y cada invocación tiene su propia “instanciación” de variables.
En el siguiente método de Java
Int f(int x) {
int y= x+x;
if (y<10)
return f(y);
else
return y-1;
Una nueva instancia de x es creada (e inicializada por el llamador de “f”) cada vez que “f” es llamada. Debido a que existen llamadas recursivas, muchas de esas x existen simultáneamente. Similarmente, una nueva instancia de y es creada cada vez que el cuerpo f es iniciado.
En muchos LP (incluyendo Pascal, C y java), las variables locales son destruidas cuando una función retorna. Ya que las variables locales son creadas y destruidas en una forma LIFO, podemos usar una pila para manejarlas.
• Si los traductores tuvieran que procesar programas
correctas el proceso de implantación se
simplificaría mucho.
• ¿Cómo debe de responder un compilador de
pascal a un código Fortran?
• Ningún método de recuperación de errores
resuelve todos los problemas
Tipos de errores
• Léxicos: como escribir mal un identificador, palabra
clave u operador.
• Sintácticos: como una expresión aritmética con
paréntesis no equilibrados.
• Semánticos: como un operador aplicado a un
operadorando incompatible.
• Lógicos: como una llamada infinitamente recursiva
• La mayoría de los errores se centra en la
fase de análisis sintáctico.
• El manejador de errores debe:
• Informar la presencia de errores con claridad
y exactitud.
Administrador de errores
• Recuperar de cada error con la suficiente
rapidez como para detectar errores posibles.
• No debe retrasar de manera significativa el
procesamiento de programas correctos.
• Debe indicar la línea del error y algún
mensaje informativo
Estrategias de recuperación de
errores
• Modo Pánico
• Nivel de Frase
• Producciones de error
• Corrección global
Recuperación en modo pánico
• Es el más sencillo de implantar.
• El analizador sintáctico desecha
componentes léxicos hasta encontrar un
carácter de sincronización. Estos caracteres
son el punto y como (;) entre otros.
int a.b,c;
struct c {
….
}
main()
{
int a;
}
Recuperación a nivel de frase
• Esta técnica utiliza una corrección de
caracteres adyacentes, ya sea por inserción,
eliminación o intercambio.
• Esta técnica permite sustituir , por ;, etc. Son
traductores que corrigen errores.
Desafortunadamente para muchos casos no
aplican por lo que no se utilizan demasiados.
Producciones de error
• Se pueden generar gramáticas para generar
producciones de error y así de esta forma seguir
con el proceso.
• La dificultad radica en el sentido de encontrar esas
reglas gramaticales para generar error. En algunos
casos sería inclusiva más extensa que la gramática
del propio lenguaje.
• for(i<3, a<10; i++)
Corrección global
• Idealmente, sería recomendable que un
traductor hiciera el mínimo de cambios para
procesar una entrada inválida. Este algoritmo
genera menores costos globales para
realizar cambios.
• El problema radica en que el implementar
estas estrategias son muy costosas en
tiempo y espacio.
= Generadores de código para analizadores sintácticos = YACC/BISON
• YACC (YET ANOTHER COMPILERCOMPILER):
provee una herramienta
general para describir la entrada de un programa de computación.
El usuario de YACC especifica las estructuras de su entrada, junto con el código que será invocado en la medida en que cada una de
esas estructuras es reconocida.
• YACC convierte esa especificación en una subrutina que maneja el proceso de entrada.
• La subrutina de entrada producida por YACC llama a la rutina provista por el usuario para devolver el próximo ítem básico de la entrada.
• GNU Bison es un generador de parsers de propósito general que convierte una descripción gramatical desde una gramática libre de contexto LALR en un programa en C para hacer el parser.
• Es utilizado para crear parsers para muchos lenguajes, desde simples calculadoras hasta lenguajes complejos.
• GNU Bison tiene compatibilidad con Yacc:
todas las gramáticas bien escritas para Yacc, funcionan en Bison sin necesidad de ser modificadas.
• Cualquier persona que esté familiarizada con Yacc podría utilizar Bison sin problemas.
Es necesaria experiencia con C para utilizar Bison
• Yet Another Compiler-Compiler
• Analizador.y (#include “lex.yy.c”) bison
analizador.c (y.tab.c) gcc analizador
• $gcc analizador.c –o analizador -lfl
Estructura de un programa en Bison
%{
Declaraciones globales C
}%
Declaraciones bison
%%
Gramáticas
Nombre:prod1|prod2|…|prodn;
%%
Código auxiliar C
Tips
• Todo lexema debe ser un entero
#define VAR 200 (256)
return (VAR);
Gramática vacía
Gramática: prod1|
prod2|
;
= R a k n A r r o K =
Que fea Edición xD
ResponderBorrar