1 Compiladores e Intérpretes Análisis Léxico Sebastian Gottifredi 2017
Organizacion Esquema General de Análisis Léxico Tokens Especificando Tokens Expresiones Regulares Reconociendo Tokens Autómatas Finitos Implementando Analizadores Léxicos 2
Esquema General del Análisis Léxico 3
Esquema General del Análisis Léxico El programa fuente es una cadena de caracteres Tenemos que reconocer si esa cadena pertenece al lenguaje utilizando las reglas de sintaxis del lenguaje Las reglas de sintaxis se expresan en términos de palabras if(id1>10) var= hola ; else print chau ; //fin TEXT: if(id1>10) var =_ hola ; else print_ chau ; //fin 4
Esquema General del Análisis Léxico if(id1>10) var=_ hol a ; else print_ chau ; //fin Analizador Léxico El Analizador Léxico es el encargado de leer directamente el texto del programa fuente Busca construir esas palabras o subcadenas agrupando caracteres Elimina blancos, separadores y comentarios Informa de Errores Léxicos if ( id > num ) id = String ; else print String ; 5
Esquema General del Análisis Léxico El Analizador Léxico funciona por demanda! El analizador sintáctico irá solicitándole palabras Analizador Léxico NEXT! id Analizador if( Sintáctico if(id1>10) var=_ hol a ; else print_ chau ; //fin 6
Esquema General del Análisis Léxico En esta etapa también se detectan los errores léxicos Estos errores se producen, por ejemplo, cuando: Aparece un caracter extraño que no es una palabra del lenguaje (por ejemplo: el carácter en un código java) Cuando una de las palabras del lenguaje está mal formada (por ejemplo en Pascal 123ab es un número o identificador mal formado) Se detecta un comentario multi-línea sin cerrar 7
Tokens 8
Tokens Las palabras o subcadenas agrupadas por el analizador léxico son llamadas Lexemas Son clasificadas en Tokens Los Tokens caracterizan subcadenas con un rol dentro del lenguaje de programación Por ejemplo: Enteros, Strings, Identificadores, palabra clave IF, Igual, etc.. 9
Tokens Caracterizan conjuntos de subcadenas! Por ejemplo: Token Identificador: subcadena que empiezan con una letra y sigue con una sequencia de letras y/o dígitos Ejemplos: id1 var myvar amigo a1244 Token String: subcadena que comienza con, sigue con una secuencia de caracteres, y termina con Ejemplos: hola me#@!!& id1 10
Tokens Otros son identificados por una única subcadena Por ejemplo: Token Igual: subcadena con el caracter = Token Mayor o Igual: subcadena con los carácteres >= Token Palabra Clave IF: subcadena con los caracteres if Los espacios, tabs, enters (blancos) y comentarios NO son tokens! 11
Tokens La salida del analizador léxico ante un pedido del analizador sintáctico es un token. El token retornado está acompañado por el lexema caracterizado por ese token. El lexema es un atributo del token retornado! Como los blancos y comentarios no son tokens, no son retornados por el analizador léxico! 12
Especificando Tokens Expresiones Regulares 13
Especificando Tokens Expresiones Regulares Para implementar el analizador léxico de un lenguaje de programación tenemos que identificar sus tokens Describir los lexemas que caracterizan, es decir, dar una especificación para los tokens del lenguaje El formalismo usual para esta tarea son los Lenguajes Regulares Por qué estos lenguajes? Son lenguajes formales menos complejos, más simples y más eficientes capaces identificar los lexemas. 14
Especificando Tokens Expresiones Regulares Los lenguajes regulares se notan con expresiones regulares (ER): Dado un alfabeto una expresión regular r puede ser: Un caracter c de la cadena vacía Dadas dos expresiones regulares r1 y r2 en se puede construir como: r1r2 (secuencia) r1 r2 (opción) r1* (clausura) r1 + (clausura positiva) Se puede usar paréntesis para indicar agrupamiento o precedencia 15
Especificando Tokens Expresiones Regulares El conjunto de cadenas o lenguaje que genera con una expresión regular r se denota L(r), Por ejemplo, si r3 = a(b c) tenemos que L(r3) = {ab, ac} Qué representa rd = (0 1 2 3 4 5 6 7 8 9)? Cómo es L(rd)? Cómo es la expresión regular re para un entero? y L(re)? Cómo sería la de un identificador? La de mayor? La de mayor o igual? Pizarrón! Por simplicidad usamos [0..9], [a..z] y [A..Z] para caracterizar dígitos, letras minúsculas y letras mayúsculas respectivamente 16
Reconociendo Tokens Autómatas Finitos 17
Reconociendo Tokens Autómatas Finitos Los Autómatas Finitos (AF) reconocen cadenas de los lenguajes regulares Un autómata finito esta formalmente caracterizado por: Alfabeto Conjunto de estados E Función de transición de estados T: E x E Estado inicial I Conjunto de estados finalizadores F E Estado Estado Inicial Estado Aceptador Transición c 18
Reconociendo Tokens Autómatas Finitos El AF va aplicando transiciones a medida que consume los caracteres de la cadena de entrada Partiendo del estado inicial, si el autómata puede consumir toda la toda la cadena y queda en un estado finalizador acepta la cadena sino rechaza la cadena b a e0 e1 e2 a a abba aabb abbaa 19
Reconociendo Tokens Autómatas Finitos Dada una ER podemos construir un AF que reconoce el lenguaje generado por esa expresión Cómo sería el autómata para reconocer X? donde X es: El operador igual El operador mayor o igual Palabra clave else Enteros Identificadores Pizarrón! 20
Implementado Analizadores Léxicos 21
Implementando Analizadores Léxicos Para implementar el Analizador Léxico vamos a usar los AF que reconocen las ER asociadas a cada token del lenguaje Cómo lo implementamos? Recibe y va leyendo el programa fuente Funciona por demanda Ante un pedido, reconoce un token y lo retorna Al retornar un token puede no haber terminado de procesar el programa fuente 22
Implementando Analizadores Léxicos Ante un pedido el Analizador Léxico debería poder reconocer cualquier token válido Entero e0 e1 e1 Entero Pizarrón! Id Mayor o Igual Mayor e0 e1 letra letra o > = e0 e1 e2 e0 > e1 e0 el Analizador Léxico se basará en un AF que se construye uniendo adecuadamente los AFs de cada ER letra > > e3 e5 e2 = letra o e4 Mayor Id Mayor o Igual 23
Implementando Analizadores Léxicos Hay tokens que comparten prefijos Mayor o Igual Mayor > = e0 e1 e2 e0 > e1 No determinista! > = e0 e3 e4 > e5 > 24
Implementando Analizadores Léxicos Hay tokens que comparten prefijos Mayor o Igual > = e0 e1 e2 > = e0 e3 e4 Mayor e0 > e1 > 25
Implementando Analizadores Léxicos Los estados terminadores deben retornar el token reconocido (con su lexema) e0 Analizador Léxico letra e1 e2 > = e3 letra o e4 Next Token! >=5 26
Implementando Analizadores Léxicos Los estados terminadores deben retornar el token reconocido (con su lexema) Analizador Léxico e1 e0 letra e2 > = e3 letra o e4 >=5 27
Implementando Analizadores Léxicos Los estados terminadores deben retornar el token reconocido (con su lexema) Analizador Léxico e1 e0 letra e2 letra o > = e3 e4 op>= >= >=5 28
Implementando Analizadores Léxicos La cadena de entrada puede contener más de un token Analizador Léxico e1 Next Token! Analizador Léxico e1 Next Token! e0 letra e2 > = e3 >=5 letra o e4 Al iniciar el reconocimiento de un token debe estar en el estado inicial e0 letra e2 > = e3 >=5 letra o e4 29
Implementando Analizadores Léxicos Reconocer el token más grande posible Analizador Léxico e1 Next Token! e0 letra e2 > = e3 543>= letra o e4 30
Implementando Analizadores Léxicos Reconocer el token más grande posible e0 Analizador Léxico letra e1 e2 > = e3 543>= letra o e4 Estoy en un estado terminador pero tengo que seguir armando el token! Aún no hay que retornar nada! 32
Implementando Analizadores Léxicos Reconocer el token más grande posible Analizador Léxico e1 e0 letra e2 > = e3 543>= letra o e4 33
Implementando Analizadores Léxicos Reconocer el token más grande posible e0 Analizador Léxico letra e1 e2 > = e3 543>= letra o e4 Termino porque mirando el caracter (sin consumirlo) no puedo seguir armando el token int 543 34
Implementando el Analizador Léxico Los blancos y comentarios no son tokens Aun así el Analizador Léxico debe ser capaz de procesarlos, ya que: Se pueden usar como separadores entre tokens (ids, números, etc) Para ignorarlos hay que consumirlos Pueden tener errores! (solo en comentarios) El autómata debería tener transiciones para realizar estas tareas Cómo consumirían los espacios, tabs y enters? Pizarrón! 35
Implementando el Analizador Léxico Cómo detectamos un error léxico? e0 Analizador Léxico letra e1 e2 > = e3 letra o e4 Estando en un estado no terminador y el caracter actual no se corresponde con ninguna transición ~ Cómo detectamos el error de un comentario multilínea sin cerrar? 36
Implementando el Analizador Léxico Estrategias para codificar el autómata Subprogramas x Estado Swtich/Case Tabla Herramientas Automáticas 37
Implementando el Analizador Léxico Subprogramas: para cada estado ei, creamos una función ei(): Si caracteractual = c1 Agregar caracteractual a lexemaactual Consumir caracter retornar el resultado de ej() Sino Si caracteractual = cn Agregar caracteractual a lexemaactual Consumir caracter retornar el resultado de ek() Sino Si ei es un estado terminador retornar token asociado a ei Sino ERROR! ei ej ek Pizarrón! NextToken(): lexemaactual = vacio retornar el resultado de e0() 38
Implementando el Analizador Léxico Switch/Case: la función nexttoken captura todos los estados Loop switch (estado): case ei: Si caracteractual = c1 Agregar caracteractual a lexemaactual Consumir carácter estado = ej break Sino Si ei es aceptador retornar token de ei Sino ERROR! case ej: end loop ei ej ek 39
Implementando el Analizador Léxico En general implementar las palabras claves del lenguaje utilizando sus AF es problemático porque: Requiere muchos estados (casi uno por letra de la palabra clave) Hay que fusionar esos estados entre sí y con los de identificadores En la mayoría de los lenguajes las palabras clave son prácticamente identificadores especiales Cómo podemos aprovechar esto? Cuando armamos un token identificador controlamos si no es una palabra clave en una tabla de palabras clave! 40