Вы находитесь на странице: 1из 89

Curso de Estructura de Compiladores

Texto recopilado de:

Compiladores, principios, tcnicas y herramientas El Libro del Dragon - Aho,


Sethi,Ullman Louden, K.C. (1997), Compiler Construction: Principles and Practice

Slides de PowerPoint Compiladores - Oscar Bonilla (slides preparados por el Prof.


Saman Amarasinghe del Massachusets Institute of Technology)

Louden, K.C. (1997), Compiler Construction: Principles and Practice, Tema 2.

Mg(e) Ing Ren Snchez Vera


1

1. Introduccin
Para iniciar tenemos que contestar las siguientes preguntas:
Qu es un lenguaje de programacin?

Cmo le damos instrucciones a una computadora?

Cmo hacemos que la computadora lleve a cabo las instrucciones eficientemente?

1.1

Lenguaje de Programacin

Para que un computador (hardware) funcione es necesario utilizar programas (software),


los cuales le indican cul es la tarea que se tiene que hacer. Un lenguaje de
programacin es el que se utiliza para escribir dichos programas.
Posteriormente estos se introducirn en la memoria del computador y ste ltimo
ejecutar todas las operaciones que se incluyen.
Pueden ser usados para describir cualquier accin. Hay muchas formas de
describir la misma accin
Un lenguaje de programacin o ms genricamente de computacin, es el medio
por el cual el hombre interacta con un ordenador

Teora de lenguajes de programacin

La teora de lenguajes de programacin (comnmente conocida como PLT) es una rama de la


informtica que se encarga del diseo, implementacin, anlisis, caracterizacin y clasificacin de
lenguajes de programacin y sus caractersticas. Es un campo multi-disciplinar, dependiendo tanto
de (y en algunos casos afectando) matemticas, ingeniera del software, lingstica, e incluso
ciencias cognitivas. Es una rama bien reconocida de la informtica, y a fecha de 2006, un rea activa
de investigacin, con resultados publicados en un gran nmero de revistas dedicadas a la PLT, as
como en general en publicaciones de informtica e ingeniera. La mayora de los programas de los
estudiantes de informtica requieren trabajar en este tema.

Un smbolo no oficial de la teora de lenguajes de programacin es la letra griega lambda en


minsculas. Este uso deriva del clculo lambda, un modelo computacional ampliamente usado por investigadores de
lenguajes de programacin.
El clculo lambda, desarrollado por Alonzo Church, Max HL. Solis Villareal y Stephen Cole Kleene en la dcada de 1930,
es considerado ser uno de los primeros lenguajes de programacin del mundo

1.1.1.

1.1.2.

Caractersticas de los Lenguajes de Programacin

Deben ser no ambiguos


Deben ser precisos
Deben ser concisos
Deben ser expresivos
Deben estar a alto nivel (muchas abstracciones)
Cmo instruir a la computadora

Escribimos un programa usando un lenguaje de programacin Descripcin


abstracta de alto nivel
3

Los microprocesadores hablan


implementacin de bajo nivel

Input: lenguaje de programacin de alto nivel

Output: instrucciones de assembler de bajo nivel

Compilador tiene que:

en

lenguaje

ensamblador

leer y entender el programa


precisamente determinar que acciones se requieren
encontrar cmo llevar a cabo esas acciones
instruir a la computadora a lleva a cabo las acciones
Ejemplo (programa de entrada)
Int expr(int n)
{
int d;
d = 4 * n * n * (n + 1) * (n + 1);
return d;
}

ldl $3,16($15)
addq $3,1,$4
mull $2,$4,$2
ldl $3,16($15)
addq $3,1,$4
mull $2,$4,$2
stl $2,20($15)
ldl $0,20($15)
br $31,$33

Ejemplo (Assembler de salida)


lda $30,-32($30)
stq $26,0($30)
stq $15,8($30)
bis $30,$30,$15
bis $16,$16,$1
stl $1,16($15)
lds $f1,16($15)
sts $f1,24($15)
ldl $5,24($15)
bis $5,$5,$2
s4addq $2,0,$3
ldl $4,16($15)
mull $4,$3,$2

$33:
bis $15,$15,$30
ldq $26,0($30)
ldq $15,8($30)
addq $30,32,$30
4

Detalles

de

ret $31,($26),1
Primeros Lenguajes
(1954 -1957) Fortran
(1958 -1959) LISP
(1958 -1960) Algo60
(1959 -1960) COBOL
Otros Lenguajes
(1972) C
(1986) C++
(1994) Java
Compiladores optimizan cdigo para...

Velocidad / Rendimiento
Tamao de cdigo
Consumo de Poder
Compilacinrpida / eficiente
Seguridad / Confiabilidad
Debugging

Paradigmas

Es el conjunto de ideas, modelos o patrones que forman una percepcin sobre algn
objeto, situacin, cosa persona.
Un cambio de paradigma en la ciencia significa un gran cambio.
Paradigmas de Programacin
Un paradigma de programacin es una propuesta tecnolgica que es adoptada por una comunidad de
programadores cuyo ncleo central es incuestionable en cuanto a que unvocamente trata de resolver
uno o varios problemas claramente delimitados.
La resolucin de estos problemas debe suponer consecuentemente un avance significativo en al menos
un parmetro que afecte a la ingeniera de software. Tiene una estrecha relacin con la formalizacin
de determinados lenguajes en su momento de definicin. Un paradigma de programacin est
delimitado en el tiempo en cuanto a aceptacin y uso ya que nuevos paradigmas aportan nuevas o
mejores soluciones que la sustituyen parcial o totalmente.
Paradigmas de programacin

Programacin imperativa
Programacin lgica
Programacin funcional
Programacin declarativa
Programacin estructurada
Programacin dirigida por eventos
Programacin modular
Programacin orientada a aspectos
Programacin orientada a objetos
Programacin con restricciones
5
Programacin a nivel funcional (John Backus)
Programacin a nivel de valores (John Backus)
Programacin orientada a componentes

1.2

Conceptos Bsicos

Un traductor es un programa que traduce o convierte desde un texto o programa escrito


en un lenguaje fuente hasta un texto o programa escrito en un lenguaje destino
produciendo, si cabe, mensajes de error. Los traductores engloban tanto al compilador
como al intrprete.
El cdigo fuente de un programa informtico (o software) es un conjunto de lneas de
texto que son las instrucciones que debe seguir la computadora para ejecutar dicho
programa. Por tanto, en el cdigo fuente de un programa est descrito por completo su
funcionamiento.
Un lenguaje de programacin de alto nivel se caracteriza por expresar los algoritmos
de una manera adecuada a la capacidad cognitiva humana, en lugar de a la capacidad
ejecutora de las mquinas.
Lenguaje de mquina es el sistema de cdigos directamente interpretable por un circuito
microprogramable, como el microprocesador de una computadora o el microcontrolador
de un autmata. Este lenguaje est compuesto por un conjunto de instrucciones que
determinan acciones a ser tomadas por la mquina.
El lenguaje ensamblador, o assembler (assemblylanguage en ingls) es un lenguaje de
programacin de bajo nivel para los computadores, microprocesadores,
microcontroladores, y otros circuitos integrados programables. Implementa una
representacin simblica de los cdigos de mquina binarios y otras constantes
necesarias para programar una arquitectura dada de CPU y constituye la representacin
ms directa del cdigo mquina especfico para cada arquitectura legible por un
programador.
En informtica, un ejecutable o archivo ejecutable, es tradicionalmente un o como se le
conoce mayormente archivo binario cuyo contenido se interpreta por el ordenador como
un programa.

1.3

Traductores y Compiladores

1.3.1. Traductores de un Lenguaje de Programacin

Los traductores son programas que traducen los programas en cdigo fuente, escritos en
lenguajes de alto nivel, a programas escritos en lenguaje mquina.
Los traductores pueden ser de dos tipos: compiladores e intrpretes

1.3.2. Interprete

Los intrpretes no producen un lenguaje objetivo como en los compiladores. Un intrprete


lee el cdigo como est escrito e inmediatamente lo convierte en acciones; es decir, lo
ejecuta en ese instante.
Existen lenguajes que utilizan un intrprete (como por ejemplo JAVA,PHP) que traduce en
el instante mismo de lectura el cdigo en lenguaje mquina para que pueda ser ejecutado.
La siguiente figura muestra el funcionamiento de un intrprete.

Ilustracin 1-1 - Esquema General de un Interprete

Dependiendo de la complejidad del cdigo a analizar, el intrprete puede contener


mdulos similares a los de un compilador tradicional: Anlisis lxico, Sintctico y
Semntico. Durante la evaluacin, el intrprete interacta con los recursos del sistema
como la memoria, discos, etc. Muchos sistemas interpretados liberan al programador del
manejo explcito de memoria mediante tcnicas de recoleccin de basura.
A la hora de evaluar la representacin interna, existen dos mtodos fundamentales: la
interpretacin iterativa y la interpretacin recursiva.
Ventaja

Los intrpretes, por definicin, realizan la fase de anlisis y ejecucin a la vez, lo


cual imposibilita optimizaciones. Por esta razn, los sistemas interpretados suelen
ser menos eficientes que los compilados. No obstante, los nuevos avances
informticos aumentan la velocidad de procesamiento y capacidad de memoria de
8

los ordenadores. Actualmente, la eficiencia es un problema menos grave y muchas


veces se prefieren sistemas que permitan un desarrollo rpido de aplicaciones que
cumplan fielmente la tarea encomendada.

Desventajas

Los intrpretes, en general, son ms sencillos de implementar.

Proporcionan una mayor flexibilidad


caractersticas del lenguaje fuente.

No es necesario contener en memoria todo el cdigo fuente. Esto permite su


utilizacin en sistemas de poca memoria o en entornos de red.

Facilitan la meta-programacin. Un programa puede manipular su propio cdigo


fuente a medida que se ejecuta. Esto facilita la implementacin de sistemas de
aprendizaje automatizado y reflectividad [AtKaci 91].

Aumentan la portabilidad del lenguaje: Para que el lenguaje interpretado funcione


en otra mquina slo es necesario que su intrprete funcione en dicha mquina.

Puesto que no existen etapas intermedias de compilacin, los sistemas


interpretados facilitan el desarrollo rpido de prototipos, potencian la utilizacin
de sistemas interactivos y facilitan las tareas de depuracin.

que

permite

modificar

ampliar

Aplicaciones de los sistemas basados en intrpretes

Los sistemas interpretados han tenido una gran importancia desde la aparicin de los
primeros ordenadores. En la actualidad, la evolucin del hardware abre nuevas
posibilidades a los sistemas interpretados. La preocupacin ya no es tanto la eficiencia
como la capacidad de desarrollo rpido de nuevas aplicaciones. Las principales
aplicaciones podran resumirse en:

Intrpretes de Comandos: Los sistemas operativos cuentan con intrpretes de


comandos como el Korn-Shell, C-Shell, JCL, etc. Estos intrpretes toman un
lenguaje fuente que puede incluir sentencias de control (bucles, condiciones,
asignaciones, etc.) y ejecutan los diferentes comandos a medida que aparecen en
el lenguaje.

Lenguajes basados en Escritos (Scripting Languages), diseados como


herramientas que sirvan de enlace entre diferentes sistemas o aplicaciones.
Suelen ser interpretados con el fin de admitir una mayor flexibilidad a la hora de
afrontar las peculiaridades de cada sistema. Podran destacarse Perl, Tcl/Tk,
JavaScript, WordBasic[Ousterhout 97]

Entornos de Programacin: Existen ciertos lenguajes que contienen


caractersticas que impiden su compilacin o cuya compilacin no es efectiva.
Estos lenguajes suelen disponer de un complejo entorno de desarrollo interactivo
con facilidades para la depuracin de programas. Entre estos sistemas pueden
destacarse los entornos de desarrollo para Lisp, Visual Basic, Smalltalk, etc.

Lenguajes de Propsito Especfico: Ciertos lenguajes incluyen sentencias que


realizan tareas complejas en contextos especficos. Existe una gran variedad de
aplicaciones en las que se utilizan este tipo de lenguajes como consultas de Bases
de Datos, simulacin, descripcin de hardware, robtica, CAD/CAM, msica, etc.

Sistemas en Tiempo Real: Entornos que permiten modificar el cdigo de una


aplicacin en tiempo de ejecucin de forma interactiva.

Intrprete de Cdigo Intermedio: Una tendencia tradicional en el diseo de


compiladores es la generacin de un cdigo intermedio para una mquina
abstracta, por ejemplo, el P-Code de Pascal o los bytecodesde Java. El siguiente
paso puede ser: generacin del cdigo objeto a partir del cdigo intermedio para
una mquina concreta, finalizando el proceso de compilacin o interpretar dicho
cdigo intermedio en una mquina concreta. La tendencia habitual es definir un
lenguaje intermedio independiente de una mquina concreta. Para ello, suele
definirse una mquina virtual que contenga las instrucciones definidas por el
lenguaje intermedio, permitiendo una mayor portabilidad. Un ejemplo sera la
Mquina Virtual de Java, que es simulada en la mayora de los visualizadores
Web.

Tipos de intrpretes

A continuacin se va a realizar una clasificacin de los diferentes mtodos de


interpretacin segn la estructura interna del intrprete. Es conveniente observar que
algunos mtodos podran considerarse hbridos, ya que mezclan los procesos de
compilacin e interpretacin.

Intrpretes puros
Intrpretes avanzados
Intrpretes incrementales

10

1.3.3. Compilador

Un compilador es un programa que lee el cdigo escrito en un lenguaje (lenguaje


origen), y lo traduce en un programa equivalente escrito en otro lenguaje (lenguaje
objetivo). Como una parte fundamental de este proceso de traduccin, el compilador le
hace notar al usuario la presencia de errores en el cdigo fuente del programa. Vea la
siguiente figura.
Los lenguajes C y C++ son lenguajes que utiliza un compilador. El trabajo del compilador
y su funcin es llevar el cdigo fuente escrito en C/C++ a un programa escrito en lenguaje
mquina. Entrando en ms detalle, un programa en cdigo fuente es compilado
obteniendo un archivo parcial (un objeto) que tiene extensin obj. Luego el compilador
invoca al linker que convierte al archivo objeto en un ejecutable con extensin exe; este
ltimo archivo es un archivo en formato binario (ceros y unos) y puede funcionar por s
slo.
Adems, el compilador al realizar su tarea realiza tambin una comprobacin de errores
en el programa; es decir, revisa que todo est en orden. Por ejemplo, variables y
funciones bien definidas, todo lo referente a cuestiones sintcticas, etc. Est fuera del
alcance del compilador que, por ejemplo, el algoritmo utilizado en el problema funcione
bien.

Ilustracin 1-2 - Esquema General de un Compilador

11

Ilustracin 1-3 , Visin General de un Compilador

12

Partes de un compilador

La construccin de un compilador involucra la divisin del proceso en una serie de fases


que variar con su complejidad. Generalmente estas fases se agrupan en dos tareas: el
anlisis del programa fuente y la sntesis del programa objeto.

Anlisis: Se trata de la comprobacin de la correccin del programa fuente, e


incluye las fases correspondientes al Anlisis Lxico (que consiste en la
descomposicin del programa fuente en componentes lxicos), Anlisis
Sintctico (agrupacin de los componentes lxicos en frases gramaticales )
y Anlisis Semntico (comprobacin de la validez semntica de las sentencias
aceptadas en la fase de Anlisis Sintctico).

Sntesis: Su objetivo es la generacin de la salida expresada en el lenguaje


objeto y suele estar formado por una o varias combinaciones de fases de
Generacin de Cdigo (normalmente se trata de cdigo intermedio o de cdigo
objeto) y de Optimizacin de Cdigo (en las que se busca obtener un cdigo lo
ms eficiente posible).

Alternativamente, las fases descritas para las tareas de anlisis y sntesis se pueden
agrupar en Front-end y Back-end:

Front-end: es la parte que analiza el cdigo fuente, comprueba su validez, genera


el rbol de derivacin y rellena los valores de la tabla de smbolos. Esta parte
suele ser independiente de la plataforma o sistema para el cual se vaya a
compilar, y est compuesta por las fases comprendidas entre el Anlisis Lxico y
la Generacin de Cdigo Intermedio.

Back-end: es la parte que genera el cdigo mquina, especfico de una plataforma,


a partir de los resultados de la fase de anlisis, realizada por el Front End.

Esta divisin permite que el mismo Back End se utilice para generar el cdigo mquina de
varios lenguajes de programacin distintos y que el mismo Front End que sirve para
analizar el cdigo fuente de un lenguaje de programacin concreto sirva para
generar cdigo mquina en varias plataformas distintas. Suele incluir la generacin y
optimizacin del cdigo dependiente de la mquina.
El cdigo que genera el Back End normalmente no se puede ejecutar directamente, sino
que necesita ser enlazado por un programa enlazador (linker)

Tipos de compiladores

Esta taxonoma de los tipos de compiladores no es excluyente, por lo que puede haber
compiladores que se adscriban a varias categoras:

Compiladores cruzados: generan cdigo para un sistema distinto del que estn
funcionando.
13

Compiladores optimizadores: realizan cambios en el cdigo para mejorar su


eficiencia, pero manteniendo la funcionalidad del programa original.

Compiladores de una sola pasada: generan el cdigo mquina a partir de una


nica lectura del cdigo fuente.

Compiladores de varias pasadas: necesitan leer el cdigo fuente varias veces


antes de poder producir el cdigo mquina.

Compiladores JIT (Just In Time): forman parte de un intrprete y compilan partes


del cdigo segn se necesitan.

1.3.4. Diferencia entre compilador e intrprete

Los compiladores difieren de los intrpretes en varios aspectos:

Un programa que ha sido compilado puede correr por s slo, pues en el proceso
de compilacin se lo transformo en otro lenguaje (lenguaje mquina).

Un intrprete traduce el programa cuando lo lee, convirtiendo el cdigo del


programa directamente en acciones. La ventaja del intrprete es que dado
cualquier programa se puede interpretar en cualquier plataforma (sistema
operativo). En cambio, el archivo generado por el compilador solo funciona en la
plataforma en donde se le ha creado. Sin embargo, hablando de la velocidad de
ejecucin, un archivo compilado es de 10 a 20 veces ms rpido que un archivo
interpretado.

1.3.5. Anatoma de un compilador

Ilustracin 1-4 , Anatoma de un compilador

14

2. Analizador Lxico

Ilustracin 2-1 , Analizador Lxico

2.1

Funcin de un analizador lxico

Leer los caracteres de cdigo fuente y formarlos en unidades lgicas para que lo aborden
las partes siguientes de compilador (generalmente el analizador Sintctico). Las unidades
lgicas que genera el analizador lxico se denominan Tokens. Los Tokens son las
palabras de un lenguaje natural: cada tokens es una secuencia de caracteres que
representa una unidad de informacin en el programa fuente.

Palabras reservadas: if, while, repeat.


Identificadores: Posicin, velocidad, tiempo.
Operadores: = * + - / == ><& =
Smbolos especiales: ; ( ) [ ] { }
Constantes Numricas: 982, 0xF678, -83.2E+2
Constantes de caracteres: Hola mundo

Atributo del token


El atributo es cualquier valor asociado a un Token. Ejm: El Token NUM puede tener un
atributo de valor de cadena como 32767, que consta de 5 caracteres numricos, pero
tambin tendr un atributo de valor numrico que consiste en el valor real de 32767
calculado a partir de su valor de cadena.

15

El token de smbolo especial como MAS, no solo se tiene el valor de cadena +, sino
tambin la operacin aritmtica real + que est asociada con l mismo. Es decir el
smbolo del token mismo se puede ver simplemente como otro atributo.
El analizador lxico opera bajo peticin del analizador sintctico devolviendo un
componente lxico conforme el analizador sintctico lo va necesitando para avanzar en la
gramtica. Los componentes lxicos son los smbolos terminales de la gramtica.
Suele implementarse como una subrutina del analizador sintctico. Cuando recibe la
orden obtn el siguiente componente lxico, el analizador lxico lee los caracteres de
entrada hasta identificar el siguiente componente lxico.

Otras funciones secundarias:


Manejo del fichero de entrada del programa fuente: abrirlo, leer sus caracteres,
cerrarlo y gestionar posibles errores de lectura.
Eliminar comentarios, espacios en blanco, tabuladores y saltos de lnea
(caracteres no vlidos para formar un token).
Inclusin de ficheros: # include ...
La expansin de macros y funciones inline: # define ...
Contabilizar el nmero de lneas y columnas para emitir mensajes de error.
Reconocimiento y ejecucin de las directivas de compilacin (por ejemplo, para
depurar u optimizar el cdigo fuente).
El anlisis lxico es una subrutina del anlisis sintctico que devuelve el tipo de
componente lxico y el lexema cada vez que es llamada.
En el analizador lxico debe haber una funcin que se encarga de gestionar el
buffer de entrada. Se leera una lnea que se almacenarla en un vector de
caracteres. Cuando haya sido procesada se carga de nuevo.
Las palabras reservadas se reconocen como identificadores y antes de devolver
un identificador se comprueba si es una palabra reservada o un identificador
consultando en una tabla previamente inicializada con las palabras reservadas.
Hay casos en los que es necesario reinsertar un carcter en el buffer de entrada.
Adems de los componentes lxicos definidos por el lenguaje es conveniente
aadir un par especiales para indicar el final de fichero y la deteccin de un error.

Ventajas de separar el anlisis lxico y el anlisis sintctico:


16

Facilita transportabilidad del traductor (por ejemplo, si decidimos en un momento


dado cambiar las palabras reservadas begin y end de inicio y fin de bloque, por{
y}, slo hay que cambiar este mdulo.
Se simplifica el diseo: el analizador es un objeto con el que se interacta
mediante ciertos mtodos. Se localiza en un nico mdulo la lectura fsica de los
caracteres, por lo que facilita tratamientos especializados de E/S.

17

2.2

Componentes Lxicos, Patrones, Lexemas

Patrn: es una regla que genera la secuencia de caracteres que puede representar a un
determinado componente lxico (una expresin regular).
Lexema: cadena de caracteres que concuerda con un patrn que describe un
componente lxico. Un componente lxico puede tener uno o infinitos lexemas. Por
ejemplo: palabras reservadas tienen un nico lexema. Los nmeros y los identificadores
tienen infinitos lexemas.

Ilustracin 2 , Componentes Lxicos, Patrones y Lexemas

Los componentes lxicos se suelen definir como un tipo enumerado. Se codifican como
enteros. Tambin se suele almacenar la cadena de caracteres que se acaba de reconocer
(el lexema), que se usar posteriormente para el anlisis semntico.
TKN_IF, TKN_THEN, TKN_ NUM, TKN_ ID, TNK_ OPADD,...
Es importante conocer el lexema (para construir la tabla de smbolos). Los componentes
lxicos se representan mediante una estructura registro con tipo de token y lexema:

Ilustracin 3 , Ejemplo componente lxico - lexema

18

2.3

Expresiones Regulares (especificacin de los componentes


lxicos)

Una expresin regular, a menudo llamada tambin patrn, es una expresin que describe
un conjunto de cadenas sin enumerar sus elementos. Por ejemplo, el grupo formado por
las cadenas Handel, Hndel y Haendel se describe mediante el patrn "H(a||ae)ndel".
La mayora de las formalizaciones proporcionan los siguientes constructores: una
expresin regular es una forma de representar a los lenguajes regulares (finitos o infinitos)
y se construye utilizando caracteres del alfabeto sobre el cual se define el lenguaje.
Especficamente, las expresiones regulares se construyen utilizando los operadores
unin, concatenacin y clausura de Kleene.
Los componentes lxicos se especifican haciendo uso de expresiones regulares. Para ello
hay que conocer las reglas que rigen la creacin de las expresiones regulares
Alternacin

Una barra vertical separa las alternativas. Por ejemplo, "marrn|castao" casa con marrn
o castao.
Cuantificacin

Un cuantificador tras un carcter especifica la frecuencia con la que ste puede ocurrir.
Los cuantificadores ms comunes son +, ? y *:
+ , El signo ms indica que el carcter al que sigue debe aparecer al menos una
vez. Por ejemplo, "ho+la" describe el conjunto infinito hola, hoola, hooola, hoooola,
etctera.
? , El signo de interrogacin indica que el carcter al que sigue puede aparecer
como mucho una vez. Por ejemplo, "ob?scuro" casa con oscuro y obscuro.
, El asterisco indica que el carcter que lo precede puede aparecer cero, una, o
ms veces. Por ejemplo, "0*42" casa con 42, 042, 0042, 00042, etctera.
Agrupacin

Los parntesis pueden usarse para definir el mbito y precedencia de los dems
operadores. Por ejemplo, "(p|m)adre" es lo mismo que "padre|madre", y "(des)?amor"
casa con amor y con desamor.
Los constructores pueden combinarse libremente dentro de la misma expresin, por lo
que "H(ae?|)ndel" equivale a "H(a|ae|)ndel".
La sintaxis precisa de las expresiones regulares cambia segn las herramientas y
aplicaciones consideradas, y se describe con ms detalle a continuacin.
Su utilidad ms obvia es la de describir un conjunto de cadenas, lo que resulta de utilidad
en editores de texto y aplicaciones para buscar y manipular textos. Muchos lenguajes de
programacin admiten el uso de expresiones regulares con este fin.

19

El Punto "."

El punto es interpretado por el motor de bsqueda como cualquier otro carcter excepto
los caracteres que representan un salto de lnea, a menos que se le especifique esto al
motor de Expresiones Regulares. Por lo tanto si esta opcin se deshabilita en el motor de
bsqueda que se utilice, el punto le dir al motor que encuentre cualquier carcter
incluyendo los saltos de lnea. En la herramienta EditPad Pro esto se hace por medio de
la opcin "punto corresponde a nueva lnea" en las opciones de bsqueda. En .Net
Framework se utiliza la opcin RegexOptions. Singleline al efectuar la bsqueda o crear la
expresin regular.
El punto se utiliza de la siguiente forma: Si se le dice al motor de RegEx que busque
"g.t" en la cadena "el gato de piedra en la gtica puerta de getisborogoot" el motor
de bsqueda encontrar "gat", "gt" y por ltimo "get". Ntese que el motor de
bsqueda no encuentra "goot"; esto es porque el punto representa un solo carcter y
nicamente uno. Si es necesario que el motor encuentra tambin la expresin "goot", ser
necesario utilizar repeticiones, las cuales se explican ms adelante.
Aunque el punto es muy til para encontrar caracteres que no conocemos, es necesario
recordar que corresponde a cualquier carcter y que muchas veces esto no es lo que se
requiere. Es muy diferente buscar cualquier carcter que buscar cualquier carcter
alfanumrico o cualquier dgito o cualquier no-dgito o cualquier no-alfanumrico. Se debe
tomar esto en cuenta antes de utilizar el punto y obtener resultados no deseados

La barra inversa o contrabarra "\"

Se utiliza para "marcar" el siguiente carcter de la expresin de bsqueda de forma


que este adquiera un significado especial o deje de tenerlo. O sea, la barra inversa no
se utiliza nunca por s sola, sino en combinacin con otros caracteres. Al utilizarlo por
ejemplo en combinacin con el punto "\." este deja de tener su significado normal y se
comporta como un carcter literal.
De la misma forma, cuando se coloca la barra inversa seguida de cualquiera de los
caracteres especiales que discutiremos a continuacin, estos dejan de tener su
significado especial y se convierten en caracteres de bsqueda literal.
Como ya se mencion con anterioridad, la barra inversa tambin puede darle significado
especial a caracteres que no lo tienen. A continuacin hay una lista de algunas de estas
combinaciones:

20

Definicin de Expresiones Regular en Herramientas

\t Representa un tabulador.
\r Representa el "retorno de carro" o "regreso al inicio" o sea el lugar en
que la lnea vuelve a iniciar.
\n Representa la "nueva lnea" el carcter por medio del cual una lnea da
inicio. Es necesario recordar que en Windows es necesaria una combinacin
de \r\n para comenzar una nueva lnea, mientras que en Unix solamente se
usa \n.
\a Representa una "campana" o "beep" que se produce al imprimir este
carcter.
\e Representa la tecla "Esc" o "Escape"
\f Representa un salto de pgina
\v Representa un tabulador vertical
\x Se utiliza para representar caracteres ASCII o ANSI si conoce su cdigo.
De esta forma, si se busca el smbolo de derechos de autor y la fuente en la
que se busca utiliza el conjunto de caracteres Latin-1 es posible encontrarlo
utilizando "\xA9".
\u Se utiliza para representar caracteres Unicode si se conoce su cdigo.
"\u00A2" representa el smbolo de centavos. No todos los motores de
Expresiones Regulares soportan Unicode. El .Net Framework lo hace, pero el
EditPad Pro no, por ejemplo.
\d Representa un dgito del 0 al 9.
\w Representa cualquier carcter alfanumrico.
\s Representa un espacio en blanco.
\D Representa cualquier carcter que no sea un dgito del 0 al 9.
\W Representa cualquier carcter no alfanumrico.
\S Representa cualquier carcter que no sea un espacio en blanco.
\A Representa el inicio de la cadena. No un carcter sino una posicin.
\Z Representa el final de la cadena. No un carcter sino una posicin.
\b Marca el inicio y el final de una palabra.
\B Marca la posicin entre dos caracteres alfanumricos o dos noalfanumricos.

Los corchetes "[ ]"

La funcin de los corchetes en el lenguaje de las expresiones regulares es


representar "clases de caracteres", o sea, agrupar caracteres en grupos o clases.
Son tiles cuando es necesario buscar uno de un grupo de caracteres. Dentro de
los corchetes es posible utilizar el guin "-" para especificar rangos de caracteres.
Adicionalmente, los metacaracteres pierden su significado y se convierten en literales
cuando se encuentran dentro de los corchetes. Por ejemplo, como vimos en la entrega
anterior "\d" nos es til para buscar cualquier carcter que represente un dgito. Sin
embargo esta denominacin no incluye el punto "." que divide la parte decimal de un
nmero. Para buscar cualquier carcter que representa un dgito o un punto podemos
utilizar la expresin regular "[\d.]". Como se hizo notar anteriormente, dentro de los
corchetes, el punto representa un carcter literal y no un metacarcter, por lo que no es
21

necesario antecederlo con la barra inversa. El nico carcter que es necesario anteceder
con la barra inversa dentro de los corchetes es la propia barra inversa. La expresin
regular "[\dA-Fa-f]" nos permite encontrar dgitos hexadecimales. Los corchetes nos
permiten tambin encontrar palabras an si estn escritas de forma errnea, por ejemplo,
la expresin regular "expresi[o]n" permite encontrar en un texto la palabra "expresin"
aunque se haya escrito con o sin tilde. Es necesario aclarar que sin importar cuantos
caracteres se introduzcan dentro del grupo por medio de los corchetes, el grupo slo le
dice al motor de bsqueda que encuentre un solo carcter a la vez, es decir, que
"expresi[o]n" no encontrar "expresioon" o "expresion".

La barra "|"

Sirve para indicar una de varias opciones. Por ejemplo, la expresin regular "a|e"
encontrar cualquier "a" o "e" dentro del texto. La expresin regular "este|oeste|norte|sur"
permitir encontrar cualquiera de los nombres de los puntos cardinales. La barra se utiliza
comnmente en conjunto con otros caracteres especiales.
El signo de dlar "$"

Representa el final de la cadena de caracteres o el final de la lnea, si se utiliza el


modo multi-lnea. No representa un carcter en especial sino una posicin. Si se utiliza
la expresin regular "\.$" el motor encontrar todos los lugares donde un punto finalice la
lnea, lo que es til para avanzar entre prrafos.

El acento circunflejo "^

Este carcter tiene una doble funcionalidad, que difiere cuando se utiliza
individualmente y cuando se utiliza en conjunto con otros caracteres especiales. En
primer lugar su funcionalidad como carcter individual: el carcter "^" representa el
inicio de la cadena (de la misma forma que el signo de dlar "$" representa el final
de la cadena). Por tanto, si se utiliza la expresin regular "^[a-z]" el motor encontrar
todos los prrafos que den inicio con una letra minscula. Cuando se utiliza en conjunto
con los corchetes de la siguiente forma "[^\w ]" permite encontrar cualquier carcter que
NO se encuentre dentro del grupo indicado. La expresin indicada permite encontrar, por
ejemplo, cualquier carcter que no sea alfanumrico o un espacio, es decir, busca todos
los smbolos de puntuacin y dems caracteres especiales.
La utilizacin en conjunto de los caracteres especiales "^" y "$" permite realizar
validaciones en forma sencilla. Por ejemplo "^\d$" permite asegurar que la cadena a
verificar representa un nico dgito, "^\d\d/\d\d/\d\d\d\d$" permite validar una fecha en
formato corto, aunque no permite verificar si es una fecha vlida, ya que 99/99/9999
tambin sera vlido en este formato; la validacin completa de una fecha tambin es
posible mediante expresiones regulares, como se ejemplifica ms adelante.

Los parntesis "()

De forma similar que los corchetes, los parntesis sirven para agrupar caracteres, sin
embargo existen varias diferencias fundamentales entre los grupos establecidos por
medio de corchetes y los grupos establecidos por parntesis:
22

Los caracteres especiales conservan su significado dentro de los parntesis.


Los grupos establecidos con parntesis establecen una "etiqueta" o "punto de
referencia" para el motor de bsqueda que puede ser utilizada posteriormente
como se denota ms adelante.
Utilizados en conjunto con la barra "|" permite hacer bsquedas opcionales. Por
ejemplo la expresin regular "al (este|oeste|norte|sur) de" permite buscar textos
que den indicaciones por medio de puntos cardinales, mientras que la expresin
regular "este|oeste|norte|sur" encontrara "este" en la palabra "esteban", no
pudiendo cumplir con este propsito.
Utilizado en conjunto con otros caracteres especiales que se detallan
posteriormente, ofrece funcionalidad adicional.
El signo de interrogacin "?"

El signo de pregunta tiene varias funciones dentro del lenguaje de las expresiones
regulares. La primera de ellas es especificar que una parte de la bsqueda es opcional.
Por ejemplo, la expresin regular "ob?scuridad" permite encontrar tanto "oscuridad" como
"obscuridad". En conjunto con los parentesis redondos permite especificar que un
conjunto mayor de caracteres es opcional; por ejemplo "Nov(\.|iembre|ember)?" permite
encontrar tanto "Nov" como "Nov.", "Noviembre" y "November". Como se mencion
anteriormente los parntesis nos permiten establecer un "punto de referencia" para el
motor de bsqueda, sin embargo, algunas veces, no se desea utilizarlos con este
propsito, como en el ejemplo anterior "Nov(\.|iembre|ember)?". En este caso el
establecimiento de este punto de referencia (que se detalla ms adelante) representa una
inversin intil de recursos por parte del motor de bsqueda. Para evitar se puede utilizar
el signo de pregunta de la siguiente forma: "Nov(?:\.|iembre|ember)?". Aunque el resultado
obtenido ser el mismo, el motor de bsqueda no realizar una inversin intil de recursos
en este grupo, sino que lo ignorar. Cuando no sea necesario reutilizar el grupo, es
aconsejable utilizar este formato. De forma similar, es posible utilizar el signo de pregunta
con otro significado: Los parntesis definen grupos "annimos", sin embargo el signo de
pregunta en conjunto con los parntesis triangulares "<>" permite "nombrar" estos grupos
de la siguiente forma: "^(?<Da>\d\d)/(?<Mes>\d\d)/(?<Ao>\d\d\d\d)$"; Con lo cual se le
especifica al motor de bsqueda que los primeros dos dgitos encontrados llevarn la
etiqueta "Da", los segundos la etiqueta "Mes" y los ltimos cuatro dgitos llevarn la
etiqueta "Ao".
Nota: a pesar de la complejidad y flexibilidad dada por los caracteres especiales
estudiados hasta ahora, en su mayora nos permiten encontrar solamente un carcter a la
vez, o un grupo de caracteres a la vez. Los metacaracteres enumerados en adelante
permiten establecer repeticiones.
Las llaves "{}

Comnmente las llaves son caracteres literales cuando se utilizan por separado en una
expresin regular. Para que adquieran su funcin de metacaracteres es necesario que
encierren uno o varios nmeros separados por coma y que estn colocados a la derecha
de otra expresin regular de la siguiente forma: "\d{2}" Esta expresin le dice al motor de
bsqueda que encuentre dos dgitos contiguos. Utilizando esta frmula podramos
convertir el ejemplo "^\d\d/\d\d/\d\d\d\d$" que serva para validar un formato de fecha en
"^\d{2}/\d{2}/\d{4}$" para una mayor claridad en la lectura de la expresin.

23

Nota: aunque esta forma de encontrar elementos repetidos es muy til, algunas veces no
se conoce con claridad cuantas veces se repite lo que se busca o su grado de repeticin
es variable. En estos casos los siguientes metacaracteres son tiles.

El asterisco "*

El asterisco sirve para encontrar algo que se encuentra repetido 0 o ms veces. Por
ejemplo, utilizando la expresin "[a-zA-Z]\d*" ser posible encontrar tanto "H" como "H1",
"H01", "H100" y "H1000", es decir, una letra seguida de un nmero indefinido de dgitos.
Es necesario tener cuidado con el comportamiento del asterisco, ya que este por defecto
trata de encontrar la mayor cantidad posible de caracteres que correspondan con el
patrn que se busca. De esta forma si se utiliza "\(.*\)" para encontrar cualquier cadena
que se encuentre entre parntesis y se lo aplica sobre el texto "Ver (Fig. 1) y (Fig. 2)" se
esperara que el motor de bsqueda encuentre los textos "(Fig. 1)" y "(Fig. 2)", sin
embargo, debido a esta caracterstica, en su lugar encontrar el texto "(Fig. 1) y (Fig. 2)".
Esto sucede porque el asterisco le dice al motor de bsqueda que llene todos los
espacios posibles entre dos parntesis. Para obtener el resultado deseado se debe utilizar
el asterisco en conjunto con el signo de pregunta de la siguiente forma: "\(.*?\)" Esto es
equivalente a decirle al motor de bsqueda que "Encuentre un parntesis de apertura y
luego encuentre cualquier carcter repetido hasta que encuentre un parntesis de cierre".

El signo de suma "+"

Se utiliza para encontrar una cadena que se encuentre repetida 1 o ms veces. A


diferencia del asterisco, la expresin "[a-zA-Z]\d+" encontrar "H1" pero no encontrar
"H". Tambin es posible utilizar este metacarcter en conjunto con el signo de pregunta
para limitar hasta donde se efecta la repeticin.

Expresiones regulares
Patrn

Significado

exp_reg

match

Cadenas

cualquier
carcter
excepto
EOL
("nueva lnea")

"."

cualquier carcter excepto EOL

carcter
especial

"\*"
"\\"

"*"
"\"

un carcter

"a
"A
"2"

"a"
"A"
"2"

xyz

varios
caracteres

"hola"

"hola"

x|y

un

"a|b"

"a" o "b"

carcter

24

otro
[xyz]

un carcter que
est en una lista

"[aeiou]"

una vocal

[a-z]

un carcter que
pertenezca a un
rango

"[a-z]
[a-zA-Z]
"[a-z][A-Z]"

una minscula
una letra
una minscula seguida de una mayscula

[x]

cualquier
carcter
excepto "x"

"[a]"

cualquier carcter excepto "a"

[xyz]

un carcter que
no est en una
lista

"[aeiou]"

una consonante

[a-z]

un carcter que
no pertenezca a
un rango

"[a-z]"

una mayscula

\w

cualquier
carcter
alfanumrico
incluyendo
el
guin bajo

equivale a [a-zA-Z0-9_]

\W

cualquier
carcter
no
alfanumrico

equivale a [a-zA-Z0-9_]

\d

cualquier dgito

equivale a [0-9]

\D

cualquier
carcter
dgito

equivale a [0-9]

\t

tabulador

\r

retorno de carro

\n

final de lnea

\s

cualquier
carcter
no
visible,
como
tabulador,
retorno
o
espacio

\S

cualquier
carcter visible

case insensitive,
con
este
modificador no
distinguir entre
maysculas
y
minsculas

no

"/una/i"

busca "una" sin distinguir entre maysculas y


minsculas

25

global,
este
modificador se
usa para que no
se detenga un
proceso
de
sustitucin
al
encontrar
la
primera
ocurrencia

"/a/g"

encontrar todas las "a" para sustituirlas

(xyz)

recuerda
el
patrn para su
posterior
utilizacin con
multiplicadores
o referencias

"(x).(ab)"

para referencias posteriores "x"=$1 y "ab"=$2

Anclas: posicin de la cadena

comienzo de lnea

"a"
"[aeiou]"
"hola"

"a" al comienzo de una lnea


una vocal al comienzo de una lnea
"hola" al comienzo de una lnea

final de lnea

"a$"
"[aeiou]$"
"hola$"
"$"

"a" al final de una lnea


una vocal al final de una lnea
"hola" al final de una lnea
una lnea vaca

\b

principio o final de una


palabra

"\bola"

"ola" al principio o final de una palabra

Multiplicadores: cuntas veces ha de aparecer la cadena

una cadena cero o ms


veces

"hola*"
"hol(as)*"
"[a-z]*"

"hol", "hola", "holaa"


"hol", "holas", "holasas"
una palabra en minsculas

una cadena una o ms


veces

"hola+"
"hol(as)+"

"hola", "holaa", "holaaa"


"holas", "holasas"

una cadena cero o una


vez

"hola?"
"hol(a)?"

"hol", "hola"
"hol", "holas"

{n}

una cadena n veces

"a{3}"
"(as){3}"

"aaa"
"asasas"

{n,m}

una cadena entre n y m


veces

"a{2,4}"
"(as){2,4}"

"aa", "aaa", "aaaa"


"asas", "asasas", "asasasas"

26

una cadena al menos n


veces

{n,}

"a{2,}"
"(as){2,}"

"aa", "aaa", "aaaa"


"asas", "asasas", "asasasas"

Algunos Ejemplos

Nmeros
nat = [0-9]+
signedNat = ( +| -)? nat
number = signedNat(.nat)? (E signedNat)?
Identificadores
letter = [a-zA-Z]
digit = [0-9]
identifier = letter (letter | digit)*
Palabras Reservadas
Tkn_ if = if
tkn _while = while
tkn _do = do

2.3.1

Definicin Regular

Definicin regular para el conjunto de identificadores que se definen como cadenas de


letras y dgitos que comienzan con una letra.
<letra> A | B | C | | Z | a | b | c | | z
<dgito> 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
<identificador> <letra>(<letra>|<digito>)*
Nmeros sin signo definidos como cadenas de la forma 4500, 34.21, 4.23E4, 1.05444E-2,
45E-23
<nmero> <dgitos><fraccin_optativa><exponente_optativo>
<dgitos> <dgito><dgito>*
<dgito> 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
<fraccin_optativa> .<dgitos> |
<exponente_optativo> E ( + | - | )<dgitos> |

2.3.2

Cmo reconocemos RE's?

La expresiones regulares son tiles para describir strings, pero necesitamos


reconocerlos.
Esta es la diferencia entre conocimiento declarativo (qu es) y conocimiento
imperativo (cmo hacerlo).
As que usamos expresiones regulares para describir los strings, pero usamos
autmatas finitos para reconocerlos.
27

2.3.3

Tratamiento de errores

Nombre ilegales de identificadores: Un nombre que contiene un carcter invlido.


Nmeros incorrectos: un numero que contiene caracteres invlidos o no est
formado correctamente [3.14 en vez de 3,14 o 0.3.14].
Errores de ortografa en palabras reservadas: Caracteres omitidos, adicionales o
cambiados de sitio, por ejemplo la palabra hwile en vez while.
Fin de archivo: Se detecta el fin de un archivo a mitad de un componente lxico.

Ejemplos
a) Sea el vocabulario {a,b} y la expresin regular aa*bb*. Indicar el lenguaje que
denota, y algunas cadenas de dicho lenguaje.
Solucin: Algunas cadenas son:
ab
aab
aaaab
abbbb
abb
aaaab
El lenguaje que se describe es L={cadenas que comienzan por una a y continan
con varias o ninguna a, y siguen con una b y continuan con varias o ninguna b}

b) Sea el vocabulario {0,1}, la expresin regular 1(01)*denota el conjunto de cadenas


que empiezan por 1 y van seguidas por (01) cualquier n de veces o ninguna.
c) Dada la expresin regular (a | b)*, el lenguaje que denota es el que se puede forma
con todas las cadenas compuestas por a y b incluida la cadena vacia. Algunos
ejemplos de sentencias de este lenguaje son :

aaa
bbb
aba
abaaa
abbaa
2.3.4

Ejercicios

Simplificar las expresiones regulares:


a) (01 | 10 | 0110 | 1001)*
b) (0(0 | 1)*)+
Encontrar una expresin regular correspondiente a cada uno delos siguientes
subconjuntos de {0, 1}*
28

a) El lenguaje de las cadenas que contienen exactamente dos 0s.


b) El lenguaje de las cadenas que contienen al menos dos 0s.
c) El lenguaje de las cadenas que no terminan con 01.
d) El lenguaje de las cadenas que comienzan o terminan con 00 o 11.
Encontrar una expresin regular correspondiente al lenguaje:
({ab, aab, abaabb}* U {abbba}){abb}{b, baa}*
Considere las dos expresiones regulares:
R1 = a* | b* y R2 = ab* | ba* | b*a | (a*b)*
a) Encontrar una cadena correspondiente a R1 pero no a R2.
b) Encontrar una cadena correspondiente a R2 pero no a R1.
c) Encontrar una cadena correspondiente tanto a R1 como a R2.

29

2.4

Autmatas

Un autmata es una construccin lgica que recibe una entrada y produce una salida en
funcin de todo lo recibido hasta ese instante.
En el caso de los Procesadores de Lenguaje un autmata es una construccin lgica que
recibe como entrada una cadena de smbolos y produce una salida indicando si dicha
cadena pertenece o no a un determinado lenguaje.

2.4.1

Definicin formal de autmata

Un autmata es una quntupla A = ( E, S, Q, f, g ) donde :

E = {conjunto de entradas o vocabulario de entrada}


S = {conjunto de salidas o vocabulario de salida}
Q = {conjunto de estados}
f: E X Q Q
g: E X Q S
E es un conjunto finito, y sus elementos se llaman entradas o smbolos de entrada.
S es un conjunto finito, y sus elementos se llaman salidas o smbolos de salida.
Q es el conjunto de estados posibles, puede ser finito o infinito.
f es la funcin de transicin o funcin del estado siguiente, y para un par del
conjunto
E Q devuelve un estado perteneciente al conjunto Q. E Q es el conjunto producto
cartesiano de E por Q.
g es la funcin de salida, y para un par del conjunto E Q, devuelve un smbolo de
salida del conjunto S.
2.4.2

Representacin de autmatas

Los autmatas se pueden representar mediante:


- Tabla de transiciones
- Diagrama de Moore
2.4.2.1

Tabla de transiciones

Las funciones f y g pueden representarse mediante una tabla, con tantas filas como
estados y tantas columnas como entradas. As por ejemplo se puede representar el
autmata A = ( E, S, Q, f, g ) donde E = {a,b}, S = {0,1}, Q = {q1, q2, q3} y las funciones f y
g se pueden representar por :

30

Ilustracin 4 , Tabla de transiciones - Autmatas

2.4.2.2

Diagramas de Moore

Los diagramas de Moore son otra forma de representar las funciones de transicin y
salida de un autmata.
El diagrama de Moore es un grafo orientado en el que cada nodo corresponde a un
estado

Ilustracin 5 , Diagrama de Moore - Autmatas

A continuacin de muestra 2 ejemplos de autmatas para poder reconocer la palabra


reservada IF y el nombre de un identificador:
31

Ms ejemplos

32

2.4.3

Lenguaje Generado

El lenguaje generado se obtiene partiendo del estado inicial y recorriendo todos los
caminos posibles para alcanzar el estado final. As se obtiene que este autmata
reconoce el lenguaje :

LA1 = abaababbbaabb
La expresin regular que denota el lenguaje es a+b+ o tambin aa*bb*.
L(A1) = {anbm/n 1m 1}
2.4.4

Ejemplo completo (diagrama de transiciones diagrama de moore)

Construir el diagrama de Moore, y determinar el lenguaje que reconoce, denotndolocon


su expresin regular.
33

Solucin: Se construye el diagrama de Moore de forma anloga al ejemplo anterior

2.4.5

Cmo transformamos una expresin regular en un autmata?

Para expresiones regulares M y N

34

2.4.6

Equivalencia entre expresiones regulares bsicas y autmatas finitos

Se muestran equivalencias entre expresiones regulares simples y autmatas finitos


expresados mediante un diagrama de Moore

Expresin regular

35

Expresin regular a

Expresin regular a*

Expresin regular a+

Expresin regular a b

36

Expresin regular (a b)*

Expresin regular (ac b)*

Expresin regular (acd b)*

37

38

39

40

41

42

String matching

43

44

45

Autmata finito no determinista

Un autmata finito no determinista (abreviado AFND) es un autmata finito que, a


diferencia de los autmatas finitos deterministas (AFD), posee al menos un estado q Q,
tal que para un smbolo a del alfabeto, existe ms de una transicin (q,a) posible.

Autmata finito determinista

Un autmata finito determinista (abreviado AFD) es un autmata finito que adems es


un sistema determinista; es decir, para cada estado en que se encuentre el autmata, y
con cualquier smbolo del alfabeto ledo, existe siempre a lo ms una transicin posible
desde ese estado y con ese smbolo.

Conversin de un AFND a AFD

Tomando en cuenta el siguiente autmata

46

Cuya tabla de transicin es la siguiente


a
{q0} {q0}
{q1}
Con ello nos aseguramos que es un AFND ,
en el estado q0 y teniendo como entrada b
ello sabemos que se trata de un AFND.

b
{q0,q1}
{q1}
dado que tomando en cuenta que estamos
llegamos a los estado {qo,q1} a la vez por

Para poder eliminar esa ambigedad (convertir un AFND a AFD ) , iniciamos en el estado
inicial q0 y elaboramos la nueva tabla de transicin :
Observando el autmata dado inicialmente, estamos en el estado q0 e ingresa a nos
lleva al estado q0 , pero si ingresa b nos lleva a q0 y q1 a la vez
a
{q0} {q0}

b
{q0,q1}

Con esta porcin de tabla de transicin elaborada nos damos cuenta que ha aparecido un
nuevo estado {q0,q1} , por ello colocamos en el lugar de los estado a este estado
encontrado.
a
q0
{q0}
{q0,q1} {q0}

b
{q0,q1}
{q0,q1}

Comenzando en el estado inicial {q0,q1} habiendo ingresado a llegamos al estado {q0}


, habiendo ingresado b llegamos al estado {q0,q1} .
No habiendo ms estados nuevos, aqu termina la elaboracin de tabla de transicin solo
nos queda el remplazo de los estados encontrado por otros estados equivalentes ms
fciles de representar.
a b
1 1 2
2 1 2

a
1

b
2

Tenemos el siguiente AFND


47

Cuya solucin es la siguiente

Que tenemos hasta ahora


Expresiones regulares proporcionan un lenguaje formal para definir los tokens.
Podemos convertir fcilmente las expresiones regulares a NDFA's.
Pero los NDFA's no son nada sencillos de implementar. Tienen que adivinar!

48

Ejercicios
1. Sea M = (Q, , , q0, F) un AFD con Q = {q0 ,q1 ,q2 }, = {a, b}, F = {q2} y la
funcin de transicin :

a) Dibuja el autmata M
b) Traza los cmputos de M que procesan las palabras abaa, bbbabb, babababbbaa
c) Qu palabras de las procesadas en (b) son aceptadas por M?

2. Busca tres palabras aceptadas y tres palabras rechazadas por cada uno de los
siguientes autmatas mostrando el cmputo que las procesa. Determina cules de
ellos estn totalmente especificados. Sabras cul es el lenguaje aceptado por
cada uno de ellos?

49

3. Construye AFDs que acepten cada uno de los siguientes lenguajes definidos
sobre el alfabeto = {a,b}:
a ) L = { x * : la longitud de x es divisible por 3}
b ) L = { x *: aba no es subpalabra de x }
c ) L = { x * : x comienza por a y termina por ab }
d ) L = { x * : x tiene un nmero par de a's y un nmero par de b's }
e ) L = { x * : x tiene tres a's consecutivas }
f ) L = { x * : toda aparicin de la subpalabra aba en x, o bien va seguida de bb, o
est al final de la palabra }
g ) L = { x * : si x empieza por a no contiene la subpalabra aa y si x empieza por b
contiene la subpalabra aa }
h ) L = { x * : x tiene un nmero par de apariciones de la cadena ab }
50

i ) L = { x * : ab es subpalabra de x si y slo si ba es subpalabra de x }


j ) L = { x * : x est formada por la concatenacin de un nmero arbitrario de
cadenas de la forma yyR , con |y|=2 }
k ) L = { x * : x no contiene ningn prefijo en el que la diferencia entre el nmero
de a's y b's sea mayor que tres (a favor de cualquiera de ellos) }

4. Construye AFD's equivalentes a los siguientes AFND's:

5. Construye AFD's equivalentes a los siguientes -AFND's:

51

3. Analizador Sintctico
Antes de continuar veamos algunas tems importantes del analizador lxico (expresiones
regulares, gramticas y lenguajes)
Una expresin regular puede ser escrita usando:

Caracteres en el alfabeto

Operadores de expresiones regulares:


* | + ? ( )

Ejemplo:
(-| ) (0|1|2|3|4|5|6|7|8|9)+ (. (0|1|2|3|4|5|6|7|8|9)*)?

Un lenguaje regular es un lenguaje definido por una expresin regular

Qu hay acerca de las variables simblicas?

Ejemplo:
num = 0|1|2|3|4|5|6|7|8|9
posint = num num*
int = ( | -) posint
real = int ( | (. posint))

Slo son una abreviacin, llamada syntactic sugar

Ejemplo:
(-| ) (0|1|2|3|4|5|6|7|8|9)+ (. (0|1|2|3|4|5|6|7|8|9)*)?

Resumen del analizador lexico

El analizador lxico crea tokens a partir de un character stream

Los tokens se definen usando expresiones regulares

Las expresiones regulares pueden mapearse a un Autmata Finito No


Determinstico (NFA)

Por construccin simple

NFA se transforma a un DFA

Algoritmo de transformacin

Ejecutar un DFA es fcil


52

3.1

Sintaxis y Semntica de un Lenguaje de Programacin?

Sintaxis

Como se ve un programa

Representacin textual o estructura

Es posible una definicin matemtica precisa

Semntica

Cul es el significado de un programa

Es ms difcil dar una definicin matemtica

3.2

Por qu hacer anlisis sintctico?

Podemos proveer una definicin precisa y fcil de entender

Una gramtica apropiada imparte estructura a un lenguaje de programacin

Podemos construir automticamente un parser que determine si el programa es


sintcticamente correcto

Ayuda en el proceso de traduccin

Fcil modificar/aadir al lenguaje

3.3

Anatoma de un Compilador Analizador Sintctico

Programa (character stream)


Analizador Lxico (Scanner)
Token Stream
Analizador Sintctico (Parser)
Arbol de Parseo
Generador de Cdigo Intermedio
Representacin Intermedia
Optimizador de Cdigo
Representacin Intermedia Optimizada
Generador de Cdigo

53

Cdigo en Assembler

3.4

Funciones del analizador sintctico:

Comprobar si la cadena de componentes lxicos proporcionada por el analizador


lxico puede ser generada por la gramtica que define el lenguaje fuente
(Gramtica Independiente del Contexto, GIC).
Construir el rbol de anlisis sintctico que define la estructura jerrquica de un
programa y obtener la serie de derivaciones para generar la cadena de
componentes lxicos. El rbol sintctico se utilizara como representacin
intermedia en la generacin de cdigo.
Informar de los errores sintcticos de forma precisa y significativa y debera estar
dotado de un mecanismo de recuperacin de errores para continuar con el
anlisis.

Ilustracin 6 , Analizador Sintctico

El anlisis sintctico se puede considerar como una funcin que toma como entrada la
secuencia de componentes lxicos producida por el anlisis lxico y produce como salida
el rbol sintctico.
En la realidad, el anlisis sintctico hace una peticin al anlisis lxico del componente
lxico siguiente en la entrada (los smbolos terminales) conforme lo va necesitando en el
proceso de anlisis, conforme se mueve a lo largo de la gramtica.

3.5

Reconocedor versus analizador sintctico

Un reconocedor trata de determinar simplemente si la cadena puede o no ser generada


por la gramtica (salida boolena). Podramos preguntar algo ms. Si queremos reconocer
las estructuras propias de los lenguajes de programacin en el fichero de entrada para
54

guiar la traduccin, es necesario conocer su estructura jerrquica, el rbol de anlisis


sintctico.

3.6

Especificacin sintctica de los lenguajes de programacin

La mayora de las construcciones de los lenguajes de programacin se pueden


representar con una gramtica independiente del contexto (GIC). La mayora de las
construcciones de los lenguajes de programacin implica recursividad y anidamientos.

G = {S, VT , VNT , P}
S: el axioma o smbolo de inicio
VT : conjunto de terminales, los componentes lxicos
VNT : conjunto de no-terminales
P: conjunto de reglas de produccin de la forma
VNT X1; : : : ;Xn; con Xi pertenece (VT U VNT )
Expresiones regulares o gramticas independientes del contexto?
Las expresiones regulares no permiten construcciones anidadas tan comunes en los
lenguajes de programacin: parntesis equilibrados, concordancia de pares de palabras
clave como begin-end,
do-while, ...
Por ejemplo: consideremos el problema de los parntesis equilibrados en una expresin
aritmtica. El hecho de que haya un parntesis abierto obliga a que haya un parntesis
cerrado. Este problema es similar a considerar el lenguaje
L = {aba; aabaa; aaabaaa; : : : ; } = {anban <= 0}
Si intentamos escribir una expresin regular, lo ms prximo seria: {a*ba*} pero no se
garantiza que el nmero de a's antes y despus sea el mismo.
Las expresiones regulares NO SABEN contar. NO es posible especificar la estructura
de un lenguaje de programacin con slo expresiones regulares.
Como tenemos el problema de las parntesis balanceados o las llaves balanceadas
segn sea el lenguaje que usamos, tenemos que tener en cuenta :
Nmero de parntesis abiertos debe ser igual a nmero de parntesis cerrados
Necesitamos mantener un conteo o necesitamos recursin
Adems: NFAs y DFAs no pueden ejecutar conteo sin lmites
Hay alguna gramtica que defina esto?
<S> ( <S> ) <S> |
La definicin es recursiva
Esta es una gramtica libre de contexto
Es ms expresiva que las expresiones regulares

55

3.7

Como convertir Expresiones Regulares a CFGs

Considere la siguiente expresin regular:


01+10(11)*
Queremos convertir una gramtica regular con las reglas de la forma V w, donde V es
un no terminal y w es una cadena de terminales /no terminales. Para comenzar, usted
puede simplemente mezclar CFG y la sintaxis de expresiones regulares.
Entonces comenzamos usando un no terminal <S>
<S> -> 01+10(11)*
Donde S es el smbolo inicial. Ahora vamos a romper un poco(y aadir espacios en blanco
para mayor claridad):
<S> -> 0 <A> 1 0 <B>
<A> -> 1+
<B> -> (11)*
La clave est en convertir *s y +s en recursivas. En primer lugar, vamos a convertir a el
asterisco a un + insertando una regla intermediaria que acepta cadenas vacas:
<S> -> 0 <A> 1 0 <B>
<A> -> 1+
<B> -> ()
<B> -> <C>
<C> -> (11)+
Finalmente, convertiremos el + en una recursin:
<S> -> 0 <A> 1 0 <B>
<A> -> 1
<A> -> <A> 1
<B> -> (empty)
<B> -> <C>
<C> -> 11
<C> -> <C> 11
Al final optemos lo siguiente:
01+10(11)*

<S> -> 0 <A> 1 0 <B>


<A> -> 1
<A> -> <A> 1
<B> -> (empty)
<B> -> <C>
<C> -> 11
<C> -> <C> 11
56

Ejercicios
Convertir las siguientes ER en CFGs
a) (a|b)*
b) xy*a+
c) (ab)+c?

57

3.8

Definiendo Context-Free Grammars (CFGs)

Terminales (VT): Smbolos para strings o tokens


No terminales (VNT ): Variables sintcticas
Smbolo de Inicio(S ) : Un no-terminal especial es designado
Producciones ( P )

La forma en que los terminales y no-terminales son combinados para formar strings
Un no-terminal en el lado izquierdo (LHS) y un string de terminales y no-terminales en el
lado derecho (RHS)

Teniendo en cuenta todos los elementos que componen una CFGs (Gramticas libres de contexto)
hace posible la creacin de arboles de derivacin que proporcionan una herramienta para hacer
posible la creacin de arboles de analizador sintctico (Parser).
La interseccin entre el vocabulario terminal y no terminal es el conjunto vaco:
{VN} {VT} = {vaco}
La unin entre el vocabulario terminal y no terminal es el vocabulario:
{VN} U {VT} = {V}
En ocasiones es importante distinguir si un determinado vocabulario incluye o no la cadena vaca,
indicndose respectivamente con superndice + o superndice *, tal como se muestra a
continuacin:
V+ = V {}
V* = V + {}
Por ejemplo para la gramtica:
E --> id | num | E + E | ( E ) | - E
Donde podemos reconocer los siguientes elementos que componen la gramtica:
Smbolo de inicio: E
No Terminales: E
Terminales: id , num , + , ( , ) , Producciones:
58

E id
E num
EE+E
E(E)
E-E

Otro ejemplo
1. <S> ( <S> ) <S> |
2. <S> ( <S> ) <S>
<S>
En este punto podemos definir algunos elementos terminales como lo son : (,), ; porque
estos smbolos no pueden llevarnos a crear produccin alguna.
Y tambin nos pueden dar los elementos no terminales como es

<S> .

Definiendo todo junto

<S> ( <S> ) <S>


Elementos terminales VT

<S>

<S> ( <S> ) <S>


Elementos no terminales VNT

<S>

Elemento de inicio <S>


<S> ( <S> ) <S>
Producciones encontradas, 2
<S>
Los lenguajes regulares son un subconjunto de los lenguajes libres de contexto

Expresin Regular

Gramtica libre de contexto

<A> a

59

Si p y q son expresiones regulares, usando CFGs <P> y <Q>


pq

<S> <P> <Q>

p|q

<S> <P>
<S> <Q>

p*

<S> <S> <P>


<S>

Si p es una expresin regular, usando una CFG <P>,


Qu es?
??? <S> <S>
<P>
<S> <P>
P?

???

Ejemplo 1
Aqu hay una gramtica libre de contexto para expresiones enteras algebraicas
sintcticamente correctas sobre las variables x, y y z:
S x | y | z | S + S | S - S | S *S | S/S | (S)
Generara, por ejemplo, la cadena (x + y) *x - z *y / (x + x)
Ejemplo 2
1) Sea la gramtica: G = ( VT, VN, S, P) donde VT = {a, b}, VN = {S}, y el conjunto de
producciones es:
S ab
S aSb
2) Sea la gramtica G = (VN, VT, S, P) donde :
VN = { <nmero> , <dgito> }
VT = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }
S = <nmero>
Las reglas de produccin P son :
<nmero> -> <dgito> <nmero>
60

<nmero> -><dgito>
<dgito> -> 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
Entonces por qu usar expresiones regulares?

Separar el anlisis sintctico en partes lxica y no-lxica es una buena


modularizacin
Las reglas lxicas son simples y pueden ser expresadas usando expresiones
regulares
Las expresiones regulares son ms concisas
Las implementaciones de analizadores lxicos para expresiones regulares son
ms eficientes

Creando una CFG


Tenemos que crear una CFG a partir de las definiciones del lenguaje, identificando cada
uno de los elementos que componen la gramtica a partir del lenguaje proporcionado.
Ejemplo: Una CFG para expresiones

Expresiones aritmticas simples con + y *

8.2 + 35.6
8.32 + 86 * 45.3
(6.001 + 6.004) * (6.035 * -(6.042 + 6.046))
Terminales (o tokens)

num para todos los nmeros


plus_op (+), minus_op (-), times_op(*), left_paren_op((),
right_paren_op())
Cul es la gramtica para todas las expresiones posibles?

<expr> <expr> <op> <expr>


<expr> ( <expr> )
<expr> - <expr>
<expr> num
<op> +
<op> *

Identificando Terminales
<expr> <expr> <op> <expr>
<expr> ( <expr> )
<expr> - <expr>
<expr> num
<op> +
<op> *

61

Identificando No Terminales , smbolo de inicio <expr>


<expr> <expr> <op> <expr>
<expr> ( <expr> )
<expr> - <expr>
<expr> num
<op> +
<op> *

Producciones
<expr> <expr> <op> <expr>
<expr> ( <expr> )
<expr> - <expr>

Producciones

<expr> num
<op> +
<op> *

Al final podemos rescribir, de esta manera


<expr> <expr> <op> <expr> | ( <expr> ) | - <expr> | num
<op> + | *

Pregunta: Cul es el lenguaje definido por esta CFG?


<S> a<S>a | aa

62

3.9

Definicin del lenguaje

Sea la gramtica G6 = ({S,A,B}, {a,b}, S, P) donde las producciones P son :


S aB
A bAA
S bA
B b
A a
BbS
A aS
B aBB
Determinar el lenguaje que genera.
Solucin : Se generan algunas instrucciones.
S aB ab
S bA ba
S aB abS abbA abba
S bA bbAA bbaa
S aB abS abaB ababS ababaB ababab
L(G6) = {cadenas que tienen igual n de a que de b}

3.10 Derivaciones. Arboles de analizador sintctico


Cmo mostramos que una secuencia de tokens es aceptada por una CFG?
Una produccin es usada para derivar una secuencia de tokens a partir del smbolo de
inicio
Dados los strings , y y una produccin A b
Un solo paso de la derivacin es
A
Por ejemplo para la gramtica:
E id | num | E + E | ( E ) | - E
Si queremos derivar la frase -(id + id)
E -E -(E + E) -(id + E) - (id + id)

Ejemplo de Derivacin
Gramtica
<expr> <expr><op><expr> | (<expr>) | -<expr> | num
<op> + | *
Entrada
36 * ( 8 + 23.4)
63

Token Stream
num * ( num + num )
<expr>

<expr> <op> <expr>

num <op> <expr>

num * <expr>

num * ( <expr> )

num * ( <expr> <op> <expr> )

num * ( num <op> <expr> )

num * ( num + <expr> )

num * ( num + num )


<expr> num * ( num + num )

3.11 Arboles de anlisis sintctico (rbol de parseo)


Un rbol de anlisis sintctico indica como a partir del axioma de la gramtica se deriva
una frase (cadena) del lenguaje. Dada una gramtica independiente del contexto, un rbol
de anlisis sintctico es un rbol tal que:
1. La raz est etiquetada con el smbolo inicial.
2. Cada hoja est etiquetada con un componente lxico. Las hojas de izquierda a derecha
forman la frase (el programa fuente).
3. Cada nodo interior est etiquetado con un no-terminal.
4. Si A es un no-terminal y X1;X2; : : : ;Xn son sus hijos de izquierda a derecha, entonces
existe la produccin A X1;X2; : : : ;Xn, con Xi pertenece (VT U VNT ).
El rbol de anlisis sintctico contiene en general mucha ms informacin que la
estrictamente necesaria para generar el cdigo.
Se puede construir una estructura ms sencilla, los arboles abstractos de anlisis
sintctico. Ejemplo: expresiones aritmticas (igual semntica, menor complejidad)

64

Otro ejemplo
num * ( num + num )

<expr>
<expr>

num

<op>

<expr>
<expr>

<expr> <op>

num

)
<expr>

num

Derivaciones left-most (mas a la izquierda) vs. right-most (mas a la derecha)

Por ejemplo para la gramtica:


E id | num | E + E | ( E ) | - E
Si queremos derivar la frase -(id + id)
E -E -(E + E) -(id + E) - (id + id)
Derivacin ms a la izquierda.
65

E -E -(E + E) -(E + id) -(id + id)


Derivacin ms a la derecha.

Otro ejemplo de right-most


String: num * ( num + num )
<expr>

<expr> <op> <expr>


<expr> <op> ( <expr> )
<expr> <op> ( <expr> <op> <expr> )
<expr> <op> ( <expr> <op> num )
<expr> <op> ( <expr> + num )
<expr> <op> ( num + num )
<expr> * ( num + num )
num * ( num + num )

Top-down vs. Bottom-up Parsing

Normalmente escaneamos de izquierda a derecha


Left-most derivation refleja top-down parsing
Comenzamos con el smbolo inicial
Terminamos con el string de tokens
Top-down Parsing

Left-most derivation

<expr>
<expr> <op> <expr>
num <op> <expr>
num * <expr>
num * ( <expr> )
num * ( <expr> <op> <expr> )
num * ( num <op> <expr> )
num * ( num + <expr> )
num * ( num + num )

Top-down vs. Bottom-up Parsing

Normalmente escaneamos de izquierda a derecha


Left-most derivation refleja top-down parsing
Comenzamos con el smbolo inicial
Terminamos con el string de tokens
Right-most derivation refleja bottom-up parsing
Comenzamos con el string de tokens
66

Terminamos con el smbolo inicial

Right-most derivation
num * ( num + num )
<expr> * ( num + num )
<expr> <op> ( num + num )
<expr> <op> ( <expr> + num )
<expr> <op> ( <expr> <op> num )
<expr> <op> ( <expr> <op> <expr> )
<expr> <op> ( <expr> )
<expr> <op> <expr>
<expr>

3.12 Gramticas ambiguas


Una gramtica es ambigua cuando para una determinada sentencia produce ms de un
rbol de derivacin.
La gramtica siguiente es ambigua:
E id | num | E + E | E * E | ( E ) | - E
Supongamos la sentencia id + id * id

Podriamos obtener : 124 + (23.5 * 86) = 2145 (124 + 23.5) * 86 = 12685 , pero cual
seria la respuesta correcta para la operacin planteada?
El significado semntico es DIFERENTE. No existe una nica traduccin posible. Se
genera cdigo diferente.
No existe un algoritmo que determine con certeza en un plazo finito de tiempo si una
gramtica es ambigua o no. A lo sumo que se ha llegado en el estudio de la ambigedad
es que hay algunas condiciones que de cumplirse determinan la ambigedad, pero en el
caso de no cumplirse no se puede decir que la gramtica es no ambigua.
Necesidad de evitar las gramticas ambiguas. Cmo? transformando la gramtica o
estableciendo precedencias entre operadores y de asociatividad.
67

Se puede eliminar la ambigedad transformando la gramtica agrupando todos los


operadores de igual precedencia en grupos y asociando a cada uno una regla, de forma
que los que tengan menor precedencia aparezcan ms cercanos al simbolo de inicio,
precedencia en cascada. Esto conlleva el aumento de la complejidad de la gramtica y
con ello en la del rbol sintctico. La gramtica deja de ser intuitiva.
Ejemplo 1: gramtica ambigua
E num | E + E | E - E | E * E | E / E
Si la transformamos, esta gramatica ya no es ambigua.
Exp exp + term | exp - term | term
term term * factor | term / factor | factor
factor ( exp ) | num

Eliminacin de gramticas ambiguas

Eliminar la ambigedad en una gramtica requiere de un proceso de anlisis propio de


cada gramtica que verifique que para ninguna palabra que esta genera se puedan
generar ms de un rbol de derivacin.
En algunos casos, la ambigedad de una gramtica se puede eliminar utilizando nuevas
variables que eliminen los rboles de derivacin no deseados.
Tambin existen los lenguajes inherentemente ambiguos para los que no existe una
gramtica no ambigua equivalente.
EE+E
EE*E
E id
E num
E -E
E (E)
Comprobamos que esta gramatica es ambigua .
Es ambigua porque la cadena id + num * id tiene dos rboles de derivacin:
rbol izquierdo representa (id + num) * id
rbol de la derecha representa id + (num * id).

68

En el ejemplo de los operadores aritmticos, adems de la variable E, que representa


expresiones, tambin se utilizan las variables F para factores y T para trminos y se
tienen las siguientes reglas:
EE+T
TT*F
F (E)
F id
ET
TF
T -F
F num

Ejercicios
1.

Para la gramtica Gcuyas producciones son

describa al lenguaje generado por G.


2. Dada la siguiente gramtica, escribe la derivacin ms a la izquierda, el rbol de
anlisis sintctico y el rbol sintctico abstracto para las siguientes expresiones:
(a) 3+4*5-6;
(b) 3*(4-5+6)
exp exp addop term j term
addop + | term term mulop factor j factor
mulop * | /
factor ( exp ) j num
3. Escribe una gramtica para expresiones booleanas que incluya las constantes true y
false, los operadores and,or y not y los parntesis. Se ha de tener en cuenta que el
operador or tiene menor precedencia que el operador and y este menor que el
operador not. Construye la gramatica de forma que los operadores and y or sean
asociativos por la izquierda y el operador not por la derecha.

69

4. Anlisis Semntico y Chequeo de Tipos


La fase de anlisis semntico revisa el programa fuente para tratar de encontrar errores
semnticos y rene la informacin sobre los tipos para la fase posterior de generacin de
cdigo. En ella se utiliza la estructura jerrquica determinada por la fase de anlisis
sintctico para identificar los operadores y operandos de expresiones y proposiciones.
Un componente importante del anlisis semntico es la verificacin de tipos. Aqu,
el compilador verifica si cada operador tiene operandos permitidos por la especificacin
del lenguaje fuente. Por ejemplo, las definiciones de muchos lenguajes de programacin
requieren que el compilador indique un error cada vez que se use un nmero real como
ndice de una matriz. Sin embargo, la especificacin del lenguaje puede imponer
restricciones a los operandos, por ejemplo, cuando un operador aritmtico binario se
aplica a un nmero entero y a un nmero real. Revisa que los arreglos tengan definido el
tamao correcto.

Dnde estamos?

Programa (character stream)


Analizador Lxico (Scanner)
Token Stream
Analizador Sintctico (Parser)
Arbol de Parseo
Analizador Semntico
Generador de Cdigo Intermedio
Representacin Intermedia +
Tabla de Smbolos

Qu es la semntica de un programa?
Sintxis
70

Cmo se ve un programa

Representacin textual o estructura

Es posible dar una definicin matemtica precisa

Semntica

Cul es el significado del programa

Es ms difcil dar una definicin matemtica precisa

El analisis semantico incluye:

La construccion de la Tabla de Simbolos para llevar un seguimiento del signicado


de los identicadores en el programa (variables, funciones, tipos, parametros y
metodo de paso de parametros en funciones, etc)

Realizar la comprobacion e inferencia de tipos en expresiones y sentencias (por


ejemplo, que ambos lados de una asignacion tengan tipos adecuados, que no se
declaren variables con el mismo nombre, que los parametros de llamada a una
funcin tengan tipos adecuados, numero de parametros correcto, )

Nos centraremos en el analisis semantico estatico: se realiza en tiempo de compilacion,


no de ejecucion.

Como vamos a implementar la estructura semntica de un lenguaje?


A partir de la construccion del arbol de anlisis sintctico, lo recorreremos en un
determinado orden y calcularemos en cada nodo la informacion semantica necesaria (el
valor de una expresin, el tipo de una variable, su ambito de declaracin, el nmero de
argumentos de una funcin, etc).
Conceptualmente, se analiza sintacticamente la cadena de componentes lexicos de
entrada, se construye el rbol de anlisis sintctico y despus se recorre el rbol, en un
determinado orden para tener en cuenta las dependencias, para evaluar las reglas
semanticas en sus nodos.

71

Por qu hacer anlisis semntico

Asegurarnos que el programa cumple con la definicin del lenguaje de


programacin

Proveer mensajes de error tiles al usuario

4.1

Atributos y gramaticas de atributos

Un atributo es cualquier propiedad de una construccion de un lenguaje de programacion.


Varan en funcion del tipo de informacin que contienen, su complejidad de calculo y el
momento en el que son calculados (en tiempo de compilacion (atributos est aticos) o de
ejecucin (dinmicos)).
Ejemplos tpicos son:

el nombre de una variable

el tipo de una variable

el ambito de una variable

el valor de una expresion

el numero de argumentos de una funcin

la posicion en memoria de una variable

un fragmento de codigo

Ejemplos de atributos que se calculan en tiempo de compilacion: el tipo de dato, el


nombre de una variable, el codigo de un procedimiento.
Ejemplos de atributos que se calculan en tiempo de ejecucion: la posicin de una variable,
el valor de una expresion. Aunque algunas expresiones son constante y se pueden
calcular en tiempo de compilacion (clculo previo de constantes), por ejemplo print(%d,
3+4*2);.
Nos centraremos en el analisis semntico esttico (construccin de la Tabla de Smbolos
y comprobaciones e inferencia de tipos), ya que el dinamico depende de la arquitectura de
la maquina, del sistema operativo (control de ejecucion, gestin de la memoria, llamadas
a funciones, etc)
Se llama enlace (binding) al proceso de calcular el valor del atributo y asociarlo a su
correspondiente construccion lingstica. Puede ser enlace dinamico o esttico segn el
momento en que se calcule.

72

Una gramatica de atributos es una generalizacion de una gramtica independiente del


contexto en la que cada smbolo gramatical (terminal o no-terminal) tiene asociado un
conjunto de atributos.

Las gramaticas de atributos se suelen escribir en forma tabular, con una parte donde
aparecen las producciones y otra donde aparecen las reglas semanticas (o ecuaciones de
atributos) que permiten calcular los atributos.

Ejemplo 1. Consideremos la gramatica para la generacin de expresiones ritmeticas


simples: Qu atributos nos interesan en esta gramtica?

El valor numerico de la expresin. Lo denotaremos por val


Las reglas semanticas para el clculo de este atributo seran:

Nota: Si un smbolo aparece mas de una vez en una produccin, entonces cada aparicion
debe ser distinguida de las otras apariciones, para que los diferentes valores de las
ocurrencias sean distinguidos.
73

Los atributos se colocan al lado de los nodos del arbol de anlisis sintctico y se dibujan
las dependencias entre ellos. Una echa que va desde los atributos que aparecen en la
parte derecha de la ecuacion hacia el del lado izquierdo. Por ejemplo, para la entrada
(4-3)*2, el arbol sera:

Ejemplo 2. La gramatica para la declaracin de variables en C. Qu atributos nos


interesan en esta gramatica?

Las reglas semanticas para el clculo de este atributo seran: Para la entrada float x,y, el
arbol de anlisis sintctico con los atributos es:

74

4.2

La Tabla de Smbolos

La Tabla de Smbolos es despues del rbol de anlisis sintctico la principal estructura


de datos de un compilador. La Tabla de Smbolos interacciona con el analizador lexico y
con el analizador sintctico, a pesar que hemos retrasado su introduccion hasta ahora.
Ambos introducen informacin o necesitan consultarla durante todo el proceso de la
compilacion. Tambininteracciona con el analisis semntico, como en la comprobacin
de tipo y con el modulo de generacin de cdigo (direccin de memoria, tipo de variable y
tipo de operacion a realizar...).

Un lugar para guardar toda la informacin adicional acerca del programa

Representaciones intermedias: expresiones, statements, control de flujo, etc.

Tabla de Smbolos: Tipos, variables, scope, etc.

75

Scope (mbito - alcance)


Un nombre puede tener significados distintos en lugares distintos

Tipos, variables, etc tiene scope (mbito)

Tenemos que mantener una tabla de smbolos para cada scope

El compilador utiliza la Tabla de Smbolos para llevar un seguimiento de los


identicadores (variables, funciones, tipos) que aparecen en el programa fuente. Se
examina la Tabla de Smbolos cada vez que se encuentra un identicador. Operaciones
de consulta, insercion y borrado con bastante frecuencia.
insercion: introduccion de la informacin de declaraciones de constantes, variables,
funciones y tipos.
busqueda: para obtener informacion de un identicador (su nombre, tipo, ambito, ..)
cuando aparece a lo largo del programa.
borrado: eliminacion de declaraciones (de constantes, variables, funciones o tipos)
cuando nos salimos del ambito en que se aplican.

Operaciones en la tabla de simbolos

make_table(parent_table) symbol_table // crear la tabla

scope(id) symbol_table // alcance de ID

lookup_variable(id, symbol_table) variable // buscar variable ID en la tabla

lookup_type(id, symbol_table) type // buscar tipo de la variable ID en la tabla

get_type(variable) type // obtener el tipo de la variable

add_type(id, symbol_table, type) type // adicionar tipo de ID en la tabla

add_variable(id, symbol_table, type) variable // adicionar variable ID en la


tabla incluyendo tipo

Tabla de smbolos en lenguaje C

Como ya se dijo en el esbozo la tabla de smbolos es una estructura de datos que se crea
en tiempo de traduccin del programa fuente. Es como un diccionario variable, debe darle
apoyo a la insercin, bsqueda y cancelacin de nombres (identificadores) con sus
atributos asociados, representando las vinculaciones con las declaraciones. Debe
76

aclararse que no necesariamente deber estar representada en una tabla como su


nombre indica ya que tambin se emplean rboles, pilas , etc.
Los smbolos se guardan en la tabla con su nombre y una serie de atributos opcionales
que dependern del lenguaje y de los objetivos del procesador, este conjunto de atributos
almacenados se denominan registro de la tabla de smbolos.
La siguiente representa una serie de atributos que no es necesaria para todos los
compiladores, sin embargo cada uno de ellos se puede utilizar en la implementacin de
un compilador particular.

nombre del identificador.

direccin en tiempo de ejecucin a partir del cual se almacenara el identificador si


es una variable.

tipo del identificador. Si es una funcin el tipo que devuelve la funcin.

nmero de dimensiones del array (arreglo), o nmero de miembros de una


estructura o clase, o nmeros de parmetros si se trata de una funcin.

tamao mximo o rango de cada una de las dimensiones de los array, si tiene
dimension estatica.

etc..

Ilustracin 7 , Ejemplo de tabla de smbolos

4.3

Chequeos de Control de Flujo

El control de flujo del programa es sensitivo al contexto


Ejemplos:

Declaracin de una variable debe ser visible al usarla (en scope)

Declaracin de una variable debe estar antes de usarla

Cada camino de salida (exit path) retorna un valor del tipo correcto (ejem return)
77

4.4

Chequeos de Unicidad

Uso (y mal uso) de identificadores


No se puede representar en una CFG (mismo token)
Ejemplos:
Ningn identificador puede ser usado para dos definiciones diferentes en el mismo scope

4.5

Chequeos de Tipo

Un comprobador de tipos tiene como funcin asegurar que el tipo de una construccin
coincida con el previsto en el contexto. Por eje.: llamada a una funcin con argumentos
adecuados, indexacin de solo variables denidas como matrices.
La comprobacin de tipos se puede realizar junto con el proceso de anlisis sintctico en
la mayora de lenguajes.
El diseo de un comprobador de tipos se basa en informacin acerca de las
construcciones sintcticas del lenguaje, la nocin de tipos y las reglas para asignar tipos
a las construcciones del lenguaje.

Que el nmero de argumentos haga match con el nmero de parmetros formales


y que los tipos correspondientes sean equivalentes
Si se llama como expresin, debe retornar un tipo
Cada acceso a una variable debe hacer match con la declaracin (arreglo,
estructura, etc.)
Los identificadores en una expresin deben ser evaluables
LHS de una asignacin debe ser asignable
En una expresin los tipos de las variables, tipos de retorno de mtodos y de
operadores deben ser compatibles

78

4.6

Arboles AST

Supongamos, por ejemplo, que nuestro lenguaje permite asignaciones segn la regla
(Asignacin) -> id:=Expresin ;
Es habitual que se impongan ciertas restricciones. En nuestro caso, estas podran ser:

El identificador de la parte izquierda debe estar declarado previamente.

El tipo de la expresin debe ser compatible con el del identificador.

El analizador semntico deber comprobar que estas dos restricciones se cumplen antes
de declarar que la sentencia de asignacin est bien formada. Pero sucede que la
informacin necesaria para comprobarlas es til tambin para generar cdigo. Esto
quiere decir que si tuviramos una separacin estricta entre las fases del compilador,
para generar cdigo deberamos volver a mirar el identificador para saber a qu objeto
(variable, funcin, constante, etc.) corresponde y que tipo tiene y tambin deberamos
volver a comprobar los tipos de la expresin para generar el cdigo adecuado.

Por otro lado, aunque en teora el rbol de anlisis sera suficiente para fases
posteriores de la compilacin o interpretacin, es una representacin que contiene
mucha informacin redundante.

As el rbol para a:=b+c; podra ser el siguiente

Ilustracin 8 , rbol AST

79

El segundo rbol se conoce como rbol de sintaxis abstracta (o AST, de las iniciales en
ingles).
Como hemos comentado, durante el anlisis semntico se recoge una serie de
informaciones que resultan de utilidad para fases posteriores. Estas informaciones se
pueden almacenar en el rbol, decorndolo:

Ilustracin 9 , rbol AST

As el objetivo de la fase de anlisis semntico ser doble: por un lado detectaremos


errores que no se han detectado en fases previas y por otro lado obtendremos el AST
decorado de la entrada.

Evaluacin de atributos sobre el AST

Todo el proceso de evaluacin de los atributos se puede ver como el etiquetado de un


rbol (el rbol de anlisis), pero no hay nada que impida que el rbol sobre el que se
realiza la evaluacin sea el AST.
Un ejemplo seria el clculo de tipos. Si tenemos la expresin (2+3.5)*4, podemos calcular
los tipos sobre el rbol de anlisis:

80

Tambin podemos realizar el clculo sobre el AST:

Comprobaciones semnticas

Los atributos nos permitirn llevar a cabo las comprobaciones semnticas que necesite el
lenguaje.

81

En algunos casos, utilizaremos los atributos directamente (posiblemente evaluados sobre


el AST), por ejemplo en la comprobacin que hacamos de que el identificador al final de
la funcin era el mismo que al principio.
En otros casos, los atributos se utilizan indirectamente mediante estructuras globales, por
ejemplo la tabla de smbolos. Un ejemplo sera la comprobacin de que un identificador
no se ha declarado dos veces. Si hemos utilizado un nodo similar a:

La tabla de smbolos
Durante la construccin del AST, las comprobaciones semnticas y, probablemente,
durante la interpretacin y la generacin de cdigo necesitaremos obtener informacin
asociada a los distintos identificadores presentes en el programa. La estructura de datos
que permite almacenar y recuperar esta informacin es la tabla de smbolos.
En principio, la tabla debe ofrecer operaciones para:

Insertar informacin relativa a un identificador.

Recuperar la informacin a partir del identificador.

La implementacin habitual es una tabla que asocia cada identificador a informacin tal
como su naturaleza (constante, variable, nombre de funcin, etc.), su tipo (entero, real,
booleano, etc.), su valor (en el caso de constantes), su direccin (en el caso de variables
y funciones), etc.

Es importante tener nicamente una tabla; si tenemos varias, por ejemplo, una para
constantes y otra para variables, el acceso se hace ms difcil ya que para comprobar las
propiedades de un identificador hay que hacer varias consultas en lugar de una.
Una cuestin importante es como se relacionan la tabla y el AST. Tenemos distintas
posibilidades, que explicaremos sobre el siguiente rbol, correspondiente a la sentencia
a= a+c:

82

La primera posibilidad es dejar el rbol tal cual y cada vez que necesitemos alguna
informacin, por ejemplo el valor de a, consultar la tabla. Esta opcin seria la ms
adecuada para situaciones en las que se vaya a recorrer el rbol pocas veces, por
ejemplo en una calculadora donde se evalu cada expresin una sola vez.
Otra posibilidad es ir decorando cada una de las hojas con toda la informacin que se
vaya recopilando. Por ejemplo, si durante el anlisis averiguamos el tipo y direccin de las
variables, pasaramos a almacenar la nueva informacin:

Equivalencia de tipos

Comprobar si dos expresiones de tipo, T1 y T2, son equivalentes es muy sencillo. Si


ambas corresponden a tipos elementales, son equivalentes si son iguales. En caso de
que correspondan a tipos estructurados, hay que comprobar si son el mismo tipo y si los
componentes son equivalentes.
En muchos lenguajes se permite dar nombre a los tipos. Esto introduce una sutileza a la
hora de comprobar la equivalencia. La cuestin es, dada una declaracin como
typedef int a;
83

typedef int b;
son equivalentes a y b? La respuesta depende del lenguaje. Existen dos criterios para la
equivalencia:

Equivalencia de nombre: dos expresiones de tipo con nombre son equivalentes si


y solo si tienen el mismo nombre.

Equivalencia estructural: dos expresiones de tipo son equivalentes si y solo si


tienen la misma estructura.

Hay argumentos a favor de uno y otro criterio. En cualquier caso, hay que tener en cuenta
que para comprobar la equivalencia estructural ya no sirve el mtodo trivial presentado
antes. En este caso, puede haber ciclos, lo que obliga a utilizar algoritmos ms
complicados.

Comprobacin de tipos en expresiones

Para comprobar los tipos en las expresiones podemos utilizar un atributo que indique el
tipo de la expresin. Este tipo se infiere a partir de los distintos componentes de la
expresin y de las reglas de tipos del lenguaje.

Por ejemplo, si vamos a crear un nodo suma a partir de los arboles:

podemos aadir un nodo intermedio para indicar la promocin:

84

4.7

Otras comprobaciones semnticas y recuperacin de errores


semnticos

Dentro de las comprobaciones estticas (en el momento de la compilacin), tenemos la


deteccin e informacin de errores como:

Comprobaciones de tipos: operadores aplicados a operandos incompatibles,


asignacin de tipos incompatibles, llamadas a funciones con tipos no adecuados,
etc.

Comprobaciones de ujo de control: las sentencias que hacen que el ujo de


control abandone una construccin debe tener algn lugar a donde transmitir el
control. Por ejemplo: unbreak debe estar dentro de una proposicin while, for o
switch en C.

Comprobaciones de unicidad: situaciones en las que solo se puede denir un


objeto una vez exactamente. Por ej: un identicador, las etiquetas case dentro de
un switch.

Solo nos hemos centrado en las comprobaciones de tipo. Las otras son en cierto modo
rutinarias y se pueden realizar fcilmente insertando acciones intercaladas en el cdigo
para realizarlas, por ejem. C uando se introduce un identicador en la Tabla de Smbolos.

85

86

Contenido
1.

Introduccin ............................................................................................................................... 2
1.1

Lenguaje de Programacin ............................................................................................. 2

1.1.1.

Caractersticas de los Lenguajes de Programacin ........................................... 3

1.1.2.

Cmo instruir a la computadora ............................................................................. 3

1.2

Conceptos Basicos........................................................................................................... 6

1.3

Traductores y Compiladores ........................................................................................... 7

1.3.1. Traductores de un Lenguaje de Programacin ....................................................... 7


1.3.2. Interprete......................................................................................................................... 8
1.3.3. Compilador ................................................................................................................... 11
1.3.4. Diferencia entre compilador e intrprete.................................................................. 14
1.3.5. Anatoma de un compilador ....................................................................................... 14
2.

Analizador Lxico ................................................................................................................... 15


2.1

Funcin de un analizador lxico ................................................................................... 15

2.2

Componentes Lxicos, Patrones, Lexemas ............................................................... 18

2.3

Expresiones Regulares (especificacin de los componentes lxicos) ................... 19

Alternacin ............................................................................................................................... 19
Cuantificacin .......................................................................................................................... 19
Agrupacin............................................................................................................................... 19
El Punto "."............................................................................................................................... 20
La barra inversa o contrabarra "" ......................................................................................... 20
Los corchetes "[ ]"................................................................................................................... 21
La barra "|" ............................................................................................................................... 22
El signo de dlar "$" ............................................................................................................... 22
El acento circunflejo "^ ......................................................................................................... 22
Los parntesis "() .................................................................................................................. 22
El signo de interrogacin "?" ................................................................................................. 23
Las llaves "{}........................................................................................................................... 23
El asterisco "* ......................................................................................................................... 24
El signo de suma "+" .............................................................................................................. 24
87

Algunos Ejemplos ................................................................................................................... 27


2.3.1

Definicin Regular .................................................................................................. 27

2.3.2

Cmo reconocemos RE's? ................................................................................. 27

2.3.3

Tratamiento de errores .......................................................................................... 28

2.3.4

Ejercicios .................................................................................................................. 28

2.4

Autmatas ........................................................................................................................ 30

2.4.1

Definicin formal de autmata .............................................................................. 30

2.4.2

Representacin de autmatas.............................................................................. 30

2.4.3

Lenguaje Generado................................................................................................ 33

2.4.4

Ejemplo completo (diagrama de transiciones diagrama de moore) ............ 33

2.4.5

Cmo transformamos una expresin regular en un autmata? ................... 34

2.4.6

Equivalencia entre expresiones regulares bsicas y autmatas finitos ......... 35

Autmata finito no determinista ............................................................................................ 46


Autmata finito determinista ................................................................................................. 46
Conversin de un AFND a AFD ........................................................................................... 46
3.

Analizador Sintctico.............................................................................................................. 52
3.1

Sintaxis y Semntica de un Lenguaje de Programacin? ....................................... 53

3.2

Por qu hacer anlisis sintctico? ............................................................................... 53

3.3

Anatoma de un Compilador Analizador Sintctico ............................................... 53

3.4

Funciones del analizador sintctico:............................................................................ 54

3.5

Reconocedor versus analizador sintctico ................................................................. 54

3.6

Especificacin sintctica de los lenguajes de programacin................................... 55

3.7

Como convertir Expresiones Regulares a CFGs....................................................... 56

3.8

Definiendo Context-Free Grammars (CFGs) ............................................................. 58

Los lenguajes regulares son un subconjunto de los lenguajes libres de contexto ...... 59
3.9

Definicin del lenguaje................................................................................................... 63

3.10

Derivaciones. Arboles de analizador sintctico ......................................................... 63

3.11

Arboles de anlisis sintctico (rbol de parseo) ........................................................ 64

Derivaciones left-most (mas a la izquierda) vs. right-most (mas a la derecha) ............ 65


Top-down vs. Bottom-up Parsing ......................................................................................... 66
3.12

Gramticas ambiguas .................................................................................................... 67

Eliminacin de gramticas ambiguas ................................................................................. 68


88

4.

Anlisis Semntico y Chequeo de Tipos ............................................................................ 70


4.1

Atributos y gramaticas de atributos ............................................................................. 72

4.2

La Tabla de Smbolos .................................................................................................... 75

Tabla de smbolos en lenguaje C ........................................................................................ 76


4.3

Chequeos de Control de Flujo ...................................................................................... 77

4.4

Chequeos de Unicidad .................................................................................................. 78

4.5

Chequeos de Tipo .......................................................................................................... 78

4.6

Arboles AST .................................................................................................................... 79

4.7

Otras comprobaciones semnticas y recuperacin de errores semnticos ...... 85

Ren
Snche
z Vera

89

Firmado digitalmente
por Ren Snchez Vera
Nombre de
reconocimiento (DN):
cn=Ren Snchez Vera,
o=IST La Recoleta,
ou=Informatica,
email=rene.sanchez.ver
a@gmail.com, c=PE
Fecha: 2014.08.20
22:06:57 -05'00'

Вам также может понравиться