Sp u3

Page 1

Análisis Léxico M.C. Juan Carlos Olivares Rojas


Agenda

• Introducción a los Autómatas finitos y expresiones regulares. • Analizador de léxico. • Manejo de localidades temporales de memoria (buffers). • Creación de tablas de símbolos. • Manejo de errores léxicos. • Generadores de código léxico: Lexy Flex.


Ensamblado en Java

• ¿Qué es un autómata? Es un modelo matemático que sirve para determinar si una cadena pertenece a un lenguaje no. • A = (Q, Σ, &, F) donde • • • •

Q = conjunto de estados Σ= alfabeto de entrada & = funciones de transición F = conjunto de estados de aceptación


AFD

• La característica que tienen los Autómatas Finitos Deterministas (AFD) es que solo existe una función de transición definida para un símbolo de entrada. Esto elimina ambigüedades • Una expresión regular es una forma abreviada de representar lenguajes: • a Representa el lenguaje de las letras a • a* Representa el lenguaje que tiene 0 hasta n a’s


AFD

• El principio de diseño de un Lenguaje de Programación radica en la utilización de un autómata genérico y de ese autómata partir de varios subautómatas. • Los autómatas suelen representarse expresiones regulares. Ejemplo: • Identificador: letra (letra | digito | gb)*

con


AFD

• Generar la expresión regular para identificar URL válidas. • Ejemplo: • http://www.patito.com/recurso.php?id=0 • ftp://ftp.sindominio.com/pub/archivo • file://casa.decera.com/recurso+20+dos


AFD

• Dada la siguiente expresión regular como queda el autómata que lo representa: • Alpha (alpha | num | sim)* • Donde alpha es un carácter de a..Z • Num es un dígito de 0 a 9 • Sim es uno de los siguientes símbolos


AFD

• ¿Cómo se programa un autómata? • Los autómatas tienen su representación en forma de grafos que a su vez se representan en forma de tablas de transiciones, se cuenta con un estado inicial y una función de siguiente estado. Al terminar de leer la cadena se verifica si el estado es algún estado de aceptación.


Práctica 5

• Programar un autómata para reconocer la URLs que son válidas. • Se deberá tener una matriz de transiciones y una función de estado siguiente. No se permitirán validaciones por otros medios. • Se deberán leer cadenas contenidas en un archivo de texto plano y deberá devolver que cadenas si son URLs


Expresiones Regulares y Gramáticas

• ¿Qué similitudes existen entre las expresiones regulares y gramáticas? • Una gramática sirve para generar cadenas de un determinado lenguaje pero también sirve para generarla. • Existente una relación uno a uno entre Lenguajes, Autómatas, Expresiones regulares y gramáticas.


Analizador Léxico

• El análisis léxico es la primera fase de la compilación. • Un analizador léxico: • Lee caracteres de entrada y generar como salida una secuencia de componentes léxicos (generalmente representados por números).


Analizador Léxico

• Un analizador léxico:

• Elimina espacios en blanco (considerados por el lenguaje como tabuladores, etc.) • Eliminar comentarios • Proporcionar información acerca de errores léxicos (caracteres inexistentes o tokens inexistentes)


Tabla de Símbolos

• La tabla de símbolos se compone de un lexema y un identificador del componente léxico. • Los componentes léxicos se conforman de un patrón (expresión regular que lo valida). • El patrón se codifica como un autómata.


Tokens, Lexemas y Patrones


Análisis Léxico

• También recibe el análisis lineal, se llama léxico o exploración. • Ejemplo: • Posicion:= inicial + velocidad * 60 • Posicion: identificador • := símbolo de asignación • Inicial: identificador


• • • •

Análisis Léxico

+: signo de suma Velocidad: identificador *: signo de multiplicación 60: numero

• Las palabras clave de muchos lenguajes son lexemas tal cual. Por ejemplo para reconocer un token if, se necesita de un patrón “if”.


Analizador Léxico

• La tabla de símbolo debe insertar y buscar componentes léxicos (aunque en el análisis léxico sólo se inserten, se debe recordar que la tabla de símbolos es utilizada por el analizador sintáctico y por otras fases del proceso de traducción. • Los componentes léxicos se tratan como terminales de la gramática del lenguaje fuente. Existen muchas herramientas para utilizar expresiones regulares.


Definiciones Regulares

• Dan nombres a las expresiones regulares. Permiten referenciar las expresiones regulares recursivamente Ejemplo: Digito  1|2|3|4|5|6|7|8|9|0 Entero  dígito+ Decimal  dígito+ | .dígito+ E (+ |- | ε) dígito+ • Real  entero (decimal | ε) • • • •


Abreviaturas

• * cero o más casos

• + uno o más casos • ? 0 ó 1 vez (opcional) • [a-zA-Z] mayúsculas y minúsculas • [0-9] dígitos


Definiciones Regulares

• Digito[0-9]

• Entero digito+ • Decimal .digito+exponente? • Exponente (E | e) (+|-)?digito+ • Real  entero decimal?


Analizador LĂŠxico


Examen 2

• Entrega: viernes 9

• Análisis de Requerimientos dado un archivo *.class correcto, encontrar los mnemónicos que tiene disponible el ensamblador (alias javap – c Archivo) • Complejidad al detectar el encabezado (formato *.class) y después la complejidad del código


Examen 2


Examen

• Se puede observar que de este pequeño hola mundo se tienen dos métodos. • El primero de ellos de 5 bytes, revisando sus mnemónicos se puede observar que su códigos de operación en byte es: • 0x2a • 0xb7 0x00 0x01 • b1


• • • • •

BB FE AF EA 77 03 05 2a b7 00 01 b1 12 Formato valido aload_o Invokespecial 0 1 Return


Examen 2


Examen 2

• Esto se puede buscar en el archivo *.class. • El detalle radica en que el código no viene sólo sino en una estructura Attribute denominada code_attribute (ver unidad pasada). Nótese por ejemplo que un byte antes del código marcado nos indica el tamaño del código de ese método.


Examen 2

• Reformulación del proyecto. Dado nuestro propio formato comenzará de la siguiente forma: 4 bytes de número mágico: BB FE AF EA, 2 bytes para indicar la versión y subversión del compilado, 2 bytes para indicar el tamaño del código, instrucciones del ensamblador de java y un byte al final como código de comprobación (tamaño total del archivo % 255).


Examen 2

• Se deberá validar que sus archivos *.obj tengan este formato. Se hará la impresión de los mnemónicos contenidos (puede ser modo texto o visual). • Se ocupa conocer el tamaño de los mnemónicos • ¿Para el viernes autómata o examen 2? Por lo tanto que queda para el lunes.


Mnemónicos en Java

• astore <varnum>: saca de la pila una referencia. • baload: recupera un byte de un arreglo de bytes y lo convierte a un entero que se coloca en la pila de operandos. • bipush <n>: coloca un entero de 8 bits en la pila (lo convierte a un entero de 32 bits)


Mnemónicos en Java

• d2f: saca de la pila un flotante de doble presición para convertile a un flotante sencillo y volverlo a colocar en la pila (esta operación puede causar pérdida de precisión). • dadd: toma dos dobles de la pila, los suma y coloca el resultado en la pila. • dup_x1: duplica el valor de la cima de la pila y la coloca una posición debajo.


Mnemónicos en Java

• fneg: niega un flotante.

• goto <label>: brinca a la dirección especificada por la etiqueta (cadena de texto), label ocupa dos bytes por lo que esta instrucción es de 3 bytes. • iand: realiza una operación lógica “Y” entre dos enteros en la cima de la pila, el resultado lo deja en la pila.


Mnemónicos en Java

• ifeq <label>: realiza un pop en la pila para comparar si el valor apuntado por etiqueta es igual al de la pila. Esta es una instrucción de 3 bytes • istore <varnum>: saca un valor de la pila y lo almacena en una variable local. • jsr_w <label>: salta a una subrutina, label hace referencia a un valor doble, por lo que esta instrucción es de 5 bytes.


Manejo de localidades temporales de memoria (buffers) • La forma más fácil de realizar el escanner de un código es a través de carácter por carácter pero esto es sumamente ineficiente. • La forma más eficiente es realizar una copia a la memoria de todo el código fuente.


Manejo de Buffers

• La desventaja de este último enfoque es que la gran mayoría de las ocasiones es impráctico por las dimensiones de los programas. Para solucionar este problema se sugiere utilizar buffers. • Existen muchas formas de dividir el trabajo, pero siempre se deberá llevar dos punteros, uno al carácter actual y otro al inicial del lexema.


Creación de Tabla de Símbolos

• En general el proceso de análisis léxico puede describirse simplemente como el reconocimiento de caracteres de un lenguaje para generar una tabla de símbolos. • El primer paso consiste en crear un escáner, el cual se encarga de verificar que no existan caracteres no presentes en el lenguaje.


Tabla de Símbolos

• La tabla de símbolos va a guardar cada palabra analizada, la va identificar como un lexema y le va asociar un identificador numérico para posteriormente utilizarlo. • La tabla de símbolos debe estar en memoria para realizar un análisis rápido.


Errores Léxicos

• Son pocos los errores que se pueden detectar al hacer análisis léxico • Por ejemplo:

– fi (a == f(x))

• ¿Es error léxico? No, es error sintáctico • Puede existir algún error si ninguno de los patrones no concuerda con el prefijo de entrada.


Técnicas de Recuperación de Errores • Borrar un carácter extraño • Insertar un carácter que falta • Reemplazar un carácter incorrecto por otro correcto • Intercambiar dos caracteres adyacentes


Técnicas para realizar analizadores léxicos

• Utilizar un analizador léxico como LEX. El generador se encarga de manejar buffers • Escribir el analizador en un lenguaje de alto nivel haciendo uso de la E/S del lenguaje • Escribir el lenguaje ensamblador y manejar explícitamente la E/S


Patrones en Java

• El lenguaje Java es un lenguaje de alto nivel de propósito general que cuenta entre sus cosas con un motor para reconocimento de patrones de texto. • El paquete javax.util.regex.*; el cual dispone de dos clases: Pattern y Matcher.


Patrones en Java

• La clase Pattern se utiliza para especificar los patrones y la clase Matcher se utiliza para procesar las cadenas y ver si coinciden con el patrón. • El método compile de la clase Pattern permite especificar la expresión regular utilizando prácticamente la misma simbología de comodines de expresiones regulares.


Patrones en Java

• Un objeto de la clase Matcher se crea a través del método matcher() del objeto instanciado de la clase Pattern. • La clase matcher tiene los siguientes métodos: matches para una coincidencia exacta, lookingAt cuando se encuentra el patrón en parte de la cadena, find permite buscar subcadenas que coincidan con el patrón.


Patrones en Java

• El método find permite utilizar los métodos start y end para encontrar la primera y última coincidencia. • El método replaceAll(), permite cambiar una subcadena por otra.


Patrones en Java

import java.util.regex.*; public class ValidarEmail { public static void main(String[] args) throws Exception { String cadena = “jcolivar@hotmail.com"; Pattern p = Pattern.compile("\\w\\+@\\w\\.\\w"); Matcher m = p.matcher(input); if (m.find()) System.err.println("Las direcciones email no empiezan por punto o @"); } }


Generadores de Código Léxico

• FLEX es la versión de software libre del popular generador de analizadores léxicos LEX para sistemas *NIX, genera código C aunque existen otras herramientas que generan código en otros lenguajes (Jflex para Java) • Analizador.lex  flex lex.yy.c Programa ejecutable analizador • $gcc lex.yy.c –o analizador –l fl

gcc


Estructura Lex

%{ Definiciones globales ‘C’ }% Definiciones flex %% Acciones %% Código ‘C’ auxiliar


Definiciones de Expresiones Regulares • %% Separadores de secciones • Def expresión • Acciones • {def} {código ‘C’ asociado} • “@”{código ‘C’ asociado}


Ejemplo Scanner Flotante

%{ #include <stdio.h> int ocurrencias; %} digito [0-9] punto [\.] exp [eE] signo[\+\-] digitos {digito}+


Ejemplo de Scanner Flotante

decimal {punto} {digitos}({exp}{signo} {digitos})? flotante {digitos}{decimal}? %% {flotante} { printf(“flotante encontrado\n”); ocurrenicas++; } “@” { printf(“Arroba\n”); } . { printf(“Inválido: %s\n”, yytext); } %%


Ejemplo de Scanner Flotante

int main(int argc, char* argv[]) { FILE *f; F = fopen(argv[1], “r”); yyin= f; while(yylex()); printf(“%dflotantes encontrados\n”, ocurrencias); fclose(f); return 0; }


JFlex

• Es otra forma de incluir expresiones regulares para crear scanners pero ahora con lenguaje java. • Se tiene que manejar una sintaxis muy similar a lex con sus respectivas variantes. • Las expresiones regulares se definen dentro de un archivo con extension .lex o jflex (realmente la extensión no importa). A continuación se muestra un ejemplo.


JFlex

/*Aqui van todas las bibliotecas*/ import javax.swing.JOptionPane; %% /*Definiciones regulares configuracion*/ %class Flotante %unicode %full %int

y

parametros

de


%line %column

JFlex

%{ /*Codigo Java genĂŠrico*/ int ocurrencias; public int getOcurrencias(){ return ocurrencias; }


%}

JFlex

/*Definiciones regulares*/ digito=[:digit:] blancos=[\n\r\t\f\b] punto =[.] exp=[eE] signo=[+-] digitos={digito}+ decimal={punto}{digitos}(("e"|"E"){signo} {digitos})?


JFlex

flotante={signo}?{digitos}{decimal}? /*Sección de acciones*/ %% /*Palabras reservadas */ <YYINITIAL> "break" { JOptionPane.showMessageDialog(null, "Se encontro un break"); } <YYINITIAL> { {flotante}


{

JFlex

JOptionPane.showMessageDialog(null, encontro un flotante: "+ yytext()); ocurrencias++; }

"Se

{blancos}{/*se ignora*/} . { /*ignoramos el token*/ } } โ ข //Falta construir la clase principal o bien incrustarla dentro del cรณdigo main


JFlex

import java.io.*; public class ScannerFlotante { public static void main(String[] args) { try { FileReader arch = new FileReader(args[0]); Flotante f = new Flotante(arch); f.yylex(); System.out.print("Numero de flotantes encontrados:" + f.getOcurrencias()); } catch (Exception e) {


JFlex

e.printStackTrace(); } } }

• La invocación de Jflex se realiza jflex archivo.lex, sino se pasan argumentos se abre una interface gráfica. • La clase generada se llama Flotante.java (si no se expecifica se crea una clase Yylex.java)


JFlex

• Al igual que lex, se puede complementar el código con algún otro código de Java, por ejemplo APIs para el manejo de gráficos. • Jflex genera autómatas finitos no determinista que luego convierte a autómatas finitos determinista para posteriormente minimizar su estado.


Referencias

• Aho, Sethi, Ullman. Compiladores Principios, técnicas y herramientas Ed. Addison Wesley. • Beck,. Software de Sistemas, Introducción a la programación de Sistemas Ed. AddisonWesley Iberoamericana. • Kenneth C. Louden. Construcción de compiladores Principios y práctica. Ed. Thomson.


Referencias

• Java Virtual Machine Specification


多Preguntas?


Turn static files into dynamic content formats.

Create a flipbook
Issuu converts static files into: digital portfolios, online yearbooks, online catalogs, digital photo albums and more. Sign up and create your flipbook.