Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Interpretes
Lenguajes regulares y expresiones regulares
UNET 2012
Repaso Cosas importantes para las
Regex (Expresiones Regulares)
Dado un alfabeto , definimos:
• 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}
• ...
• L+ = L1 L2 L3 ... = LL*
Repaso Cosas importantes para las
Regex (Expresiones Regulares)
Ejemplo de concatenación
• L = {0, 11}
• L0 = {}
• 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.
• L = {aa}{a, b}* {a, b}*{bb}
• L1 = {bb} y L2 = {, bb, bbbb}. L1* = ¿?, L2* = ¿?
• Tanto L1* como L2* consisten de cadenas que tienen un número par de b’s.
• {aa, bb, ab, ba}*
• Consiste de todas las cadenas sobre {a, b} de longitud par.
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.
Repaso Cosas importantes para las
Regex (Expresiones Regulares)
• 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 desde el punto
de vista matemático
Son expresiones que permiten describir lenguajes regulares de manera simple,
sencilla y precisa.
En otras palabras permiten abreviar la descripción de conjuntos regulares.
• 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= )
• Notación
• u+ = uu*
• u2 = uu, u3 = u2u, ...
Ejemplo
El conjunto {bawab | w {a, b}*} es regular sobre {a, b}
Demostración:
Conjunto Expresión Justificación
1. {a} a Base
2. {b} b Base
3. {a}{b}={ab} ab Concatenación de 1 y 2
4. {a} {b}={a,b} a+b Unión de 1 y 2
5. {b}{a}={ba} ba Concatenación de 2 y 1
6. {a,b}* (a+b)* Cerradura Kleene de 4
7. {ba}{a,b}* ba(a+b)* Concatenación de 5 y 6
8. {ba}{a,b}*{ab} ba(a+b)*ab Concatenación de 7 y 3
Lenguajes Regulares
• (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.
• 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.
• 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:
Expresión
NFA DFA programa
regular
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 completa. (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):
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 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:
(0|1|2|3|4|5|6|7|8|9)(0|1|2|3|4|5|6|7|8|9)*
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)*
natural = [0-9]+
naturalconsigno = natural | + natural | - natural
o con
natural=[0-9]+
naturalconsigno=(+|-)? natural
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:
nat = [0-9]+
natconSigno = (+|-)? nat
exponencial = natconSigno (“.” nat)?(E natconsigno)
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, 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.
letra
letra
inicio Entrada_id
error
cualquiera
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
+
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
+ +
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)?
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
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 su definición matemática no describe todos
los aspectos del comportamiento de un algoritmo del DFA.
letra Entrada
inicio
_id
+ dígito
otro otro
otro
error
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
ID de
[Otro] retorno
inicio letra entrad
a_id final
dígito +
=
2 5 +
<
< >
1 3 6 +
+
<
4 +
Ɛ
2
a b
a Ɛ
1 3 4 +
En este NFA la cadena abb puede ser aceptada de las siguientes maneras:
letra
ID de
[Otro] retorno
1 letra 2 3
dígito +
EJERCICIO JFLAP
• Expresiones regulares.
• Transformación regex a NFA.
• Determinización DFA.
• Minimización DFA.