Clase #4 - Lenguajes regulares y Expresiones regulares [Compiladores e interpretes UNET]

Clase#4- - Compiladores Compiladores e Interpretes Lenguajes regulares y expresiones regulares Luis Ochoa [email protected] Dado un alfabeto Σ

Info iconThis preview shows page 1. Sign up to view the full content.

View Full Document Right Arrow Icon
This is the end of the preview. Sign up to access the rest of the document.

Unformatted text preview: Compiladores Compiladores e Interpretes Lenguajes regulares y expresiones regulares Luis Ochoa [email protected] Dado un alfabeto Σ, definimos: Repaso Cosas importantes para las Regex (Expresiones Regulares) • Σk = {x | x es una palabra sobre Σ y |x| = k} Ejemplo: Σ = {0, 1} ▫ Σ0 ={λ} ▫ Σ1 ={0, 1} ▫ Σ2 ={00, 01, 10, 11} ▫ Σ3 ={000, 001, 010, 011, 100, 101, 110, 111} ▫ ... • Σ* = Σ0 ∪ Σ1 ∪ Σ2 ∪ Σ3 ∪... es el conjunto de todas las palabras que pueden ser formadas con letras del alfabeto Σ, incluyendo a λ. A Σ* se le llama la Cerradura de Kleene de Σ. • Σ+ = Σ1 ∪ Σ2 ∪ Σ3 ∪... es el conjunto de todas las palabras novacías que pueden ser formadas con letras de Σ, es decir, Σ+ = Σ* − {λ}. Repaso Cosas importantes para las Regex (Expresiones Regulares) Concatenación de lenguajes • L1L2 = {w | w = xy, x ∈ L1 y y ∈ L2} • Para un lenguaje L: ▫ ▫ ▫ ▫ ▫ ▫ ▫ L0 = {λ} L1 = L L2 = L L L3 = L L L ... L* = L0 ∪ L1 ∪ L2 ∪ L3 ∪... (Cerradura de Kleene) L+ = L1 ∪ L2 ∪ L3 ∪... = LL* Repaso Cosas importantes para las Regex (Expresiones Regulares) Ejemplo de concatenación • X = {a, b, c}; Y = {abb, ba} ▫ ▫ ▫ ▫ ▫ XY ={aabb, aba, babb, bba, cabb, cba} X0 = {λ} X1 = {a, b, c} X2 = XX = {aa, ab, ac, ba, bb, bc, ca, cb, cc} X3 = X2X = {aaa, aab, aac, aba, abb, abc, aca, acb, acc, baa, bab, bac, bba, bbb, bbc, bca, bcb, bcc, caa, cab, cac, cba, cbb, cbc, cca, ccb, ccc} Repaso Cosas importantes para las Regex (Expresiones Regulares) Ejemplo Cerradura de Kleene • L = {0, 11} ▫ ▫ ▫ ▫ ▫ L 0 = {λ } L1 = {0, 11} L2 = {00, 011, 110, 1111} L3 = {000, 0011, 0110, 01111, 1100, 11011, 11110, 111111} L4 = {0000, 00011, 00110, 001111, 01100, 011011, 011110, 0111111, 11000, 110011, 110110, 1101111, 111100, 1111011, 1111110, 11111111} ▫ L* son todas las que se pueden formar concatenando cualquier número de veces (excepto ∞) palabras de L. Las palabras pueden ser iguales o distintas. Repaso Cosas importantes para las Regex (Expresiones Regulares) Ejemplos Varios • L = {a, b}*{bb} {a, b}* ▫ Consiste de las cadenas sobre {a, b} que contienen la subcadena bb. • Lenguaje que consiste de todas las cadenas que empiezan con aa o terminan con bb. • L1 = {bb} y L2 = {λ, bb, bbbb}. L1* = ¿?, L2* = ¿? • {aa, bb, ab, ba}* ▫ Consiste de todas las cadenas sobre {a, b} de longitud par. ▫ L = {aa}{a, b}* ∪ {a, b}*{bb} ▫ Tanto L1* como L2* consisten de cadenas que tienen un número par de b’s. Repaso Cosas importantes para las Regex (Expresiones Regulares) En lingüística la jerarquía de Chomsky es una clasificación jerárquica de distintos tipos de gramáticas formales que generan lenguajes formales. • Gramáticas de tipo 0 (sin restricciones), que incluye a todas las gramáticas formales. Estas gramáticas generan todos los lenguajes capaces de ser reconocidos por una máquina de Turing. Los lenguajes son conocidos como lenguajes recursivamente enumerables. Nótese que esta categoría es diferente de la de los lenguajes recursivos, cuya decisión puede ser realizada por una máquina de Turing que se detenga. • Gramáticas de tipo 1 (gramáticas sensibles al contexto) generan los lenguajes sensibles al contexto. Estas gramáticas tienen reglas de la forma con A un no terminal y α, β y γ cadenas de terminales y no terminales. Las cadenas α y β pueden ser vacías, pero γ no puede serlo. La regla está permitida si S no aparece en la parte derecha de ninguna regla. Los lenguajes descritos por estas gramáticas son exactamente todos aquellos lenguajes reconocidos por una máquina de Turing no determinista cuya cinta de memoria está acotada por un cierto número entero de veces sobre la longitud de entrada. • Gramáticas de tipo 2 (gramáticas libres del contexto) generan los lenguajes independientes del contexto. Las reglas son de la forma con A un no terminal y γ una cadena de terminales y no terminales. Estos lenguajes son aquellos que pueden ser reconocidos por un autómata con pila. • Gramáticas de tipo 3 (gramáticas regulares) generan los lenguajes regulares. Estas gramáticas se restringen a aquellas reglas que tienen en la parte izquierda un no terminal, y en la parte derecha un solo terminal, posiblemente seguido de un no terminal. La regla también está permitida si S no aparece en la parte derecha de ninguna regla. Estos lenguajes son aquellos que pueden ser aceptados por un autómata finito. También esta familia de lenguajes pueden ser obtenidas por medio de expresiones regulares. Expresiones Regulares Son expresiones que permiten describir lenguajes regulares de manera simple, sencilla y precisa. En otras palabras permiten abreviar la descripción de conjuntos regulares. • El conjunto regular {a} es representado por a. • ∅ y λ son expresiones regulares. • Cada símbolo de∑ es una expresión regular. • Si e1 y e2 son expresiones regulares entonces: ( e1+ e2 ) es una expresión regular. ( e1 . e2 ) es una expresión regular. • Si e es una expresión regular, entonces e* es una expresión regular. • Ninguna otra es una expresión regular. Definición Recursiva de las Expresiones Regulares • Sea Σ un alfabeto. Las expresiones regulares sobre Σ se definen recursivamente de la siguiente manera: ▫ Base: ∅ (Lenguaje que no contiene ninguna palabra, lenguaje vacio), λ (Lenguaje que contiene la palabra vacía) y a, para toda a ∈ Σ, son expresiones regulares sobre Σ. (Importante: no se debe confundir a ∅ con λ porque por ejemplo, si L{λ}={λ}L=L, mientras que L∅= ∅L= ∅) ▫ Paso recursivo: Si u y v son expresiones regulares sobre Σ, entonces las expresiones (u+v), (uv) y (u*) también lo son y representan a los conjuntos {u} ∪ {v}, {u}{v} y {u}*, respectivamente. ▫ Cerradura: u es una expresión regular sobre Σ sólo si puede ser obtenido a partir de los elementos base mediante un número finito de aplicaciones del paso recursivo. Ejemplos Expresiones Regulares Lenguaje {λ} {0} {001} = {0}{0}{1} {0, 1} = {0}∪{1} {0, 10} = {0}∪{10} {1, λ}{001} {110}*{0, 1} {1}*{10} {10, 111, 11010}* {0, 10}*({11}*∪{001, λ}) (00 + 01 + 10 + 11)* Expresión Regular λ 0 001 0+1 0 + 10 (1 + λ)001 (110)*(0 + 1) 1*10 (10 + 111 + 11010)* (0 + 10)*((11)* + 001 + λ) ((0 + 1)(0 + 1))* Convenciones Expresiones Regulares • Tomando en cuenta que la unión y la concatenación son asociativas, además conviniendo en que la precedencia u orden de ejecución de las operaciones está dada por: ▫ ▫ ▫ ▫ Paréntesis Cerradura de Kleene Concatenación Unión Igualmente las expresiones se pueden simplificar aún más reduciendo el número de paréntesis: ▫ {a, b}*{bb}{a, b}* = (a + b)*bb(a + b)* ▫ {a}{a, b}*{b}{a, b}*{a} = a(a + b)*b(a + b)*a ▫ u+ = uu* ▫ u2 = uu, u3 = u2u, ... • Notación Ejemplo El conjunto {bawab | w ∈ {a, b}*} es regular sobre {a, b} Demostración: Conjunto 1. {a} 2. {b} 3. {a}{b}={ab} 4. {a} ∪ {b}={a,b} 5. {b}{a}={ba} 6. {a,b}* 7. {ba}{a,b}* 8. {ba}{a,b}*{ab} Expresión a b ab a+b ba (a+b)* ba(a+b)* ba(a+b)*ab Justificación Base Base Concatenación de 1 y 2 Unión de 1 y 2 Concatenación de 2 y 1 Cerradura Kleene de 4 Concatenación de 5 y 6 Concatenación de 7 y 3 Lenguajes Regulares • Definición: Un lenguaje es regular si se puede representar por una expresión regular o conjunto regular. • (a+b)*aa(a+b)*+(a+b)*bb(a+b)*: ▫ Representa al conjunto de cadenas sobre {a, b} que contienen a la subcadena aa o a la subcadena bb o a ambas subcadenas. Más Ejemplos • Expresión regular que represente al conjunto de cadenas sobre {a, b} que contienen exactamente dos b’s: ▫ a*ba*ba* • a*ba*b(a+b)*, (a+b)*ba*ba*, (a+b)*b(a+b)*b(a+b)* ▫ representan al conjunto de cadenas sobre {a, b} que contienen dos o más b’s. • a*(a*ba*ba*)* y a*(ba*ba*)* ▫ Representan cadenas con un número par de b’s. • Expresión regular para el lenguaje sobre {a, b} en cuyas palabras inmediatamente antes de toda b aparece una a: ▫ (a+ab)*. • Expresión regular que representa a las palabras que contienen exactamente una vez dos b’s contiguas: ▫ (ba+bc+a+c)*bb(a+c+ab+cb)* Ejercicio • Escriba una expresión regular para el lenguaje sobre {0 ,1} que consiste de las palabras en las que no hay dos símbolos iguales contiguos, es decir, los 0’s y los 1’s se alternan. Posible Solución al Ejercicio ▫ (01)* + (10)* + 0(10)* + 1(01)* ▫ (λ + 1)(01)*(λ + 0) ▫ (λ + 0)(10)*(λ + 1) Equivalencia en las expresiones regulares • Una expresión regular define un patrón; una palabra pertenece al lenguaje definido por esa expresión regular si y sólo si sigue el patrón. • Una expresión regular que represente un lenguaje debe cumplir cumplir dos condiciones: ▫ Correcta: todas las palabras representadas por la expresión regular deben ser parte del lenguaje. ▫ Completa: toda palabra del lenguaje debe ser representada por la expresión regular. • Concatenación indica orden de los símbolos, la cerradura de Kleene permite repeticiones y + indica selección. • Dos expresiones que representan al mismo conjunto son llamadas equivalentes. Identidades en expresiones regulares • • • • • • • • • • • • • • • • ∅u = u∅ = ∅ λu = uλ = u ∅* = λ λ* = λ u+v = v+u u+∅ = u u+u = u u* = u* u* = (u*)* u(v+w) = uv + uw (u+v)w = uw+vw (uv)*u = u(vu)* (u+v)* = (u*+v)* = u*(u+v)* = (u+vu*)* = (u*v*)* = u*(vu*)* = (u*v)*u* u*(u + λ) = u* u*u* = u* u* + v* = v* + u* (u*v*)* = (u + v)* = (u + v)*uv(u + v)* + v*u* Ejemplos • Expresión que representa las cadenas sobre {a, b} que no contienen la subcadena aa: ▫ b*(ab+)*+b*(ab+)*a = b*(ab+)*(λ+a) = b*(abb*)*(λ+a) = (b+ab)*(λ+a) • Expresión regular que representa las cadenas sobre {a, b, c} que contienen la subcadena bc: ▫ (a+b+c)*bc(a+b+c)* • c*(b+ac*)* ▫ Representa las cadenas que no contienen la subcadena bc. • Cadenas sobre {0, 1} de longitud igual a 6: ▫ (0 + 1)(0 + 1)(0 + 1)(0 + 1)(0 + 1)(0 + 1) = (0 + 1)6 • Cadenas sobre {0, 1} de longitud mayor o igual a 6: ▫ (0 + 1)(0 + 1)(0 + 1)(0 + 1)(0 + 1)(0 + 1)(0 + 1)* = (0 + 1)6(0 + 1)* • Cadenas sobre {0, 1} de longitud menor o igual a 6: ▫ (0 + 1 + λ)(0 + 1 + λ)(0 + 1 + λ)(0 + 1 + λ)(0 + 1 + λ)(0 + 1 + λ) = (0 + 1 + λ)6 Ejercicios • Obtenga una expresión regular para el conjunto de palabras sobre {a, b, c} que tienen tienen al menos una a y al menos una b. • Obtenga una expresión regular para el lenguaje sobre {0 , 1} que consiste de las palabras cuyo décimo símbolo contado de la derecha a la izquierda es un 1. Posibles soluciones a los ejercicios c*a(a + c)*b(a + b + c)* + c*b(b + c)*a(a + b + c)* (0+1)*1(0+1) (0+1) (0+1) (0+1) (0+1) (0+1) (0+1) (0+1) (0+1) = (0 + 1)*1(0 + 1)9 Pregunta ¿Hay ¿Hay lenguajes para los que no existe una expresión regular que los represente? Respuesta Construcción intuitiva del autómata finito de una expresión regular Si tenemos en cuenta que: 1. El lenguaje ∅ es reconocido por el autómata: 2. El lenguaje {λ} es reconocido por el autómata: 3. El lenguaje {a} es reconocido por el autómata: Construcción intuitiva del autómata finito de una expresión regular • Tomando en cuenta los procedimientos de construir los autómatas de unión, concatenación y cierre de Kleene en lenguaje regulares, podemos construir el autómata que reconoce el lenguaje de una expresión regular, a partir de los autómatas mostrados en la diapositiva anterior. • Por ejemplo: ▫ Dada la expresión regular b*(a+b)a, construir el autómata que reconozca el lenguaje descrito por esta expresión regular. Construcción intuitiva del autómata finito de una expresión regular 1. El autómata que reconoce b es el siguiente: 2. A partir de este hallamos el que reconoce b*: Construcción del autómata finito de una expresión regular 3. El autómata que reconoce a + b a partir de los que conocen a y b respectivamente, es el siguiente: 4. A partir de los anteriores se encuentra el que reconoce b*(a+b): Construcción del autómata finito de una expresión regular 5. A partir del que reconoce a y del que reconoce b*(a+b) se encontraría el que reconoce b*(a+b)a: 6. Aunque ya esta listo el autómata, el ultimo paso que deberíamos llevar a cabo es la determinación (DFA) y minimización del resultado obtenido. Desde las expresiones regulares hasta el analizador léxico Normalmente durante la construcción de un analizador léxico, el primer método usado para reconocer los patrones de los testigos de un lenguaje son las expresiones regulares, es por esto que la generalización del analizador léxico comienza por estas y continua luego hacia la construcción de un NFA para las mismas, que luego es convertido en un DFA y por ultimo se construye con este un programa analizador léxico final. Por esta razón es de nuestro interés estudiar las conversiones antes mencionadas: Expresión regular NFA DFA programa Desde una expresión regular hasta un NFA Para esta conversión estudiaremos la construcción de Thompson, que utiliza transiciones Ű, para “pegar” las maquinas de cada segmento de una expresión regular con el fin de formar una máquina que corresponda a la expresión expresión completa. (estado aceptador con doble circulo en esta notación) Expresiones regulares básicas: Una expresión regular básica como un carácter, Ű, ɸ tiene como NFA equivalente a: Desde una expresión regular hasta un NFA (estado aceptador con doble circulo en esta notación) Concatenación: Si deseamos construir un NFA para la expresión regular rs, donde r y s son expresiones regulares. Primero suponemos que tenemos los NFA equivalentes de r y s, al escribir (ej. solo para r): Y con estos construimos el NFA equivalente, al conectar el estado de aceptación de la maquina r, con el inicial de la maquina s, mediante una transición Ű. Desde una expresión regular hasta un NFA (estado aceptador con doble circulo en esta notación) Selección entre alternativas: Si deseamos construir un NFA para la expresión regular r|s, donde r y s son expresiones regulares. Agregamos un nuevo estado de inicio y un nuevo estado de aceptación aceptación y los conectamos como se muestra utilizando transiciones Ű. Desde una expresión regular hasta un NFA (estado aceptador con doble circulo en esta notación) Repetición: Si deseamos construir un NFA para la expresión regular r*, donde r es una expresión regular. Agregamos un nuevo estado de inicio y un nuevo estado de aceptación y mediante una transición Ű proporcionamos la repetición de esta esta máquina: Desde una expresión regular hasta un NFA (estado aceptador con doble circulo en esta notación) Ejemplo: Traduciremos la expresión regular ab|b en un NFA de acuerdo con la construcción de Thompson: Entonces formamos la maquina ab: Ahora formamos la maquina ab|b, al unir una copia de a con ab para la selección: Expresiones regulares para analizadores léxicos • Una expresión regular r se encuentra definida por el conjunto de cadenas con las que concuerda, denominándose este conjunto el lenguaje generado por la expresión regular, escribiéndose como L(r). • Este lenguaje solo se refiere a cadenas de caracteres y por el momento no tiene nada que ver con los lenguajes de programación. • Una expresión regular usara símbolos de un alfabeto (∑), pero estos caracteres tendrán un significado diferente, ya que todos indicaran patrones. Expresiones regulares Definición básica: 1. Una expresión regular básica esta constituida por un solo carácter proveniente del alfabeto definido, el meta-carácter Ű (palabra vacía) o el lenguaje vacio (ɸ). 2. 2. Una expresión de selección entre alternativas, de la forma r|s, donde r y s son expresiones regulares. 3. Una expresión de concatenación de caracteres, de la forma rs (algunas veces se usa un •, aunque este se puede obviar) donde tanto r como s son expresiones regulares. 4. Una expresión de repetición de la forma r*, para expresar una cerradura de Kleene, donde r es una expresión regular. Expresiones regulares Precedencia, paréntesis y nombres. • La precedencia viene dada por: ▫ Repetición (*) Mayor precedencia. ▫ Concatenación. ▫ Selección entre opciones (|) Menor precedencia. • Si deseamos una precedencia diferente debemos usar paréntesis ( ), por ejemplo a|b * sin usar paréntesis se puede interpretar como: ( a| b) *, interpretación incorrecta, a | (b *), interpretación correcta pero era lo que se quería expresar. Expresiones regulares Precedencia, paréntesis y nombres. • A las expresiones regulares largas se le pueden asignar nombres como una forma de simplificar la notación, de modo que no tengamos que escribirla cada vez que deseemos utilizarla, por ejemplo podríamos escribir una expresión regular para la secuencia de uno o más dígitos numéricos como: (0|1|2|3|4|5|6|7|8|9)(0|1|2|3|4|5|6|7|8|9)* o podríamos usar nombres dígito dígito* donde digito = 0|1|2|3|4|5|6|7|8|9 Ejemplos con expresiones regulares Consideremos el alfabeto ∑= {a,b,c}, como sería una expresión regular que genere las cadenas de este alfabeto que contengan exactamente una b: (a|c)*b(a|c)* Ejemplos con expresiones regulares Consideremos el alfabeto ∑= {a,b,c}, considere el conjunto de todas las cadenas que contienen como máximo una b: (a|c)*|(a|c)*b(a|c)* (a|c)*(b|Ű)(a|c)* Ejemplos con expresiones regulares Consideremos el alfabeto ∑= {a,b,c}, y la expresión regular que se muestra, determine para la misma una descripción concisa del lenguaje que genera: ((b|c)*a(b|c)*a)*(b|c)* Esto genera el lenguaje de todas las cadenas que contengan un numero par de letras a. Expresiones regulares Extensiones para las expresiones regulares: 1. Una o más repeticiones, también conocida como la clausula positiva de Kleen, se expresa con el símbolo +, por ejemplo (1|0)+, es equivalente a la expresión regular (1|0)(1|0)* 2. Cualquier carácter, para generar cualquier carácter en el alfabeto, se utiliza el metacarácter punto “.”, con lo que podemos escribir por ejemplo una expresión regular para todas las cadenas que contengan una b como .*b.* 3. Un intervalo de caracteres, a menudo se necesita escribir un intervalo de caracteres, para esto tenemos dos opciones los enumeramos con una selección de alternativas como por ejemplo 0|1|2|…|9 o usamos una clase de caracteres como [0-9], otros ejemplos son: [abc] que equivale a (a|b|c) o [a-zA-Z] que equivale a todas las letras mayúsculas y minúsculas. Expresiones regulares Extensiones para las expresiones regulares: 4. Cualquier carácter que no este en un conjunto dado, es decir se lleva a cabo la búsqueda del complemento de un conjunto dado, normalmente se representa con la tilde “~” o el carat “^”, y se usa por ejemplo para generar un carácter que no sea a como ~a (equivale a [^ a]), o un carácter que no sea a, ni b ni c, como ~(a|b|c) (equivale a [^ abc]). Subexpresiones opcionales, sirve para cadenas que contienen partes opcionales que pueden o no aparecer en cualquier cadena generada, se expresa con el símbolo “?”, por ejemplo un numero puede o no tener signo inicia + o -, lo cual se puede expresar como natural = [0-9]+ naturalconsigno = natural | + natural | - natural o con natural=[0-9]+ naturalconsigno=(+|-)? natural 5. Expresiones regulares para testigos o tokens de lenguajes de programación • Los testigos de los lenguajes de programación tienden en varias categorías limitadas que son fácilmente clasificables de manera estándar: ▫ Números: Pueden ser solo secuencias de dígitos (números naturales), números decimales o números con exponente, pudiéndose escribir expresiones regulares para los mismos: nat = [0-9]+ natconSigno = (+|-)? nat exponencial = natconSigno (“.” nat)?(E natconsigno) El punto va entre “” para enfatizar que no debe ser interpretado como un metacarácter. Expresiones regulares para testigos o tokens de lenguajes de programación ▫ Identificadores y palabras reservadas: son las más simples de escribir como expresiones regulares, ya que están representadas por secuencias fijas de caracteres., a excepción de los identificadores que no son fijos pero por lo general comienzan por una letra, contienen solo letras o números, Por ejemplo: reservada = if | while | do | … letra = [a-zA-Z] digito = [0-9] identificador = letra (letra|digito)* Expresiones regulares para testigos o tokens de lenguajes de programación ▫ Comentarios: ya que los comentarios se deben ignorar durante la fase de análisis léxico, el analizador léxico debe ser capaz de reconocerlos e ignorarlos, por lo tanto se necesitan conocer sus expresiones regulares así no se usen durante el análisis, los comentarios pueden tener varias formas, por ejemplo los comentarios de pascal ▫ {éste es un comentario}: {(~})*} Expresiones regulares para testigos o tokens de lenguajes de programación • Ambigüedades, espacios en blanco y búsquedas hacia adelante: Un lenguaje debe proporcionar reglas de no ambigüedad, pero cadenas como <> se pueden interpretar como el símbolo mayor, menor o el no igual a, por lo que existen ciertas reglas que ayudan a lidiar con estos y otros aspectos y estas son: ▫ Cuando una cadena puede ser un identificador o una palabra reservada reservada, se prefiere por lo general la interpretación como palabra reservada. ▫ Cuando una cadena puede ser un testigo (token) simple o una secuencias de varios testigos (tokens), por lo general se prefiere la interpretación de testigo simple. Esto a menudo se conoce también como el principio de la subcadena más larga, que dice: la cadena más larga de caracteres que podrían constituir un testigo simple en cualquier punto se supone que representa el siguiente testigo ▫ Pero esto trae a juego la cuestión de los delimitadores de testigos o testigos que implican que una cadena más larga no puede pasar del punto donde este se consiga, es decir son parte no ambigua de otro testigos, ejemplo xvar=yvar, donde el signo de igualdad limita el tamaño de un identificador, para lidiar con esto se crean pseudotestigos como: espacioenblanco=(nuevalinea|blanco|tabulación|comentario)+ Autómatas finitos para testigos o tokens de lenguajes de programación • Los autómatas son un manera matemática para describir clases particulares de algoritmos (o “máquinas”), en nuestro caso específicamente los mismos se utilizan para describir el proceso de reconocimiento de patrones en cadenas de entrada, y de este modo se pueden usar para construir analizadores léxicos. • Sus principales componentes son: los estados, las transiciones, el estado inicial y los estados de aceptación. • Existen dos tipos principales de autómatas finitos: Los determinísticos (DFA). Los no determinísticos (NFA). Autómatas finitos para testigos o tokens de lenguajes de programación Autómatas finitos determinísticos (DFA): • Son autómatas donde el estado siguiente está dado de forma inequívoca por el estado actual y el carácter de entrada actual. • Por ejemplo el DFA que reconoce identificadores letra letra Entrada_id inicio otro error otro otro + cualquiera dígito Autómatas finitos para testigos o tokens de lenguajes de programación Autómatas finitos determinísticos (DFA): • Aspectos importantes para facilitar su uso: ▫ Los estados se pueden llamar de cualquier forma u omitirse el nombre si este no es necesario. ▫ Se pueden etiquetar las transiciones con nombres que representen un conjunto de caracteres y no necesariamente con caracteres. ▫ Las transiciones de error son opcionales y se puede suponer su existencia, pero se debe tener cuidado con no confundir el DFA con un NFA. ▫ Se asume que el estado de error es también de no aceptación. Autómatas finitos para testigos o tokens de lenguajes de programación Ejemplo #1: usando las recomendaciones El conjunto de cadenas que contienen exactamente una b. nob nob b + Autómatas finitos para testigos o tokens de lenguajes de programación Ejemplo #2 El conjunto de cadenas que contienen como máximo una b: nob nob b + + Autómatas finitos para testigos o tokens de lenguajes de programación Ejemplo#3 El DFA para la definición de constantes numéricas en notación científica: digito = [0-9] nat = digito+ natconSigno =(+|-)? Nat numero = natconSigno (“.” nat)?(E natconsigno)? Para esto procedemos paso a paso a construir el DFA. Autómatas finitos para testigos o tokens de lenguajes de programación Ejemplo#3 continuación Primer paso es escribir un DFA para los números naturales: nat = digito+ digito digito + Autómatas finitos para testigos o tokens de lenguajes de programación Ejemplo#3 continuación El segundo paso es escribir un DFA para los numeros naturales con signo: natconSigno = (+|-)?nat + digito digito digito + Autómatas finitos para testigos o tokens de lenguajes de programación Ejemplo#3 continuación Como tercer paso agregamos la parte fraccional: natconSigno = (+|-)?nat digito digito digito . digito digito + + + Autómatas finitos para testigos o tokens de lenguajes de programación Ejemplo#3 continuación Por ultimo agregamos la parte exponencial opcional numero = natconSigno (“.” nat)?(E natconsigno)? + - digito digito digito . digito E digito E + - digito digito digito + + + Autómatas finitos para testigos o tokens de lenguajes de programación Ejemplo#4 Los comentarios en pascal son aceptados por el siguiente DFA: otro } } + Autómatas finitos para testigos o tokens de lenguajes de programación Búsqueda hacia adelante y retroseguimiento: • Debemos recordar que el diagrama de un DFA no representa todo lo que debe tener un DFA sino que solo proporciona un esbozo de su funcionalidad, e incluso incluso su definición matemática no describe todos los aspectos del comportamiento de un algoritmo del DFA. • Por ejemplo no se especifica que hará un programa de un DFA al alcanzar un estado de aceptación, o incluso cuando iguale un carácter durante una transición. Autómatas finitos para testigos o tokens de lenguajes de programación Búsqueda hacia adelante y retroseguimiento: • Siempre se debe mover hacia adelante el carácter de la cadena de entrada al llevar a cabo una transición, hasta que se consiga un token o testigo simple, denominándose denominándose a esto búsqueda hacia adelante. • Cuando se alcanza un estado aceptador se debe devolver el testigo o token que se reconoció, junto con cualquier atributo asociado. • Cuando se alcanza un estado de error normalmente se retrocede hacia la entrada o se genera un testigo de error. Autómatas finitos para testigos o tokens de lenguajes de programación Búsqueda hacia adelante y retroseguimiento: Pero por ejemplo el DFA propuesto para un testigo de identificador, no muestra el comportamiento que queremos de una analizador léxico porque: ▫ El estado de error no es un error absoluto, ya que puede representar dos cosas, el identificador no va a ser reconocido o se ha detectado un delimitador y ahora debe ser reconocido el testigo o token. letra letra inicio Entra da_id otro otro otro error + dígito cualquiera Autómatas finitos para testigos o tokens de lenguajes de programación Búsqueda hacia adelante y retroseguimiento: Entonces podemos indicar que se ha detectado un delimitador desde el estado entrada_id y debería generarse un testigo o token. letra inici o letra [Otro] entra da_id fina l ID de retorno retorno dígito + Otro se encuentra entre [ ] para indicar que el carácter delimitador debería considerarse como una búsqueda hacia adelante, es decir debería ser devuelto a la entrada y no consumido por el autómata, además el estado de error se ha convertido en uno de aceptación y no hay transiciones fuera del estado de aceptación. Autómatas finitos para testigos o tokens de lenguajes de programación Búsqueda hacia adelante y retroseguimiento: • Lo anterior es lo que queremos puesto que el analizador léxico debería reconocer un testigo a la vez y comenzar de nuevo en su estado de inicio después después de reconocer un testigo. • Allí también se expresa el principio de la subcadena más larga, hasta que se encuentra un delimitador. • En contraste el DFA original permitía aceptar un identificador en cualquier punto mientras se leía una cadena de identificador. Autómatas finitos para testigos o tokens de lenguajes de programación Autómatas finitos No Determinísticos Supongamos que tenemos varios testigos que comienzan por el mismo carácter como <,<= y <>. Ahora no se puede escribir un DFA puesto que dado dado un estado y carácter (ej. <) siempre debe haber una transición única hacia un estado único, pero aquí existen tres: hacia aceptado como <, hacia = o hacia >, aunque podría arreglar esto añadiendo una transición delimitadora para el (<) ¿Cómo?, la complejidad de una tarea así se vuelve enorme. Autómatas finitos para testigos o tokens de lenguajes de programación Autómatas finitos No Determinísticos Una solución a esto es ampliar la definición de autómata finito para incluir el caso de que pueda existir más de una transición para un carácter en particular. < 1 2 = > 5 + < < 3 6 + + 4 + Esta nueva clase de autómatas se conoce como autómatas finitos no determinísticos, e introducen nuevos conceptos útiles como la transición Ű las cuales ocurren sin una búsqueda hacia adelante y sin modificación de la cadena de entrada, es decir de manera “espontanea”, teniendo como ventaja que mantienen intacto el autómata original y solo agrega un nuevo estado de conexión. Autómatas finitos No Determinísticos Una consecuencia de esto es que una cadena puede ser aceptada por diferentes secuencias de transiciones, por ejemplo: Ű a 1 2 Autómatas finitos para testigos o tokens de lenguajes de programación b Ű 4 a 3 + Ű En este NFA la cadena abb puede ser aceptada de las siguientes maneras: ▫ -> 1 ->2 ->4 ->2 ->4 ▫ ->1 ->3 ->4 ->2 ->4 ->2 ->4 Paso siguiente • Todo comienza por una expresión regular que de algún modo se convirtió en un NFA, y luego en DFA y posteriormente en un algoritmo. • El paso siguiente es la construcción del analizador léxico. letra 1 letra [Otro] 2 ID de retorno 3 dígito + ...
View Full Document

This note was uploaded on 05/13/2010 for the course REDES 7 taught by Professor Asesor during the Spring '10 term at UNE.

Ask a homework question - tutors are online