Compiladores

M. en C. Joel Omar Juárez Gambino

COMPILADORES E INTÉRPRETES

Compilador
• Un compilador es un programa que lee un programa escrito en algún lenguaje (lenguaje fuente) y lo traduce a un programa equivalente en otro lenguaje (lenguaje objeto)

Historia de los compiladores    La palabra compilador se atribuye a Grace Murray Hopper El concibió la implementación de un lenguaje de alto nivel como “una compilación de una secuencia de subrutinas desde una librería” Los primeros compiladores tipo traductor fueron escritos a fines de los 50 .

Historia de compiladores     El lenguaje FORTRAN se considera el primer lenguaje compilado con exito El diseño de este compilador lo encabezó John Backus y su desarrollo tomó 18 años Existia un gran escepticismo con respecto a que un lenguaje semejante al inglés pudiera diseñarse y traducirse en algo que la máquina pudiera ejecutar eficazmente “Los verdaderos programadores utilizan el lenguaje ensamblador” .

Historia de los compiladores  En la actualidad es posible diseñar e implementar un compilador mejor y más rápido que FORTRAN por las siguientes razones:    Los lenguajes se comprenden mejor Se han desarrollado herramientas que facilitan algunas tareas del compilador Se han desarrollado estructuras de datos y algoritmos que realizan las tareas que son comunes a todos los compiladores .

.

FUNDAMENTOS DE TEORÍA DE LENGUAJES .

Alfabetos • Es un conjunto no vacio y finito de símbolos • Se utiliza el símbolo Σ para denotar un alfabeto • Ejemplo: –Σ = {0.1} Descripción: El alfabeto Σ consiste en los dígitos 0 y 1 .

1} • Longitud de cadena. Cadena con 0 ocurrencias de símbolos. Es una secuencia finita de símbolos Ejemplo: C=1010 sobre el alfabeto Σ = {0. Es denotada por ε . Es el número de símbolos que tiene una cadena Ejemplo: |C|= 4  Cadena vacia.Cadenas o palabras • Cadena o palabra.

se definen las siguientes operaciones: – – – Concatenación de cadenas.Cadenas o palabras • Sea w=101 y z=111 dos cadenas. La concatenación de w y z es wz=101111 Potencia de cadenas ( w k): Denota la concatenación de k copias de la cadena w Igualdad de cadenas: w y z estas cadenas son iguales si tienen la misma longitud y los mismos símbolos en la misma posición .

Lenguaje • Conjunto de cadenas las cuales son parte de un alfabeto Σ • Una cadena L sobre un alfabeto Σ no necesita incluir todos los símbolos de Σ .

Lenguaje • Ejemplos: – El conjunto de todas las cadenas que consisten en n 0's seguida de n 1's para n≥0 – El conjunto de cadenas formadas por 0's y 1's en cualquier posición con igual número de repeticiones cada uno – El lenguaje vacio ∅ – El lenguaje que consiste solo en la cadena vacia {ε} .

ACTIVIDAD GRUPAL 2 .

Proceso de compilación Programa fuente Compilador Programa objeto Errores .

Proceso de compilación • Es importante señalar que diferentes lenguajes de programación requieren distintos compiladores No existen compiladores genéricos Que pasa con MSIL!!! • • .

Evidencia 2   Realizar en equipo un trabajo de investigación sobre el Common Intermediate Languaje (CIL o MSIL) de Microsoft y el Bytecode de Java La evidencia de este trabajo es documento que consta de los siguientes puntos:    Introducción Cuadro comparativo (al menos 5 características que ustedes consideren importantes) Conclusiones  Se envía al correo a más tardar antes de la siguiente clase .

LENGUAJES DE PROGRAMACIÓN .

Evolución de los LP • Las computadora son capaces de ejecutar procedimientos que están escritos en su lenguaje nativo Dicho lenguaje está definido en las instrucciones que el procesador es capaz de ejecutar Con estos lenguajes se producian programas gigantescos y con alta probabilidad de errores • • .

Evolución de los LP • • • Con el paso del tiempo los LP han evolucionado Se acercan cada vez más a los lenguajes algorítmicos Esto obliga a traducir los programas al lenguaje de las computadoras .

2.      DESPLEGAR Suma. 13.         NO: 14. FIN DE PROCESO . HACER Valor = 0 .            VOLVER AL PASO 5 15. 5.1. 6. 3. HACER Suma = 0. Valor 17.   SI:  16. 10. LEER Elemento . 18.            HACER Valor = Elemento.   NO: 9. 4.         SI:  12. 7.      HACER Suma = Suma + elemento.      ES Elemento > Valor ? 11. HACER Elemento = 0 . ES Elemento < 0 ? 8.

Evolución de los LP • Actualmente los compiladores no producen programas objetos escritos en código máquina Compilan el programa fuente a un código intermedio Este código intermedio puede ser interpretado directamente o traducido a código máquina • • .

Funciones del compilador .

Fases de un compilador Programa fuente Analizador léxico Analizador sintáctico Analizador semántico Administrador de la tabla de símbolos Generador de código intermedio Manejador de errores Optimador de código Generador de código Programa objeto .

constantes.Analizador léxico • • • Lee los caracteres de entrada (programa fuente) Genera como salida una secuencia de componentes léxicos Mediante algunas técnicas descompone los cadenas en una serie de elementos fundamentales del lenguaje – variables. ect . palabras reservadas.

Analizador léxico area :=( base∗altura)/2 .El signo de división / 9. 1.El signo de multiplicación * 6.El símbolo de paréntesis cerrado ) 8.El número 2 .El identificador altura 7. 5.El identificador area 2.El identificador base.El símbolo de paréntesis abierto ( 4.El símbolo de asignación := 3.

Analizador sintáctico • Determina si una cadena de componentes léxicos puede ser generada por una gramática Agrupa los componentes léxicos en frases gramaticales que se utilizan para sintetizar la salida Las frases gramaticales se representan mediante un árbol de análisis sintáctico • • .

Analizador sintáctico .

Cualquier número es una expresión 3. Si expresión1 y expresión2 son expresiones. Cualquier identificador es una expresión 2. entonces también lo son • • • expresión1 + expresión2 expresión1 / expresión2 (expresión1) .Analizador sintáctico • • La estructura jerárquica de un programa normalmente se expresa utilizando reglas recursivas Ejemplo: 1.

Si expresión1 es una expresión y proposición2 es una proposición. entonces while (expresión1) do proposición2 if (expresión1) do proposición2 son proposiciones .Analizador sintáctico • • Muchos lenguajes definen recursivamente las proposiciones mediante reglas Ejemplo: 1. entonces identificador1:=expresión2 es una proposición 1. Si identificador1 es un identificador y expresion2 es una expresión.

Tabla de símbolos • Estructura de datos que contiene un registro por cada identificador con campos específicos para sus atributos • Permite encontrar rápidamente el registro de cada identificador • Se puede almacenar y consultar datos de ese registro .

Tabla de símbolos • Los atributos que comúnmente se almacenan para un identificador son: –Memoria asignada –Tipo –Ámbito • Los atributos para un procedimiento: –Cantidad y tipo de argumentos –Método de envío de argumentos –Tipo retornado .

Tabla de símbolos • Gran parte de la información almacenada en la tabla de símbolos se introduce durante la fase de análisis léxico • Sin embargo. • Las fases restantes complementaran los atributos restantes de los identificadores de la tabla de símbolos . altura : real . algunos atributos no se pueden determinar durante esta fase –var area. base.

Análisis semántico
• Revisa el programa en busca de errores semánticos y reúne información sobre los tipos • Uno de los errores más comunes revisados por esta fase es la verificación de tipos • Esta verificación comprueba si cada operador tiene los operandos permitidos por la especificación del lenguaje
int x=4, z; char y[3]=“abc” z = x + y;

Etapas del compilador
• En ocasiones el trabajo del compilador se suele dividir en solo dos fases:
– Fase de análisis. Verifica posibles errores en diferentes niveles – Fase de síntesis. construye el programa objeto a partir de la representación intermedia

Etapa de análisis
• Se suelen identificar las siguientes etapas:
– Análisis lineal. La cadena de caracteres del programa fuente se leen de izquierda a derecha y se agrupan en componentes léxico Análisis jerárquico. Los componentes léxicos se agrupan jerárquicamente en colecciones anidadas con un significado colectivo Análisis semántico. Se realizan ciertas revisiones para asegurar que los componentes de un programa se ajustan de un modo significativo

Código intermedio • Algunos compiladores incluyen una última etapa que genera un código intermedio • Este código se considera como un programa para una máquina abstracta • Esta representación debe de tener dos propiedades importantes: –Fácil de producir –Fácil de traducir .

temp:=entreal(2) temp2:=id2*id3 temp3:=temp2/temp id1:=temp3 .Código intermedio • Una representación intermedia utilizada es el código de tres direcciones • Consiste en una secuencia de instrucciones. cada una con un máximo de tres operandos • Ejemplo: area :=( base∗altura)/2 .

Etapa de síntesis • Una tarea importante de esta etapa es la optimización de código • La optimización trata de mejorar el código intermedio de modo que el código máquina se ejecute más rápido • Existen incluso compiladores que le dedican mucho tiempo de la compilación a esta etapa .

Optimización de código temp:=entreal(2) temp2:=id2*id3 temp3:=temp2/temp id1:=temp3 temp1:=id2*id3 id1:=temp1/2.0 .

Generación de código objeto • Después de la optimización el compilador traduce las instrucciones a código objeto • El código objeto generalmente se representa en lenguaje ensamblador • Cada una de las instrucciones máquina se traducen a una secuencia de instrucciones máquina que ejecutan la misma tarea .

Generación de código objeto temp1:=id2*id3 id1:=temp1/2. R2 MOVF #2. R1 DIVF R2. R2 MULF id2. R1 MOVF R1. id1 .0.0 MOVF id3.

0 . R1 MOVF R1. temp:=entreal(2) temp2:=id2*id3 temp3:=temp2/temp id1:=temp3 Verificación de tipos MOVF id3. R2 MOVF #2.area :=( base∗altura)/2 .0. id1 temp1:=id2*id3 id1:=temp1/2. R1 DIVF R2. R2 MULF id2.

Agrupamiento de las fases • Las fases del compilador se pueden agrupar en: – Etapa inicial – Etapa final .

sintáctico.Etapa inicial • • • Comprende las fases que dependen principalmente del lenguaje fuente Las fases de esta etapa son en gran parte independientes de la máquina objeto Generalmente incluye los análisis léxico. generación de la tabla de símbolos. generación de código intermedio y manejo de errores . semántico.

Etapa final • • • Incluye fases del compilador que dependen de la máquina objeto Estas fases no trabajan con el código fuente. generación de código. sino con el código intermedio Generalmente incluye la optimización de código. manejo de errores y operaciones con la tabla de símbolos .

Nota libro compiladores (1986) • “Resulta tentador compilar varios lenguajes distintos en el mismo lenguaje intermedio y usar una etapa final común para las distintas etapas iniciales. Sin embargo. obteniendose así varios compiladores para una máquina. sólo se han obtenido un éxito limitado en ese aspecto” . dadas las sutiles diferencias en los puntos de vista de los distintos lenguajes.

Pasadas • • • • • Una pasada consiste en la lectura de una archivo de entrada y la escritura de un archivo de salida Normalmente se aplican varias fases de compilación en una sola pasada Siguiendo esta idea se podría traducir directamente los componentes léxicos a código intermedio Es deseable tener relativamente pocas pasadas. dado que la lectura y escritura de archivos intermedios lleva tiempo Una solución a estos problemas es el relleno de retroceso (backpatching) .

puede ser necesario mantener el programa completo en memoria En ocasiones el programa interno puede ser mayor que el programa fuente o el programa objeto El manejo de memoria no es un problema trivial .Pasadas    Si se agrupan varias fases dentro de una pasada.

por lo que no se puede generar código objeto si no se conocen los tipos de la variables implicadas En las sentencias goto no se puede determinar la dirección objeto de dichos saltos hasta haber visto el código objeto implicado y haber generado el código objeto correspondiente • .Pasadas • • El agrupamiento de las fases en una sola pasada no siempre es posible Algunos lenguajes permiten usar variables antes de declararlas.

Pasadas • Es posible dejar un segmento de la tabla en blanco para la información que falta y llenarlo cuando la información esté disponible La generación de código intermedio y código objeto se puede fusionar en una sola pasada utilizando la técnica de relleno de retroceso (backpatching) • .

Análisis léxico .

Analizador léxico • Lee los caracteres de entrada y genera como salida una secuencia de componentes léxicos Otras tareas del analizador léxico: – Eliminar comentarios. tabulaciones. espacios en blanco y saltos de línea – Relacionar los errores con las lineas del programa fuente • .

Fases del analizador léxico • En algunas ocasiones los analizadores léxicos se dividen en dos fases: – Fase de examen: Encargada de eliminar espacios en blanco. – Fase de análisis: Reconoce los componentes léxicos . tabuladores. etc.

Interacción entre analizadores • Los componentes identificados por el analizador léxico son utilizados por el analizador sintáctico Esta interacción se logra convirtiendo al analizador léxico en una subrutina del analizador sintáctico • .

Interacción entre analizadores Componente léxico Programa fuente Analizador léxico Obtén el siguiente componente léxico Analizador sintáctico Tabla de símbolos .

Interacción entre analizadores • Los componentes léxicos producidos se pueden conservar en un buffer hasta ser consumidos por el analizador sintáctico El analizador léxico no puede avanzar mientras el buffer este lleno El analizador sintáctico no puede continuar cuando e buffer está vacio • • .

Interacción entre analizadores • Es importante separar las etapas de análisis léxico y sintáctico – Diseño claro y sencillo – Mejorar eficiencia (manejo de buffers) – Mejorar transportabilidad (identificación de símbolos que no son parte del alfabeto) .

Reglas mediante las cuales se describen los componentes léxicos Lexema. Secuencia de caracteres en el programa fuente con la que concuerda el patrón para un componente léxico • • . Cadenas que el analizador léxico es capaz de identificar y agrupar de acuerdo a un significado colectivo Patrón.Análisis de cadenas • Componente léxico.

altura if 1492.1 * = Descripción informal del patrón Letra seguida de letras o dígitos Letra i seguida de letra f Dígito seguido de más dígitos Caracter * Carcater = .Ejemplos Componente léxico Identificador if num_entero op_mult op_asign Lexemas area. base. 2.

etc. punto y coma. paréntesis.) .Componentes léxicos • En la mayoria de los lenguajes de progamación se consideran componentes léxicos: – – – – – Palabras clave Operadores Identificadores Constantes Signos de puntuación (coma.

Palabras reservadas • • En algunos lenguajes ciertas cadenas tienen un significado predefinido Esas cadenas se reservan para usos exclusivo del lenguaje y el usuario no las puede modificar Si dichas palabras no se reservan el analizador léxico tendrá la tarea de distinguir entre palabras reservadas e identificadores • .

Ejemplo • En el lenguaje PL/I las palabras clave no son reservadas y se pueden complicar muchos las proposiciones     IF THEN THEN THEN = ELSE     ELSE ELSE = THEN .

el patrón de identificador Por lo que varios lexemas pueden concordar con un mismo patrón Bajo estas circunstancias el analizador léxico debe proporcionar información adional sobre el lexema • • .Atributos de los componentes léxicos • Algunos patrones describen a más de un lexema. por ejemplo.

Atributos de los componentes léxicos • • • Los componentes léxicos influyen en las decisiones del análisis sintáctico Los atributos influyen en la traducción de los componentes léxicos En la práctica los componentes léxicos suelen tener un solo atributo. el apuntador al registro de la tabla de símbolos donde se especifican sus atributos .

apuntador> <op_multiplicacion. apuntador> <op_asignacion.Ejemplo perímetro = lado * 2 • Secuencia de parejas <identificador. > <identificador. > <num_entero. valor entero 2> .

Errores léxicos • • Son pocos los errores que pueden ser detectados durante esta etapa Un error detectado en esta etapa es cuando no se encuentra un patrón que describa a una cadena del programa fuente Estos errores deben ser manejados correctamente por el compilador para poder continuar con el análisis • .

Errores léxicos • Existen varias estrategias que el compilador puede tomar para manejar el problema: – Borrar caracteres extraños hasta reconocer un componente – Insertar un carácter faltante – Reemplazar un carácter incorrecto por otro correcto – Intercambiar dos caracteres adyacentes .

la concatenación y la cerradura .Lenguajes • • • Un lenguaje es un conjunto de cadenas de un alfabeto fijo Hay varias operaciones importantes que se pueden aplicar a los lenguajes Para el análisis léxico son interesantes principalmente la unión.

LD Cerradura de Kleene de L. L υ D Concatenación de L y D. L+ Definición L υ D = {s | s está en L o está en D} LD = {st | s está en L y t está en D} L* denota “cero concatenaciones de” L L+ denota “una concatenaciones de” L o o más más .Operaciones sobre los lenguajes Operación Unión de L y D. L* Cerradura positiva de L.

... al aplicar las operaciones se forman los siguientes lenguajes LυD LD • • • • L 4 L* L(L υ D)* D + ..9}.z} y D el conjunto {0..b..1..Ejemplo • Sea L el conjunto {a..

Expresiones regulares • • Es una notación utilizada para especificar patrones Una expresión regular se construye a partir de expresiones regulares más simples utilizando un conjunto de reglas definitorias Cada expresión regular r representa un lenguaje L(r) • .

el conjunto que contiene la cadena vacía 2. Aunque usa la misma notación para las 3. técnicamente la expresión regular a es distinta de la cadena a o del símbolo a. Si a es un símbolo de Σ . . entonces a es una expresión regular designada por {a}. por ejemplo el conjunto que contiene la cadena a.Expresiones regulares • Las siguientes reglas definen las expresiones regulares del alfabeto Σ 1. ε es una expresión regular designada por {ε}.

entonces: • (r) | (s) es una expresión regular representada por L(r) υ L(s) • (r)(s) es una expresión regular representada por L(r)L(s) • (r)* es una expresión regular representada por (L(r))* • (r) es una expresión regular representada por L(r) .Expresiones regulares 1. Suponiendo que r y s sean expresiones regulares representadas por los lenguajes L(r) y L(s).

Expresiones regulares • Se pueden evitar los paréntesis innecesarios en las expresiones regulares si se adoptan las siguientes convenciones 1. | tiene la menor precedencia y es asociativo por izquierda . La concatenación tiene la segunda mayor precedencia y es asociativa por izquierda 3. El operador unario * tiene la mayor pr y es asociativo por izquierda 2.

Expresiones regulares • Siguiendo las convenciones anteriores – (a)|((b)*(c)) es equivalente a – a|b*c • ¿Qué conjunto de cadenas se forman con esa expresión? .

4. definir el conjunto de cadenas que especifican las siguientes expresiones regulares 1. 3. 5.b}. 2.Ejemplo • Sea Σ = {a. a|b (a|b)(b|a) a* (a|b)* a|a*b .

se dice que r y s son equivalentes (r = s) – (a|b) = (b|a) ¿? • Son varias las leyes algebraicas que obedecen las expresiones regulares y pueden ser usadas para transformar dichas expresiones a otras equivalentes .Expresiones regulares • Si dos expresiones regulares r y s representan al mismo lenguaje.

Propiedades algebraicas AXIOMA r|s = s|r r|(s|t) = (r|s)|t (rs)t = r(st) r(s|t)= rs|rt (s|t)r = sr|tr εr=r rε=r r* = (r|ε)* r** = r* DESCRIPCIÓN | es conmutativo | es asociativo La concatenación es asociativa La concatenación distribuye sobre | ε es elemento identidad de la concatenación La relación entre * y ε * es idempotente .

Definiciones regulares • Por conveniencia de notación es deseable dar nombres a las expresiones expresiones regulares Se pueden definir nuevas expresiones regulares utilizando dichos nombres como si fueran símbolos A esta operación se le conoce como definición regular • • .

|z dígito → 0|1|.|9 ¿Cómo se definirían los identificadores en C? • • . entonces una definición regular es una secuencia de definiciones Ejemplo: letra → A|B|.....Definiciones regulares • Si Σ es un alfabeto de símbolos básicos..|Z|a|b|..

La notación r? es una abreviatura de r|ε Clase de caracteres.|z. La expresión regular a representa al conjunto de todas las cadenas de una o más a. El operador unitario postfijo + significa “uno o más casos de”. Una clase abreviada de carácter como [a-z] designan la expresión regular a|b|. se puede definir los identificadores como cadenas generadas por la expresión regular [A-Za-z][A-Za-z0-9]*  . El operador unitario postfijo ? significa “cero o un caso de”. El operador + tiene la misma precedencia y asociatividad que el operador * +  Cero o un caso. Utilizando clase de caracteres.Abreviatura en la notación  Uno o más casos...

Conjuntos no regulares
• Las expresiones regulares se utilizan para describir un número fijo o no especificado de repeticiones de una determinada construcción En general fallan al describir construcciones equilibradas o anidadas Por ejemplo:
– – Conjunto de cadenas con parentesis equilibrados {wcw | w es una cadena de símbolos a y b}

• •

Conjuntos no regulares
• Para especificar este tipo de conjuntos se utiliza una gramática independiente (libre) del contexto Para reconocer una cadena de está gramática se utiliza un autómata de pila (push-down)

Teoría de Autómatas
• La teoría de autómatas estudia dispositivos de computo abstractos • En la época de 1930, antes de que existieran las computadoras, Alan Turing inicio el estudio de máquinas abstractas • Dichas máquinas tenían todas las capacidades de las computadoras actuales • El estudio pretendía describir con precisión lo que estos dispositivos podían y no podían hacer

sino a las computadoras de hoy en día • Entre 1940 y 1950 se realizó el estudio unas máquinas simples llamadas autómatas finitos (AF) • Estos autómatas pretendían modelar el funcionamiento del cerebro • Los autómatas se han aplicado en muchas áreas de la computación donde han sido muy útil .Teoría de Autómatas • Las conclusiones obtenidas por Turing aplican no solamente a sus máquinas abstractas (máquinas de Turing).

y otros patrones 4. frases. protocolos de comunicación . Software para la verificación de cualquier tipo de sistema que requiera un número finito de estados distintos. Analizador léxico de un compilador típico 3. Software para analizar grandes cantidades de texto. para encontrar palabras. Software para diseño y verificación del comportamiento de circuitos digitales 2.Aplicaciones de los autómatas 1. por ejemplo.

Definición informal de los AF • Un AF es un diagrama de transiciones. el cual cuenta con un conjunto de estados definidos • La transición de un estado a otro se realiza como respuesta a una entrada externa .

Elementos de una AF • Un estado • Estado de inicio • Estado de aceptación • Una transición a .

Ejemplo .

Ejemplo .

Ejemplo • Si se tiene el siguiente alfabeto ∑ = {0.1} diseñar un autómata finito que acepte la cadena 01 .

Estado de aceptación • Un AF acepta una cadena w si se pueden seguir las etiquetas de los arcos con los símbolos de la cadena w desde el estado de inicio hasta su estado de aceptación • En caso de hacer el seguimiento de los símbolos y no llegar a un estado de aceptación la cadena no es valida .

por lo tanto ambos pueden reconocer lo que denotan las expresiones regulares .Autómatas finitos • Un AF puede ser determinista (AFD) o no determinista (AFN) • El “no determinismo” se refiere a que un estado puede tener más de una transición para el mismo símbolo de entrada • Tanto los AFN como los AFD pueden reconocer con precisión los conjuntos regulares.

Un conjunto de estados F considerados como estados de aceptación (o finales) . Un estado So que se considera el estado de inicio (o inicial) 5. Un conjunto de símbolos de entrada Σ (el alfabeto de los símbolos de entrada) 3.Autómata finito no determinista Es un modelo matemático formado por: 1. Una función de transición “mueve” que transforma pares estado-símbolo en conjuntos estados 4. Un conjunto de estados S 2.

Ejemplo de un AFN • Autómata que acepta cualquier cantidad de 0’s y 1’s y termina con un 0 .

Ejemplo AFN (a|b)*abb .

b} 3. Conjunto de estados aceptación F={3} . Alfabeto Σ = {a. Conjunto de estados S={0.1. Estado inicial S0=0 4.Ejemplo AFN En el ejemplo anterior podemos identificar los siguientes elementos del AFN 1.3} 2.2.

1} b {0} {2} {3} .Tabla de transiciones La función de transición se puede especificar mediante una tabla de transiciones Estado 0 1 2 Símbolo de entrada a {0.

Tabla de transiciones • La tabla de transiciones es una alternativa sencilla de implementar un autómata • En esta tabla existirá una fila por cada estado • Y una columna por cada símbolo de entrada. incluyendo ε de ser necesario .

Transiciones vacías • Los AFN permiten transiciones de ε • Ejemplo: aa*|bb* .

Cadenas que contengan a la subcadena 010 3. Cadenas que solo contienen una cantidad impar de 1’s . Cadenas que solo contienen una cantidad par de 0’s 4.1} diseñar el autómata que reconozca las siguientes cadenas 1. Cadenas que contengan cualquier cantidad de 0’s y 1’s y que terminen con la subcadena 00 o 11 2.Ejercicios Dado el alfabeto Σ={0.

Todas las cadenas que contienen solo pares consecutivos de 0’s o 1’s o ambos 2. Todas las cadenas de 0’s y 1’s con al menos un número par de dígitos 0 consecutivos .Ejercicios 1. Todas las cadenas de 0’s y 1’s que no contienen la subcadena 001 3.

El número de 0’s y 1’s leídos son impares .Análisis ejercicio 5 En el ejercicio 5 se pueden identificar 4 casos: 1. El número de 0’s leídos es par. El número de 0’s y 1’s leídos hasta el momento son pares 2. El número de 1’s leídos es par. pero el número de 0’s es impar 4. pero el número de 1’s es impar 3.

Ejercicios Construir un autómata que reconozca las siguientes cadenas 1. Todas las cadenas de letras que contienen las 5 vocales en orden 2. Comentarios que consisten en una cadena encerrada entre /* y */ sin ningún */ intermedio 3. Todas las cadenas de 0’s y 1’s con al menos un número impar de dígitos 1 consecutivos .

Autómata finito determinista Es un caso especial de un AFN en el cual: • Ningún estado tiene una transición ε. hay a lo sumo una arista etiquetada a que sale de S . es decir una transición con la entrada ε • Para cada estado S y cada símbolo de entrada a.

Autómata finito determinista • Un AFD tiene a lo sumo una transición desde cada estado con cualquier entrada • Cada entrada en la tabla de transiciones es un solo estado • Los AFD y los AFN son capaces de reconocer las mismas cadenas • Debido a las diferencias entre los AFD y AFN. dos autómatas que reconocen la misma cadena pueden ser distinto (estados y transiciones) .

Ejemplo AFD (a|b)*abb .

Implementación del analizador léxico .

en vez de “menor que” y “mayor que” . Por ejemplo: <> se interpreta como el operador “distinto de”.Aspectos prácticos de la implementación • Principio de máxima longitud – Se da prioridad al componente léxico de máxima longitud.

Aspectos prácticos de la implementación
• Palabras reservadas e identificadores
– El patrón que define a un identificador también se aplica a una palabra reservada, por lo tanto antes de determinar el tipo de componente léxico la cadena se busca en una tabla previamente inicializada con las palabras reservadas del lenguaje

Conversión de AFN a AFD

Ejemplo AFD
(a|b)*abb

AFN y AFD • Los autómatas no deterministas pueden moverse a dos estados distintos leyendo el mismo símbolo • Esto produce ambigüedad y esta situación es difícil de simular en un programa de computadora • Otro problema que se presenta son las transiciones de cadena vacía. ya que estas permiten estar en varios estados sin leer un símbolo • Es más sencillo convertir un AFN a un AFD que realizar una simulación de su comportamiento .

Conversión de un AFN a AFD • La idea general de la transformación de un AFN a un AFD es que cada estado de un AFD utiliza un estado para localizar todos los posibles estados en los que puede estar el AFN después de leer los símbolos de entrada .

Operaciones para la conversión .

Algoritmo (construcción de subconjuntos) • Entrada: Un AFN N • Salida: Un AFD D que acepta el mismo lenguaje • Método: El algoritmo construye una tabla de transiciones tranD para D. Cada estado del AFD es un conjunto de estados del AFN y se construye tranD de modo que D simulará “en paralelo” todos los posibles movimientos que N puede realizar con una cadena de entrada • El algoritmo usa las operaciones descritas anteriormente para construir los subconjuntos .

a]:=U fin fin . tranD[T.a)).Algoritmo Al inicio. para cada símbolo de entrada a hacer U := cerradura-ε (mueve(T. cerradura-ε (So) es el único estado dentro de estadosD y no está marcado. mientras haya un estado no marcado T en estadosD hacer marcar T. si U no está en estadosD entonces añadir U como estado no marcado a estadosD.

incluidas todas las transiciones ε anteriores a la lectura • El estado de inicio de D es cerradura-ε(So) • Se añaden los estados y las transiciones a D utilizando el algoritmo anterior • Un estado de D es de aceptación si es un conjunto de estados del AFN que contenga al menos un estado de aceptación de N .Construcción de estadoD Para construir estadosD y tranD se siguen los siguientes pasos: • Cada estado de D corresponde a un conjunto de estados del AFN en los que podría estar N después de leer alguna secuencia de símbolos de entrada.

por lo tanto el AFN resultante tendrá a lo más el doble de estados que símbolos y operadores que hay en la ER .Paso de una ER a un AFN • El algoritmo esta dirigido por la sintaxis en el sentido de que utiliza la estructura sintáctica de la expresión regular para guiar el proceso de construcción • Los casos del algoritmo siguen a los casos de la definición de una expresión regular • Cada paso del algoritmo introduce a lo sumo dos nuevos estados.

En un lenguaje de programación. El significado del programa se describe en téminos de lo que éste hace al ser ejecutado • • . las “frases” son los programas bien construidos sintácticamente Análisis semántico: ¿Qué “significa” cada frase del lenguaje?.Etapas de análisis • Análisis léxico: ¿Cuáles son las “palabras” del lenguaje?. Las palabras de un lenguaje de programación reciben el nombre de símbolos o componentes léxicos (tokens) Análisis sintáctico: ¿Cuáles son las “frases” del lenguaje?.

Métodos para especificar lenguajes .

Estructura Léxica Sintáctica Especificación Reconocimiento Autómatas finitos deterministas Autómatas de pila Reglas “ad-hoc” Expresiones regulares Gramática libre de contexto Semántica Semántica formal. lenguaje natural .

verbo.Gramáticas • • Las gramáticas describen lenguajes Los lenguajes naturales son descritos por una gramática que agrupa palabras en categorías sintácticas tales como sujeto. etc. Una gramática impone una estructura a las sentencias en el lenguaje Una gramática G. define un lenguaje L(G) mediante la definición de un mecanismo para derivar todas las cadenas de un lenguaje • • . predicados.

S) • Donde: V..Gramáticas libres de contexto • Una gramática libre de contexto es un cuarteto G = (V.Conjunto de Reglas de Producción S.Conjunto de Variables T...Símbolo inicial de la gramática .P..T.Conjunto de Terminales P.

Gramáticas libres de contexto • • Las reglas de producción son de la forma: A →α Donde A∈Vyα ∈ ( V ∪T ) Para saber si una cadena forma parte de un lenguaje podemos verificar si se puede derivar a partir del símbolo inicial de la gramática L= { α∣S ⇒ αyα ∈T } .

P.Ejemplo • La siguiente gramática describe el lenguaje de todas las cadenas de ceros y unos que son palíndromos G = ({A}.1}. {0.A) A → 0A0 A → 1A1 A → 0∣1∣ε Derivemos la cadena 001100 A ⇒ 0A0⇒ 00 A00 ⇒ 001 A 100 ⇒001100 .

frase verbal.Gramática libre de contexto • En 1957 Noam Chomsky empleo una notación denominada producciones para definir la sintaxis del inglés (también aplicable al español) Los términos oración.. frase sustantiva. etc. más otras reglas describen un conjunto pequeño oraciones en español • .

<oración> <frase sustantiva> <frase verbal> <artículo> <adjetivo> <sustantivo> <verbo> <adverbio> →<frase sustantiva><frase verbal> →<artículo><frase sustantiva> | <sustantivo><adjetivo> →<verbo><adverbio> →<un | el> →<pequeño> →<niño> →<corrió> →<rápidamente> .

Ejemplo <oración> <frase sustantiva> <artículo > <frase sustantiva> <sustantiv o> <El> <niño> <adjetivo> <pequeño> <corrio> <frase verbal> <verbo> <adverbio> <rápidamente > .

Forma Backus-Naur (BNF) • • El metalenguaje BNF es una forma de especificar lenguajes libres de contexto Fue creado por John Backus y Peter Naur como una forma de describir la sintaxis del lenguaje de programación Algol .

Ejemplo Gramatica para definir una expresión consistente solo en la suma y multiplicación <expresión> <término> <factor> <nombre> <entero> <letra> <dígito> aritmética ::= <expresión> + <término> | <término> ::= <término> * <factor> | <factor> ::= (<expresión>) | <nombre> | <entero> ::= <letra> | <nombre><letra> | <nombre><dígito> ::= <dígito> | <entero><dígito> ::= A | B | ... | Z ::= 0 | 1 | 2 | . | 9 ...

Análizador sintáctico • El analizador sintáctico obtiene una cadena de componentes léxicos del analizador léxico y comprueba si la cadena puede ser generada por la gramática del lenguaje fuente El analizador sintáctico informará de cualquier error de sintaxis También debería recuperarse de los errores que ocurren frecuentemente para poder continuar procesando el resto de la entrada • • .

Programa fuente Analizador léxico Componente léxico Obtén el siguiente componente léxico Analizador sintáctico Árbol de análisis sintáctico Resto de la etapa inicial Representación intermedia Tabla de símbolos .

un símbolo a la vez . se examina la entrada de izquierda a derecha.Análisis sintáctico • Los métodos empleados por los compiladores se clasifican generalmente en ascendentes y descendentes • Los analizadores sintácticos descentes construyen árboles de análisis sintáctico desde arriba (la raíz) hasta abajo (las hojas) • Los analizadores sintácticos ascendetes comienzan en las hojas y terminan en la raíz • En ambos casos.

son lo suficientemente expresivas para describir la mayoria de las construcciones sintácticas de los lenguajes de programación • . como las gramáticas LL y LR.Análisis sintáctico • Los métodos descendentes y ascendentes más eficientes trabajan sólo con subclases de gramáticas Varias de estas subclases.

..T. entonces A → A1 . y los nodos n1.Árboles sintácticos y derivaciones • • De las derivaciones hechas por izquierda y por derecha se puede producir un árbol de análisis sintáctico Este árbol se define como G = (V..P. Am..S) y cumple con las siguientes propiedades: – Cada nodo tiene una etiqueta – La raíz tiene etiqueta S – La etiqueta de los nodos que no son hojas debe estar en V. con etiquetas respectivamnete A1... . .. nm son sus hijos (de izquierda a derecha). Am ∈ P . y las de las hojas en T – Si un nodo n tiene etiqueta A.. .

Árboles sintácticos y derivaciones • Al efectuar un recorrido en orden del árbol de derivación recuperamos la cadena a partir de la cual se construyo dicho árbol De esta forma el problema de analizar una cadena consiste en construir el árbol de derivación a partir del producto de este • .

Gramáticas ambiguas • Es importante señalar que una frase puede generar más de un árbol de análisis sintáctico Este problema se le denomina gramáticas ambiguas Una gramática es ambigua si produce más de un árbol de análisis sintáctico para una frase (derivación izquierda y derecha) • • .

Gramáticas ambiguas • • La mayoria de los compiladores no pueden trabajar con gramáticas ambiguas No podrían determinar de manera exclusiva que árbol de análisis sintáctico seleccionar para una frase Los compiladores que manejan estas gramáticas implementan reglas que desechan árboles de análisis sintáctico indeseables. dejando solo un árbol para cada frase • .

E→E + E E→E * E E→x E→y E x + y * x x + Derivar la cadena: x+y*x E E E y * x . 4.Ejemplo 1. 3. 2.

Gramáticas ambiguas
• Existen dos formas para evitar las gramáticas ambiguas
– Tranformar la gramática – Establecer precedencias entre operadores y de asociatividad

Gramáticas ambiguas
• La transformación de la gramática agrupa todos los operadores de igual precedencia en grupos y asocia a cada uno una regla De esta forma los que tienen menor precedencia aparecen más cercanos al símbolo de inicio Esto conlleva el aumento de la complejidad y del árbol sintáctico generado La gramática deja de ser intuitiva

• •

Ejemplo
1. 2. 3. 4. E→E + E E→E * E E→x E→y x + (y * x)
1.exp → exp + term | term 2.term → term * factor | factor 3.factor → (exp) | x | y

exp → exp + term → term + term → factor + term → x + term → x + factor → x + (exp) → x + (term) → x + (term * factor) → x + (factor * factor) → x + (y * factor) → x + (y * x)

se retrocede para hacer otro intento de producción • Un analizador sintáctico que no requiere retroceso es el analizador sintáctico predictivo .Análisis sintáctico predictivo La selección de una producción para un no terminal puede implicar un proceso de prueba y error • En caso de que no se pueda generar el árbol que concuerde con la cadena de entrada.

Análisis sintáctico predictivo • El análisis sintáctico descendente recursivo es un método descendente en el que se ejecuta un conjunto de procedimientos recursivos para procesar la entrada Una forma especial de este análisis uno denominado análisis sintáctico predictivo El análisis sintáctico predictivo utiliza un símbolo de preanálisis para determinar sin ambigüedad la producción que genera la cadena deseada • • .

Gramáticas recursivas • • • • Es posible que una analizador sintáctico descendente recursivo entre en un ciclo infinito El problema se presenta con producciones recursivas del tipo expr → expr + término El símbolo situado más a la izquierda del lado derecho es el mismo que el no terminal del lado izquierdo de la producción Debido a que el símbolo de preanálisis cambia solo cuando coincide un terminal del lado derecho y la producción inicia con el no terminal expr. entrando a un ciclo infinito . no se realiza ningún cambio en la entrada entre llamadas recursivas.

Gramáticas recursivas • • Las gramáticas pueden ser recursivas por izquierda o por derecha Los analizadores sintácticos requieren que la gramatica este libre de recursividad .

Gramáticas recursivas por izquierda • Una gramática es recursiva por izquierda si tiene un no terminal A tal que existe una derivación A ⇒ Aα para alguna cadena α Ejemplo: βααα A→Aα A → Aα → Aαα A→β → Aααα → βααα • .

Algoritmo para eliminar la recursividad izquierda 1) Se agrupan las producciones de A en la forma A → Aα 1∣Aα 2∣..∣β n 1) Se sustituyen las producciones de A por: A → β 1 A' ∣ β 2 A'∣. . . ..∣ β n A' A' → α 1 A'∣α 2 A' ∣. ..∣α m A'∣ε .∣Aα m∣ β 1∣β 2∣. .

Algoritmo para eliminar la recursividad izquierda A → Aα →β βααα A → βA' → βαA' → βααA' → βαααA' → βααα A → βA' A' → αA' | ε .

Ejemplo E→E+T|T T→T*F|F F → (E) | id E → TE' E'→ +TE' | ε T → FT' T' → * F' | ε F → (E) | id .

Factorización • En ocasiones un símbolo no terminal genera más de una producción y no esta claro cual es mejor opción para el análisis Se pueden reescribir las producciones para retrasar la desición hasta haber visto lo suficiente de la entrada como para elegir la opción correcta Esta técnica se conoce como factorización • • .

Factorización • La factorización por izquierda es una transformación gramatical adecuada para el análisis sintáctico predictivo La factorización izquierda ayuda a seleccionar una de varias producciones con prefijo común • .

Algoritmo para realizar la factorización izquierda • Para cada no terminal A. encuentrese el prefijo α más largo común a dos o más de sus alternativas .

∣αβ n∣γ. existe un prefijo común no trivial. . por A → αA'∣γ A' → β 1∣β 2∣.∣β n . donde γ representa todas las alternativas que no comienzan con α. .. A → αβ 1∣αβ 2∣. sustitúyanse todas las producciones de A. .Algoritmo para realizar la factorización izquierda • Si α≠ε es decir.

Algoritmo para realizar la factorización izquierda • Esta transformación se aplica hasta que no haya dos alternativas para un no terminal con un prefijo común .

Ejemplo A → αβ 1∣αβ 2 A → αA' A' → β 1∣β 2 P → iE+P∣iE+PeP∣a E →b P → iE+PP'∣a P → eP∣ε E →b .

Análisis sintáctico descendente • El análisis sintáctico descendente es un método que intenta encontrar una derivación por la izquierda para una cadena de entrada El árbol de análisis sintáctico generado por este método es construido desde la raíz. creando los nodos del árbol en preorden • .

el primer símbolo de w Después se utiliza la primera producción de S para expandir el árbol .Ejemplo Dada la gramática y la cadena • S → cAd A → ab∣a w=cad • Primero se utiliza el nodo etiquetado como S y un apuntador a la izquierda que apunta a C.

Ejemplo • En cada nueva producción se intentará emparejar la hoja situada más a la izquierda. se indica el fallo y se regresa al no terminal anterior para verificar si existe otra alternativa de reescritura • • . con el símbolo apuntado por w Si se encuentra una concordancia entonces se avanza el apuntador al siguiente símbolo de w En caso de que no exista concordancia.

Ejemplo S → cAd A → ab∣a S c A d c a S A b d c S A a d .

Análisis sintáctico predictivo • Si se diseña una gramática eliminando su recursión izquierda y factorizando por izquierda se puede obtener una gramática que puede utilizar un analizador sintáctico descendente recursivo que no necesite retroceso Este analizador se conoce como sintáctico predictivo • .

.Analizador sintáctico predictivo • Para construir un analizador sintáctico predictivo se debe conocer dado el símbolo actual a de entrada y el no terminal A a expandir. .∣α n es la única alternativa que da lugar a una cadena que comience con a . cual de las alternativas de producción A → α 1∣α 2∣.

también se puede crear un diagrama de transiciones como plan para un analizador sintáctico predictivo .Diagramas de transiciones para analizadores sintácticos predictivos • Al igual que existen diagramas de transiciones para un analizador léxico.

Diagramas de transiciones para analizadores sintácticos predictivos • Existen varias diferencias entre los diagramas del analizador léxico y el sintáctico – En un analizador sintáctico existe un diagrama para cada no terminal – Las etiquetas de las aristas son componentes léxicos y no terminales .

.x 2 ..Ejemplo • Para cada no terminal se hace los siguiente: 1) Crear un estado inicial y un estado final 2) Para cada producciónA → x 1∣x 2∣.∣x n crear un camino desde el estado inicial al estado final. . con aristas etiquetadas con x 1 . . . .x n .

Ejemplo E → TE' E'→ +TE' | ε T → FT' T' → * FT' | ε F → (E) | id id + id .

en vez de hacerlo implicitamente con las llamadas recursivas • .Análisis sintáctico predictivo no recursivo • Los algoritmos recursivos generalmente ocupan más recursos (memoria y procesamiento) que los iterativos Se puede construir un analizador sintáctico predictivo no recursivo manteniendo explicitamente una pila.

Análisis sintáctico predictivo no recursivo • El problema clave durante el análisis sintáctico predictivo es determinar la producción que debe aplicarse a un no terminal El analizador sintáctico no recursivo busca la producción que debe aplicarse en una tabla de análisis sintáctico • .

Modelo del analizador sintáctico predictivo no recursivo Entrada a+b$ Programa para análisis sintáctico predictivo Tabla de análisis sintáctico M buffer X Pila Y Z $ Salida .

que indica la base de la pila. donde A es un no terminal.Componentes del analizador sintáctico predictivo no recursivo • Buffer de entrada: contiene la cadena que se va a analizar. a]. Al principio. y a es un terminal o el símbolo $ • • . la pila contiene el símbolo inicial de la gramática encima de $ Tabla de análisis sintáctico: es una matriz bidimensional M [A. seguida de un símbolo $. un símbolo utilizado como delimitador derecho para inidicar el fin de la cadena de entrada Pila: contiene una secuencia de símbolos gramaticales con $ en la parte de abajo.

Algoritmo de análisis sintáctico predictivo no recursivo • • Entrada: una cadena w y una tabla de análisis sintáctico predictivo no recursivo Salida: si w está en L(G). de lo contrario una indicación de error . una derivación por la izquierda de w.

..Apuntar al primer símbolo de w$ Repetir    Sea x el símbolo de la cima en la pila y a el símbolo apuntado   Si x es un terminal o $ entonces     Si x = a entonces       Extraer x de la pila y avanzar al siguiente símbolo     Si no       Error()   Si no /* x no es terminal */     Si M [x.a] = x → y1y2.. y1 en la pila. yk­1.. .. con y1 en la cima     Else       Error()     Fin si Hasta x = $ /* la pila está vacia */ .yk entonces       Extraer x de la pila       Meter yk.

Gramática: E → TE’ No terminal +TE’ | ε E’ → T → FT’ T’ → *FT’ | ε F → (E) | id Símbolo de entrada PILA ENTRADA SALIDA .

permiten rellenar siempre que sea posible. las entradas de una tabla de análisis sintáctico predictivo También se pueden utilizar los conjuntos de componentes léxicos devueltos por la función siguiente como componentes léxicos de sincronización durante la recuperación de errores en modo pánico • .Cálculo de conjuntos primero y siguiente • Las funciones primero y siguiente.

aplíquense las reglas siguientes hasta que ya no se puedan agregar terminales o ε a ningún conjunto primero • . se considera primero (α) como el conjunto de terminales que inician las cadenas derivadas de α Para calcular primero (x) para todos los símbolos gramaticales x.Conjunto primero • Si α es una cadena de símbolos gramaticales.

entonces primero (x) es {x} Si x → ε es una producción. 3. . y k donde y k puede ser un terminal o no terminal Para cada producción realizar las siguientes acciones: .Conjunto primero 1. Si x es terminal. . 2. entonces añádase ε a primero (x) Si x es no terminal entonces se analizan todas las reglas de producción con x en la izquierda de la forma: x → y 1 y 2 y 3.

Conjunto primero – Añadir primero ( y 1 ) .. entonces añadir primero ( y 3 ) en primero(x) – .{ε} en primero (x) – Si ε está en primero ( y 2 ).. entonces añadir primero ( y 2 ) . – Si ε está en primero ( y i ) para1≤i≤k (todas sus producciones del lado derecho) entonces poner ε dentro de primero (x) .{ε} a primero (x) – Si ε está en primero ( y 1 ).

x n toda i primero( ) contiene ε • xi . . y así sucesivamente x3 Por último. . x)n todos los símbolos distintos de ε primero ( ) x1 Si ε está en primero( x ) añádase también los 1 símbolos distintos de ε de primero( ) x 2 Si ε está tanto en primero( ) como en primero( ) x1 x2 añádase también los símbolos distintos de ε de primero( ). .En resumen. .. • • • Añádase a primero ( x 1 x 2 x 3 .. añádase ε a primero( ) si para x 1 x 2 x 3.

siguiente(A) es el conjunto de terminales que pueden aparecer inmediatamente a al derecha de A en alguna derivación parcial • Por ejemplo: – El terminal t está en siguiente(A) si s → ..At. donde t es un terminal ...Siguiente • Para un no terminal A..

Siguiente 1. poner primero – Para cada producción ( ) . Si A es el no terminal inicial.poner siguiente (X) – Por cada producción β en siguiente(X) en siguiente(A) x → αA .{ε} en siguiente (A) – Si ε está en primero( ) entonces poner x → αAβ siguiente(X)βen siguiente(A) . 2. poner $ en siguiente(A) Encontrar las producciones con A en el lado derecho .

a] de la tabla de análisis sintáctico está vacia – .Recuperación de errores en el análisis sintáctico predictivo • Durante el análisis sintáctico predictivo se detecta un error cuando: – el terminal de la cima de la pila (tope) no concuerda con el siguiente símbolo de entrada Cuando el no terminal A esta en la cima de la pila. y la entrada M[A. a es el siguiente símbolo de entrada.

Recuperación de errores en el análisis sintáctico predictivo • La recuperación en modo de pánico se basa en la idea de saltarse símbolos de la entrada hasta que aparezca un componente léxico que pertenezca a un conjunto seleccionado de componentes léxicos de sincronización .

es probable que el análisis sintáctico pueda continuar .Recuperación de errores en el análisis sintáctico predictivo • Para generar los componentes léxicos de sincronización se aplica el siguiente procedimiento: – Se colocan todos los símbolos de siguiente (A) dentro del conjunto de sincronización para el no terminal A • Si se saltan componentes léxicos hasta encontrar un elemento de siguiente (A) y se saca a A de la pila.

Ejemplo No terminal Símbolo de entrada .

se saca el no terminal de la cima de la pila para continuar el análisis Si un componente léxico de la cima de la pila no concuerda con el símbolo de entrada.a] y ve que está en blanco. debe saltarse el símbolo de entrada a Si la entrada es sinc. como ya se ha mencionado • • . entonces se saca el componente léxico de la pila.Aplicación del algoritmo • Si el analizador sintáctico busca la entrada M[A.