You are on page 1of 16

Apuntes de compiladores

Toms Barros a 4 de septiembre de 2008

1.

Introduccin o

Un compilador es simplemente un programa que puede leer un programa en un lenguaje y traducirlo a otro lenguaje programa fuente Compilador programa objetivo

1.1.

procesos de un programa
programa fuente preprocesador Assembler relocable machine code Linker cdigo de mquina o a

programa fuente modicado compilador programa en assembler

1.2.

arquitectura de un compilador
programa fuente anlisis lxico a e generacin de cdigo intermedio o o cdigo intermedio o optimizacin de cdigo o o cdigo intermedio optimizado o generacin de cdigo o o cdigo de mquina o a

stream de tokens anlisis sintctico a a a rbol sintctico a anlisis semntico a a a rbol sintctico a

1.3.

Anlisis lxico a e

Es el primer paso, consiste en reconocer palabras Esto es una oracin. o Notar que: E inicia la oracin o separa las palabras . termina la oracin o El analizador lxico divide el programa de entrada en tokes e If x == y then z = 1; else z = 2; Tokens: If then ; 2 x z else ; == = z y 1 =

Una vez reconocidas las palabras es necesario reconocer la oracin: o Esta es una oracin corta o

Esta

es

una

oracin o

corta

articulo

sustantivo

adjetivo

sujeto

verbo

predicado

oracin o Es igual para programas If x == y then z = 1; else z = 2; x == y z 1 z 2

relacin o

asignacin o

asignacin o

predicado

then-stmt

else-stmt

condicional

1.4.

anlisis semntico a a

Una vez que se ha entendido la estructura de una oracin, es necesario eno tender el signicado de esta oracin o Sin embargo, esto suele ser muy dif para los compiladores cil Los compiladores suelen hacer un anlisis muy semntico muy simple y lia a mitado. Por ejemplo: Pedro le dijo a Juan que dejara su tarea en su casa de quien es la tarea? en la casa de quien?

2.

Anlisis lxico a e
Consiste en reconocer tokens en strings de entrada Ejemplo:

i f ( i == j ) z = 0; else z = 1; La entrada es simplemente una entrada de caracteres: \tif (i == j);\n\t\tz=0;\n\telse\n\t\tz=1; Objetivo: Particionar este string en substrings, donde los substrings son los tokes. Un Token es una categor sintctica: a a En espaol: sustantivo, verbo, adjetivo, . . . n En un lenguaje de programacin: Identicador, Entero, Palabra Reservao da, Espacio en Blanco, . . . Los tokens corresponden a una tupla <conjunto,valor>, algunos conjuntos utiles son: Indenticador: strings de letras o d gitos, partiendo con una letra Entero: un string no vac de d o gitos Palabras Reservadas: else, if, begin, . . . Espacios en blanco: Una secuencia no vac de blancos, tabular, nueva a l nea, . . .

2.1.

Rol del analizador lxico e


Analizador Lxico e token getNextToken Analizador Sintctico a Anlisis a Semntico a

Programa fuente

Tabla de S mbolos

2.2.

Realizacin o

Para el anlisis lxico, se usan expresiones regulares para especicar los toa e kens. Denicin 1. Alfabeto. Un alfabeto es un conjunto (nito) de s o mbolos Denicin 2. Palabra. Una palabra sobre un alfabeto , es una secuencia (o nita) de s mbolos pertenecientes a El conjunto de todas las palabras sobre un alfabeto se denota . Denicin 3. Lenguaje. Un Lenguaje sobre el alfabeto es un subconjunto de o (L ) Asumiremos que L, L, donde Ejemplos: Alfabeto: Caracteres del espaol n ASCII Binario {0, 1} Lenguajes: Frases del espaol n Programas en C Notar que no toda combinacin de caracteres del alfabeto espaol pertenecen o n al lenguaje espaol n Lo mismo sucede en lenguajes de programacin. Necesitamos una notacin o o para especicar cuales subconjuntos son los que nos interesan 2.2.1. Algebra de Kleene es la palabra de largo 0.

Sean L y M dos lenguajes. Denicin 4. Unin. L M = {s|s L s M } o o Denicin 5. Concatenacin. LM = {st|s L t M } o o Denimos L0 = { }, L1 = L, Li = Li1 L Denicin 6. Clausura. L = o
i=0

Li

2.2.2.

Expresiones Regulares

Denicin 7. Las expresiones regulares sobre un alfabeto es el conjunto ms o a pequeo de expresiones incluyendo: n c A|B AB A donde donde donde donde c A, B, son expresiones regulares sobre A, B, son expresiones regulares sobre A es un aexpresin regular sobre o

Las expresiones regulares denen un lenguaje segn la siguiente semntica: u a Denicin 8. Semntica de expresiones regulares. o a L( ) = {} L( c ) = {c} L(A|B) = L(A) L(B) L(AB) = {st|s L(A) t L(B)} i L(A ) = i=0 L(A ) Algunas leyes para expresiones regulares: r|s | es commutativo r|(s|t) = (r|s)|t | es asociativo r(st) = (rs)t Concatenacin es asociativa o r(s|t) = rs|rt; (s|t)r = sr|tr Concatenacin distribuye sobre | o r=r =r es la identidad para la concatenacin o r = (r|e) est garantizado en una clausura a r = r es idempotente Ejemplos: (a|b) = {a, b} (a|b)(a|b) = {aa, ab, ba, bb} a|a b, el string a o que empieza con cero o ms a terminando en una b a Sea digits = (0|1| . . . |9)(0|1| . . . |9), entoces los nmeros enteros y reales u (2321, 21213.32, 334.54E2, etc.) ser an: digits (.digits | )((E(+| | )digits)| )

2.3.

Implementacin o

A partir de una expresin regular, hacer un programa que sea capaz de o decidir si una palabra pertenece o no a el lenguaje generado por tal expresin o regular. Extendemos las expresiones regulares con: A? = A|

A+ = AA [a z] = a | b | . . . | z Exclusin, [a z] = complemento de [a z] o Veamos el caso para relaciones lgicas, la tabla de tokens es: o Lexeme Token Valor < Rel. LT <= Rel. LE = Rel. EQ <> Rel. NE > Rel. GT >= Rel. GE A partir de esta informacin, se puede construir un diagrama de transicin. o o < = 0 1 2 return LE > = otro > 3 return NE

return EQ

return LT

= 6 otro

return GE

return GT

La implementacin en C ser o a: while ( 1 ) { switch ( s t a t e ) { case 0 : c = getc ( fd ) ; i f ( c == EOF) e x i t ( 0 ) ; i f ( c == < ) s t a t e = 1 ; e l s e i f ( c == = ) s t a t e = 5 ; e l s e i f ( c == > ) s t a t e = 6 ; e l s e i f ( c == \n ) ; e l s e p r i n t f ( Error , no r e c o n o c e lexeme %c \ n , c ) ; break ; ... case 1 :

c = getc ( fd ) ; i f ( c == = ) s t a t e =2; e l s e i f ( c == > ) s t a t e =3; else state = 4; break ; case 2 : s t a t e =0; return (LE ) ; ... case 4 : u n g e t c ( c , f d ) ; / b a c k t r a k i n g / s t a t e =0; return (LT ) ; ... Para identicadores podemos usar el autmata: o letra

letra

otro

En general, todas las expresiones regulares pueden ser traducidas a autmao tas con las siguientes frmulas del algoritmo McNaughton-Yamada-Thompson: o

i : i a: s i r r|s i rs: r s a

f f

r: Con estas frmulas se construye un autmata nito no determin o o stico (NFA) de aceptacin de los tokens. Notar que cuando se reconocen varios tokens, por o ejemplo t1 y t2 , es equivalente a la expresin regular (t1 |t2 ). o Ejemplo (1|0)*1: 1 1 0

Este NFA se transforma a un DFA:

0 a 1 1

b 0 c

Luego para reconocer tokens, simplemente corro la entrada en el autmata o y voy viendo cuando acepta.

3.

Anlisis sintctico a a
Recordemos la denicin de una gramtica o a

Denicin 9. Una gramtica libre de contexto G = (T, N, S, R) consiste en: o a un conjunto de terminales T un conjunto de no terminales N un s mbolo de inicio S un conjunto de producciones R o reglas de derivacin, cada una de la o forma forma: X Y1 Y2 . . . Yn donde X N e Yi T N { } Por ejemplo, una gramtica para operaciones matemticas simples puede a a ser (1) (que tambin se puede escribir con el operador |1 como en (2)): e SE SE E E+E E EE E (E) (1) E E+E |EE | (E) (2)

E id | id Las expresiones gramaticales derivan en rboles sintcticos, por ejemplo para a a la expresin: o id id + id La derivacin se hace reemplazando los no terminales por la regla de proo duccin hasta calzar la expresin, segun el ejemplo: o o S E E + E E E + E id E + E id id + E id id + id
1 o-exclusivo

10

Esta es una derivacin por la izquierda porque a cada paso reemplazamos el o no terminal de ms a la izquierda. De esta derivacin se forma el rbol sintctico a o a a mostrado en Figura 2. E E

id

id

id

id

id

id

Figura 1: Derivacin por la deo recha

Figura 2: Derivacin por la izo quierda

De la misma forma se puede derivar por la derecha obteniendo el rbol a mostrado en Figura 1. Cuando una gramtica permite formar dos rboles distintos para la misma a a expresin, se dice que es ambiga, lo cual no es deseable (la compilacin se o u o vuelve no determin stica). Una de las formas ms usuales de corregir la ambigedad es reescribir la a u gramtica en forma no ambiga, en nuestro ejemplo podemos reescribirla dando a u prioridad a sobre +: SE E E+F |F F id F | id (E) F | (E) | (E) | id Con esta gramtica la expresion id id + id slo puede ser derivada al lbol a o a en Figura 2 To cont nue.. lef assosiation, if-then-else (3)

4.

Top-Down Parsing

En top-down parsing el arbol sintctico se va construyendo de la ra hacia a z las hojas (como en la seccin anterior). o En cada nodo no terminal se intenta aplicar alguna de las reglas de derivacin o (si una falla, pruebo la siguiente).

11

Si encuentro terminal en la regla y calza con el input, avanzo el input. El algoritmo para un no terminal A ser a: Algorithm 1 A()
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:

for all S R / S X1 X2 . . . Xk do for i = 1 to k do if Xi es un no terminal then Xi (); else if Xi = a y a es el token input actual then avanzar el input al siguiente s mbolo else retroceder puntero y probar siguiente derivacin S o end if end if end for end for Si ninguna S pas error sintctico o a

El algoritmo anterior se llama un analizador sintctico recursivo, sin ema bargo, no puede resolver gramticas recursivas por la izquierda ya que entrar a a en un ciclo innito.

4.1.

Eliminando la recursin por la izquierda o

Afortunadamente una gramtica recursiva por la izquierda se puede reescria bir para eliminar la recursin inmediata por la izquierda: o Una gramtica recursiva inmediatamente por la izquierda tiene la forma: a A A1 |A2 | . . . |Am |1 |2 | . . . |n La recursin se elimina reemplazando la produccin A por: o o A 1 A |2 A | . . . |n A A 1 A |2 A | . . . |m A | Esta tcnica elimina la recursin por la izquierda inmediata, sin embargo e o una gramtica como en la ecuacin 4 es adems indirectamente recursiva (por a o a ejemplo A Ba Aba). A Ba | Aa | c B Bb | Ab | d (4)

En general, una gramtica indirectamente recursiva por la izquierda tendr la a a forma:

12

A0 A1 1 | . . . A1 A2 2 | . . . ... An A0 n+1 | . . . Si la gramtica no tiene ciclos (A + A) y no tiene producciones , entonces a el siguiente algoritmo elimina la recursin: o Algorithm 2 Elimina Recursion Izq()
1: 2: 3: 4:

(5)

poner en algn orden los no terminales A1 , A2 , . . . , An u for i = 1 to n do for j = 1 to i 1 do reemplace cada produccin de la forma Ai Aj , donde Aj o 1 | . . . | k por: Ai 1 | . . . | k

elimine la recursin inmediata por la izquierda entre las producciones o Ai 6: end for 7: end for
5:

Usando el algoritmo 2 en (4) obtenemos la gramtica (6): a A BaA | cA A aA | B cA bB | dB B bB | aA bB | (6)

4.2.

Descenso predictivo

Para evitar el backtraking del descenso recursivo, se puede usar otro tipo de analizador sintctico que se llama analizador sintctico predictivo a a Este analizador ve el prximo input antes de decidir que regla de derivacin o o aplicar. Antes de introducir la tcnica, introduciremos dos funciones: F IRST y e F OLLOW Denicin 10. F IRST (X) = {t Terminales | X t} { | X } o Denicin 11. F OLLOW (X) = {t Terminales; | S Xt} o Computo de F IRST y F OLLOW

13

Algorithm 3 FIRST(X)
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:

if X es un terminal then F IRST (X) = {X} end if if X es un no terminal y X Y1 Y2 . . . Yn , n 1 then for all Yi | a F IRST (Yi ) Y1 . . . Yi1 do agrega a a FIRST(X) end for if Y1 . . . Yn then agrega a FIRST(X) end if end if

Notar que si F IRST (X), entonces existe una derivacin X . En o este caso se dice que X es anulable Algorithm 4 FOLLOW()
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:

$ F OLLOW (S) while Hayan cambios en los conjuntos F OLLOW do for all A X1 X2 , . . . , Xn do for all Xi | Xi es no terminal do F IRST (Xi+1 Xi+2 . . . Xn ) { } F OLLOW (Xi ) if F IRST (Xi+1 Xi+2 . . . Xn ) i = n then F OLLOW (A) F OLLOW (Xi ) end if end for end for end while

Con los conjuntos de F IRST y F OLLOW construimos una tabla de parsing predictiva con el algoritmo: Algorithm 5 M() for all A do a F IRST (A), M [A, a] = A if F IRST () then b F OLLOW (A), M [A, b] = A end if 6: end for 7: si hay celdas vacias en M , marcarlas como error.
1: 2: 3: 4: 5:

Por ejemplo:

14

E T T E

TE FT F T | (E)|id (7)

E +T E |

F IRST (F ) = F IRST (T ) = F IRST (E) = {(, id} F IRST (E ) = {+, } F IRST (T ) = {, } F OLLOW (E) = F OLLOW (E ) = {), $} F OLLOW (T ) = F OLLOW (T ) = {+, ), $} F OLLOW (F ) = {+, , ), $} id E TE T FT T F id T F T F (E) + E +T E T FT T T * ( E TE ) E $ E

E E M T T F

Con esta tabla M se puede hacer un anlisis sintctico llamado anlisis a a a predictivo gu ado por la tabla sintctica. Para hacer el anlisis sintctico a a a usamos la tabla M , un stack P y la entrada I, usamos el algoritmo 6. Esta tcnica no funciona cuando hay dos derivaciones que empiezan por el e mismo terminal, por ejemplo: S if E then S else S | if E then S (8)

Para solucionar eso se usa left factoring que es reescribir la gramtica para a posponer la desicin hasta que se tenga suciente input. La tcnica es simple o e A 1 | 2 A A A 1 | 2

5.

Notas

Es indecidible si una gramtica es ambigua (Hopcroft) una gramtica LR(0) a a es no ambigua (Hopcroft)

15

Algorithm 6 LL(M,P,I)
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21:

ip inicio de I put($, P ); put(S, P ) while head(P )! = $ do if head(P ) = ip then pop(P ) ip + + else if head(P ) es terminal then error else if M (head(P ), ip) = error then error else if M (head(P ), ip) = X Y1 Y2 . . . Yn then pop(P ) put(Y1 Y2 . . . Yn ) end if end if end if end if end while

16

You might also like