Documente Academic
Documente Profesional
Documente Cultură
Facultad de Ingeniera
Departamento de Ingeniera Informtica
APUNTES DE LA ASIGNATURA
COMPILADORES
Compiladores
TABLA DE CONTENIDOS
1 INTRODUCCIN ................................................................................................................................. 7
1.1 QU ES UN PROGRAMA? ......................................................................................................... 8
1.2 DEFINICIN DE COMPILADOR ................................................................................................ 8
1.3 COMPILADORES E INTRPRETES ........................................................................................... 9
1.4 CONTEXTO EN QUE SE SITA EL COMPILADOR ................................................................ 9
1.5 FASES DE UN COMPILADOR .................................................................................................. 11
1.6 CLASIFICACIN DE LOS COMPILADORES.......................................................................... 13
1.7 HERRAMIENTAS TILES ......................................................................................................... 13
2 ANLISIS LXICO ............................................................................................................................ 14
2.1 FUNCIN DEL ANALIZADOR LXICO.................................................................................. 14
2.2 COMPONENTES LXICOS, PATRONES Y LEXEMAS ......................................................... 15
2.3 ERRORES LXICOS ................................................................................................................... 16
2.4 IMPLEMENTACIN DE ANALIZADORES LXICOS .......................................................... 17
2.4.1 MTODOS GENERALES..................................................................................................... 17
2.4.2 CONSTRUCCIN DE UN ANALIZADOR LXICO ......................................................... 17
2.5 EJERCICIOS ................................................................................................................................. 21
3. ANLISIS SINTCTICO .................................................................................................................. 23
3.1 CONCEPTOS PREVIOS .............................................................................................................. 23
3.1.1 RECURSIVIDAD POR LA IZQUIERDA ............................................................................. 23
3.1.2 FACTORIZACIN POR LA IZQUIERDA .......................................................................... 24
3.1.3 CONJUNTOS ANULABLE, PRIMERO Y SIGUIENTE ..................................................... 27
3.1.3.1 Conjunto Anulable ........................................................................................................... 27
3.1.3.2 Conjunto Primero ............................................................................................................. 27
3.1.3.3 Conjunto Siguiente........................................................................................................... 27
3.2 DESCRIPCIN GENERAL DEL ANLISIS SINTCTICO .................................................... 28
3.3 ALGUNOS ASPECTOS DEL MANEJO DE ERRORES SINTCTICOS................................. 29
3.4 ANLISIS SINTCTICO PREDICTIVO ................................................................................... 30
3.4.1 ASPECTOS GENERALES .................................................................................................... 30
3.4.2 CONSTRUCCIN Y FUNCIONAMIENTO DE ANALIZADORES SINTCTICOS LL(1)
......................................................................................................................................................... 31
Jacqueline Khler C. - USACH
Compiladores
3.4.3 GRAMTICAS LL(1) ........................................................................................................... 35
3.4.4 RECUPERACIN DE ERRORES EN ANLISIS SINTCTICO LL(1) ........................... 35
3.4.4.1 Recuperacin de errores en modo de pnico ................................................................... 35
3.4.4.2 Recuperacin de errores a nivel de frase ......................................................................... 36
3.5 ANLISIS SINTCTICO DESCENDENTE (POR DESPLAZAMIENTO Y REDUCCIN).. 37
3.5.1 ASPECTOS GENERALES .................................................................................................... 37
3.5.2 GRAMTICAS LR(K) .......................................................................................................... 38
3.5.3 ANLISIS SINTCTICO SLR ............................................................................................. 38
3.5.3.1 Elemento LR(0)................................................................................................................ 38
3.5.3.2 Operacin Clausura .......................................................................................................... 39
3.5.3.3 Construccin del autmata ............................................................................................... 40
3.5.3.4 Construccin y operacin del analizador sintctico SLR ................................................ 42
3.5.4 USO DE GRAMTICAS AMBIGUAS ................................................................................ 48
3.5.5 RECUPERACIN DE ERRORES ........................................................................................ 49
3.5.5.1 Recuperacin en modo de pnico .................................................................................... 49
3.5.5.2 Recuperacin a nivel de frase .......................................................................................... 50
3.5.6 ANLISIS SINTCTICO LR(1)........................................................................................... 51
3.5.6.1 Elemento LR(1)................................................................................................................ 51
3.5.6.2 Operacin clausura........................................................................................................... 52
3.5.6.3 Construccin del AFD ..................................................................................................... 53
3.5.6.4 Construccin de la tabla de anlisis sintctico LR(1) ...................................................... 53
3.5.7 ANLISIS SINTCTICO LALR .......................................................................................... 58
3.5.7.1 Notas preliminares ........................................................................................................... 58
3.5.7.2 Construccin del AFD a partir del analizador sintctico LR(1) ...................................... 58
3.5.7.3 Construccin directa del AFD.......................................................................................... 63
3.6 EJERCICIOS ................................................................................................................................. 64
4 ANLISIS SEMNTICO ................................................................................................................... 66
4.1 DEFINICIONES DIRIGIDAS POR LA SINTAXIS.................................................................... 66
4.1.1 ATRIBUTOS SINTETIZADOS ............................................................................................ 67
4.1.2 ATRIBUTOS HEREDADOS ................................................................................................. 68
4.1.3 GRAFOS DE DEPENDENCIAS ........................................................................................... 69
Jacqueline Khler C. - USACH
Compiladores
4.2 RBOLES SINTCTICOS .......................................................................................................... 71
4.3 COMPROBACIN DE TIPOS .................................................................................................... 72
4.4 OTRAS COMPROBACIONES SEMNTICAS ......................................................................... 76
4.4.1 VALORES DEL LADO IZQUIERDO .................................................................................. 76
4.4.2 PARMETROS DE FUNCIN ............................................................................................ 77
4.4.3 PALABRA CLAVE return ..................................................................................................... 78
4.4.4 CASOS DUPLICADOS EN UN switch................................................................................. 79
4.4.5 ETIQUETAS goto .................................................................................................................. 79
4.5 EJERCICOS .................................................................................................................................. 79
5 AMBIENTES PARA EL MOMENTO DE EJECUCIN .................................................................. 82
5.1 ASPECTOS DEL LENGUAJE FUENTE .................................................................................... 82
5.1.1 PROCEDIMIENTOS ............................................................................................................. 82
5.1.2 RBOLES DE ACTIVACIN .............................................................................................. 82
5.1.3 PILAS DE CONTROL ........................................................................................................... 83
5.1.4 MBITO DE UNA DECLARACIN ................................................................................... 85
5.1.5 ENLACE DE NOMBRES ...................................................................................................... 85
5.2 ORGANIZACIN DE LA MEMORIA ....................................................................................... 86
5.2.1 SUBDIVISIN DE LA MEMORIA DURANTE LA EJECUCIN..................................... 86
5.2.2 REGISTROS DE ACTIVACIN .......................................................................................... 86
5.2.3 DISPOSICIN ESPACIAL DE LOS DATOS LOCALES EN EL MOMENTO DE LA
COMPILACIN.............................................................................................................................. 87
5.3 ESTRATEGIAS PARA LA ASIGNACIN DE MEMORIA ..................................................... 88
5.3.1 ASIGNACIN ESTTICA ................................................................................................... 88
5.3.2 ASIGNACIN POR MEDIO DE UNA PILA ....................................................................... 89
5.3.3 ASIGNACIN POR MEDIO DE UN MONTCULO .......................................................... 89
5.4 ACCESO A NOMBRES NO LOCALES ..................................................................................... 89
5.4.1 BLOQUES .............................................................................................................................. 90
5.4.2 MBITO LXICO SIN PROCEDIMIENTOS ANIDADOS................................................ 91
5.4.3 MBITO LXICO CON PROCEDIMIENTOS ANIDADOS .............................................. 92
5.4.4 MBITO DINMICO ........................................................................................................... 92
5.5 PASO DE PARMETROS .......................................................................................................... 93
Compiladores
5.5.1 LLAMADA POR VALOR ..................................................................................................... 94
5.5.2 LLAMADA POR REFERENCIA .......................................................................................... 95
5.5.3 COPIA Y RESTAURACIN................................................................................................. 95
5.6 TABLA DE SMBOLOS .............................................................................................................. 96
5.6.1 ENTRADAS DE LA TABLA DE SMBOLOS .................................................................... 97
5.6.2 INFORMACIN SOBRE LA ASIGNACIN DE MEMORIA ........................................... 97
5.6.3 TIPOS DE TABLAS DE SMBOLOS ................................................................................... 98
5.6.4 IMPLEMENTACIN DE LA TABLA DE SMBOLOS ...................................................... 98
5.6.5 REPRESENTACIN DE LA INFORMACIN SOBRE EL MBITO ............................... 99
5.7 ASIGNACIN DINMICA DE LA MEMORIA ...................................................................... 101
5.7.1 INSTRUMENTOS DE LOS LENGUAJES ......................................................................... 101
5.7.2 ASIGNACIN EXPLCITA DE BLOQUES DE TAMAO FIJO .................................... 102
5.7.3 ASIGNACIN EXPLCITA DE BLOQUES DE TAMAO VARIABLE ........................ 102
5.7.4 DESASIGNACIN IMPLCITA ......................................................................................... 103
5.7.4.1 Cuenta de referencias ..................................................................................................... 104
5.7.4.2 Tcnicas de marca .......................................................................................................... 104
5.8 EJERCICIOS ............................................................................................................................... 104
6 GENERACIN DE CDIGO INTERMEDIO ................................................................................. 106
6.1 LENGUAJES INTERMEDIOS .................................................................................................. 106
6.1.1 REPRESENTACIONES GRFICAS .................................................................................. 106
6.1.2 CDIGO DE TRES DIRECCIONES .................................................................................. 107
6.1.2.1 Tipos de proposiciones de tres direcciones .................................................................... 108
6.1.2.2 Implementaciones de cdigo de tres direcciones ........................................................... 109
6.1.2.3.1 Cudruplos............................................................................................................... 109
6.1.2.3.2 Triples ...................................................................................................................... 110
6.1.2.3.3 Triples indirectos ..................................................................................................... 110
6.2 TRADUCCIN DIRIGIDA POR LA SINTAXIS ..................................................................... 111
6.2.1 DECLARACIONES ............................................................................................................. 111
6.2.1.1 Declaraciones dentro de un procedimiento .................................................................... 112
6.2.1.2 Nombres de campos dentro de registros ........................................................................ 114
6.2.3 PROPOSICIONES DE ASIGNACIN ............................................................................... 114
Jacqueline Khler C. - USACH
Compiladores
6.2.3.1 Expresiones aritmticas.................................................................................................. 115
6.2.3.2 Expresiones booleanas ................................................................................................... 117
6.2.3.3 Acceso a elementos de matrices..................................................................................... 119
6.2.3.4 Acceso a elementos de registros .................................................................................... 121
6.2.4 SENTENCIAS DE FLUJO DE CONTROL ........................................................................ 121
6.2.4.1 Sentencia goto ................................................................................................................ 121
6.2.4.2 Sentencia if ..................................................................................................................... 121
6.2.4.3 Sentencia if-else ............................................................................................................. 122
6.2.4.4 Sentencia switch ............................................................................................................. 123
6.2.4.5 Sentencia while .............................................................................................................. 124
6.2.4.6 Sentencia do-while ......................................................................................................... 125
6.2.4.7 Sentencia repeat-until ..................................................................................................... 126
6.2.4.8 Sentencia for .................................................................................................................. 126
6.2.5 LLAMADAS A PROCEDIMIENTOS ................................................................................ 127
6.3 EJERCICIOS ............................................................................................................................... 127
BIBLIOGRAFA .................................................................................................................................. 129
ANEXO: NOCIONES DE LENGUAJES FORMALES ...................................................................... 130
A.1 JERARQUA DE LOS LENGUAJES ....................................................................................... 130
A.2 GRAMTICAS .......................................................................................................................... 131
A.2.1 GRAMTICAS REGULARES .......................................................................................... 135
A.2.2 GRAMTICAS LIBRES DE CONTEXTO ....................................................................... 136
A.2 EXPRESIONES REGULARES ................................................................................................. 138
A.3 AUTMATAS FINITOS........................................................................................................... 139
A.3.1 AUTMATA FINITO DETERMINSTICO (AFD) .......................................................... 141
A.3.2 AUTMATA FINITO NO DETERMINSTICO (AFND)................................................. 144
A.3.3 EQUIVALENCIA ENTRE AFD Y AFND ......................................................................... 145
A.3.4 MINIMIZACIN DE AFD ................................................................................................. 148
A.3.5 EQUIVALENCIA ENTRE AF Y ER: MTODO DE THOMPSON ................................. 149
A.4 AUTMATAS APILADORES ................................................................................................. 153
Compiladores
1 INTRODUCCIN
Un lenguaje es una abstraccin que permite la comunicacin y coordinacin mediante la creacin de
conceptos que pueden ser entendidos de la misma forma por los distintos participantes. As, un
lenguaje puede entenderse como una forma de hablar o de describir algo.
Para poder hablar de lenguaje es importante conocer algunos elementos. Por ejemplo, cmo se crean
los conceptos? Cmo hacer que todos entiendan lo mismo? El primer paso para responder esta
pregunta est en el concepto de smbolo. En el caso del castellano, se puede pensar en las letras como
smbolos elementales, que se emplean para construir conceptos sencillos denominados palabras. El
conjunto de todos los smbolos se conoce como alfabeto. Ahora bien, las palabras tambin pueden
formar parte de estructuras ms complejas: frases y oraciones. A su vez, stas pueden conformar
prrafos, etc.
A partir de los conceptos anteriores podra pensarse que cualquier secuencia de letras es una palabra o
que una oracin podra ser una secuencia aleatoria de palabras. Pero de nuestra experiencia previa
sabemos que no es as. Existe una serie de reglas que limitan la forma de las palabras o la estructura de
un texto:
Reglas lxicas: corresponden a las reglas de ortografa de un lenguaje, e indican la forma que deben
tener las palabras. Por ejemplo, en castellano no puede haber palabras que contengan una n seguida
de una b.
Reglas sintcticas: definen la forma en que se debe estructurar un texto. Por ejemplo, una oracin
debe tener sujeto y predicado. El predicado debe tener un ncleo que puede ir acompaado de
diversos complementos.
Reglas semnticas: determinan el significado de lo que se dice en el texto sintcticamente correcto
y guardan relacin con el contexto. Por ejemplo, la frase se rbol puede referirse a un rbol de
un parque, o bien a una estructura de datos empleada en la resolucin de un problema
computacional.
Con todo lo anterior, ya tenemos una primera nocin de qu es un lenguaje. Ahora bien, sabemos que
existen muchos lenguajes y que en ocasiones es necesario pasar un mensaje o texto de un lenguaje a
otro. De aqu surgen los conceptos de traduccin (generar una copia escrita del mensaje original en un
idioma distinto) e interpretacin (repetir verbalmente un mensaje en un lenguaje diferente al empleado
por el emisor).
Existen diferentes tipos de lenguajes. Por ahora, nos basta distinguir entre:
Lenguajes naturales: son aquellos que las personas utilizan para comunicarse entre ellas, como el
castellano, el ingls o el chino. Son muy complejos, tienen una gran cantidad de reglas y sin
embargo presentan situaciones de ambigedad que los hablantes resuelven recurriendo al contexto
tanto de espacio como de tiempo.
Lenguajes formales: son lenguajes artificiales, diseados para lograr una comunicacin
(unidireccional) entre personas y mquinas. Estas ltimas deben comprender los mensajes y
ejecutarlos, por lo que las reglas de los lenguajes formales deben estar muy bien definidas y no
pueden dar lugar a ambigedades.
Compiladores
En ciencias de la computacin, el estudio de los lenguajes formales se limita a sus caractersticas
intrnsecas e internas, sin tener en cuenta su significado ni su uso como herramienta de comunicacin,
puesto que esto ltimo corresponde a una atribucin asignada por un observador externo al lenguaje.
En este curso daremos respuesta a una pregunta que se desprende de todo lo expuesto anteriormente:
cmo aplicar la teora de lenguajes formales para poder comunicarnos con las mquinas?
1.1 QU ES UN PROGRAMA?
En cursos anteriores siempre hemos pensado en un programa como una secuencia estructurada de
sentencias escritas en algn lenguaje y que son ejecutadas por un computador para resolver un
problema. Sin embargo, antes de comenzar a hablar de compiladores tenemos que definir qu es un
programa desde otra perspectiva: como una cadena de caracteres construida sobre un alfabeto
determinado (habitualmente ASCII o un subconjunto de l) y almacenada en un archivo. En otras
palabras, un programa es una palabra del lenguaje, generalmente un lenguaje libre de contexto.
Sin embargo, tambin podemos considerar que esta gran palabra contiene subsecuencias que, a su vez,
son palabras pertenecientes a lenguajes ms sencillos que conforman las denominadas categoras
lxicas. Cada una de estas categoras puede ser definida por un lenguaje ms sencillo (casi siempre un
lenguaje regular) y da origen a un tipo especfico de palabras. Entre los ms habituales podemos
encontrar, por ejemplo:
Identificadores predefinidos para elementos propios del lenguaje (palabras reservadas, operadores,
etc.).
Identificadores definidos por el programador.
Representacin literal de valores.
Delimitadores.
Comentarios.
Compiladores
En consecuencia, tampoco es sencillo escribir un buen compilador. Para ello se requieren
conocimientos en diferentes reas: lenguajes de programacin, arquitectura de computadores, teora de
lenguajes, algoritmos e ingeniera de software. En este curso solo nos centraremos en la teora de
lenguajes.
Pero, para qu hacer esta traduccin? Aho et al. afirman que: el 90 % del tiempo de ejecucin de un
programa se encuentra en el 10 % del mismo. En consecuencia, una de las grandes ventajas de usar un
compilador es la optimizacin de cdigo que realizan. Dichas optimizaciones no solo se traducen en un
menor tiempo de ejecucin, sino tambin en una reduccin del consumo de energa por parte del
procesador y en una menor cantidad de accesos a memoria.
10
Compiladores
ensamblador, el cual debe ser traducido a cdigo de mquina por un ensamblador y luego enlazado a
algunas rutinas de biblioteca para finalmente generar el cdigo que podr ser ejecutado en la mquina.
Ventajas de compilar
Se compila una vez y se ejecuta muchas
veces.
La ejecucin del programa objeto es
mucho ms rpida que la interpretacin
del programa fuente.
Ventajas de interpretar
Un intrprete requiere menos memoria
que un compilador.
Permite mayor interaccin con el cdigo
en tiempo de desarrollo.
11
Compiladores
Algunos elementos nuevos que aparecen en la figura 1.2 son:
1. Cdigo de mquina relocalizable: es cdigo que puede cargarse empezando en cualquier posicin
L de la memoria. Es decir, si se suma L a todas las direcciones del cdigo, entonces todas las
referencias sern correctas.
2. Proceso de carga: consiste en tomar el cdigo de mquina relocalizable, modificar las direcciones
de memoria y colocar las instrucciones y los datos modificados en las posiciones apropiadas de la
memoria.
3. Editor de enlace: permite formar un nico programa a partir de varios archivos de cdigo de
mquina relocalizable.
12
Compiladores
informacin sobre los tipos para la posterior fase de generacin de cdigo. El anlisis semntico
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, donde el compilador verifica que cada operador tenga
operandos permitidos por la especificacin del lenguaje fuente. Sin embargo, la especificacin del
lenguaje puede permitir ciertas conversiones.
13
Compiladores
8. Tabla de smbolos: es una estructura de datos que contiene un registro por cada identificador, donde
los campos son llenados con los atributos de este ltimo.
9. Manejador de errores: cada una de las fases descritas puede encontrar errores. No obstante, cada
fase debe tratar adecuadamente el error detectado para poder continuar la compilacin y as permitir
la deteccin de ms errores en el programa fuente.
14
Compiladores
2 ANLISIS LXICO
El anlisis lxico corresponde a la primera etapa del proceso de compilacin. Puede pensarse como una
correccin ortogrfica del programa fuente.
15
Compiladores
Se seal anteriormente que el analizador lxico suele ser una subrutina del analizador sintctico.
Existen varias razones para separar estos dos tipos de anlisis en etapas diferentes:
Quiz la ms importante de las consideraciones sea la de lograr un diseo sencillo. Separar el
anlisis lxico del anlisis sintctico a menudo permite simplificar una u otra de estas etapas. Por
ejemplo, un analizador sintctico que incluya las convenciones de espacios en blanco y comentarios
resulta mucho ms complejo que otro que solo deba comprobar que stos ya hayan sido eliminados
por el analizador lxico. En el caso de la creacin de un lenguaje nuevo, la separacin de las
convenciones lxicas de las sintcticas puede traducirse en un diseo ms claro del lenguaje.
Mejorar la eficiencia del compilador. Un analizador lxico independiente permite construir un
procesador especializado y potencialmente ms eficiente para esta funcin. Gran parte del tiempo
se consume en leer el programa fuente y dividirlo en componentes lxicos. Con tcnicas
especializadas de manejo de buffers para la lectura de caracteres de entrada y procesamiento de
componentes lxicos se puede mejorar significativamente el rendimiento de un compilador.
Mejorar la portabilidad del compilador. Las peculiaridades del alfabeto de entrada y otras
anomalas propias de los dispositivos pueden limitarse al analizador lxico. Por ejemplo, la
representacin de smbolos especiales o no estndar (como en Pascal) puede ser aislada en esta
etapa.
16
Compiladores
Tipo
ID
NUM
REAL
IF
COMMA
NOTEQ
LPAREN
RPAREN
Ejemplo
foo
n14
73
66.1
sum
00
.5
515
10.
1e67
082
5.5e-10
If
,
!=
(
)
Componente
lxico
const
if
relacin
id
num
literal
Lexemas de ejemplo
const
if
<, <=, =, <>, >, >=
pi, cuenta, D2
3.1416, 0, 6.02E23
vaciado de memoria
17
Compiladores
debe retornar el componente lxico correspondiente. La deteccin de este error depender, en
consecuencia, de otra fase del compilador.
Si surge una situacin en la que el analizador lxico no puede continuar porque ninguno de los patrones
concuerda con el prefijo de la entrada restante se pueden efectuar diferentes acciones de recuperacin
de error:
Borrar caracteres hasta encontrar algn componente lxico bien formado.
Insertar caracteres faltantes.
Reemplazar un carcter incorrecto por otro correcto.
Intercambiar caracteres adyacentes.
18
Compiladores
accin. Esta accin corresponde a lo que debe hacerse al momento de detectar un lexema que
concuerda con el patrn asociado al AFND-.
A continuacin se unen los autmatas obtenidos para dar lugar a un nico AFND-. Para efectuar esta
unin basta con crear un estado inicial con transiciones vacas hacia cada uno de los estados iniciales
de los AFND- de cada patrn. Los estados finales conservan sus acciones asociadas.
Cuando ya se ha construido el AFND- que reconoce todos los componentes lxicos del lenguaje, se
debe proceder a convertirlo en un AFD mnimo. Al momento de minimizar se debe recordar que
estados finales que tengan diferentes acciones asociadas no pueden ser equivalentes. El AFD mnimo
obtenido corresponde al analizador lxico para el lenguaje especificado.
Ejemplo 2.1:
Construir el lxico mnimo que reconoce los patrones dados en la tabla 2.3 y les asigna el
componente lxico correspondiente.
patrn
, en cambio, coincide con un conjunto ms amplio de lexemas: todos aquellos que
tengan cero o ms a seguidas de una o ms b. En este caso, podemos observar que el lexema
abb coincide con dos patrones:
y . Como el patrn
es ms limitado, debe tener
19
Compiladores
=
, , , , , con:
=
, , , , ,
= ,
=
=
, ,
=
,
,
=
=
,
,
,
=
=
,
,
,
,
=
20
Compiladores
,
,
=
=
,
,
=
=
!,
!,
=
=
",
",
=
=
,
=
,
,
,
=
=
=
=
$,
$,
=
=
=
=
,
=
=
=
=!
,
,
="
=!
=
=
=$
Los estados finales del AFD tambin llevan asociada una accin. En caso de que uno de los
estrados finales comprenda ms de una accin, se escoge aquella de mayor prioridad. Por
ejemplo, el estado $ del AFD comprende los estados finales correspondientes a las acciones
por tener una precedencia ms alta.
y , pero se le asocia solamente
21
Compiladores
realizar. As, aquellos estados finales en que se ejecute una accin no sern equivalentes a los
estados finales que ejecuten una accin diferente. La figura 2.4 muestra el AFD mnimo.
% =&
% =
' '
, (
!
' ) '
(
$ & , ,
"
)
'
$ &
) '
% =%
* * "
, (
+
*
2.5 EJERCICIOS
1. Dados los patrones de la tabla 2.4 y sus componentes lxicos asociados:
a. Asigne las prioridades a considerar para construir el analizador lxico correspondiente.
b. Indique, para cada uno de los siguientes lexemas, el componente lxico que debiera asociarle el
analizador lxico. En caso de no corresponder con ninguno, seale la existencia de un error
lxico.
.
.
.
.
.
22
Compiladores
2. Construya el analizador lxico mnimo para los siguientes patrones (El smbolo entre parntesis
asociado a cada patrn corresponde al componente lxico asociado).
+
( ).
( ).
( ).
3. Construya el analizador lxico mnimo para los siguientes patrones (El smbolo entre parntesis
asociado a cada patrn corresponde al componente lxico asociado).
/+0 /+0
( ).
/+0
( ).
//
( ).
23
Compiladores
3. ANLISIS SINTCTICO
As como en la construccin de analizadores lxicos trabajamos con lenguajes regulares, los
analizadores sintcticos se construyen sobre la base de una gramtica libre de contexto o GLC (ver
anexo A). Aqu la gramtica corresponde a la especificacin del lenguaje de programacin, y se usan
autmatas apiladores (ver anexo A) como reconocedores de programas sintcticamente correctos.
24
Compiladores
Consideremos los no terminales en el orden C, D. Para cada no terminal, siguiendo el orden
asignado a ellos, ejecutar los siguientes pasos:
Paso 1 (no aplica para el primer smbolo): en cada produccin del no terminal actual que
comience por un no terminal ya revisado , crear nuevas producciones para en que se
reemplace con sus respectivas producciones.
Paso 2: eliminar la recursin directa por la izquierda para el no terminal actual.
C D | : como C es el primer no terminal, solo se debe eliminar la recursin directa. En este
caso no existe recursin.
D D C | C: en primer lugar, se busca cada produccin de D que comience con algn no
terminal ya revisado (en este caso C) y se crean nuevas producciones para D en que C sea
sustituido por sus producciones. As, se obtiene D D C | D | .
D D C | D | : una vez realizado el primer paso, se debe eliminar la recursin directa por la
izquierda, con lo que se obtiene D D | , C | .
As, la gramtica sin recursin por la izquierda es $ = , N, %, C , donde:
= , , , .
N = C, D, .
P = C D | ,
D D | ,
C | .
C = C.
3.1.2 FACTORIZACIN POR LA IZQUIERDA
La factorizacin por la izquierda se ocupa de agrupar producciones semejantes, descomponindolas en
un fragmento comn y otro diferente. Esto es de utilidad al momento de construir algunos analizadores
sintcticos, pues sirve en aquellos casos en que no est claro cul de dos o ms producciones
alternativas utilizar para ampliar un no terminal . As, las producciones de pueden reescribirse para
postergar la decisin hasta haber visto lo suficiente de la entrada como para tomar la decisin correcta.
Tmense por ejemplo las producciones A | . Como puede ser difcil saber si escoger o
, se pueden crear las siguientes producciones para postergar la decisin: A B y B | .
El algoritmo para factorizar completamente una gramtica es el siguiente:
1. Repetir:
a. Para cada no terminal A, encontrar el prefijo ms largo comn a dos o ms de sus
producciones.
b. Si , sustituir todas las producciones de A, A | | | L | (donde representa
a todas las producciones de A que no comienzan por ) por A B | y B | | | L,
donde B es un nuevo no terminal.
Mientras haya dos producciones para un no terminal con un prefijo comn.
25
Compiladores
Ejemplo 3.2:
Factorice por la izquierda la gramtica $ = , N, P, S :
= a, b
N = A, B, C, D
P=
|
! |
| ! | ,
|
! |
| ! | ,
|
! | | !,
!
|
!
|
| !
|
|
!|
!
!|
!| !
S = A.
|
!|
"|
| ! |
"
|!
Ahora podemos factorizar aquellas producciones de la forma , quedando:
|
| !
"|
Y terminar la factorizacin de este no terminal con las producciones de la forma
donde se obtiene:
| "
"
|!
, de
Ntese que no se cre un no terminal nuevo porque ya exista uno con exactamente las mismas
producciones.
Para el no terminal , podemos comenzar con las producciones de la forma
$|
| ! |
$ |!
Continuar con las de la forma
T|
| !
T
$|
Y terminar con las de la forma
T| $
U| | !
U!|
Y terminar con las de la forma
U| U
26
Compiladores
!
U|
!|
|
!| !
| !
!|
|
!
:
|
U|
:
| !
U|
!| !
!| !
!| !
!
:
| ",
T | $,
U | U,
!
W | V,
"
|! ,
"| ,
$ |! ,
T
$| ,
U!| ,
V
U|!
U,
W V| U
S = A.
!| !
!|
!
27
Compiladores
3.1.3 CONJUNTOS ANULABLE, PRIMERO Y SIGUIENTE
Existen dos funciones asociadas a una gramtica $ que facilitan la construccin de analizadores
sintcticos: Primero y Siguiente. Ambas aportan informacin relativa al contexto de un smbolo dado.
28
Compiladores
Note que la regla 4 es una combinacin de las dos reglas anteriores. En ella, 6 podra no anularse, en cuyo
caso debemos considerar la regla 2. Pero tambin puede darse que 6 se anule, en cuyo caso se cumple la regla 3.
En consecuencia, debemos considerar todas las posibilidades.
Ejemplo 3.3:
Determine el Conjunto Anulable y los conjuntos % c y C c , c _, para $ = , N, %, C ,
donde:
= +,, , , / .
N = , , , !, " .
P=
!,
",
| /,
!+ !| ,
" " | .
C= .
El conjunto anulable est conformado por todos aquellos terminales que, en una o ms
derivaciones, pueden generar la secuencia vaca. As, el conjunto anulable para $ est dado por
_` = !, " . _` pues todas sus producciones contienen terminales. _` pues su nica
produccin comienza por , que tampoco lo es. Lo mismo ocurre para .
%
%
%
= %h i % / = % / =
=% " =%
= ,/
=% ! =%
= ,/
% ! =% + ! %
% " = % !" %
/ =
,/
= % + = +
=% =
C
= $ %
= $
C ! =C
C ! = C
C
=% ! C
% !
C " =C
C " = C
C
= % " C
% "
= $,
= $,
C ! = + $, $, = $, , +
= $, , +
C " = $, , + $, , + = $, , +,
29
Compiladores
Anteriormente vimos que el analizador lxico y el analizador sintctico trabajan en conjunto y que este
ltimo obtiene como entrada una cadena de componentes lxicos entregada por el primero (ver figura
3.1). En este punto el analizador sintctico comprueba que la cadena pueda ser generada por la
gramtica del lenguaje fuente. Tambin informa de cualquier error de sintaxis de manera inteligible, y
debera recuperarse de los errores que ocurren frecuentemente para poder continuar procesando el resto
de su entrada. Como resultado del anlisis sintctico se obtiene un rbol de derivacin que genera la
secuencia de componentes lxicos a partir del smbolo inicial de la gramtica.
Los analizadores sintcticos empleados generalmente en los compiladores se clasifican como
descendentes o ascendentes. Como sus nombres indican, los analizadores sintcticos descendentes
construyen el rbol desde arriba (la raz, dada por el smbolo inicial de la gramtica) hacia abajo (las
hojas, consistentes en los componentes lxicos), mientras que los analizadores sintcticos ascendentes
comienzan en las hojas y suben hacia la raz. En ambos casos, se examina la entrada al analizador
sintctico de izquierda a derecha, un smbolo a la vez.
Los mtodos descendentes y ascendentes ms eficientes trabajan slo con subclases de las gramticas
libres de contexto, pero varias de estas subclases, como las gramticas LL y LR, son lo suficientemente
expresivas para describir la mayora de las construcciones sintcticas de los lenguajes de programacin.
Los analizadores sintcticos implementados a mano a menudo trabajan con gramticas LL(1). Los
analizadores sintcticos para la clase ms grande de gramticas LR se construyen normalmente con
herramientas automatizadas.
30
Compiladores
compilador debera ayudar al programador a identificar y localizar errores. Estos errores pueden ser de
diversos tipos, por ejemplo:
Lxicos, como escribir mal un identificador, palabra clave u operador.
Sintcticos, como una expresin aritmtica con parntesis no equilibrados.
Semnticos, como un operador aplicado a un operando incompatible.
Lgicos, como una llamada infinitamente recursiva.
A menudo, gran parte de la deteccin y recuperacin de errores en un compilador se centra en la fase
de anlisis sintctico. Una razn es que muchos errores son de naturaleza sintctica o se manifiestan
cuando la cadena de componentes lxicos que proviene del analizador lxico desobedece las reglas
gramaticales que definen al lenguaje de programacin.
El manejador de errores en un analizador sintctico tiene objetivos fciles de establecer:
Informar de la presencia de errores con claridad y exactitud.
Recuperarse de cada error con la suficiente rapidez como para detectar errores posteriores.
No retrasar de manera significativa el procesamiento de programas correctos.
Existen diferentes estrategias generales que puede emplear un analizador sintctico para recuperarse de
un error:
Recuperacin en modo de pnico: al descubrir un error, el analizador sintctico desecha smbolos
de entrada, de uno en uno, hasta que encuentra uno perteneciente a un conjunto designado de
componentes lxicos de sincronizacin. Estos componentes lxicos de sincronizacin suelen ser
elementos de los conjuntos Primero y Siguiente, como por ejemplo los delimitadores (punto y
coma, parntesis derecho) o el indicador de trmino de la entrada ($).
Recuperacin a nivel de frase: al descubrir un error, el analizador sintctico puede realizar una
correccin local de la entrada restante; es decir, puede sustituir un prefijo de sta por alguna cadena
que permita continuar al analizador sintctico (suprimir un punto y coma sobrante, reemplazar una
coma por un punto y coma, etc.).
Producciones de error: si se tiene una buena idea de los errores comunes que pueden encontrarse,
se puede aumentar la gramtica del lenguaje con producciones que generen las construcciones
errneas. Entonces se usa esta gramtica aumentada con las producciones de error para construir el
analizador sintctico. Si el analizador sintctico usa una produccin de error, se pueden generar
diagnsticos de error apropiados para indicar la construccin errnea reconocida en la entrada.
Correccin global: idealmente, sera deseable que un compilador hiciera el mnimo de cambios
posibles al procesar una cadena de entrada incorrecta. Existen algoritmos para elegir una secuencia
mnima de cambios para obtener una correccin global de menor costo. Por desgracia, la
implementacin de estos mtodos es, en general, demasiado costosa en trminos de tiempo y
espacio, as que estas tcnicas en la actualidad slo son de inters terico.
31
Compiladores
anlisis sintctico LL(1) o anlisis sintctico por descenso recursivo), que es el ms utilizado gracias a
su eficiencia.
En el anlisis sintctico descendente se ejecuta un conjunto de procedimientos recursivos para procesar
la entrada. En el caso particular del anlisis sintctico predictivo, el smbolo de la entrada determina sin
ambigedad el procedimiento seleccionado para cada no terminal. En otras palabras, para construir un
analizador sintctico de este tipo es necesario conocer, dada la entrada y el no terminal a expandir,
cul de todas las posibles producciones de 2 | 2 | | 27 es la nica alternativa que genera una
cadena que comience por . Es decir, debe ser posible detectar la alternativa apropiada con solo ver el
primer smbolo que genera.
De lo anterior se desprende que no cualquier gramtica libre de contexto es apropiada para el anlisis
sintctico predictivo, sino que se requieren gramticas que no contengan recursiones por la izquierda y
que estn factorizadas tambin por la izquierda.
| /,
!+ !| ,
Jacqueline Khler C. - USACH
32
Compiladores
" " |
C= .
,/
En primer lugar, para cada produccin 2 no vaca, debemos aadir dicha produccin en la
posicin jk , l de la tabla para cada terminal % 2 :
33
Compiladores
34
Compiladores
Ejemplo 3.5:
Construya la tabla de anlisis sintctico LL(1) para $ = , N, %, C , donde:
n = k, l, <, >, +,, , #, / .
N = , , ,! .
%=
k l|
,
!| ,
! | ,
! #! | < > | /
C= .
$ No requiere eliminacin de recursin ni factorizacin, Por lo que podemos trabajar con ella
tal como est.
Comenzamos por determinar los conjuntos Anulable, Primero y Siguiente:
_` = , ,
= % k l %
= #, <, /, , k
%
=% ! %
%
=% ! %
% ! = % #! % <
%
C
C
C
C !
= k %
= k #, <, /, #, <, / =
=%
% = #, <, / = #, <, /,
= % ! = #, <, /
> % / = # < / = #, <, /
= $ % l = $ l =
=%
C
C
%
=C
% ! = $, l
=C
% C ! =
$, l
> = #, <, / $, l $, l, > = $, l, , #, <, /, >
= $, l,
$, l, , #, <, /, > = $, l, , #, <, /, >,
35
Compiladores
36
Compiladores
Colocar dentro del conjunto de sincronizacin para el no terminal todos los smbolos contenidos
en C . Probablemente el anlisis sintctico podr continuar si se eliminan componentes de la
entrada hasta encontrar algn elemento de C
y se elimina el no terminal de la pila.
En ocasiones puede ser necesario un conjunto de elementos de sincronizacin ms grande. Por
ejemplo, podra ser til aadir al conjunto de sincronizacin de una construccin de menor
jerarqua aquellos componentes que inician las construcciones de una jerarqua mayor.
Pueden aadirse al conjunto de sincronizacin aquellos smbolos terminales contenidos en %
.
Si un no terminal puede generar , puede usarse esta produccin por omisin.
Si no se puede descartar un terminal de la pila, puede eliminarse dicho terminal.
Ejemplo 3.6:
Considere el analizador sintctico LL(1) del ejemplo 3.4. Muestre la traza para la entrada m =
/ / usando recuperacin de errores en modo de pnico.
Usaremos C c como conjunto de sincronizacin para cada no terminal:
C
= C ! = $,
= C " = $, , +
C
C
= $, , +,
TABLA 3.5: Traza con recuperacin de errores en modo de pnico para la entrada m = / / usando
el analizador sintctico de la tabla 3.2.
37
Compiladores
C = C.
La cadena m =
)'*
)'*
'*
*
C
'*
)'*
)'*.
Una manera de implementar el anlisis sintctico por desplazamiento y reduccin es mediante un AFD
con una pila asociada. Inicialmente, la pila solo contiene el estado inicial del AA, mientras que la
cadena m a analizar se encuentra en la entrada seguida del delimitador (es decir, m$). El analizador
sintctico desplaza cero o ms smbolos de la entrada a la pila hasta que se reconozca el lado derecho 2
de una produccin 2 y entonces se reduce 2 reemplazndolo por el lado izquierdo de la
produccin correspondiente (el no terminal ). Se repite este proceso hasta encontrar un error o hasta
que la pila solo contenga al smbolo inicial de la gramtica y la entrada est vaca.
Aunque las principales operaciones de este tipo de analizador sintctico son el desplazamiento y la
reduccin, existen en realidad cuatro acciones diferentes:
Desplazar: se desplaza el siguiente smbolo de la entrada al tope de la pila, seguido del nuevo
estado del AFD.
Reducir: se sustituye el lado derecho de una produccin, contenido en la pila, por su lado izquierdo.
Jacqueline Khler C. - USACH
38
Compiladores
Aceptar: anuncia el trmino exitoso del anlisis sintctico.
Error: llama a una rutina de recuperacin de error.
Ahora bien, existen algunas GLC en que un analizador sintctico por desplazamiento y reduccin
puede alcanzar una configuracin donde, conociendo el contenido de la pila y el siguiente smbolo de
la entrada, sea imposible decidir si efectuar un desplazamiento o una reduccin (conflicto
desplazamiento/reduccin), o bien qu reduccin efectuar (conflicto reduccin/reduccin). Para evitar
este tipo de problemas se utilizar un subconjunto de las gramticas independientes del contexto: la
clase de gramticas LR(k). En consecuencia, el anlisis sintctico ascendente suele recibir el nombre de
anlisis sintctico LR, por left-to-right parse, rightmost derivation. Lee la entrada de izquierda a
derecha y construye una derivacin por la derecha en orden inverso. Adicionalmente, la k entre
parntesis corresponde al nmero de smbolos de la entrada que son considerados al momento de
decidir qu accin ejecutar. Cabe sealar que en la prctica no se usa r > 1 para la compilacin, pues
se requieren tablas demasiado grandes.
La familia de mtodos LR permite analizar un superconjunto de la clase de gramticas LL(1), es decir,
DD 1 Dt. Es posible construir analizadores sintcticos LR para reconocer prcticamente todas las
construcciones de los lenguajes de programacin definidos mediante GLC, por lo que este esquema es
el ms utilizado.
39
Compiladores
cuv
c uv
cu v
cuv
Es importante sealar que una produccin
,
+ | ,
! | !,
!
|/
C= .
Sea adems
Por regla 1:
x yzy{
. Determine x yzy{
, ! /
40
Compiladores
3.5.3.3 Construccin del autmata
La idea central del mtodo SLR es construir, a partir de $, un AFD (considerando la definicin no
estricta, en que cada estado tiene a lo ms una transicin por cada smbolo del alfabeto) con una pila
asociada que permita reconocer los prefijos viables (es decir, que se pueden derivar a partir de alguna
produccin). Para este fin se agrupan los elementos LR(0) en conjuntos que conforman los estados del
AFD. Adems, el alfabeto del AFD est dado por todos los terminales y no terminales de la gramtica.
El primer paso necesario para la construccin del AFD es aumentar la gramtica $ con una nueva
produccin C C, donde C es un nuevo smbolo inicial, a fin de asegurar que el smbolo inicial tenga
una nica produccin. Esta modificacin tiene por objeto indicar en qu momento se debe detener el
anlisis sintctico y aceptar la cadena: es decir, cuando se est a punto de hacer la reduccin de C C.
Ntese que esta nueva produccin no pasa a formar parte de la gramtica, sino que se usa
exclusivamente para la construccin del estado inicial del AFD.
El estado inicial del AFD est dado por
= x yzy{
= C C . A continuacin se determinan
las transiciones con todos aquellos smbolos precedidos por un punto en algn elemento LR(0) de .
Para los nuevos estados, se determina la x yzy{
de los elementos LR(0) que le dan origen, es
decir, aquellos del estado anterior con el punto desplazado en una posicin hacia la derecha. Las
transiciones se determinan igual que para . Si nos encontramos ante un grupo idntico de elementos
LR(0) que avanzan con un mismo smbolo que en algn estado anterior, dicha transicin avanza al
estado ya conocido.
Ejemplo 3.9:
Sea $ = , N, %, C , donde:
n = ,, , , , , +
N=
%=
, , ,!
| ,
| ,
||+
|
C=
Construya el AFD asociado al analizador sintctico SLR.
Comenzamos por agregar la produccin C . El estado inicial del AFD queda dado por:
= x yzy{
= C , es decir:
= C
41
Compiladores
Ahora debemos determinar las transiciones de . Como solo podemos tener a lo ms una
transicin por cada smbolo del alfabeto, tenemos que:
= C
1
2
2
Ahora es necesario determinar los elementos LR(0) que conforman cada uno de los nuevos
estados, as como las transiciones de estos ltimos:
= x yzy{
= C ,
As, se tiene que:
=C
10
7
11
11
12
12
7
13
14
8
42
Compiladores
La tabla 3.6 muestra las transiciones del AFD obtenido.
TABLA 3.6: Tabla de transiciones del AFD asociado al analizador sintctico SLR.
Antes de incorporar las reducciones, necesitamos conocer los conjuntos siguientes para cada no
terminal. As, tenemos que:
_` =
%
%
%
= % %h i % % + =
+ = , , , +
=%
%
=%
= , , , +
=% %
=% %
=%
%
= , , , +
43
Compiladores
= $ %
=C
C
=C
C
%
= $
= $, ,
% = $, , = $, ,,
C
= $, ,,
Ahora debemos asignar un nombre a cada produccin a fin de poder identificarlas en la tabla de
anlisis sintctico:
%=
| |+
Como en
tenemos , debemos incorporar una reduccin por la segunda produccin en
con cada smbolo en C . Lo mismo debe hacerse para cada estado en que se termine una
produccin, como muestra la tabla 3.8, con lo que el analizador sintctico SLR queda terminado.
44
Compiladores
La figura 3.4 muestra el funcionamiento del analizador sintctico SLR y muestra el rbol
sintctico resultante para la entrada m = + .
N=
,@
%=
, ,
,
,
@
C=
Muestre la traza para m = @ .
Comenzamos por la construccin del AFD:
= C
=C
45
Compiladores
=
2
3
=C
=
@
@
5
5
,C
= $ %
C
= $ % @
= $, @ C
= $, @
=C
C
= $, @ C
C
C
%=
yC
%
= $ @ C
= $, @
La tabla 3.9 muestra el analizador sintctico SLR resultante, mientras que la traza 3.10 muestra
la traza para la entrada m = @ .
Ejemplo 3.12:
Construya un analizador sintctico SLR para $ = , N, %, C , donde:
n = +,, , , /
N= "
C="
46
Compiladores
TABLA 3.10: Traza para la entrada m = @ con el analizador sintctico SLR de la tabla 3.9.
Comenzamos por la construccin del AFD:
= C "
" 1
" " + "
" 1
" " + " " " 1
" " "
" 1
" "
2
" /
/ 3
=C"
" " +"
+
" " +" " +
" " "
4
4
=" "
" 6
" 6
" " + "
" " + " " " 6
" " "
" 6
" "
2
" /
/ 3
Jacqueline Khler C. - USACH
="/
="
"
"
"
"
"
"
" + "
" 7
" + " " " 7
" + "
" 7
" + " " " 7
" "
" 7
2
"
/
/ 3
="
"
"
"
"
"
" "
" 8
" + "
" 8
" + " " " 8
" "
" 8
"
2
/
/ 3
47
Compiladores
=" "
" " +"
+
" " +" " +
" " "
=" "+"
" " + " "
" " +"
+
" " +" " +
" " "
=" ""
" " +"
"
" " +" " "
"
" " "
4
4
10
4
=" "+""
" ""
" " +"
+ 4
" " +" " +
" " "
5
10
4
4
5
=" "
A continuacin, necesitamos conocer C " y asignar nombres a las producciones:
C " = $ % +" C " % " C " % +" " % " C " %
= $ + +
= $, +,,
% = " " + " | " " |" + " " | "
|/
Ahora construimos la tabla del analizador sintctico SLR, que se muestra en la tabla 3.11.
mayor precedencia que +, que la suma es asociativa por la izquierda y que la multiplicacin es
asociativa por la derecha.
48
Compiladores
3.5.4 USO DE GRAMTICAS AMBIGUAS
Existen casos en que es ms cmodo trabajar con gramticas ambiguas, pues estas ofrecen una
representacin ms corta y natural que una gramtica no ambigua equivalente. Al usar este tipo de
gramticas se pueden producir dos tipos de conflictos: desplazamiento/reduccin y
reduccin/reduccin. Para que el analizador sintctico pueda funcionar correctamente es necesario
reducir estos conflictos, a fin de que en cada entrada de la tabla figure a lo ms una accin. Esta tarea
resulta muy sencilla al trabajar con gramticas de operadores. Para todos los analizadores sintcticos de
la famila LR se usan los mismos principios.
Un conflicto reduccin/reduccin significa que, dado el estado del AFD que se encuentra al tope de la
pila y el siguiente smbolo de la entrada, es posible efectuar dos reducciones diferentes (podran ser
ms). Para eliminar este tipo de conflictos de la tabla de anlisis sintctico LR siempre se escoge la
reduccin correspondiente a la produccin ms larga, pues las reducciones para las producciones ms
cortas habrn aparecido ya en otros estados del AFD.
Similarmente, un conflicto desplazamiento/reduccin significa que, dado el estado del AFD que se
encuentra al tope de la pila y el siguiente smbolo de la entrada, es posible efectuar tanto un
desplazamiento como una reduccin (podran ser ms desplazamientos y reducciones). La resolucin
de los conflictos desplazamiento/reduccin se har en base a la precedencia y la asociatividad de los
operadores de la siguiente manera:
Si se tiene la configuracin 2 6 A y tiene mayor precedencia que , entonces se
escoge la reduccin. En caso contrario, se escoge el desplazamiento.
Si se tiene la configuracin 2 6 A es asociativo por la derecha, entonces se escoge el
desplazamiento. En caso contrario, se escoge la reduccin.
Ejemplo 3.13:
Elimine conflictos en el analizador sintctico del ejemplo 3.12.
Para los conflictos entre reducciones existentes en
, habamos explicado que se conserva
nicamente la produccin ms larga. En consecuencia, descartamos t2 y conservamos
nicamente t3.
En jk7, +l nos encontramos ante el escenario " + " +". En otras palabras, debemos decidir si
reducir la primera suma o terminar de leer la segunda. Como + es asociativo por la izquierda,
conservamos la reduccin.
En j k7,l se tiene " + " ". En otras palabras, debemos decidir si reducir suma o leer la
multiplicacin. Como tiene mayor precedencia, conservamos el desplazamiento.
En jk8, +l nos encontramos ante el escenario " " +". Como tiene mayor precedencia,
conservamos la reduccin.
En jk8,l se tiene " " ". En otras palabras, Como es asociativo por la derecha,
conservamos el desplazamiento.
49
Compiladores
Los conflictos restantes en jk11, +l y jk11,l son anlogos a los de j k8, +l y j k8,l,
respectivamente, por lo que tomamos las mismas decisiones.
As, la tabla 3.12 muestra el analizador sintctico SLR libre de conflictos.
TABLA 3.12: Analizador sintctico SLR del ejemplo 3.12 sin conflictos.
3.5.5 RECUPERACIN DE ERRORES
Al igual que en el caso del anlisis sintctico predictivo, existen dos grandes esquemas para la
recuperacin de errores en la familia de analizadores sintcticos LR: en modo de pnico y a nivel de
frase.
50
Compiladores
51
Compiladores
TABLA 3.14: Analizador sintctico SLR del ejemplo 3.12 sin conflictos.
52
Compiladores
smbolo solo ser utilizado directamente al momento de llevar a cabo una accin de reduccin, como se
explica ms adelante.
53
Compiladores
La definicin de la clausura coincide en muchos aspectos con la utilizada en la construccin del AFD
SLR. La nica diferencia radica en la determinacin de los smbolos de anticipacin.
54
Compiladores
Ejemplo 3.16:
Construya un analizador sintctico LR(1) para $ = , N, %, C , donde:
n= ,
N= ,
%=
|
C=
Compare el analizador sintctico LR(1) con otro SLR para la misma gramtica.
Comenzamos por la construccin del AFD LR(1):
= C , $
,$
,
,
,
,
Ntese que en el caso de las producciones de
debemos considerar como smbolos de
anticipacin todos los elementos de % $ = , , lo que nos lleva a los siguientes pares de
elementos LR(1): , ; , y , ;
, .
Por comodidad, podemos reescribir
= C , $
,$
, /
, /
de la siguiente forma:
, $
,$
, $
, $
,$
, $
, $
, /
, /
, /
, /
, $
, /
, $
Asignamos un nombre a las producciones para poder identificarlas al hacer las reducciones:
Asignamos un nombre a las producciones para poder identificarlas al hacer las reducciones:
%=
,
|
Ahora construimos la tabla LR(1), que se muestra en la tabla 3.16.
Jacqueline Khler C. - USACH
55
Compiladores
,
=C
=
,$
, $
$ = $, ,
56
Compiladores
Otra observacin importante es que, para este ejemplo, ninguna de las dos tablas presenta
conflictos, por lo que $ es SLR. Debemos recordar que al ser SLR es tambin LR(1), pues
CDt Dt 1 .
Ejemplo 3.17:
Construya un analizador sintctico LR(1) para $ = , N, %, C , donde:
n = =,, /
N = C, D, t
% = C D = t | t,
D t | /,
tD
C=C
Compare el analizador sintctico LR(1) con otro SLR para la misma gramtica.
Comenzamos por la construccin del AFD LR(1):
= C C, $
C
C D = t, $ D
C t, $
t
D t, =/$
D /, =/$
/
t D, $
D
= D t , =/$
= C D = t , $
= t D , $
= C t , $
= D t, =/$
t D, =/$
D t, =/$
D /, =/$
t
D
/
= t D , =/$
= C C , $
= C D = t, $
t D , $
= C D = t, $
t D, $
D t, $
D /, $
t
D
/
= D / , =/$
= D t, $
t D, $
D t, $
D /, $
t
D
/
= D / , $
= D t , $
Asignamos un nombre a las producciones para poder identificarlas al hacer las reducciones:
Asignamos un nombre a las producciones para poder identificarlas al hacer las reducciones:
% = C D = t |t , D t | / , t D
Ahora construimos la tabla LR(1), que se muestra en la tabla 3.18.
57
Compiladores
=Ct
= D t
t D
D t
D /
t
D
/
=D/
= C D = t
t D
D t
D /
t
D
/
= D t
=tD
=CD=t
58
Compiladores
59
Compiladores
Ejemplo 3.18:
Construya un analizador lxico LALR para la gramtica del ejemplo 3.27. Tome como base el
analizador sintctico LR(1) obtenido en dicho ejemplo.
Podemos ver que es muy semejante a
= D t, =/$ t
t D, =/$
D
D t, =/$
D /, =/$
/
Tambin es muy semejante a
= D / , =/$
Lo mismo ocurre con
= D t , =/$
As como con y
= t D , =/$
= D t, $
t D, $
D t, $
D /, $
t
D
/
= D / , $
= D t , $
= t D , $
Si juntamos los pares de estados semejantes, para cada elemento LR(1) tendremos los smbolos
de anticipacin de ambos estados. En este caso particular, nos basta simplemente con conservar
, ,
y . Los estados que no se agrupan con otros quedan tal como estn. As, el AFD
resultante es:
Comenzamos por la construccin del AFD LR(1):
= C C, $
C
C D = t, $ D
C t, $
t
D t, =/$
D /, =/$
/
t D, $
D
= t D , =/$
= C D = t , $
= C t , $
= D t, =/$
t D, =/$
D t, =/$
D /, =/$
= C D = t, $
t D, $
D t, $
D /, $
= D t , =/$
= C C , $
= C D = t, $
t D , $
= D / , =/$
t
D
/
t
D
/
60
Compiladores
Ahora construimos la tabla LALR, como se ve en la tabla 3.20.
|
|
|
,
) | ',
)|*
C=
Qu puede concluir acerca de $?
Comencemos por la construccin del analizador sintctico LR(1):
= C , $
=
,$
,$
),
,$
',
,$
),
*,
= C , $
=
= ,$
,$
=
),
)
= ) ,
',
'
) ,
),
)
*,
*
= ' ,
Jacqueline Khler C. - USACH
,$
,$
)
'
)
*
,$
,$
61
Compiladores
=
* ,
* ,
, $
,$
, $
, $
, $
,$
) ,
) ,
' ,
Ahora asignamos un nombre a las producciones y construimos la tabla LR(1), que se muestra en
la tabla 3.21.
%=
) |' ,
) |*
62
Compiladores
63
Compiladores
3.5.7.3 Construccin directa del AFD
En este caso, se tiene que la construccin del AFD se realiza igual que en SLR, siendo necesario
adems incorporar los smbolos de anticipacin.
Ejemplo 3.20:
Construya el analizador sintctico LALR, usando el mtodo directo, para $ = , N, %, C , con:
n = , @, , , k, l
N=
%=
@ |
|k l|
C=
Resuelva conflictos considerando que @ es asociativo por la izquierda.
Comenzamos por la construccin del AFD LALR:
= C , $
@ , $/@
, $/@
k l, $/@
k
, $/@
=C
, $
@ , $/@
= C , $/@/ /l
@ , /@
, /@
k l, /@
, /@
= C k l, $/@/ /l
@ , l/@
, l/@
k l, l/@
, l/@
, $/@/ /l
@ , $/@/ /l
@ , $/@/ /l
, $/@/ /l
k l, $/@/ /l
, $/@/ /l
=C
, $/@/ /l
@ , /@
=Ck
l, $/@/ /l
l
@ , l/@
@
@ , $/@/ /l
@ , $/@/ /l @
=C
, $/@/ /l
= C k l , $/@/ /l
64
Compiladores
TABLA 3.25: Analizador sintctico LALR del ejemplo 3.20 tras la eliminacin de conflictos.
3.6 EJERCICIOS
1. Determine los conjuntos Anulable, Primero y Siguiente para $ = , N, %, C , con:
n=
N=
%=
C=
, , ,!
@ |
| @/ | ,
| 0 | 0 |
k l| !/ | 0, ! # |
2. Construya un analizador sintctico predictivo para la gramtica del ejercicio anterior. Modifquela
en caso necesario.
65
Compiladores
3. Construya analizadores sintcticos SLR, LR(1) y LALR para la gramtica del ejercicio 1 y la
gramtica modificada del ejercicio 2.
4. Sea $ = , N, %, C , con:
n=
N=
%=
C=
,, . , +, ,
c. Muestre la traza y el rbol resultante para m = + . con cada uno de los analizadores del
punto anterior.
d. Construya analizadores sintcticos SLR, LR(1) y LALR para la gramtica obtenida en a.
5. Considere el analizador sintctico SLR de la tabla 3.12 y la entrada m = / / . Qu ocurre al
hacer la traza usando recuperacin de errores en modo de pnico? Por qu?
6. En qu casos se tiene que las tablas SLR y LALR son iguales? Por qu?
7. Compruebe la equivalencia de los dos mtodos para construie analizadores sintcticos LALR
repitiendo el ejercicio del ejemplo 3.20 usando la construccin a partir del analizador sintctico
LR(1).
66
Compiladores
4 ANLISIS SEMNTICO
La palabra semntica, proveniente del griego semantikos (lo que tiene significado), se refiere a los
aspectos del significado o interpretacin de un determinado cdigo simblico, lenguaje o
representacin formal. Etapa del proceso de compilacin se asocia informacin a una cierta
construccin del lenguaje de programacin proporcionando atributos a los smbolos de la gramtica
que la conforman.
A nivel conceptual, esta etapa est situada a continuacin del anlisis sintctico, donde se construye el
rbol de anlisis sintctico. Durante el anlisis semntico se recorre el rbol para evaluar las reglas
semnticas presentes en sus nodos (es decir, las reglas semnticas correspondientes a la produccin
empleada en dicho nodo). Al evaluar una regla semntica se pueden efectuar diversas actividades, entre
ellas generar cdigo, almacenar informacin en una tabla de smbolos y emitir mensajes de error. Al
finalizar esta etapa se obtiene como resultado la traduccin de la cadena de componentes lxicos.
En la prctica, las tareas del anlisis semntico se realizan simultneamente con el anlisis sintctico,
en una dependencia similar a la que existe entre este ltimo y el anlisis lxico. Como las reglas
semnticas estn asociadas a las producciones de la gramtica, pueden ser ejecutadas una vez que se ha
reconocido la produccin correspondiente.
67
Compiladores
Se asume que los smbolos terminales solo tienen atributos sintetizados, ya que la definicin dirigida
por la sintaxis no proporciona reglas semnticas para estos smbolos. El valor de estos atributos es, en
general, proporcionado por el analizador lxico. Tambin se asume que el smbolo inicial de la
gramtica no tiene atributos heredados, a menos que se indique lo contrario.
Las funciones de las reglas semnticas a menudo se escriben como expresiones. No obstante, cuando el
nico propsito de una regla semntica es crear un efecto colateral, la regla se escribe como una
llamada a un procedimiento o un fragmento de programa.
Ejemplo 4.1:
La tabla 4.1 muestra la definicin dirigida por la sintaxis para un programa que efecta las
operaciones de adicin y multiplicacin. A cada uno de los no terminales ", j y se le asocia
un atributo sintetizado llamado x y la regla semntica correspondiente calcula el valor del
atributo x del no terminal del lado izquierdo de la produccin a partir de los atributos x de
los no terminales del lado derecho. El componente lxico tiene un atributo sintetizado
x*/, cuyo valor es proporcionado por el analizador lxico. La regla semntica asociada a la
produccin D " para el no terminal D es un procedimiento que imprime el valor de la
expresin aritmtica generada por ". Obsrvese que es simplemente un carcter de salto de
lnea.
TABLA 4.1: Definicin dirigida por la sintaxis para efectuar las operaciones de adicin y
multiplicacin.
68
Compiladores
semntica correspondiente, . x . x*/, establece el atributo . x con un valor de
3, que es el valor de . x*/. De manera similar, se asigna tambin valor 3 al atributo
j. x. A continuacin se procede del mismo modo con el siguiente subrbol izquierdo, de
donde se obtiene que . x 5. Al usar la produccin j j , se tiene que j. x
j . x . x = 3 5 = 15. Finalmente, la regla semntica asociada a D " imprime por
pantalla el valor de la expresin generada por ".
69
Compiladores
TABLA 4.2: Definicin dirigida por la sintaxis para declarar variables reales y enteras.
70
Compiladores
nodo de )8 hacia el nodo de
Ejemplo 4.4:
La figura 4.3 muestra las aristas que s aaden al grafo de dependencias al usar la regla
semntica ". x " . x + " . x, asociada a la produccin " " + " .
FIGURA 4.4: Grafo de dependencias para el rbol de anlisis sintctico de la figura 4.2.
Jacqueline Khler C. - USACH
71
Compiladores
72
Compiladores
crearHoja(
73
Compiladores
TABLA 4.3: Creacin de nodos del AST para sentencias de flujo de control.
Se debe efectuar la comprobacin en cada nodo del AST donde se utilice la informacin de los tipos
presentes en una expresin, e informar al usuario en aquellos casos en que no pueda darse una solucin
a un conflicto. Este proceso consta de dos partes:
Llenar el AST con los tipos correspondientes para los literales (variables o valores).
Propagar los tipos por los nodos restantes del AST considerando:
Tipos correctos para los operadores y operandos.
Tipos correctos para los argumentos de funcin.
Tipos correctos de retorno.
Aplicar coercin en caso de que los tipos no coincidan.
74
Compiladores
Ejemplo 4.9:
Considere el AST para la expresin = + 1.0, que se muestra en la figura 4.8 (a). El
recorrido post-orden visita primero las hojas del rbol incorporando su tipo, con lo que se
obtiene el AST de la figura 4.8 (b).
75
Compiladores
La figura 4.9 (a) muestra el AST con los tipos para los valores e identificadores literales
obtenido en el ejemplo anterior. Ah se puede observar que el operador de adicin tiene un
operando entero y otro real. De acuerdo a la tabla de prioridades de conversin, se determina
que el tipo float tiene mayor prioridad que el tipo int. En consecuencia, se utiliza la suma de
nmeros reales para efectuar la operacin. Como el resultado de la suma es de tipo float y la
variable a la que se asigna este valor es del mismo tipo, no es necesario efectuar ninguna
conversin para efectuar la asignacin. La figura 4.9 (b) muestra el AST con los tipos para
operandos y operadores.
76
Compiladores
77
Compiladores
Se define lvalue como la abreviacin de left hand value, es decir, valor del lado izquierdo. Corresponde
a una expresin o referencia que puede ser puesta en el lado izquierdo de una asignacin. Para que un
lvalue sea vlido, debe ser una entidad modificable (como por ejemplo una variable).
78
Compiladores
La figura 4.11 muestra la lista para efectuar la comprobacin al momento de usar dichas
funciones.
79
Compiladores
Por ltimo se debe verificar que no exista cdigo inalcanzable, que corresponde al cdigo situado
despus de la sentencia de retorno.
4.5 EJERCICOS
1. Considere la tabla de prioridades y la tabla de coercin que se muestran en las tablas 4.7 y 4.8.
Suponga, para este ejercicio, que la precedencia de los operadores, de mayor a menor, es: ^, /, , +.
El operador ^ corresponde a la exponenciacin. Sea la expresin : = ^)/' * + +/ ^;,
donde es de tipo Complex; , ), +, y son de tipo Natural; ' e ; son de tipo Int; * es de tipo
Float.
a. Construya el AST para la expresin dada.
b. Construya el AST con coerciones y etiquetas de tipos.
c. Indique si existe algn tipo de error semntico en la expresin dada y justifique su respuesta.
d. Qu ocurrira si ahora es de tipo Int? Por qu?
e. Qu ocurrira si ahora es de tipo Complex y ' es de tipo String? Por qu?
80
Compiladores
81
Compiladores
3. Dado el fragmento de cdigo del listado 4.1, efecte las siguientes comprobaciones semnticas:
a. Cdigo inalcanzable.
b. Retorno de funciones cuyo tipo es distinto de void.
c. Cuando un goto es encontrado, la etiqueta debe existir.
d. Que no haya trazas para las que no haya un retorno.
LISTADO 4.1: Fragmento de cdigo para el ejercicio 3.
int pvoiAgregarPaquete(listaPaquete *plpqLista, int pintPaquete) {
numeroPaquete
*pnpqAuxiliar
=
(numeroPaquete
*)
malloc(sizeof(struct
numeroPaquete));
pnpqAuxiliar->intNumero = pintPaquete;
// si la lista esta vacia
if (fbooVaciaListaPaquete(plpqLista)) {
pnpqAuxiliar->anterior = NULL;
pnpqAuxiliar->siguiente = NULL;
plpqLista->primero = pnpqAuxiliar;
plpqLista->ultimo = pnpqAuxiliar;
return;
printf("La lista fue creada exitosamente.");
}
// no esta vacia
numeroPaquete *indice = plpqLista->primero;
numeroPaquete *antecesor = NULL;
while (indice) {
1: if (indice->intNumero < pintPaquete) {
antecesor = indice;
indice = indice->siguiente;
}
else {
pnpqAuxiliar->siguiente = indice;
plpqLista->primero = pnpqAuxiliar;
return;
}
}
pnpqAuxiliar->siguiente = NULL;
plpqLista->ultimo->siguiente = pnpqAuxiliar;
plpqLista->ultimo = plpqLista->ultimo->siguiente;
goto 1
}
4. Dadas las siguientes funciones, dibuje la estructura de datos que permite efectuar la comprobacin
de sus parmetros.
elipse(float eje1, float eje2, int x0, int y0, float orientacion).
circulo(float radio, int x0, int y0) .
82
Compiladores
5.1.1 PROCEDIMIENTOS
Una definicin de un procedimiento es una declaracin que, en su forma ms bsica, asocia un
identificador con una proposicin. El identificador se denomina nombre del procedimiento, mientras la
proposicin conforma su cuerpo.
Cuando aparece el nombre de un procedimiento dentro de una proposicin ejecutable, se dice que el
procedimiento es llamado. Cuando esto ocurre, la llamada provoca que el procedimiento se ejecute. Es
importante recordar que las llamadas a procedimientos tambin pueden ocurrir dentro de expresiones.
En la definicin de un procedimiento suelen aparecer diversos identificadores. Estos identificadores
son los parmetros formales del procedimiento. Los parmetros actuales, en cambio, son los
argumentos entregados a un procedimiento cuando es llamado. Estos valores son sustituidos por los
parmetros formales.
83
Compiladores
En un rbol de activacin:
Cada nodo representa la activacin de un procedimiento.
La raz representa la activacin del programa principal.
El nodo es el padre del nodo si y solo si el control fluye de la activacin a la .
El nodo est a la izquierda del nodo si y slo si la duracin de ocurre antes que la de .
Ejemplo 5.1:
La figura 5.1 muestra el rbol de activacin correspondiente al programa en Pascal del listado
5.1.
LISTADO 5.1: Programa en Pascal que lee y ordena enteros.
Program ordenamiento(input, output);
var a: array[0..10] of integer;
procedure leemartriz;
var i: integer;
begin
for i:=1 to 9 do read(a[i])
end;
function particion(y, z: integer): integer;
var i, j, x, v: integer;
begin
end;
procedure clasificacion_por_particiones(m, n: integer);
var i: integer;
begin
if(n>m) then begin
i:=particion(m, n);
clasificacion_por_particiones(m, i-1);
clasificacion_por_particiones(i+1, n);
end
end;
begin
a[0]:=-9999; a[10]:=9999;
leematriz;
clasificacion_por_particiones(1, 9);
end.
84
Compiladores
contenidos de la pila se relacionan con los caminos hasta la raz del rbol de activaciones: cuando un
nodo n est al tope de la pila de control, la pila contendr a todos los nodos en el camino desde n hasta
la raz.
FIGURA 5.1: rbol de activacin correspondiente a la salida de la ejecucin del programa del
listado 5.1.
Ejemplo 5.2:
La figura 5.2 muestra la pila de control para un instante dado de la ejecucin del programa del
listado 5.1, demarcado por las lneas continuas del rbol de activacin.
FIGURA 5.2: Pila de control para el momento de ejecucin demarcado con lneas
continuas en el rbol de activacin.
85
Compiladores
5.1.4 MBITO DE UNA DECLARACIN
Una declaracin es una construccin sintctica que asocia informacin a un nombre. Por otra parte,
toda declaracin tiene un mbito, es decir, una parte del programa donde puede ser aplicada.
Pueden existir diferentes declaraciones de un mismo nombre en distintas partes de un programa. En
este caso, son las reglas de mbito del lenguaje fuente las que determinan qu declaracin utilizar al
encontrarse el nombre en el programa fuente. Se dice que un nombre es local a un procedimiento si ha
sido declarado al interior de ste. En caso contrario, se dice que no es local.
Al momento de compilar se puede usar la tabla de smbolos para encontrar la declaracin que aplica a
un nombre. Al declararse un nombre, se crea la entrada correspondiente en la tabla de smbolos. Se
retornar dicha entrada al buscar el nombre mientras dure el mbito de la declaracin.
86
Compiladores
87
Compiladores
88
Compiladores
La cantidad de memoria que se asigna a un nombre viene dada por el tipo de ste. Los tipos de datos
elementales generalmente pueden ser almacenados en un nmero entero de bytes. En el caso de datos
agregados, como matrices y registros, se debe asignar un bloque de memoria lo suficientemente grande
como para almacenar todos los componentes. Lo ms usual es que se asignen bloques contiguos de
bytes para facilitar el acceso a cada uno de los datos.
En la seccin anterior se mostr el registro de activacin. En l, el campo para los datos locales se
determina durante la compilacin, a medida que se examinan las declaraciones al interior del
procedimiento (no se incluyen aqu los datos cuya longitud es variable). La direccin relativa o
desplazamiento de un valor local con respecto a una posicin de memoria, como el primer byte del
registro de activacin, es la diferencia entre la posicin del objeto y la direccin considerada como
referencia.
89
Compiladores
5.3.2 ASIGNACIN POR MEDIO DE UNA PILA
Este tipo de asignacin est basado en la idea de una pila de control. Se da a la memoria la
organizacin de una pila, y en ella se agregan y se retiran los registros de activacin cuando las
llamadas a procedimientos comienzan y terminan, respectivamente. La figura 5.6 muestra un ejemplo
de este de asignacin mediante una pila.
Este esquema de asignacin permite que para cada activacin las variables locales se enlacen a nueva
memoria, puesto que se introduce un nuevo registro de activacin a la pila. Adems, al terminar la
activacin las variables locales son eliminadas pues se quita el registro de activacin de la pila.
En este punto es importante definir un problema muy habitual: las referencias suspendidas, que se
producen cuando se hace referencia a memoria desasignada. Este tipo de error corresponde a un error
lgico y no puede ser detectado mediante ninguno de los analizadores que se emplean en un
compilador. Esto se debe a que los lenguajes no consideran en su semntica el valor de la memoria
desasignada y a que muchas veces la memoria puede asignarse posteriormente a otro dato y crear as
errores ocultos en el programa.
La asignacin por medio de una pila no puede utilizarse cuando ocurre alguna de las siguientes
situaciones, en que la desasignacin de memoria no tiene por qu ser de la forma ltimo en entrar,
primero en salir:
Se debe retener los valores de los nombres locales cuando finaliza una activacin.
Una activacin llamada sobrevive al autor de la llamada. Este caso no es posible en aquellos
lenguajes en que los rboles de activacin representan correctamente el flujo de control.
90
Compiladores
FIGURA 5.6: Asignacin de registros de activacin por medio de una pila que crece hacia abajo.
5.4.1 BLOQUES
Un bloque es una proposicin que contiene sus propias declaraciones de datos locales. En C, por
ejemplo, un bloque tiene la siguiente sintaxis:
{declaraciones proposiciones}
91
Compiladores
Una caracterstica de los bloques es su estructura de anidamiento. Los delimitadores marcan el inicio y
el fin de un bloque (llaves en C). stos garantizan que un bloque sea independiente de otro o bien que
est anidado dentro de otro. Esta propiedad de anidamiento recibe el nombre de estructura de bloques.
En un lenguaje con estructura de bloques el mbito de una declaracin viene dado por la regla de
anidamiento ms cercano. sta se ejemplifica en la figura 5.7, donde se muestra un programa en C y se
sealan claramente los bloques y el mbito de cada variable. La regla de anidamiento ms cercano es:
1. El mbito de una declaracin en un bloque B incluye B.
2. Si un nombre x no est declarado en un bloque B, entonces un caso de x en B est en el mbito de
una declaracin de x en un bloque abarcador B que cumple las siguientes condiciones:
a. B tiene una declaracin x.
b. B est anidado ms cerca alrededor de B que cualquier otro bloque con una declaracin de x.
92
Compiladores
nombre debe declararse fuera de cualquier procedimiento. En este caso, el mbito de una declaracin
hecha fuera de alguna funcin consta de los cuerpos de todas las funciones que aparezcan despus de
dicho nombre, excepto aquellas funciones que contengan una declaracin homnima.
En ausencia de procedimientos anidados es posible utilizar el esquema de asignacin mediante pilas
para los nombres locales, pues es posible asignar estticamente la memoria para todos los nombres
declarados fuera de cualquier procedimiento. Esto se debe a que la posicin de cada uno de estos
nombres es conocida al momento de la compilacin.
Una ventaja de este esquema es que los nombres no locales pueden pasarse como parmetros y
devolverse como resultado.
93
Compiladores
interior de l usar la memoria asignada estticamente para dicho nombre. En este caso es necesario
guardar el valor previo de = para restaurarlo una vez terminada la ejecucin del procedimiento.
FIGURA 5.8: Enlaces de acceso para encontrar las posiciones de memoria de los nombres no locales.
Existen diferentes mtodos para asociar parmetros actuales y formales, de los cuales se estudiarn solo
los tres primeros por ser de uso ms frecuente:
Llamada por valor.
Llamada por referencia.
Copia y restauracin.
Llamada por nombre o macroexpansin.
94
Compiladores
Es importante conocer el mtodo de paso de parmetros que utiliza un lenguaje (o compilador), pues el
resultado de un programa puede depender del mtodo empleado.
a
b
:= x
y
temp
LISTADO 5.3: Programa en Pascal con un procedimiento que recibe parmetros por valor.
program referencia(input, output);
var a, b: integer;
procedure permuta(var x, y: integer);
var temp: integer;
begin
temp := x;
x := y;
y := temp;
end;
begin
a := 1; b := 2;
permuta(a,b);
writeln(a = ,a); writeln(b =,b);
end.
Una caracterstica distintiva de la llamada por valor es que las operaciones sobre los parmetros
formales no afectan a los valores en el registro de activacin del autor de la llamada.
El listado 5.4 muestra un segundo ejemplo, esta vez en C, donde se hace uso de punteros para pasar
parmetros por valor. En este caso se emula el comportamiento de la llamada por referencia.
95
Compiladores
LISTADO 5.4: Programa en C con un procedimiento que usa punteros y llamada por valor.
void permuta(x,y)
{
int *x, *y;
int temp;
temp = *x;
*x = *y;
*y = temp;
}
main()
{
int a = 1, b = 2;
permuta(&a, &b);
printf(a es ahora %d, b es ahora %d\n, a, b);
}
96
Compiladores
valores de lado izquierdo calculados antes de la llamada. Esta copia se efecta solo para aquellos
parmetros actuales con valor de lado izquierdo (es decir, aquellos parmetros que son un nombre
y, por ende, tienen un enlace en memoria).
El listado 5.6 muestra un procedimiento en Pascal en que el resultado cambia segn qu mtodo de
paso de parmetros se emplee. En este caso, existen dos maneras de acceder a la posicin de a en el
registro de activacin de copiaafuera() cuando ste llama a inseguro(): como nombre no local o
mediante el parmetro formal x. As, al usar las formas mencionadas de paso de parmetros se obtienen
los siguientes resultados:
Llamada por referencia: en este caso, las asignaciones hechas a x y a a afectan de inmediato a a,
por lo que el valor final para este nombre que se muestra por pantalla es 0.
Copia y restauracin: aqu el valor 1 del parmetro actual a se copia en el parmetro formal x.
Justo antes de terminar la ejecucin de inseguro(), se copia el valor final de x (que es 2) en el valor
de lado izquierdo de a, por lo que el valor para este nombre que se muestra por pantalla es 2.
LISTADO 5.6: Programa en Pascal para el cual cambian los resultados segn si se pasan parmetros
por referencia o mediante copia y restauracin.
program copiaafuera(input,output);
var a : integer;
procedure inseguro(var x : integer);
begin
x := 2;
a := 0
end
begin
a := 1;
inseguro(a);
writeln(a)
end.
97
Compiladores
5.6.1 ENTRADAS DE LA TABLA DE SMBOLOS
Como se puede desprender de la descripcin anterior, cada entrada de la tabla de smbolos corresponde
a la declaracin de un nombre. Ahora bien, los nombres pueden corresponder a distintos tipos de datos
o a funciones y procedimientos, por lo que no todos los nombres tendrn los mismos atributos. Esto
hace que sea difcil e ineficiente crear un registro de tamao uniforme para poder almacenar la
informacin para cada tipo de datos, por lo que una buena alternativa es almacenar esta informacin en
algn lugar de la memoria fuera de la tabla de smbolos y en sta mantener un puntero a dicha
informacin.
Otro problema importante en la construccin de la tabla de smbolos es que no todas las entradas se
agregan a la vez:
Si el analizador lxico no reconoce palabras clave o reservadas, stas deben estar presentes en la
tabla de smbolos antes de comenzar esta etapa de anlisis.
Una entrada de la tabla de smbolos solo puede establecerse cuando se conoce claramente el papel
que juega el nombre en el programa y los valores de los atributos solo se van agregando a medida
que se conoce esa informacin.
Cuando un nombre puede ocuparse solo una vez, es posible crear la entrada de la tabla de smbolos
durante el anlisis sintctico. En otro caso, las diferentes entradas para un mismo nombre se van
creando a medida que se descubre el rol sintctico de cada instancia del nombre.
Los atributos de los smbolos se introducen frecuentemente como consecuencia de su declaracin, que
puede ser implcita. Adems, es la sintaxis de las declaraciones de procedimientos la que especifica que
algunos identificadores corresponden a parmetros formales.
Un ltimo problema a considerar es que los nombres, vistos como lexemas, pueden ser difciles de
manejar debido a las diferentes longitudes de los nombres. En consecuencia, se debe implementar
alguna representacin de un nombre de longitud fija que pueda ser incorporado en la tabla de smbolos.
No obstante, se debe tener cuidado de conservar en memoria, fuera de la tabla de smbolos, el
identificador completo a fin de poder comprobar si dicho lexema ya ha aparecido.
98
Compiladores
5.6.3 TIPOS DE TABLAS DE SMBOLOS
Existen tablas de smbolos estticas y dinmicas, y es importante poder determinar qu tipo de tabla se
debe ocupar:
Esttica: es til cuando se debe acceder a los smbolos en mltiples ocasiones.
Dinmica: se usa cuando la informacin de los smbolos es utilizada en solo una pasada.
La figura 5.9 muestra un pequeo programa en C y los elementos presentes en la tabla de smbolos
tanto para el caso esttico como para el dinmico. Se puede observar que en el caso esttico se
incorporan los nombres de todos los procedimientos a medida que van apareciendo, pero no se
eliminan. En el caso dinmico, en cambio, solo figuran aquellos elementos pertenecientes a los
procedimientos activos.
99
Compiladores
Listas enlazadas:
Similares a las pilas.
La implementacin de operaciones resulta ms sencilla.
Al igual que en los arreglos, las bsquedas toman un tiempo lineal.
rboles binarios:
Si los elementos se encuentran ordenados, se reduce el tiempo de bsqueda en forma
significativa.
El manejo del alcance de los smbolos se vuelve ms complejo.
Las operaciones de insercin y eliminacin de elementos son muy costosas en tiempo.
rboles n-arios:
Todo nodo es un alcance, y todos los smbolos de ese nivel de alcance estn contenidos en
dicho nodo.
Cada nodo tiene n hijos, y cada hijo implica un nuevo alcance de su alcance padre.
Tablas de dispersin (tablas hash): corresponden a una de las tcnicas ms utilizadas para la
implementacin de tablas de smbolos y se ilustran en la figura 5.10. Se construye de la siguiente
manera:
Se crea en primer lugar una tabla de dispersin, que es una matriz fija con punteros a
entradas de la tabla.
Las entradas de la tabla se organizan en listas enlazadas, independientes entre s, donde cada
registro de la tabla de smbolos aparece solo en una de estas listas. Para determinar en qu lista
debe ir la entrada para el nombre z se utiliza una funcin de dispersin z que devuelve un
entero entre 0 y 1. Si s se encuentra en la tabla de smbolos, estar en la lista numerada con
z . En caso contrario, se debe crear una nueva entrada en dicha lista.
100
Compiladores
Ejemplo 5.3:
Considere el fragmento de cdigo con procedimientos anidados del listado 5.7 (se listan solo las
declaraciones y llamadas a procedimientos). En la tabla de smbolos dicho fragmento de cdigo
(figura 5.11) se puede observar que cada tabla contiene al inicio un campo con un puntero al
lugar desde donde se hizo la llamada al procedimiento. Adems, en las entradas
correspondientes a nombres de procedimientos, se tienen punteros que apuntan a la tabla de
smbolos correspondiente.
LISTADO 5.7: Programa en pseudo-Pascal para el ejemplo 5.3.
// Main
var nota;
calcular_promedio();
// calcular_promedio
var n_cat;
var n_lab;
calcular_n_cat();
calcular_n_lab();
// calcular n_cat
var n_peps;
var n_controles;
ponderar_peps();
promediar_controles();
// calcular n_lab
var i;
var j;
// ponderar_peps
var ponderacion;
var p1;
var p2;
var p3;
determinar_por();
// promediar_controles
var c1;
var c2;
var c3;
var c4;
// determinar_por
var aprueba;
var promedio;
var reprueba;
101
Compiladores
102
Compiladores
Implcita: se debe determinar cundo un bloque de memoria ya no es necesario.
Un concepto importante que se debe definir es el de basura. Corresponde a todas aquellas posiciones
de memoria asignadas que ya no pueden alcanzarse. Por ejemplo, considere una lista enlazada en C. Si
se asigna NULL a la cabeza de la lista, ya no es posible alcanzar ninguno de los nodos restantes an
cuando stos ya han sido asignados.
Algunos lenguajes, como Lisp y Java, realizan un proceso de recoleccin de basura y reclaman la
memoria inaccesible. Otros lenguajes, como C y Pascal, no tienen esta funcionalidad, por lo que el
programador debe liberar explcitamente la memoria que ya no se ocupar. Estos lenguajes permiten
reutilizar la memoria liberada, pero la basura se mantiene hasta el trmino de la ejecucin del
programa.
Un concepto relacionado con el de basura es el de referencias suspendidas.
Si se desasigna la memora antes de la ltima referencia a ella, se crea una referencia suspendida.
Si se mantiene la memoria despus de la ltima referencia, pasa a ser basura.
103
Compiladores
bloques de tamao variable no es posible asignar una porcin de memoria mayor que el ms grande de
los bloques disponibles, an cuando se cuente con el espacio necesario.
104
Compiladores
secuencia de ellos. Por ende, el compilador necesita conocer la posicin donde se encuentra cada uno
de esos punteros. Estos pueden guardarse en una posicin fija dentro del bloque. Se supone que el rea
del bloque con informacin del usuario no contiene punteros.
Para llevar a cabo la desasignacin implcita pueden emplearse dos enfoques diferentes, que se
describen en los puntos siguientes.
5.8 EJERCICIOS
1. Dado el fragmento de cdigo del listado 5.8:
a. Muestre su rbol de activacin.
b. Muestre el estado de la pila de control cuando se efecta la llamada a factorial(2).
2. Considere la porcin de memoria que se muestra en la figura 5.15, donde los bloques ms oscuros
corresponden a fragmentos utilizados:
a. Muestre el estado final de la memoria tras efectuar las siguientes asignaciones considerando los
mtodos de primer ajuste y mejor ajuste.
Un bloque de 6 bytes.
Un bloque de 2 bytes.
Un bloque de 4 bytes.
Un bloque de 8 bytes.
105
Compiladores
b. Muestre el estado final de la memoria (tras defragmentar por medio de compactacin.
Considere para este fin el estado dado en la figura.
LISTADO 5.8: Fragmento de cdigo para el ejercicio 1.
int fibonacci(int n) {
if(n == 0) {
return 0;
}
if(n == 1) {
return 1;
}
return fibonacci(n - 2) + fibonacci(n - 1);
}
int factorial(int n) {
if(n == 0) {
return 1;
}
return n * factorial(n - 1);
}
void main() {
unsigned long x = fibonacci(5);
unsigned long y = factorial(4);
}
106
Compiladores
107
Compiladores
=
) +
).
) + ).
Los AST para las proposiciones de asignacin de un lenguaje se pueden producir mediante las
definiciones dirigidas por la sintaxis de la tabla 6.1. Esta misma definicin se puede usar para construir
los GDA, siempre y cuando las funciones )*{_' y )*{_'= {; retornen un puntero a un
nodo ya existente siempre que sea posible.
TABLA 6.1: Definicin dirigida por la sintaxis para construir AST para proposiciones de asignacin.
Una tercera representacin grfica es la representacin postfija, que es una representacin lineal del
rbol sintctico.
108
Compiladores
Ntese que no se permiten operaciones aritmticas compuestas, pues solo se puede tener un operador al
lado derecho de una proposicin. En consecuencia, una expresin de la forma / + 0 se puede
traducir en una secuencia:
:= 0
:= / +
Donde y son variables temporales generadas por el compilador. Al hacer esto se debe tener
cuidado de respetar la precedencia de los operadores.
El listado 6.1 muestra el cdigo de tres direcciones que se obtiene para el AST y el GDA
correspondientes a la expresin = ) + ).
LISTADO 6.1: Cdigo de tres direcciones.
(a) Para el AST de la figura 6.2.
(b) Para el GDA de la figura 6.2.
El cdigo de tres direcciones recibe ese nombre porque en cada proposicin suele contener tres
direcciones de memoria: una por cada operando y otra para el resultado.
109
Compiladores
/ es un parmetro.
corresponde a un procedimiento o funcin.
= es la cantidad de parmetros del procedimiento.
0 representa el valor devuelto (es opcional).
Por ejemplo, la llamada al procedimiento % / , / , , /7 queda:
/
/
/7
, =
7. Las asignaciones con ndices de la forma /: = 0k;l y /k;l: = 0. La primera asigna a / el valor de la
posicin en ; unidades de memoria ms all de la posicin 0. La segunda asigna el contenido de la
posicin en ; unidades de memoria ms all de la posicin / al valor de 0.
8. Las asignaciones de direcciones y punteros de la forma /: = &0, /: = 0 y /: = 0. La primera de
estas proposiciones asigna a / la direccin de 0. La segunda asigna a / el valor contenido en la
direccin apuntada por 0. La tercera hace que el valor del objeto apuntado por / tenga igual valor
que 0.
6.1.2.2 Implementaciones de cdigo de tres direcciones
Una proposicin de 3 direcciones es una forma abstracta de cdigo intermedio. En un compilador, estas
proposiciones pueden implementarse como registros con campos para el operador y los operandos. A
continuacin se muestran tres implementaciones diferentes.
6.1.2.3.1 Cudruplos
Corresponden a estructuras de tipo registro con cuatro campos: , que contiene un cdigo interno para
el operador, { y { contienen los operandos y {*zyx ', como su nombre lo indica, contiene el
resultado de la operacin. Por supuesto, solo se usan todos los campos en el paso de los operadores
binarios, por lo que se debe aclarar qu ocurre con los dems tipos de instrucciones:
Operadores unarios: no se utiliza { .
param y similares: no se utilizan { ni {*zyx '.
Saltos condicionales e incondicionales: se pone la etiqueta objeto en {*zyx '.
En general, los contenidos de los campos { , { y {*zyx ' son punteros a las entradas
correspondientes de la tabla de smbolos. Adicionalmente, se debe sealar que los nombres temporales
deben introducirse en la tabla de smbolos conforme van siendo creados.
La tabla 6.2 muestra la representacin mediante cudruplos del cdigo de tres direcciones para la
expresin : = ) + ).
110
Compiladores
) +
6.1.2.3.2 Triples
Esta representacin tiene la ventaja de no introducir nombres temporales a la tabla de smbolos. Para
esto, los valores temporales son referenciados de acuerdo a la posicin de la proposicin en que son
calculados. Como consecuencia, las proposiciones de tres direcciones se pueden representar mediante
registros con solo tres campos: , { y { . Los campos { y { contienen punteros a la
tabla de smbolos para las variables y constantes definidas por el programador o bien punteros dentro
de la misma estructura de triples para hacer referencia a los valores temporales.
La tabla 6.3 muestra la representacin mediante triples del cdigo de tres direcciones para la expresin
: = ) + ).
) +
En la prctica, la informacin necesaria para interpretar las distintas clases de entrada en los campos
{ y { se puede codificar dentro del campo o en campos adicionales.
Obsrvese que las operaciones ternarias, como /k;l: = 0 requieren dos entradas en la estructura de
triples, como se puede ver en la tabla 6.4 (a). La figura 6.4 (b) muestra que la operacin / 0k;l se
representa mediante dos entradas en forma natural.
111
Compiladores
6.2.1 DECLARACIONES
Conforme se examina la secuencia de declaraciones dentro de un procedimiento (o funcin), un
registro o un bloque, se puede distribuir la memoria para los nombres locales. Para cada uno de ellos se
crea una entrada en la tabla de smbolos con informacin, por ejemplo, referente al tipo y la direccin
relativa de la memoria que le corresponde. La direccin relativa consiste en un desplazamiento desde la
base del rea de datos esttica o del campo para los datos locales en un registro de activacin.
112
Compiladores
6.2.1.1 Declaraciones dentro de un procedimiento
La sintaxis de lenguajes como C y Pascal permite que todas las declaraciones en un mismo
procedimiento se procesen como un grupo. Para este fin se utiliza una variable global, por ejemplo
'*zx ;*=, que indica la siguiente direccin relativa de memoria disponible.
La tabla 6.6 muestra una gramtica que permite efectuar declaraciones junto a un esquema de
traduccin. La variable '*zx ;*= es inicializada en 0 antes de considerar la primera
declaracin. Los nuevos nombres son incorporados a la tabla de smbolos a medida que van
apareciendo, en una posicin relativa igual a '*zx ;*=. Al incorporar un nuevo smbolo, es
necesario aumentar '*zx ;*= en el ancho (usualmente en bytes) del objeto de datos indicado
por el nombre.
El esquema de traduccin de la tabla 6.6 hace uso de las siguientes funciones:
;={'y);{ = {*, ;, '*zx ;*= : crea una nueva entrada en la tabla de smbolos para
= {* y le asocia su tipo de dato (;) y su posicin relativa en la memoria ('*zx ;*=).
En el caso de arreglos y punteros, ; corresponde a una expresin de tipos construida a partir de
los tipos bsicos, enteros y reales en este caso.
{{ 0 x, ; : expresin de tipo que indica que indica que la variable a la que se asocia esta
expresin es un arreglo de tamao x cuyos elementos son de tipo ;.
;=*{ ; : expresin de tipo que indica que indica que la variable a la que se asocia esta
expresin es un puntero a un objeto de tipo ;.
113
Compiladores
En un lenguaje con procedimientos anidados, se pueden asignar direcciones relativas a los nombres
locales a cada procedimiento. Se puede suponer que existe una tabla de smbolos diferente para cada
procedimiento, mecanismo que puede ser implementado, por ejemplo, mediante una lista enlazada.
La figura 6.3 muestra el esquema de procedimientos anidados, mientras que la tabla 6.7 muestra un
esquema de traduccin (que se agrega al de la tabla 6.6) que permite crear las diferentes tablas de
smbolos y sus punteros. El esquema hace uso de las siguientes funciones:
){* {j x {*; : crea una nueva tabla de smbolos y retorna un puntero a la nueva tabla. El
argumento {*; corresponde a un puntero a la tabla de smbolos del procedimiento que abarca al
nuevo procedimiento declarado. En la figura 6.3, {*; podra ser, por ejemplo, el puntero desde
{;);= hacia *=) * '.
;={'y);{ x , = {*, ;, '*zx ;*= : crea en la tabla de smbolos apuntada por
x una nueva entrada para = {*, con su tipo ; y su posicin relativa '*zx ;*=.
';{ =) x , =) : registra el ancho acumulado de todas las entradas de tabla en el
encabezamiento asociado a dicha tabla de smbolos.
;={'y);{%{) x , = {*, x _y* : crea en la tabla de smbolos apuntada por x
una nueva entrada para el procedimiento = {*. El puntero x _y* apunta a la tabla de
smbolos del procedimiento nombre.
114
Compiladores
'*zx ;*= es una pila que almacena la siguiente posicin relativa disponible para un
nombre local del procedimiento en curso. Convertir '*zx ;*= en una pila es la extensin
natural para ajustar el esquema de la tabla 6.6 para procedimientos anidados.
115
Compiladores
6.2.3.1 Expresiones aritmticas
Al generar cdigo de tres direcciones se crean nombres temporales para los nodos interiores del rbol
sintctico. El valor del no terminal " al lado izquierdo de la produccin " " + " se calcula en un
temporal . Se crear un nuevo temporal cada vez que sea necesario.
En el caso de que una expresin contenga solamente un identificador, por ejemplo 0, entonces 0
contiene el valor de la expresin.
TABLA 6.8: Creacin de la tabla de smbolos para los nombres de los campos de un registro.
La tabla 6.9 muestra las reglas semnticas que permiten crear cdigo de tres direcciones para
proposiciones de asignacin. Si se toma la entrada = ) + ), el cdigo resultante es el del
listado 6.1 (a).
Volviendo a la tabla 6.9 se tiene que:
El atributo sintetizado C. )'; representa el cdigo de tres direcciones para la asignacin de C.
". xy { corresponde al nombre que contendr el valor de ".
". )'; es la secuencia de proposiciones de tres direcciones que evalan ".
La funcin *_y* retorna el nombre para un nuevo temporal.
La notacin *= / : = 0 + representa la proposicin de tres direcciones /: = 0 + .
Hasta ahora se haban formado las proposiciones de tres direcciones utilizando los nombres de las
variables considerados como punteros hacia sus entradas en la tabla de smbolos. El esquema de
traduccin de la tabla 6.10 muestra cmo se puede efectuar la bsqueda de las entradas en la tabla de
smbolos. En dicha tabla:
El atributo . = {* corresponde al lexema del nombre.
La operacin yz) { = {* verifica la existencia de una entrada en la tabla de smbolos para
= {*. En caso afirmativo retorna un puntero a la entrada, mientras que en caso contrario retorna
un puntero nulo.
La funcin *;;{ ) '*= escribe las proposiciones de tres direcciones generadas (representadas
por ) '*= ) a un archivo de salida. Esto elimina la necesidad del atributo )'; de la tabla 6.9.
Se haba sealado que la funcin *_y* crea un nuevo temporal cada vez que sea necesario. Esto
resulta especialmente til en compiladores optimizadores. No obstante, los temporales que almacenan
valores intermedios requieren espacio de almacenamiento y tienden a obstruir la tabla de smbolos.
Jacqueline Khler C. - USACH
116
Compiladores
Esta funcin puede ser modificada para que utilice una pequea matriz en un rea de datos del
procedimiento como si fuera una pila para guardar los temporales. Como la mayora de los temporales
solo se ocupan una vez, se puede crear un contador ), inicializado en 0, que se decrementa en 1 cada
vez que se utilice como operando un nombre temporal. Cuando se genera un temporal nuevo, se utiliza
la posicin $) y se incrementa ) en 1. A aquellos poco frecuentes temporales que se usan ms de una
vez se les puede asignar un nombre propio.
TABLA 6.9: Definicin dirigida por la sintaxis que permite producir cdigo de tres direcciones para
las asignaciones.
Ejemplo 6.1:
Genere cdigo intermedio para la expresin / = 15 43 +
/2 + 5.
*=zy 43
+
15
/2
3
+5
117
Compiladores
6.2.3.2 Expresiones booleanas
Las expresiones booleanas tienen dos grandes propsitos en los lenguajes de programacin. Se utilizan
para calcular valores lgicos y como expresiones condicionales para alterar el flujo de control.
Las expresiones booleanas pueden ser generadas por una gramtica con las siguientes producciones:
" " " | " " | " | " | | | , donde se considera un atributo
para determinar el operador de comparacin representado por . Se asume que tanto como
asocian por la izquierda, y que la precedencia de operadores (de mayor a menor) es , y .
Es habitual usar una representacin numrica para los valores booleanos. En este caso se considera el
valor 1 como y el valor 0 como . La evaluacin de las expresiones se efecta de izquierda
a derecha y siguiendo la precedencia de operadores, de manera similar a las expresiones aritmticas.
TABLA 6.10: Esquema de traduccin para generar cdigo de tres direcciones para asignaciones.
Ejemplo 6.2:
Genere cdigo intermedio para la expresin / =
) ' .
118
Compiladores
LISTADO 6.3: Cdigo intermedio para la expresin / =
) ' .
) '
119
Compiladores
En el esquema de la tabla 6.11 se tiene, una vez ms, que *;;{ escribe proposiciones de cdigo de
tres direcciones a un archivo de salida. Adems, z* da el ndice de la siguiente proposicin de tres
direcciones en la secuencia de salida (*;;{ debe incrementar z* despus de generar una
proposicin de tres direcciones).
Ejemplo 6.3:
La expresin < ) >= ! = ) se traduce a cdigo de tres direcciones,
usando el esquema de la tabla 6.11, como muestra el listado 6.4.
LISTADO 6.4: Cdigo intermedio para la expresin
100: < 103
101: 0
102: 104
103: 1
104: ) >= 107
105: 0
106: 108
107: 1
<
) >=
! = ).
108:
109:
110: ! = ) 113
111: 0
112: 114
113: 1
114:
120
Compiladores
121
Compiladores
LISTADO 6.5: Cdigo intermedio para la expresin / k0lkl.
0:
1:
2:
3:
4:
5:
6: /
1000
01
20
+
1
4
k l
// base
// y - ;=+
// ; ;=+
// ; ;=+
// ; ;=+
// h ; ;=+
=
= +;
= + ; ;=+
= + ; ;=+ i
6.2.4.2 Sentencia if
Esta sentencia, en primer lugar, debe verificar el cumplimiento de una condicin. Si es verdadera, se
ejecutan las sentencias anidadas. En caso contrario, se salta a la primera sentencia fuera del bloque .
En el ejemplo 6.5, las sentencias etiquetadas de 0 a 3 evalan la condicin. La sentencia 4 determina si
la condicin es verdadera, y en caso de ser as salta al cdigo contenido en el bloque (sentencia 6),
continuando luego en forma secuencial con el cdigo posterior (sentencia 7). En caso contrario, salta a
la primera instruccin posterior al bloque .
Ejemplo 6.5:
Considere el fragmento de cdigo en C del listado 6.6 y tradzcalo a cdigo de tres direcciones.
122
Compiladores
LISTADO 6.6: Un fragmento de cdigo en C.
if(x!=0) {
y=3;
}
z=x*y;
4: 6
5: 7
6: 0 3
7: / 0
5: 8
6: 0 3
7: 9
8: 0 5
9: / 0
123
Compiladores
6.2.4.4 Sentencia switch
Existen diversas maneras de implementar el cdigo de tres direcciones para esta sentencia, y algunas de
ellas dependen de las especificaciones del lenguaje fuente. Un mecanismo sencillo, no obstante, puede
ser el de evaluar la expresin de prueba e ir evaluando el resultado: si es distinto del caso comprobado,
saltar al siguiente, hasta llegar al valor buscado, ejecutando entonces su cdigo asociado y saltando
luego fuera del bloque , o al final del bloque . Si existe un valor por defecto, el cdigo
asociado a l se ejecuta siempre que no se haya encontrado un valor coincidente.
Ejemplo 6.7:
Considere el fragmento de cdigo en C del listado 6.10 y tradzcalo a cdigo de tres
direcciones.
LISTADO 6.10: Un fragmento de cdigo en C.
c=2*y-1;
switch(c) {
case 1:
z=5;
case 3:
z=36;
case 5:
z=8;
default:
z=0;
}
x=y+z;
7: 12
8: )! = 5 11
9: 8
10: 12
11: 0
12: / 0
En el caso real del lenguaje C, la traduccin anterior es incorrecta. En C, se ejecuta el caso vlido y
todos los casos siguientes a menos que se encuentre un salto al exterior del bloque switch, sealado por
la palabra reservada .
Ejemplo 6.8:
Considere el fragmento de cdigo en C del listado 6.12 y tradzcalo a cdigo de tres
direcciones.
Jacqueline Khler C. - USACH
124
Compiladores
LISTADO 6.12: Un fragmento de cdigo en C.
Z=0;
c=2*y-1;
switch(c) {
case 1:
z=5;
case 3:
z=z+2;
break;
case 5:
z=8;
}
x=y+z;
7: + 1
8: 12
9: )! = 5 12
10: 8
11: 12
12: 13: / 0
125
Compiladores
Ejemplo 6.9:
Considere el fragmento de cdigo en C del listado 6.14 y tradzcalo a cdigo de tres
direcciones.
LISTADO 6.14: Un fragmento de cdigo en C.
x=0;
i=0;
while(i<10){
x=x*i;
i++;
}
4: / / ;
5: ; ; + 1
6: 2
126
Compiladores
LISTADO 6.16: Cdigo de tres direcciones para una sentencia .
0: / 0
1: ; 0
2: / / ;
3: ; ; + 1
4: ; < 10 2
5: 6
3: ; ; + 1
4: ; == 10 6
5: 2
127
Compiladores
LISTADO 6.20: Un fragmento de cdigo en C.
x=0;
for(i=0; i<10; i++){
x=x+x*i;
}
4: / ;
5: / / +
6: ; ; + 1
7: 2
6.3 EJERCICIOS
1. Sea la expresin aritmtica
a. Un AST.
b. Cdigo de tres direcciones.
+ ) . Tradzcala a:
128
Compiladores
2. Considere la asignacin / =
a. Un AST.
b. Cdigo de tres direcciones.
c. Cudruplos.
d. Triples.
e. Triples indirectos.
)+' +h /
) i. Tradzcala a:
129
Compiladores
BIBLIOGRAFA
1. AHO, A. V.; LAM, M. S.; SETHI, R.; ULLMAN, J. D. (2008) Compiladores. Principios, tcnicas
y herramientas (2 ed.), Pearson Educacin, Mxico. ISBN 978-970-26-1133-2.
2. LVAREZ, J. (2005). Apuntes de la Asignatura Programacin de Lenguajes Formales,
Departamento de Ingeniera Informtica, Facultad de Ingeniera, Universidad de Santiago de Chile.
3. CAMPOS, A. E. (1995). Teora de Autmatas y Lenguajes Formales, Departamento de Ciencia de
la Computacin, Escuela de Ingeniera, Pontificia Universidad Catlica de Chile.
4. HOPCROFT, J. E.; ULLMAN, J. D. (1993). INTRODUCCIN A LA TEORA DE AUTMATAS,
LENGUAJES Y COMPUTACIN, Compaa Editorial Continental S. A., Mxico. ISBN 968-261222-5.
5. KOLMAN, B.; BUSBY, R. C. (1986). Estructuras de Matemticas Discretas para la
Computacin, Prentice-Hall Hispanoamericana S. A., Mxico. ISBN 968-880-080-5.
130
Compiladores
131
Compiladores
A.2 GRAMTICAS
Un mecanismo para representar lenguajes de manera finita son las gramticas. stas pueden definirse
como un sistema o algoritmo para la generacin de palabras basado en el reemplazo de subsecuencias
de acuerdo a determinadas reglas o producciones.
Una produccin est conformada por un lado izquierdo o antecedente y un lado derecho o consecuente.
El mecanismo de funcionamiento es simple: cada vez que se encuentre el antecedente en alguna
palabra parcialmente generada, ste debe ser reemplazado por el consecuente, formando as una nueva
palabra total o parcialmente generada.
Formalmente, una gramtica $ es una tupla de 4 elementos, $ = , N, P, S , donde:
es un conjunto finito no vaco que contiene los smbolos que conforman el alfabeto del lenguaje
generado. Tambin se conoce como conjunto de terminales.
N es un conjunto finito no vaco que contiene smbolos auxiliares variables o de reemplazo
denominados no terminales, que facilitan la escritura de las producciones. N conforman el
vocabulario de la gramtica.
P es un conjunto finito no vaco de producciones.
S N es el smbolo inicial a partir del cual, mediante la aplicacin sucesiva de producciones, se
puede generar cualquier palabra vlida del lenguaje.
Ejemplo A.1:
La siguiente gramtica genera palndromos sobre el alfabeto binario. Es importante destacar que
la palabra vaca no pertenece al vocabulario de $.
$ = , N, P, S :
= 0, 1
N= A
P = A 0A0 | 1A1 | 0 | 1 |
S=A
Jacqueline Khler C. - USACH
132
Compiladores
A continuacin se muestra una notacin alternativa para el mismo ejemplo.
$ = , N, P, S :
= 0, 1
N = secuencia
P = secuencia = 0secuencia0 | 1secuencia1 | 0 | 1 |
S = secuencia
Es importante destacar algunos aspectos de notacin, pues es fundamental en la escritura de gramticas
poder distinguir claramente entre smbolos terminales y no terminales. Las convenciones que se
emplean son las siguientes:
1. Los terminales o elementos de se denotan por:
Letras latinas minsculas ( , , ), ).
Palabras en negrita o subrayado (, m;x* , .
Palabras encerradas entre comillas simples o dobles (ab, 0110, ).
2. Los no terminales o elementos de N se denotan por:
Letras latinas maysculas ( , , , ).
Palabras encerradas entre parntesis triangulares (secuencia, entero, ).
3. Se usan letras griegas minsculas (2, 6, A, ) para designar indistintamente smbolos terminales o
no terminales, o incluso secuencias de ellos.
4. Una produccin de % se denota por 2 6 bien por 2 = 6. Tanto el antecedente como el
consecuente pueden estar conformados por cualquier secuencia no vaca de terminales y no
terminales. En el caso del consecuente, puede aparecer tambin la palabra vaca.
5. Las reglas 2 6, 2 A, 2
Ahora que est bien definida la idea de gramtica, es importante estudiar cmo se generan las palabras.
Para una gramtica $, se dice que una secuencia 2 : = 2 22 N genera o deriva otra
secuencia 6 : = 2 62 N , operacin denotada por 2 6, si y solo si 2 6 % para
2 , 2 , 2, 6 N .
Observacin:
1. L es una derivacin de n pasos y corresponde a la clausura reflexiva y transitiva de .
2. El conjunto de las palabras generadas sobre N a partir del smbolo inicial C se denota por
C $ .
Ejemplo A.2:
Retomemos la gramtica del ejemplo anterior, $ =
0, 1 , A , A 0A0 | 1A1 | 0 | 1 | , A .
133
Compiladores
En este caso, para la segunda derivacin se hace uso de la produccin A .
Tambin es posible representar las derivaciones en forma grfica mediante un rbol de anlisis
sintctico, el cual tiene las siguientes propiedades:
La raz est etiquetada con el smbolo inicial.
Cada hoja est etiquetada con un componente lxico o con .
Cada nodo interior est etiquetado con un no terminal.
Si A es el no terminal que etiqueta a algn nodo interior y X , X , ... XL son las etiquetas de los
hijos de ese nodo, de izquierda a derecha, entonces X1 X2 Xn es una produccin.
Si bien en ocasiones este mecanismo resulta ms cmodo y claro, puede ser inadecuado en ocasiones
porque no muestra el orden en que se realizan las sustituciones. La figura A.2 muestra esta
representacin para las secuencias generadas en el ejemplo anterior.
FIGURA A.2: rboles de derivacin para las palabras (a) 001101100 y (b) 11 con $ =
0, 1 , A , A 0A0 | 1A1 | 0 | 1 | , A .
Los ejemplos A.1 y A.2 son bastante sencillos, puesto que se trata de una gramtica con un nico no
terminal. Pero podemos tener una gran cantidad de ellos, como ocurre al crear la gramtica de un
lenguaje de programacin. As pues, el ejemplo A.3 muestra una gramtica que genera los nmeros
naturales.
Ejemplo A.3:
La gramtica $ genera el lenguaje de todos los nmeros naturales, respetando las convenciones
de notacin habituales al no permitir ceros a la izquierda. La figura A.3 muestra los rboles de
derivacin para generar varios nmeros.
134
Compiladores
$ = , N, P, S :
= 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
N = significativo, digito, secuencia, natural
P = significativo 1 | 2 | 3 | 4 | 5 |6 | 7 |8 | 9, digito
0 |1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9, secuencia digitosecuencia | , natural
0 | significativosecuencia
S = natural
La nocin de derivacin de palabras conduce a la definicin de lenguaje generado por una gramtica $,
denotado por D $ . Corresponde al conjunto de palabras generadas a partir del smbolo inicial C y que
solo contienen smbolos terminales. Matemticamente: D $ = C $ = m : C w .
En general, pueden existir varias gramticas que generen un mismo lenguaje, lo que las hace
equivalentes. As, $ $ : zz; D $ = D $ .
FIGURA A.3: rboles de derivacin para las palabras (a) 0, (b) 5 y (c) 3907.
135
Compiladores
A.2.1 GRAMTICAS REGULARES
Un lenguaje es regular si y solo si puede ser generado constructivamente por composicin de
operaciones regulares y operandos de lenguajes regulares a partir de los lenguajes bsicos.
Los lenguajes bsicos son:
: lenguaje nulo o conjunto vaco.
: lenguaje que solo contiene la palabra vaca.
: lenguajes que contienen solo una palabra de longitud 1 para cada smbolo del alfabeto.
Las operaciones regulares, ordenadas segn su precedencia, son:
Clausura o estrella de Kleen: operacin unaria, denotada por como superndice, que indica que el
operando puede repetirse cero o ms veces. En ocaciones, se usa tambin la variante denotada por
un + como superndice, que indica una o ms repeticiones del operando.
Concatenacin: operacin binaria que indica que el segundo operando debe ir a continuacin del
primero en cualquier palabra vlida del lenguaje. Se denota por la ausencia de operador o, en
ocasiones, con un punto.
Unin: operacin binaria denotada por + que indica que se debe escoger uno de entre sus
operandos.
Se dice que una gramtica $ = , N, P, S es lineal si y solo si en cada regla de produccin existe a lo
ms un no terminal en el lado derecho. En otras palabras, todas las producciones son de la forma A
uBv o bien A w, con A, B _ y y, , m . Hay dos casos interesantes a considerar en esta
definicin:
y = : las producciones son de la forma A B o bien A w. En este caso, se dice que $ es
lineal izquierda.
= : las producciones son de la forma A uB o bien A w. En este caso, se dice que $ es lineal
derecha.
Las gramticas lineales derechas se denominan tambin gramticas regulares, y son las que generan los
lenguajes regulares.
Ejemplo A.4:
$ = a, b , S, A, B, C , S aC, A aA | b, B bB | b, C A | B , S
Esta gramtica genera el lenguaje sobre el alfabeto = a, b cuyas palabras comienzan con
terminan con , y entre medio pueden contener solo o solo :
D=
Podemos ver que, en este ejemplo, estn presentes las tres operaciones regulares. Los no
terminales A, B y C tienen dos producciones cada uno, separadas por |, con lo que con cada uno
de ellos tenemos la unin entre dos subsecuencias.
La concatenacin est presente en toda produccin que contenga dos o ms smbolos en su lado
derecho. En el caso de la produccin de S tenemos una a concatenada con alguna subsecuencia
generada a partir de C.
Jacqueline Khler C. - USACH
136
Compiladores
En el caso de A aA | b tenemos presentes la clausura y la concatenacin, puesto que A genera
todas las subsecuencias que comienzan por cero o ms a y terminan con una b.
A.2.2 GRAMTICAS LIBRES DE CONTEXTO
La sintaxis de los lenguajes de programacin puede ser descrita por medio de gramticas libres de
contexto (GLC). stas ofrecen ventajas significativas al momento de disear un lenguaje o escribir un
compilador:
Especificacin sencilla y fcil de entender para lenguajes de programacin.
Facilitar la tarea de construir analizadores sintcticos. Para algunas clases de gramticas incluso
pueden ser generados automticamente.
Una gramtica adecuada da al lenguaje de programacin una estructura til para la traduccin de
cdigo fuente a cdigo objeto y para la deteccin de errores.
Resulta ms fcil aadir nuevas construcciones a un lenguaje de programacin ya existente
(evolucin).
Se define una GLC como una cudrupla $ = , N, %, C , donde:
: conjunto finito de smbolos terminales.
N: conjunto finito de no-terminales.
P: conjunto de producciones.
S: smbolo inicial, que debe ser no-terminal.
Una gramtica es un modelo que permite generar secuencias sintcticamente vlidas en algn lenguaje,
aunque sin tener en cuenta su significado. Por ejemplo, en castellano podemos decir que una oracin
simple tiene un artculo, un sustantivo, un verbo y un punto. De acuerdo a esta definicin, son
oraciones El nio corre. y Unos planeta piensa. Tambin podramos pensar en un prrafo como una
secuencia de una o ms oraciones.
Tomemos el ejemplo anterior del castellano para explicar la definicin de GLC:
corresponde al conjunto de elementos que puede aparecer en secuencias vlidas, que en nuestro
ejemplo seran los artculos, los verbos, los sustantivos y el punto.
Los no terminales pueden pensarse como variables temporales que no pueden aparecer en una
secuencia completamente generada, pero que pueden ser reemplazadas por alguna secuencia de
terminales y no terminales. En el ejemplo anterior, los no terminales estaran dados por los
conceptos de oracin, artculo, sustantivo y verbo.
El conjunto de producciones indica cmo pueden ser reemplazados los no terminales. En nuestro
ejemplo, tenemos que oracin es reemplazado por la secuencia artculo-sustantivo-verbo-punto.
El smbolo inicial es un no terminal especfico a partir del cual se construyen las secuencias vlidas.
En nuestro ejemplo sera prrafo.
Para llevar esta nocin al modelo anterior, digamos que el smbolo A corresponde a prrafo; B, a
oracin; C a artculo, D a sustantivo, y E, a verbo. As, tendramos que:
= . , El, La, , Unos, nio, planeta, casa, , lpiz, corre, salta, piensa, , vuela .
N = A, B, C, D, E .
P=
| ,
Jacqueline Khler C. - USACH
137
Compiladores
!".,
El | La | | Unos,
! nio | planeta | casa | | lpiz,
" corre | salta | piensa | | vuela .
S = A.
Las gramticas libres de contexto (GLC) son aquellas en que todas las producciones tienen la forma
2, con _ y 2 _ . As, el lado izquierdo de cada produccin contiene nicamente un
smbolo no terminal. Esta restriccin no es trivial, puesto que no todos los lenguajes pueden ser
generados por una gramtica independiente del contexto. En consecuencia, los lenguajes generados por
este tipo de gramticas se denominan lenguajes independientes del contexto. Adems se tiene que las
producciones de los no terminales pueden tener cualquier secuencia de terminales y no terminales,
dejando fuera la restriccin de tener a lo ms un no terminal al extremo derecho de la produccin. Cabe
destacar que el conjunto de los lenguajes regulares es un subconjunto de los lenguajes libres de
contexto. Las gramticas de los ejemplos A.1 y A.3 son, en consecuencia, libres de contexto.
En el caso de las gramticas lineales (y en particular de las gramticas regulares), en que toda
produccin tiene a lo ms un no terminal, no es necesario preocuparse del orden en que se realicen las
derivaciones o de si existen rboles distintos para generar una misma palabra, pues hay uno solo por
cada secuencia. En el caso de las GLC, como podemos tener ms no terminales en una produccin, s
es necesario tomar en consideracin el orden en que se efectan las derivaciones.
Por la derecha: siempre se reemplaza el no terminal de ms a la derecha.
Por la izquierda: siempre se reemplaza el no terminal de ms a la izquierda.
Ejemplo A.5:
Dada la GLC $ = /, , , +, , " , " " + " | " " | " | / , " , muestre una derivacin
por la derecha y otra por la izquierda para la palabra / + / /. Muestre adems sus rboles de
derivacin.
Derivacin por la derecha:
" "+" "+"" "+"/ "+// /+//
Derivacin por la izquierda:
" "+" /+" /+"" /+/" /+//
Las dos derivaciones anteriores pueden representarse por medio del mismo rbol de derivacin,
que se muestra en la figura A.4.
138
Compiladores
Ahora que est clara la idea de derivacin por la derecha y por la izquierda, es importante introducir el
concepto de gramtica ambigua. Una gramtica $ GLC es ambigua m D $ m tiene dos
derivaciones por la izquierda m tiene dos derivaciones por la derecha m tiene dos rboles de
derivacin.
Ejemplo A.6:
Consideremos como base el ejemplo A.5. Ahora podemos buscar nuevas derivaciones por la
izquierda y por la derecha para la misma palabra, as como un nuevo rbol de derivacin, y as
probar que $ es ambigua.
Derivacin por la derecha:
" "" "/ "+"/ "+// /+//
Derivacin por la izquierda:
" "" "+"" /+"" /+/" /+//
Al igual que en el ejemplo A.5, las dos derivaciones anteriores pueden representarse por medio
del mismo rbol de derivacin (figura A.5).
139
Compiladores
Concatenacin, que se denota por la ausencia de operador o, en ocasiones, con un punto.
Unin, denotada por +.
Ejemplo A.7: Algunas expresiones regulares sencillas.
Algunas expresiones regulares sencillas son:
+
+
: denota el lenguaje de todas las palabras sobre el alfabeto = ,
que tienen a lo menos un par de
consecutivas. Algunos ejemplos de palabras que
pertenecen a este lenguaje son: ,
,
,
, etc.
)
+
): denota el lenguaje de todas las palabras sobre el alfabeto = , , ) que
comienzan con una ), tienen cualquier cantidad de pares consecutivos de y y terminan
con otra ). Algunos ejemplos de palabras que pertenecen a este lenguaje son: )), ) ),
) ), )
), )
), etc.
140
Compiladores
Desde una perspectiva de implementacin fsica, un AF puede verse como un dispositivo conformado
por los siguientes elementos, algunos de los cuales se ilustran en la figura A.6:
Una cinta infinita que contiene smbolos pertenecientes a un alfabeto, formando una secuencia de
entrada.
Un cabezal Un cabezal capaz de leer un smbolo de la cinta y desplazarse automticamente hacia la
derecha.
Un control finito, compuesto de una cantidad, tambin finita, de estados y una especificacin
(transicin) que permite determinar el estado siguiente de acuerdo a la lectura realizada en la cinta.
Algunos estados distinguibles dentro del conjunto de estados:
Un estado inicial.
Uno o ms estados finales o de aceptacin (que indican que la secuencia pertenece a un
lenguaje dado).
141
Compiladores
F Q es el conjunto de estados finales.
Podemos distinguir dos grandes clases de AF, dependiendo de la forma que tenga la definicin de
transicin : determinsticos y no determinsticos.
indica que, al estar en el estado y leer el smbolo , el AFD pasa al siguiente estado . El cabezal
pasa automticamente al smbolo siguiente.
Cabe destacar que de esta definicin de se desprenden las siguientes conclusiones:
Al encontrarse el AFD en un estado y leer un smbolo de entrada, hay uno y solo un estado al que
puede avanzar.
No puede haber un cambio de estado si no se ha ledo un smbolo desde la entrada.
Para todo estado y todo smbolo del alfabeto debe existir una transicin definida, por lo que la
cantidad de transiciones de un AFD es de | | ||.
Ejemplo A.8:
Considere el AFD
, , ,
,
,
,
,
, , ,
,
, donde:
,
Otra manera de representar la funcin de transicin es mediante una tabla, como se muestra en
la tabla A.1.
\
142
Compiladores
Cada transicin de tiene un estado de origen, sealado por la base de la flecha; un estado
de destino, sealado por la cabeza de la flecha, y un smbolo asociado.
El estado inicial est sealado con una flecha no rotulada que incide en l.
Cada estado final de , en este caso solo , se denota por un doble crculo.
, m m = m :
, =
Cabe destacar que 7 denota = pasos de computacin y que corresponde a la clausura reflexiva y
transitiva de .
En tercer lugar, es necesario definir el concepto de aceptacin de una palabra m . Se dice que es
aceptada por un AFD M si y solo si, comenzando desde la configuracin inicial, al terminar de leer m
el AFD se encuentra en un estado final, es decir:
m es aceptada por M
, m
Ejemplo A.9:
Consideremos el AFD del ejemplo A.8 y la entrada m = abbaab. La configuracin inicial de M
est dada por
, abbaab . Tras el primer paso de computacin, se tiene:
143
Compiladores
, abbaab
, bbaab
, baab
, abbaab
, aab
y adems
, ab
,b
Ejemplo A.10:
Consideremos ahora el AFD del ejemplo A.8 y la entrada m = bab. La configuracin inicial de
M est dada por
, bab . La secuencia de pasos de computacin para determinar la aceptacin
de m es:
, bab
As,
, ab
, bab
,b
y adems
La nocin de aceptacin de una palabra conduce a la nocin de lenguaje aceptado por un AFD M,
denotado por D
, que corresponde al conjunto de todas las palabras aceptadas por M, es decir
D
= m : m es aceptada por M .
Ejemplo A.11:
Si estudiamos el AFD del ejemplo A.8, podemos notar que D
+ .
representado por la ER { =
corresponde al lenguaje
=D
, m = m
, m
As, se tiene que un estado es alcanzable desde otro estado si existe una palabra m tal que la
secuencia de pasos de computacin comenzando desde y el primer smbolo de m culmina en
cuando no quedan smbolos por leer. Cabe destacar que : tiene las siguientes propiedades:
:
, =
:
, =
,
:
, m = :
, ,m
:
, m = : , , m
144
Compiladores
A.3.2 AUTMATA FINITO NO DETERMINSTICO (AFND)
Habamos estudiado que el estado al que va un AFD al leer un smbolo de la entrada est
completamente determinado, puesto que cada estado cuenta con una y solo una transicin por cada
smbolo del alfabeto. En el caso del AFND, en cambio, el cambio de estado solo est parcialmente
especificado, puesto que puede ocurrir lo siguiente:
Las transiciones entre estados estn dadas por palabras ms que por smbolos individuales,
pudiendo incluso haber transiciones con , denominadas transiciones vacas, en que el AF puede
cambiar de estado sin necesidad de haber ledo algo desde la entrada.
Puede haber ms de una transicin definida desde un estado determinado con alguna lectura dada
(transiciones mltiples). En consecuencia, el AFND debe ir a alguno cualquiera de los estados de
destino, de manera no determinada.
De lo anterior podemos concluir que, en realidad, el AFD estudiado no es ms que un caso particular
del AFND. En estos ltimos, la especificacin de transicin
es una relacin ,
conformada por un conjunto de tros , m, donde cada tro indica que, estando en el estado , al
leer en la entrada una secuencia de smbolos m, el AFND puede quedar en el estado . No obstante,
como pueden existir dos o ms transiciones que compartan los dos primeros componentes, por ejemplo
, m, , , m, , esto puede reformularse de modo tal que el tercer elemento del tro sea un
conjunto de estados: , m, : , .
En el caso de los AFND, las nociones de configuracin, paso de computacin, aceptacin de palabra,
aceptacin de lenguaje y equivalencia son semejantes al caso de los AFD. No obstante, la existencia de
transiciones vacas da origen a una nueva definicin: la clausura- . Corresponde al conjunto de estados
alcanzables desde el estado mediante transiciones vacas, es decir:
= z : , z,
Se puede extender la nocin de clausura- para un conjunto de estados j, que corresponde
simplemente a la unin de las clausuras- de cada estado en j:
j =
Ejemplo A.12:
Considere el AFND = , , , , , donde:
=
, , , ,
= ,
=
, ,
,
, ,
,
, ,
,
, ,
,
, ,
, ,
,
, ,
,
, ,
,
, ,
,
, ,
,
,
=
=
,
, ,
, ,
Otra manera de representar la funcin de transicin es mediante una tabla, como se muestra en
la tabla A.2.
\m
Jacqueline Khler C. - USACH
145
Compiladores
,
,
A.3.3 EQUIVALENCIA ENTRE AFD Y AFND
La incorporacin del no determinismo, a pesar de facilitar la capacidad de abstraccin al disear un AF,
no aumenta el poder de aceptacin de estos reconocedores, es decir, no incrementa el conjunto de
lenguajes que pueden ser reconocidos usando mquinas de estados finitos. As pues, es posible
demostrar que para cada AFND existe un AFD equivalente.
Para construir un AFD equivalente a un AFND dado, se deben seguir dos grandes pasos:
1. Eliminar aquellas transiciones que avanzan con secuencias cuya longitud es mayor que 1.
2. Eliminar transiciones vacas y transiciones mltiples.
146
Compiladores
Para eliminar las transiciones con secuencias de longitud mayor a 1, se incorporan nuevos estados al
AFND a fin de descomponer las transiciones para que solo tengan un smbolo.
Sea
, , , ,
un AFND tal que sus transiciones son de la forma , y, , donde ,
:
nueva relacin de transicin
se obtiene como
=
, y, : |y| 1
, , , , , , , @ , @ , para cada , y, tal que y = @ y |y| = r >
1, como se ilustra en la figura 2.6.
La
El segundo paso, entonces, consiste en eliminar las transiciones vacas y las transiciones mltiples.
Para este fin, creamos un conjunto de estados para el AFD :: = , , , , tal que cada uno
de sus estados corresponde a un conjunto de estados del AFND = , , , , , que sintetiza
todos los caminos posibles para reconocer una determinada secuencia. Se puede garantizar que es
posible realizar esta tarea, ya que para un conjunto de estados de tamao = se tienen 27 subconjuntos.
El primer estado del AFD
el estado inicial de .
Los nuevos estados de se determinan junto con las transiciones. Para cada smbolo de se
determina el conjunto de estados de que es posible alcanzar desde y se les incorporan sus
respectivas clausuras- . Cada nuevo conjunto forma un nuevo estado del AFD. Se repite este proceso
hasta que no queden estados sin transiciones definidas. Los estados finales de sern todos aquellos
conjuntos de estados que contengan algn estado final de .
Ejemplo A.13:
Consideremos el AFND de la figura A.9 y determinemos su AFD equivalente
inicial de est dado por la clausura- del estado inicial de :
,$ =
,1 =
==
, , $ = , , , !, ", $ =
,1 = ,T
,T = ,T =
,0 =
,1 =
=
=
. El estado
147
Compiladores
,0 =
,1 =
, ,$
, ,T
, ,$
, ,T
=
=
, , , !, ", $ =
, ,T =
,0 = !
, 1 = ",
! =
",
= ",
,0 =
,1 =
=
=
,0 =
,1 = "
=
" = " =
,0 = ,"
,1 =
,"
=
,0 =
,1 =
=
=
=
=
,0 =
,1 =
Jacqueline Khler C. - USACH
= !, " =
=
=
=
," =
148
Compiladores
,0 =
,1 = ,
=
,
=
,0 =
, 1 = ",
=
",
Note que
es el conjunto vaco, por lo que al haber ledo una secuencia no vlida se convierte
en un estado trampa.
El conjunto de estados finales del AFD es
::
Ahora asignamos un nombre a cada grupo y estudiamos el comportamiento de cada estado para cada
uno de los smbolos del alfabeto. Llamemos 1 al grupo que contiene a los estados no finales y 2 al
grupo de estados finales.
va a
al leer un 0, y est en el grupo b. Adems,
va a
al leer un
0, y est en el grupo a.
% =
Para la siguiente particin, podemos descomponer los grupos de acuerdo a su comportamiento. Son
potencialmente equivalentes aquellos estados de un mismo grupo que vayan a las mismas particiones
con los mismos smbolos. Es importante destacar que lo que ya estaba separado no puede juntarse
nuevamente. As, tenemos que todos los estados se comportan de manera diferente en el grupo a,
mientras que hay algunos del grupo b que siguen siendo potencialmente equivalentes. Ahora, tras la
nueva particin, repetimos el proceso para ver si hay ms grupos que se puedan separar:
% =
+ *
'* '' +* +) +
,
,
, , , ,
'
149
Compiladores
De acuerdo al resultado anterior, la nueva particin queda:
%
'
x x
,
;
>
. En
Tras el anlisis de comportamiento de los grupos, se tiene que % = % , por lo que
consecuencia, podemos tener el AFD mnimo quitando
y redirigiendo sus transiciones entrantes a
.
FIGURA A.11: AFND reconocedor para palabras de largo 1 segn el mtodo de Thompson.
Jacqueline Khler C. - USACH
150
Compiladores
{ { + { : el mecanismo para construir un autmata reconocedor correspondiente a la unin de dos
subexpresiones regulares es bastante sencillo. Basta con tomar los dos autmatas reconocedores, crear
un nuevo estado inicial que vaya con transiciones vacas a los que fueran los estados iniciales y crear
un nuevo estado final alcanzable con transiciones vacas desde el que fuera el estado final (figura
A.12).
FIGURA A.14: Esquema para construir la estrella de Kleene segn el mtodo de Thompson.
Ejemplo A.14:
Construir un AF reconocedor para el lenguaje representado por la siguiente expresin regular:
{ 011 00 + 11 + 01 + 0 .
151
Compiladores
La figura A.15 muestra los pasos seguidos para construir el AFND reconocedor para la ER
dada.
{
{{
{{
{{
{{
FIGURA A.15: Esquema para construir la estrella de Kleene segn el mtodo de Thompson.
152
Compiladores
{
{ +{
{{
{ +{
153
Compiladores
{
{{
{ +{
154
Compiladores
, ,
, donde:
Para comprender adecuadamente este modelo es necesario explicar con detenimiento la relacin de
transicin . Por definicin, un AA corresponde a un AFND con una pila asociada. Adems, si se tiene
h ? , 6i, entonces:
8 , m, 2
El estado actual del AA es 8 , debe leer desde la entrada la secuencia m y la secuencia 2 se
encuentra al tope de la pila.
Una vez efectuada la lectura, pasa al estado ? y reemplaza 2 por 6 al tope de la pila.
Cabe destacar como casos particulares a dos operaciones especiales:
h ? , i, inserta el smbolo al tope de la pila.
Push(a):
8 , m,
h ? , i, quita el smbolo que se encuentre al tope de la pila.
Pop:
8 , m,
Se define como configuracin de un AA al estado en que se encuentra, la porcin no leda de la entrada
y el contenido de su pila, es decir, a un elemento de
.
Un paso de computacin, denotado por , corresponde a un cambio en la configuracin del AA:
2.
tiene su pila vaca, es decir,
, m,
.
8, ,
Resulta interesante la conclusin de que, al bastar con uno solo de los criterios para la aceptacin,
puede darse que para un AA se tenga
.
155
Compiladores
Otra observacin interesante es que, puesto que Dt DD , se tiene que un AF corresponde a un caso
especial de AA en que no se realizan operaciones sobre la pila.
,D
Ejemplo A.15:
Sea el AA
,
.
0, 1, ) .
t, , $ .
.
t.
.
, ,
, , , ,
, 0, t
, 0,
, 0, $
, 1, t
, 1,
, 1, $
, ), t
, ),
, ), $
, 0,
, 1, $
, ,t
m: *z )* ' {
, donde:
, t
,
, $
, $t
,$
, $$
,t
,
,$
,
,
,
m)m : m 0, 1
Ntese que este AA solo puede aceptar una palabra por medio de la pila vaca. Para ver su
funcionamiento, veamos en primer lugar la traza para la entrada m
011)110, que se muestra
en la tabla A.3.
156
Compiladores
TABLA A.3: Traza para m
La tabla A.4 muestra que la entrada m
tenemos que m D
, pero m D
.
011)110.
01)11.