Subido por ineverdie10

Compiladores

Anuncio
Universidad
Enrique Díaz de
León
Ingeniería en software
Materia
Compiladores
Tabla de contenido
ANALISIS SINTACTICO .................................................................................................... 2
Introducción al análisis gramatical .................................................................................. 2
Gramáticas y ambigüedad en gramáticas. .................................................................. 2
Descripción de métodos y algoritmos de análisis sintáctico ........................................ 2
Sintagma Sujeto ......................................................................................................... 2
Análisis Sintáctico descendente ..................................................................................... 4
Análisis sintáctico descendente recursivo. .................................................................. 4
Gramática LL y análisis sintáctico LL .......................................................................... 4
Implementación del análisis sintáctico descendente ................................................... 2
Análisis Sintáctico Ascendente ....................................................................................... 2
Gramática LR ............................................................................................................. 3
Análisis sintáctico LR .................................................................................................. 3
Implementación del método de análisis sintáctico ascendente. .................................. 4
Recuperación y manejo de errores................................................................................. 4
Listados de errores ..................................................................................................... 5
Presentación de ocurrencia de errores .............................................................................. 6
Tablas de Símbolos........................................................................................................ 6
Atributos de las tablas de símbolos ................................................................................ 6
Estructuras de datos para tablas de símbolos ............................................................ 7
ANALISIS SEMANTICO Y GENERACION DE CODIGO INTERMEDIO ............................ 8
Código intermedio .......................................................................................................... 8
Generación de código intermedio ............................................................................... 8
Traducción dirigida por la sintaxis .................................................................................. 8
Declaraciones ................................................................................................................ 8
Llamadas a procedimientos............................................................................................ 9
Comprobación de tipos .................................................................................................. 9
ANALISIS SINTACTICO
Consiste en estudiar la función gramatical que cumple cada palabra dentro de la oración.
Dentro de la gramática hay palabras variables, es decir, presentan terminaciones para
indicar los accidentes gramaticales de género, número; también para formar
aumentativos, diminutivos y despectivos. Dentro de esas palabras que son variables se
encuentran: los artículos, los sustantivos, los adjetivos, los adverbios y los verbos.
G R AM Á T IC A S
Y A MB I G Ü E DA D EN G R AM Á T I CA S .
Si una gramática general más de una estructura a partir de la misma raíz y con la misma
cosecha (más de una estructura para la misma cadena), dicha gramática es ambigua. Dos
tipos de ambigüedad:
1. En la gramática
2. En el lenguaje
Si una gramática es ambigua, posiblemente (no necesariamente) existe una gramática no
ambigua que genere el mismo lenguaje. Un lenguaje es inherentemente ambiguo si todas
sus gramáticas son ambiguas. ¡No existe un algoritmo que decida si una gramática es
ambigua!
A cada derivación le corresponde una estructura sintáctica:
 Derivaciones diferentes pueden generar la misma estructura (para la misma
cadena)
 La ambigüedad surge cuando derivaciones diferentes generan estructuras
diferentes (para la misma cadena)
D E S CR I P CI Ó N
D E M É T O DO S Y A LG O R I T M O S DE A NÁ L I S I S
S I NT Á CT I CO
Para analizas una oración sintácticamente, primero se busca el verbo conjugado y se le
pregunta ¿Quién? Realiza la acción del verbo. Lo que contesta es el sujeto y
automáticamente lo demás el predicado.
SINTAGMA SUJETO
El sintagma sujeto consta de:
 Núcleo (N): Es siempre un nombre, pronombre o infinitivo
 Determinante(Det): Es cualquier clase de determinante: artículo, posesivo,
infinitivo, demostrativos, etc. y van junto al nombre.
 Adjunto(Adg): Es un adjetivo que va junto al nombre.
 Aposición (Apo): Es un sustantivo que no va precedido de preposición.
 Complemento del nombre(CN): Es un grupo de palabras que acompañan al
núcleo (normalmente son preposición y sustantivo)
El algoritmo empleado para realizar el análisis sintáctico con las reglas ponderadas
relaciona cadenas de símbolos con el conocimiento lingüístico almacenado en las reglas y
con el diccionario de palabras marcadas. Este algoritmo es el mecanismo computacional
que infiere la estructura de las cadenas de palabras a partir del conocimiento almacenado.
Un algoritmo de análisis sintáctico de este tipo es un procedimiento que prueba diferentes
formas de combinar reglas gramaticales para encontrar una combinación que genere un
árbol que represente la estructura de la oración de entrada para su interpretación
correcta. Durante el procesamiento de los datos se crean muchas estructuras temporales,
las estructuras finales son el resultado del análisis. Los algoritmos de análisis sintáctico
más empleado por su eficiencia se basan precisamente en gramáticas independientes del
contexto.
Los algoritmos deciden que reglas probar y en que orden, para lo cual combinan
diferentes estrategias y estructuras temporales. Existen diferentes estrategias para este
proceso:
1. dirigido por las hipótesis o por los datos
2. procesamiento secuencial o paralelo
3. análisis determinista o no determinista
Las estructuras están relacionadas directamente con las estrategias empleadas. El
análisis sintáctico dirigido por las hipótesis o por la gramática es conocido también como
descendente. Busca primero en la gramática las reglas y va construyendo estructuras
hasta completar las palabras de la secuencia de entrada. Va construyendo estructuras
desde el símbolo inicial S correspondiente ala oración, hacia abajo, hasta encontrar la
secuencia de palabras de la entrada. El análisis sintáctico dirigido por los datos es
conocido como ascendente, e inicia con las palabras de la secuencia de entrada para ir
encontrando las reglas cuya parte derecha contiene esas combinaciones de palabras
adyacentes. Va construyendo estructuras hacia arriba hasta llegar al símbolo inicial que
representa a la oración.
Intenta encontrar entre las producciones de la gramática la derivación por la izquierda del
símbolo inicial para una cadena de entrada.
Se construye el árbol de análisis sintáctico partiendo de la raíz hacia las hojas. Se estudia
los siguientes tokens a analizar para decidir la regla a expandir. Lookahead: N° de tokens
necesario para realizar la elección de la regla a expandir. Gramáticas LL(1): con
Lookahead =1.
A N Á LI S I S
S I NT Á CT I C O DE S C E N D E N T E R E C U R S I V O .
Su funcionamiento se basa en un conjunto de funciones recursivas. Cada símbolo no
terminal genera una función, en esta función se selecciona la regla de producción a
ejecutar en función del valor del siguiente token. La pila se sustituye implícitamente por la
pila de llamadas
G R A MÁ T I C A LL
Y A N Á LI S I S S I NT Á C T I C O
LL
Es la condición que debe cumplirse para poder realizar un análisis descendente
predictivo. Para cada símbolo no terminal <A>
Dadas todas las producciones <A> → ∝
Los conjuntos Pred(<A> → ∝ ) deben ser disjuntos
Modificación de gramáticas no LL(1)
No siempre es posible convertir una gramática no LL(1) en una gramática equivalente
LL(1)
Eliminación de la ambigüedad
Es la modificación más difícil y obliga a detectar ambigüedades y replantear el diseño de
la gramática
Modificación de gramáticas no LL(1),
Factorización por la izquierda.
Transformar
En
<A> → ∝ 𝛽
<A> → ∝ < 𝐴´ >
<A> → ∝ 𝛽
<A´> → 𝛽
<A´> → 𝛽
Eliminación de la recursividad por la izquierda
Transformar
<A> → <A> ∝
<A> → 𝛽
(Genera el lenguaje: β, 𝛽 ∝, 𝛽 ∝∝,…)
En
<A> → 𝛽 < 𝐴´ >
<A´> → ∝ < 𝐴´ >
<A´> → 𝜆
I M P L EM E N T A CI Ó N
D E L A NÁ L I S I S S I NTÁ CT I CO D E S C E N DE NT E
El objetivo de un análisis ascendente consiste en construir el árbol sintáctico desde abajo
hacia arriba, esto es, desde los tokens hacia el axioma inicial, lo cual disminuye el número
de reglas mal aplicadas con respecto al caso descendente (si hablamos del caso con
retroceso) o amplía el número de gramáticas susceptibles de ser analizadas (si hablamos
del caso LL(1)).





Análisis ascendente con retroceso: al igual que ocurría con el caso
descendente, este tipo de análisis intenta probar todas las posibles operaciones
(reducciones y desplazamientos) mediante un método de fuerza bruta, hasta llegar
al árbol sintáctico, o bien agotar todas las opciones, en cuyo caso la cadena se
rechaza.
En el análisis con retroceso no se permiten las reglas Ԑ, puesto que estas se
podrán aplicar de forma indefinida.
Análisis ascendente sin retroceso:
o El análisis ascendente sin retroceso busca una derivación derecha de la
cadena de entrada de forma determinista.
o Este se sustenta en su aplicación a las gramáticas LR(K).
o La L viene de la lectura de la cadena de entrada de izquierda a derecha.
o La R de producir un árbol de derivación derecho.
o La K indica el número de símbolos que es necesario leer a la entrada para
tomar la decisión de que producción emplear.
o Un parser del tipo shift-reduce puede verse como un autómata de pila
determinista extendido que realiza el análisis de abajo hacia arriba.
o Dada una cadena de entrada w, simula una derivación más a la derecha.
G R AM Á T IC A LR
Una gramática que puede crear una tabla de parseo LR(0) sin ningún conflicto
shift/reduce o reduce/reduce.
Una gramática que puede crear una tabla de parseo LR(1) sin ningún conflicto
shift/reduce o reduce/reduce.
Una gramática que puede crear una tabla de parseo LR(k) sin ningún conflicto shift/reduce
o reduce/reduce
Un lenguaje libre de contexto es un lenguaje LR sí y sólo sí puede ser generado por una
gramática LR(k) para algún k. El conjunto de lenguajes LR es independiente de la
distancia de lookahead k. Dada cualquier gramática LR(k) 𝐺 , existe una gramática LR(0)
𝐺 tal que L(𝐺 ) = L(𝐺 ).
Para todos los lenguajes que vimos con gramáticas SLR(1), LALR(1) y LR(1), podríamos
haber encontrado una gramática LR(0).
ANÁLISIS
S IN T ÁC T IC O
LR
La técnica se denomina análisis sintáctico LR(k); la “L” es por el examen de la entrada de
izquierda a derecha (en inglés, left-to-right), la “R” por construir una derivación por la
derecha (en ingles, rightmost derivation) en orden inverso, y la k por el número de
símbolos de entrada de examen por anticipado utilizados para tomar las decisiones del
análisis sintáctico. Cuando se omite, se asume que k, es:

El análisis LR es atractivo por varias razones:
o Pueden reconocer la inmensa mayoría de los lenguajes de programación
que puedan ser generados mediantes gramáticas de contexto-libre.
o El método de funcionamiento de estos analizadores posee la ventaja de
localizar un error sintáctico en el mismo instante que se produce con lo que
se adquiere una gran eficiencia de tiempo de compilación frente a
procedimientos menos adecuados como pueden ser los de retroceso.
I M P L EM E N T A CI Ó N
ASCENDENTE.
D E L M ÉT O DO D E AN Á L I SI S S I NT Á CT I CO
Ejemplo:
Cero o más paréntesis abiertos seguidos de un número igual de paréntesis cerrados o un
solo paréntesis abierto.
Gramática LR(1)
<S> → <X> $
<X> → <Y>
<X> → (
<Y> → (<Y>)
<Y> → Ԑ
Un compilador es un sistema que en la mayoría de los casos tiene que manejar una
entrada incorrecta. Sobre todo en las primeras etapas de la creación de un programa, es
probable que el compilador se utilizará para efectuar las características que debería
proporcionar un buen sistema de edición dirigido por la sintaxis, es decir, para determinar
si las variables han sido declaradas antes de usarla, o si faltan corchetes o algo así. Por lo
tanto, el manejo de errores es parte importante de un compilador y el escritor del
compilador siempre debe tener esto presente durante su diseño.
Hay que señalar que los posibles errores ya deben estar considerados al diseñar un
lenguaje de programación.
El compilador debe ser capaz de detectar errores en la entrada;


El compilador debe recuperarse de los errores sin perder demasiada información.
Y sobre todo, el compilador debe producir un mensaje de error que permita al
programador encontrar y corregir fácilmente los elementos (sintácticamente)
incorrectos de su programa.
L I ST A D O S
DE E R R O R E S
1. Errores léxicos: Los errores léxicos se detectan cuando el analizador léxico
intenta reconocer componentes léxicos en el código fuente.
2. Errores sintácticos: Un error de sintaxis se detecta cuando el analizador
sintáctico espera un símbolo que no corresponde al que se acaba de leer. Los
analizadores sintácticos LL y LR tienen la ventaja de que pueden detectar errores
sintácticos lo más pronto posible, es decir, se genera un mensaje de error en
cuanto el símbolo analizado no sigue la secuencia de los símbolos analizados
hasta ese momento.
3. Error semántico: Los errores semánticos corresponden a la semántica del
lenguaje de programación, la cual normalmente no está descrita por la gramática.
Los errores semánticos más comunes son la omisión de declaraciones.
4. Errores lógicos: los comete el programador.
Presentación de ocurrencia de errores
La tabla almacena la información que en cada momento se necesita sobre la variables del
programa, información tal como: nombre, tipo, dirección de localización, tamaño, etc. La
gestión de la tabla de símbolos es muy importante, ya que consume gran parte del tiempo
de compilación. De ahí que su eficiencia sea crítica. Aunque también sirve para guardar
información referente a los tipos creados por el usuario, tipos enumerados y, en general, a
cualquier identificador creado por el usuario, nos vamos a centrar principalmente en las
variables de usuario. Respecto a cada una de ellas podemos guardar:





Almacenamiento del nombre: se puede hacer con o sin límite. Si lo hacemos con
límite, emplearemos una longitud fija para cada variable, lo cual aumenta la
velocidad de creación, pero limita la longitud en unos casos, y desperdicia espacio
en la mayoría. Otro método es habilitar la memoria que necesitemos en cada caso
para guardar el nombre. En C esto es fácil con los char *. Si hacemos el
compilador en MODULA-2, por ejemplo, habría que usar el tipo ADDRESS.
El tipo también se almacena en la tabla
Dirección de memoria en que se guardará: esta dirección es necesaria, porque
las instrucciones que referencian a una variable deben saber donde encontrar el
valor de esa variable en tiempo de ejecución, también cuando se trata de variables
globales. En lenguajes que no permiten recursividad, las direcciones se van
asignando secuencialmente a medida que se hacen las declaraciones. En
lenguajes con estructuras de bloques, la dirección se da con respecto al comienzo
del bloque de datos de ese bloque, (función o procedimiento) en concreto.
El número de dimensiones de una variable array, o el de parámetros de una
función o procedimiento: junto con el tipo de cada uno de ellos es útil para el
chequeo semántico. Aunque esta información puede extraerse de la estructura de
tipos, para un control más eficiente, se puede indicar explícitamente.
También podemos guardar información de los números de línea en los que se
ha usado un identificador, y de la línea en que se declaró.
Los símbolos se guardan en la tabla con su nombre y una serie de atributos opcionales
que dependerán del lenguaje y de los objetivos del procesador. Este conjunto de atributos
almacenados en la TS para un símbolo determinado s define como registro de la tabla de
símbolos (symbol-table record).
Identificador
companya
𝒙𝟑
𝒇𝒐𝒓𝒎𝒂𝟏
b
Dirección
STATIC
STATIC
𝑆𝑇𝐴𝑇𝐼𝐶
𝑺𝑻𝑨𝑻𝑰𝑪 𝟏𝟑
Tipo
C
I
B
F
Dimensión
10
0
0
3
Otros
…
…
…
…
La lista siguiente de atributos no es necesaria para todos los compiladores.









Nombre de identificador
Dirección en tiempo de ejecución
Tipo del identificador
Número de dimensiones del arrays
Tamaño máximo o rango de cada uno de los miembros de las estructuras,
uniones o clases
Valor del descriptor del fichero y tipo de los elementos del fichero en el caso de
lenguajes basados en ficheros homogéneos
Número de la línea del texto fuente en que la variable está declarada
Número de la línea del texto fuente en que se hace referencia a la variable
Campo puntero para construir una lista encadenada que permita listar las
variables en orden alfabético en las fases de depuración de código
E S T R U C T URA S
D E DA T O S PA R A TA BL A S D E S Í M BO LO S
En la siguiente tabla de símbolos de matriz para el almacenamiento de cadenas, una
cadena fija de espacios no puede ser lo suficientemente grande para guardar un
identificador muy largo, y puede ser innecesariamente grande para un identificador corto,
donde se determina que al final de cada cadena se finaliza con un fin-de-cadena
representado por FDC, y que no puede aparecer en los
identificadores.
Div
Mod
I
d
I
V
FDC
M
O
D
FDC
I
FDC
ANALISIS SEMANTICO Y GENERACION DE CODIGO INTERMEDIO
-
-
Proceso de síntesis
o Lenguaje intermedio
o Generación de código
Ventajas del código intermedio
o Facilitar la fase de optimización
o Aumentar la portabilidad del compilador de una máquina a otra
 Se puede utilizar el mismo analizador para diferentes generadores
 Se pueden utilizar optimizadores independientes de la máquina
o Facilitar la división en fases del proyecto
G E N E R A C IÓ N
-
D E C ÓD I G O I N T E R M E D I O
Aumentar la portabilidad del compilador de una máquina a otra
o Se puede utilizar el mismo analizador para diferentes generadores
o Se pueden utilizar optimizadores independientes de la máquina
Cada símbolo de una gramática puede tener asociados uno o más atributos. Los atributos
pueden ser de cualquier tipo de dato, y su significado depende del programador (valor de
una constante, valor de una expresión, puntero, etc…)
𝑁 → 𝐴 ′𝑡′ 𝐵 𝐶
Representación: N.n
A.a
‘t’.t
B.b
C.c
Definición de atributos con CI (sintetizado) + acciones semánticas.
Construcción explícita de la tabla de símbolos
-
Se crean entradas para cada variable según su tipo
-
-
Reserva de espacio en función del tipo empleado
o offset es una variable global con dirección de la tabla actual
o T.tipo, T.ancho atributos que caracterizan cada entrada en la tabla
Simplificación: tabla de un solo procedimiento
o Extensiones para declaraciones en procedimientos y ámbitos anidados
La llamada a un procedimiento especifica la relación entre los parámetros reales y los
formales y ejecuta el procedimiento. Lo parámetros se asocian normalmente por posición,
aunque, opcionalmente, también se pueden asociar por nombre. Si el procedimiento tiene
parámetros formales por omisión, no es necesario asociarles un parámetro real.
Sintaxis
procedure_call_statement ::=
procedure_name; | procedure_prefix actual_parameter_part;
actual_parameter_part ::=
(parameter_association {, parameter_association})
Parameter_association ::=
[formal_parameter_selector_name =>] explicit_actual_parameter
Explicit_actual_parameter ::= expression | variable_name
-
-
Un lenguaje especifica que operaciones son válidas para cada tipo
o Formalización de reglas semánticas de verificación
Se detectan errores
o Acceso incorrecto a memoria
o Limites de abstracción, mal uso de estructuras, etc.
Tipos de lenguajes:
o Estáticamente tipificados: la mayoría de comprobaciones se realizan en
tiempo de compilación (C, JAVA)
o
o
Dinámicamente tipificados: la mayoría de comprobaciones en ejecución
(Scheme, LISP)
No tipificados: ninguna comprobación (código ensamblador)
Descargar