TEORÍA DE LOS LENGUAJES DE PROGRAMACIÓN TEMA 4 ANALISIS LÉXICO Objetivos 2 Objetivos: Concepto de un analizador léxico Iteración entre el AL y AS Especificación de los componentes léxicos de un lenguaje Representación de los componentes léxicos de un lenguaje Estructura de un analizador léxico Construcción de un AL Generadores automáticos de AL Teoría de los lenguajes de programación - Tema 4 Índice 3 Léxico de un lenguaje: 4.1 Concepto de un analizador léxico 4.2 Iteración o comunicación entre el AL y el AS 4.3 Categorías léxicas de un lenguaje 4.4 Funcionalidad de un AL 4.5 Definición formalizada de un AL 4.6 Construcción de un AL 4.7 Generadores automáticos de AL Teoría de los lenguajes de programación - Tema 4 4.1 Léxico - Concepto de un AL 4 Analizador léxico- se encarga de obtener y analizar las palabras que componen un texto fuente Lexema - secuencia de caracteres con significado propio obtenidos de la entrada Comp. léxico, categoría léxica (tokens) – conjunto de lexemas con significado propio, que suelen definirse como un tipo enumerado Patrón- modelo que describe el conjunto de lexemas de una categoría léxica Texto fuente Área_trianglo := (base*altura)/2 Analizador Léxico Identificador (variable) símb. asig p_abrir Identificador (variable) operador Identificador (variable) p_cerrar operador const_entera Teoría de los lenguajes de programación - Tema 4 4.1 Léxico - Concepto de un AL Tabla que representa las descripciones de las categorías léxicas, para los lexemas de entrada en el ejemplo anterior. lexema Categoría léxica Descripción - patrón área p_ident Letra seguida de letra o dígito := p_asignar := ( p_abrir ( base Ident Letra seguida de letra o dígito * p_por * altura p_ident Letra seguida de letra o dígito ) p_cerrar ) / P_div_real / 2 P_cont_ent Letra seguida de letra o dígito Teoría de los lenguajes de programación - Tema 4 4.1 Léxico - Concepto de un AL El AL asocia a ciertos componentes léxicos unos atributos que guarda en TS que son necesarios en siguientes fases de la traducción lexema Categoría léxica atributos Descripción área p_ident Nombre(área) Letra seguida de letra o dígito := p_asignar ------- := ( p_abrir ------ ( base Ident Nombre(base) Letra seguida de letra o dígito * p_por ------- * altura p_ident Nombre(altura) Letra seguida de letra o dígito ) p_cerrar ------- ) / P_div_real ------- / 2 P_cont_ent Valor(2) Letra seguida de letra o dígito El AL envía el componente léxico al AS bajo petición de este Teoría de los lenguajes de programación - Tema 4 4.1 Léxico - Concepto de un AL Para describir los patrones se utilizan la notación de expresiones regulares, como descriptores de lenguajes regulares. lexema area Categoría léxica identificador atributos Descripción Expresión regular Nombre(area) letra seguida de letra o dígito Letra(letra|dígito)* := simb_asignación -- := := ( par_abrir -- ( ( base identificador Nombre(base) letra seguida de letra o dígito Letra(letra|dígito)* * operador_* -- * * altur identificador Nombre(altura) letra seguida de letra o dígito Letra(letra|dígito)* ) par_cerrar -- ) ) / operador_/ -- / / 2 const_entera Valor(2) Dígito seguido de dígito Digito+ Teoría de los lenguajes de programación - Tema 4 4.2 Léxico – Comunicación entre AL y AS 8 Iteración entre AL y AS - se pueden destacar tres formas: Ambas actividades se realizan de forma independiente, dos algoritmos independientes. Al realizar los análisis de forma independiente, no se sabrá si la secuenciación de los componentes léxicos es correcta hasta que se pase por el análisis sintáctico con la correspondiente perdida de tiempo y memoria - Ambas actividades se realizan de forma concurrente, un único algoritmo En este caso se está cargando el analizador sintáctico de acciones que no son propias de él, tales como ignorar los comentarios, saltos de líneas. El analizador léxico es una subrutina o corrutina del analizador sintáctico, Dos algoritmo donde uno usa el otro (ambos análisis avanzan simultáneamente), es el tipo de iteración de nuestro estudio. Prog. fuente Analizador Léxico Comp. léxico Obtener Comp. léxico atributos Tabla de símbolos Teoría de los lenguajes de programación - Tema 4 Analizador Sintáctico 4.2 Léxico - Iteración entre AL y AS 9 En el análisis del programa fuente el AL debe conocer la forma de los componentes léxicos El AS debe configurar estructuralmente las piezas que recibe del AL Dicha configuración permite la relación entre ambos analizadores, pues mientras el AS pide el componente que tiene que recibir, es el léxico el que se la tiene que enviar y coincidir. Teoría de los lenguajes de programación - Tema 4 4.2 Léxico - Ejemplo de iteración entre AL y AS 10 •Los elementos de conexión se pueden ver en la siguiente gramática. - Especificación sintáctica de las sentencias de asignación G1=({ident, sim_asig, cte_ent, p_abrir, …}, N={sent_asig, Epresión, …},… Sent_asig → ident sim_asig Expresion Expression → Expresion Operador Operando |Operando Operando → ident | cte_ent|…..| p_abrir Expresión p_cerrar Operador → operador_+ | operador_* | operador_/ |…. - Especificación léxica de los identificadores G1=( ∑={ letra=a,b, digito=0,1}, {N={ident, sim_asig, cte_ent, p_abrir, p_cerrar, …},,… ident → letra ident | digito ident | letra| digito cte_ent→ digito cte_ent | digito letra → a|….|z digito→ 0|….|9 operador_+→ “+” simb_asig→ “:=” Teoría de los lenguajes de programación - Tema 4 4.2 Léxico-Ejemplo de iteración entre AL y AS 11 El alfabeto terminal de la gramática sintáctica {ident, cte_ent,…} coincide con el alfabeto no terminal de la gramática léxica. El alfabeto terminal de la gramática léxica coincide con el alfabeto del lenguaje fuente, para el que se quiere construir el analizador léxico. El alfabeto no terminal de la gramática sintáctica representan la estructura de las palabras del lenguaje, para el que se quiere construir el analizador sintáctico. En definitiva mientras que el AS se encarga de la colocación de las piezas el AL de la forma de cada una de ellas. Teoría de los lenguajes de programación - Tema 4 4.2 Léxico- Ejemplo de iteración entre AL y AS 12 Comunicación entre el A. léxico y el A. sintáctico Sent_asig ident Sim_asig Expresión Expresión Operador Operando Sim_asig Operando Oper_/ P_abrir ident A sintáctico Cte_ent Expresión P_cerrar P_abrir …. P_cerrar Oper_/ Cte_ent A. léxico area := ( base * altura ) / Teoría de los lenguajes de programación - Tema 4 2 Entrada 4.2 Léxico- Iteración entre AL y AS 13 A continuación se proponen algunas razones de esta separación: Modularidad La separación de tareas facilita el mantenimiento y mejora del traductor Simplificación del diseño Se puede simplificar una, otra o ambas fases. Permite realizar modificaciones o extensiones al lenguaje Elimina procesos innecesarios en el AS, tratando comp. léxicos especiales Los lenguajes regulares son más fácil de tratar Eficiencia Permite construir un procesador especializado y más eficiente. Eficacia con técnicas especiales de manejo de buffers por la complejidad de lectura escritura Portabilidad Las peculiaridades del alfabeto de entrada (códigos: ASCII, EBCDIC,…) Símbolos especiales y otras anomalías propias de los dispositivos de entrada pueden quedar limitados al ámbito del AL, Si se quiere cambiar begin y end por { y } solo hay que cambiar el AL Patrones complejos Centrarse en el reconocimiento de componentes complejos y resolver ambiguedades. Teoría de los lenguajes de programación - Tema 4 4.3 Léxico- Categorías léxicas de los lenguajes de programación 14 Entre las categorías léxicas habituales a usar en los LP están las siguientes: Identificadores de objetos : nombres de variables, clases , métodos, tipos definidos por el usuario,… Constantes numéricas : literales que representan valores enteros, reales etc, Literales – representan cadenas concretas de caracteres Operadores - operadores para realizar las tareas propias de cálculo Símbolos especiales - separadores y delimitadores de diferentes construcciones Palabras reservadas - Palabras con significado concreto dentro del lenguaje Categoría léxicas especiales: Comentarios - Información que se incluye en el texto del programa fuente Separadores - para separar componentes léxicos , blancos, tabuladores, fin de línea,… Fin de entrada - categoría léxica ficticia Teoría de los lenguajes de programación - Tema 4 4.4 Léxico - Funcionalidad del AL 15 Acciones principales : Leer la cadena de caracteres de la entrada (buffer), bajo petición del AS. Analizar y acumular el carácter si no se ha determinado aún un token (una categoría léxica) Entregar al AS la unidad sintáctica, junto con información adicional relevante para las siguientes fases del traductor (atributo). En lenguajes sencillos con variables globales, declaraciones,.. la información se guarda en TS. Sin embargo en lenguajes imperativos la información se guarda durante el AS. En ocasiones sólo se puede determinar un token cuando se ha recibido un carácter que pertenece al siguiente token. En este caso se debe reinsertar dicho carácter a la entrada para realizar el análisis léxico de la siguiente petición del analizador léxico ). Rechazar aquellos caracteres o conjunto de éstos que no pertenezcan al lenguaje, indicándolo mediante mensaje de error al usuario Manejar el fichero fuente ( abrir, leer, cerrar). Teoría de los lenguajes de programación - Tema 4 4.4 Léxico - Funcionalidad del AL 16 Acciones secundarias: Ignorar del programa fuente los comentarios, los espacios en blanco, tabuladores, retorno de carro, etc, y en general, todo aquello que carezca de significado según la sintaxis del lenguaje. Contar los saltos de línea y asociar los mensajes de error con el número de la línea del programa fuente donde se producen. Si el formato de línea no es libre, informar del fin de línea. La posibilidad de utilizar un preprocesador para expandir macros. ………………………………… Teoría de los lenguajes de programación - Tema 4 4.4 Léxico - Estructura funcional de un Analizador léxico 17 La función principal del AL es entregar el componente léxico al AS El resto de las funciones dependen del traductor y del propio lenguaje a procesar Interfaces en un analizador léxico: Interfaz con el analizador sintáctico - entrega del token Interfaz con entrada - leer y analizar el siguiente lexema Interfaz con la tabla de símbolos - guarda el lexema de los identificadores y valor de las constantes Interfaz con el tratamiento de errores - lee un carácter que no es del lenguaje o no encuentra ningún lexema que concuerde con los patrones especificados siguiente Fichero Comp. léxico Siguiente carácter fuente Guardar lexema Analizador Léxico Siguiente token Mensaje Error Interfaz T. S. Interfaz T.E. Tabla de símbolos Trat. de errores Teoría de los lenguajes de programación - Tema 4 Analizador Sintáctico 4.4 Léxico - Estructura funcional de un AL 18 Gestión de errores Detección: imposibilidad de concordar un prefijo de la entrada con ningún patrón. Errores más frecuentes: presencia de un carácter que no pertenece al vocabulario terminal. escritura incorrecta de un componente: identificador, constante, palabra reservada, etc. Tratamiento: (dos modalidades) Sin recuperación: se detecta el error y se cancela el análisis del programa fuente, escribiendo el mensaje de dicho error Con recuperación: se detecta un error, se toma alguna acción que permita seguir con el análisis, tras haber advertido del error. A veces se eliminan los caracteres de la entrada restante hasta que el (anal_lex (token,..)) pueda reconocer un patrón ( por ejemplo un delimitador ). En otras ocasiones se utiliza un recuperador de errores, que no es más que una “reparación” para continuar con el análisis. Teoría de los lenguajes de programación - Tema 4 4.5 Léxico - Especificación de los componentes léxicos 19 Especificación de los componentes léxicos de un analizador léxico Podemos destacar tres modalidades a la hora de la especificación del léxico: No formalizada Describiendo los componentes léxicos por medio de un lenguaje ordinario, sin aplicar reglas para su definición. Formalizada Describiendo los componentes léxicos por medio de mecanismos regulares Especificar un token de una manera formalizada, consiste en dar una expresión regular (o patrón) que describe, el conjunto de lexemas asociados A partir de las expresiones regulares podemos transformarlas en otros mecanismos regulares que facilitan la especificación de algoritmos para su reconocimiento. A la hora de la especificación lexicográfica de un lenguaje habrá que crear la relación de todas las piezas sintácticas, con sus definiciones léxicas. Gráfica Mediante la utilización de algún método gráfico, como los diagramas sintácticos que también se utilizan para especificar las características sintácticas. Teoría de los lenguajes de programación - Tema 4 4.5 Léxico - Descripción formal de las categorías léxicas 20 Simulación de las categorías léxicas mediante diagrama de transiciones Categoría léxica Identificador de java: Descripción por medio de una ER Identificador →( letra | $ | ´_´) ( letra | digito | $ | ´_´)* letra → [a-z] dígito → [0-9] Letra,digito,$,- Letra,$,q0 q1 & q2 (* Seudocódigo que simula el anterior diagrama de transiciones . *) Estado:=0; (* estado inicial *) REPETIR obtener (símbolo) CASE estado OF 0 : CASE símbolo OF Letra, $, _ : estado:=1; otro: llama_error END; 1 : CASE símbolo OF Letra, dígito, $,_: estado:=1; &: estado:=2; otro: llama_error END; ELSE llama_error END; UNTIL estado =2 or llama_error Si estado no es de aceptación llama_error Teoría de los lenguajes de programación - Tema 4 4.5 Léxico - Descripción formal de las categorías léxicas Simulación de las categorías léxicas mediante tabla de transiciónRepresentación tabular convencional de la función de transición δ, que toma dos argumentos (estado, entrada) y devuelve un estado o error letra, $, _ digito & q0 q1 error error q1 q1 q1 aceptar q2 error error error (*Pseudocódigo que simula la anterior tabla de transiciones.*) Estado:=0; (* estado inicial *) REPETIR obtener (símbolo); CASE símbolo OF letra : entrada:= letra; dígito: entrada:=dígito; & : entrada:= &; otro: llama error; END ; estado:= tabla [estado, entrada ]; If estado=”error” llama_error; UNTIL estado=”aceptar” Teoría de los lenguajes de programación - Tema 4 4.6 Léxico - Construcción de un analizador lexicográfico 22 Construcción de un analizador lexicográfico Podemos destacar tres formas básicas para construir un analizador lexico: Ad hoc. Consiste en la codificación de un programa reconocedor que no sigue los formalismos propios de la teoría de autómatas. Este tipo de construcciones es muy propensa a errores y difícil de mantener. Se basa en el uso de sentencias if y case para simular las posibilidades que se pueden dar en la lecturas de los caracteres de entrada para formar los componentes léxicos. Mediante la implementación manual de los autómatas finitos. Este mecanismo consiste en identificar la colección de categorías léxicas (tokens) en construir los patrones necesarios para cada categoría léxica, construir sus autómatas finitos individuales, fusionarlos y estructurarlos por medio de un mecanismo selector ( también llamado máquina discriminadora determinista) ,finalmente, implementar los autómatas resultantes. De forma automática. mediante un metacompilador, un generador automático de analizadores léxicos. Teoría de los lenguajes de programación - Tema 4 4.6 Léxico – Construcción de AL de forma manual 23 La comunicación entre el AL y AS: Se hace por medio de unas variables globales que devuelven el valor y el tipo enumerado de la pieza. Token (pieza) - contiene las diferentes piezas que el AL va reconociendo del texto de va a pasar al AS bajo su petición entrada y Para representar las piezas sintácticas en la implementación del analizador léxico se suele emplear un tipo enumerado formado por nombres significativos. Con el tipo enumerado se van a tener todas las piezas que se pueden reconocer por el léxico. Token= record Tipo: TipoToken; lexema:String [] end TipoToken= ( TK_ident, TK_punto, TK_mas, ….. , TK_error) Teoría de los lenguajes de programación - Tema 4 4.6 Léxico – Construcción de AL de forma manual 24 Esquema estructural de un analizador léxico Siguiente lexema Entrada Lexema analizar Fichero fuente A.S Delimitador,.. Modulo selector Mensaje de error tokens otros return(Tok) identificador literal return (Tok,val) return Tok,Lex) Teoría de los lenguajes de programación - Tema 4 4.6 Léxico - Construcción de un analizador lexicográfico 25 Condiciones iniciales Antes de llamar por primera vez el AS al AL para obtener una pieza ha de realizar: Inicializar el contenido de la tabla de palabras reservadas: Nombres de las palabras reservadas Longitud del lexema que forma la palabra reservada Representación interna de la palabra reservada Leer la primera línea y ponerla en el buffer de entrada, Saltar blancos, tabuladores (caracteres no significativos) Posicionarse al principio del lexema a analizar Teoría de los lenguajes de programación - Tema 4 4.6 Léxico - Construcción de un analizador lexicográfico 26 Lectura de entrada- gestión del buffer La lectura se realiza por líneas que se lleva a una estructura estática, así se facilita el examen de los símbolos por adelantado. Pudiendo retroceder sin mayor complejidad, llevando la contabilidad de los caracteres leídos. línea lexema apuntadores inicio posición límite Línea , vector de caracteres de la última línea leída del fichero fuente Los punteros inicio y posición señalan el primer carácter del lexema que hay que analizar El puntero posición (columna) va avanzando hasta encontrar un componente léxico Encontrado el siguiente lexema, inicio y posición se coloca en el carácter del siguiente lexema Entre inicio y posición delimitan el lexema Al devolver el componente léxico, inicio toma el valor de la posición (el primer carácter del siguiente lexema) Teoría de los lenguajes de programación - Tema 4 4.6 Léxico- Construcción de un analizador lexicográfico 27 Caracteres por adelantado Caracteres que han de examinarse más allá de la terminación de un lexema para decidir si la pieza que corresponde a ese lexema. ++, area:= El número de caracteres por adelantado necesarios para analizar un lexema determinan la complejidad del analizador léxico. Situaciones posibles que podemos encontrar en la delimitación de los lexemas: - La longitud del lexema es desconocida, su fin se encontrará cuando se llega a un carácter que no forma parte de su definición. area:= , area := - La longitud del lexema es conocida, su fin se encontrará cuando se llega al final de la cuenta de los caracteres considerados en dicho lexema. Teoría de los lenguajes de programación - Tema 4 4.6 Léxico - Construcción de un analizador lexicográfico 28 Prioridad de tokens - Cuando se está analizando un lexema se da prioridad al token con el lexema más largo que se reconoce primero: ejemplo ´+´ y ´+=´ este último es el primero, 23.45 se trata de un componente léxico constante real - Si el mismo lexema se puede asociar a dos tokens, estos patrones estarán definidos en el orden de aparición. Ejemplo: Palabras reservadas { case, while,….} formadas por una secuencia de símbolos alfabéticos Identificadores – letra (letra |dígito)* símbolos alfabéticos seguidos de alfanuméricos Teoría de los lenguajes de programación - Tema 4 4.6 Léxico - Construcción de un analizador lexicográfico 29 Forma de tratar las palabras reservadas Resolución implícita Reconociendo todas como identificadores, utilizando una tabla adicional con las palabras reservadas, que se consulta para ver el lexema reconocido es un identificador o palabra reservada Si es_palabra_reservada ( lexema, tabla_palabras_reservadas) Entonces TK_palabra_rservada Resolución explícita Se indican todas las expresiones regulares de todas las palabras reservadas y se integran los diagramas de transiciones resultantes de su especificaciones en una sola If [f|F] [o|O] [r|R] return (Token_for) If [w|W]…..[e|E] return (Token_while) ……….. [a-zA-Z]( [a-zA-Z]|[0-9])* return (Token_identificador) Teoría de los lenguajes de programación - Tema 4 4.6 Léxico - Construcción de un analizador lexicográfico 30 Módulo selector Módulo que mediante el primer carácter del lexema permite determinar por medio de una estructura de bucles anidados (CASE) qué AFD puede simular el reconocimiento del lexema de la entrada y devolver la pieza sintáctica correspondiente. En el caso de no reconocerlo se creará un mensaje de error. El módulo selector no intenta reconocer la entrada sino segmentarla conociendo el primer carácter del lexema. El módulo selector actúa repetidamente sobre la entrada, empezando siempre en cada caso en punto distinto pero siempre en estado inicial de un AFD Seleccionar según el primer símbolo del lexema y devolver el comp. léxico Modulo selector letra dígito Pal_reservadas Rec_ identificadores Rec_constantes …………….. ´´ Rec_literales 4.6 Léxico - Construcción de un analizador lexicográfico 31 En cada una de las alternativas el módulo selector ha de realizar las operaciones: - Terminar de leer el lexema - Determinar el token de que se trata y cuáles son sus atributos - Devolver el token y sus atributos en las variables globales correspondientes Diagrama de bloques de un analizador léxico Abrir ficheros Inicializar tabla Leer entrada siguiente componenteo Analizador léxico Comp_lex_finito 'a'..'z' Componente cerrar ficheros Selector autómatas AFD identificador '0'..'9 '''' Teoría de los lenguajes de programación - Tema 4 AFD cte_real o AFD cte entera AFD cadena 4.6 Léxico - Implementación manual de un AL 32 Antes de llamar por primera vez al AL el AS para obtener una pieza el AL hace: InicializarAnalizadorLexico Inicializar el contenido de la tabla de palabras reservadas: Nombres de las palabras reservadas Longitud del lexema que forma la palabra reservada Representación interna de la palabra reservada Leer la primera línea y ponerla en el buffer de entrada Saltar blancos (caracteres no significativos) Obtención de un componente léxico (pieza) ObtenerPieza; Posicionarse al principio del lexema a analizar Obtener el componente léxico del texto fuente Teoría de los lenguajes de programación - Tema 4 4.6 Léxico - Implementación manual de un AL al que inicializa el AS 33 Procedure Analisis_Sintáctico; Begin InicializarAnalizadorLexico; (*inicializar palabras reservadas, saltar blancos *) ObtenerPieza; (* primera pieza*) AnPrograma; (* símbolo inicial de la gramática*) ComprobarFinalAnálisis; (* comprobar si pieza es p_ultima *) End; Para obtener una pieza a petición del AS, el analizador léxico determinará de que token se trata para comparar con el pedido del AS Teoría de los lenguajes de programación - Tema 4 4.6 Léxico - Implementación manual de un AL 34 Módulo central que devuelve la pieza correspondiente al lexema de entrada ObtenerPieza(); … BuscarInicio Inicio := posición; case linea [inicio] of Letra: tratar_id ; Digito: tratar_cte ; ‘+’ : pieza:=TKN_SUMA; ……………….. ‘<’: Ver_si_menor ‘{‘ : begin saltarComentario ; Obtener Pieza ‘EOF’ : TKN_EOF; else begin errorlexicográfico ; ObtenerPieza ; ……. Teoría de los lenguajes de programación - Tema 4 Lexicografía - Implementación manual de un AL 35 Ejemplo simple: main nombre_fuente is <objetos> begin <operaciones> end AnPrograma, procedimiento asociado al símbolo inicial de la gramática sintáctica, trata de construir de una forma ficticia el árbol sintáctico Procedure AnPrograma; begin Aceptar (prmain); Aceptar (pId); Aceptar (prIs); AnObjetos; Aceptar(prbegin) AnOperaciones; Aceptar (prend); end. Comprueba si la pieza pedida por el AS es la obtenida por el AL Procedure Aceptar (p: piezaSint); begin If pieza= p then ObtenerPieza() else ErrorSintactico end; Teoría de los lenguajes de programación - Tema 4 Lexicografía- Implementación manual de un AL 36 Analiza el tipo de objeto Procedure AnObjetos; Begin IF pieza= prType THEN AnDefTipo; IF pieza= p_id THEN AnDefVar; IF pieza= prPrcedure THEN AnDefProcedure; IF pieza= prFunction THEN AnDefFunction; ……………. End; Procedure AnOperaciones(); ……………………………… ComprobarFinalAnálisis; La tarea de reconcimiento de los tokens del texto fuente concluye con (EOF). Cuando el AL encuentra esa marca, ha de indicar AS de alguna forma que ha concluido el reconocimiento de tokens en el texto fuente. Para ello, el AL pone en la variable token un símbolo especial, él cual va a servir al modulo selector de dicho analizador para que devuelva al sintáctico una pieza ficticia (p_ultima). Pieza que el analizador sintáctico espera para finalizar, en otro caso se producirá una situación de error. Teoría de los lenguajes de programación - Tema 4 Ejemplo - Estructura de un lenguaje 37 main nombre_fuente is <objetos> begin <operaciones> end *objetos: Tipos type tipo_vector is array [ cte_ent .. cte_ent ]of <tipo_basico> ; tipo_basico - integer,real,boolean o string type tipo_registro is record <componentes> end record ; componente - nom_camp1,nom_camp2,..: <tipo_basico> ; variables nom_var0 , nom_var1 ,... : <tipo> ; tipo – tipo_basico, vector, registro ……………………… * operaciones: op. control while <expression> loop <operaciones> end loop ; loop <operaciones> end loop ; op. Selección if<expression>then<operaciones>else<operaciones> end if ; case expresión is <alternativas> end case ; <alternatives> when cte_ent | cte_ent |….: op. e/s put ( expr0, expr1,...) ; get ( var0 , var1 ,...) ; asignación var_0 , var_1 ,... := expresión ; llamada Llama_proc ( par_act1 , par_act2 , ... ) ; expresión operandos - variables, constantes enteras, reales, lógicas y operadores +, -, *,div, <=,!=,… Teoría de los lenguajes de programación - Tema 4 Ejemplo - Componentes léxicos del lenguaje 38 Componentes léxicos del lenguaje Componentes léxicos finitos: - palabras reservadas: main,begin,end, …… - operadores: =,<=,!=,*,… - separadores: (,[,’,’,’;’,… -… Componentes léxicos infinitos: - identificadores: { lenguaje regular } – componente léxico ident - constantes enteras : { lenguaje regular } – componente léxico cte_ent - constantes reales: { lenguaje regular } – componente léxico cte_real - cadena: { lenguaje regular } – componente léxico cadena Teoría de los lenguajes de programación - Tema 4 Ejemplo - Definición léxica que denota los identificadores 39 Palabras que comienzan por letra minúscula seguida de letra , digito o el símbolo subrayado (_), no pudiendo darse mas de dos subrayados consecutivos , ni finalizar en subrayado Definición regular que denota los identificadores - ident : Ident: letra_min (letra_min| digito |_letra_min| _digito|_ _ letra_min| _ _digito)* letra_min: 'a'..'z' ; digito : '0'..'9' - Autómata finito determinista AFD que reconoce los identificadores - ident a-z,0-9 a-z q0 _ q1 _ q2 a-z,0-9 a-z.0-9 Teoría de los lenguajes de programación - Tema 4 q3 Ejemplo - Implementación de un AL 40 Analizador léxico independiente del analizador sintáctico Abrir ficheros Diagrama de bloques de un analizador léxico Leer entrada Reconocer palabra Comp_lex_fin 'a'..'z' Escribir salida Selector autómatas '0'..'9 '''' cerrar ficheros AFD identificador AFD cte_real o AFD cte entera AFD cadena Teoría de los lenguajes de programación - Tema 4 Ejemplo - Implementación de un AL en C++ 41 #include <stdio.h> #include <string.h> #include <cTipo.h>.. #define LONG_BUFFER 1024 #define LONG_LEX … #define PALABRAS_RES … typedef enum { TK_BEGIN, TK_END, TK_PARD, TK_ID, TK_NUM, TK_EOF, TK_ERROR,… } tipo_token; typedef enum { INICIO, IN_ID, IN_NUM, IN_PARD, IN_PARI, IN_EOF, ERROR, ACEPTACION,… } estado; typedef struct { tipo_token tipo; char lexema[LONG_LEX]; }Token; Token PalabrasReservadas[PALABRAS_RES]={ {TK_BEGIN, "begin"}, {TK_END, "end"}, … }; int nlinea=0; int ncolumna=0; char buffer[LONG_BUFFER]; char *nombreFichero;//Nombre del fichero fuente FILE* entrada; //Fichero de entrada Teoría de los lenguajes de programación - Tema 4 Ejemplo - Implementación de un AL en C++ 42 Lexico( char * nombreFichero); Token EsPalabraReser (char *); char obtenerCa r(FILE *); void retocederCar (void); Token obtenerToken(FILE *); int esDelimitador (char c) ; //devuelve 1/0 si c es un blanco, tab, \n }; Lexico::Lexico(char *NombreFichero) { entrada=fopen(unNombreFichero, "rt"); if((entrada==NULL)) { cout<<"No se puede abrir el archivo"<<endl; system("pause"); exit(-2); } } Token EsPalabraReservada(char *s) { int i=0; Token token; if (strcmp(s, PalabraReservadas[i].lexema)==0) {return(PalabrasReservadas[i]);} strcpy(token.lexema, s); token.tipo=TKN_ID; return(token); } Teoría de los lenguajes de programación - Tema 4 Ejemplo - Implementación de un AL en C++ 43 char obtener_Car( FILE *fp) { char c; static int n; //longitud línea leida, se guarda valor de llamada a llamada if (( ncolumna==0) || (ncolumna==n) ) { if (NULL!=fgets(buffer, Long_Buffer, fp)) /* lee hasta el salto de linea */ { n=strlen(buffer); ncolumna=0; nlinea++;} else { return(EOF); } } c=buffer[ncolumna++]; return (c); } void retrocederCar() { ncolumna−−;} int esDelimitador(char c) { char delimitadores[3]={’ ’, ’\t’, ’\n’}; int i; for (i=0;i<3;i++) { if (c==delimitadores[i]) {return(1);} return (0);} Teoría de los lenguajes de programación - Tema 4 Ejemplo - Implementación de un AL en C++ 44 ******************************************************************* Token obtenerToken (FILE *fp) { char c; Estados estado=INICIO; Token token; int indice=0; //indice al caracter actual del lexema while (estado!=FINAL) { switch (estado) { case INICIO: { c=obtenerCar (fp); while ( esDelimitador (c)) {c=obtenerCar(fp);} if (esAlfabetico ((int) c)) { estado=IN_ID; token.lexema[indice++]=c;} else if esDigito ((int) c)) { estado=IN_NUM; token.lexema[indice++]=c;} else if (c==’)’) { token.tipo=TKN_RPAREN; estado=FINAL; token.lexema[indice++]=c;} else if (c==’:’) {estado=IN_ASSIGN;token.lexema[indice++]=c;} else if (c==’=’) {estado=TKN_ASSIGN;estado=FINAL; retrocdeCar(); indice--;} ………………………………. else if (EOF==c) {token.type=TKN_EOF;estado=FINAL } break; } Teoría de los lenguajes de programación - Tema 4 Ejemplo - Implementación de un AL en C++ 45 case IN_ID: { c=obtenerCar (fp); token.lexema[indice++]=c; if (! ( esAlfanumerico( (int) c) ) || (c==’_’) ) ) Token.ipo=TKN_ID; estado=FINAL; retrocedeCar(); indice−−; token.lexema[indice]=’\0’; token=esPalabraResser(token.lexema); } break; } case IN_ASSIGN: {c=obtenerCar(fp);token.lexema[indice++]=c; if (c==’=’) { token.tipo=TKN_ASSIGN; estado=FINAL; indice−−; } break; } …………………………… default: { token.tipo=TKN_ERROR; estado=FINAL; token.lexema[indice++]=c; } } //end switch }//end while if (token.tipo==TKN_ERROR) { fprintf (stderr, "\nLinea %d:%d, Error: \n", nlinea, ncolumna, c);} token.lexema[indice]=’\0’; //FINALIZA LA CADENA return(token); } }//end obtenerToken Teoría de los lenguajes de programación - Tema 4 Ejemplo - Implementación de un AL en C++ 46 I********************************** int main (int argc, char **argv){ FILE *fp; Token token; if (argc==2) { if ( NULL== (fp= fopen(argv[1],"r")) ) { fprintf(stderr, “error en apertura de fichero\n", argv[1]); return(0); } else { token=obtenerToken(fp); while (TKN_EOF != token.tipo) { fprintf(stderr,"(%d,%s) ", token.tipo, token.lexema); token=obtenerToken (fp); } printf("\n%d lineas analizadas", nlinea); return(0); } Teoría de los lenguajes de programación - Tema 4 Ejemplo - Implementación de un AL en C++ 47 #include <iostream.h> #include “ cSintactico.h” using namespace std: Int main (){ cSintactico anSintactico(“entrada.txt”); return 0; } #ifndef “ cSintactico.h” #define “ cSintactico.h” #include “cLexico.h” using namespace std: class cSintactico { private: cLexico anLexico: public: aSintactico( char * fuente); aSintacitco(); void anPrograma(); ……………………….. cSintactico::cSintactico( char * fuente){ lexico (fuente); token =lexico.obtenerToken() programa(); } #ifndef “ cLexico.h” #define “ clexico.h” #include “cLexico.h” using namespace std: File * f; Token token; public: cLexico(); -------Teoría de los lenguajes de programación - Tema 4