lunes, 14 de noviembre de 2016

Analisis Lexico

  
Análisis Léxico 

Analizador sintáctico PLY (Python Lex Yacc) de Python.

Creación y generalidades:El metacompilador hecho en lenguaje Python PLY es originario de la universidad de Chicago, por el profesor de ciencias de la computación David Beazly, esta api presenta una integrativa de Lex y Yacc que son dos apis que permiten la creación de analizadores léxicos, ambos escritos en lenguaje C.

Fue creado como una herramienta de instrucción primeramente para usuarios iniciados, pero la herramienta demostró ser robusta y por ello también es usada por usuarios experimentados, esto tampoco implica la creación de árboles sintácticos y la generación de herramientas avanzadas, si no tomado como una herramienta de análisis.

En general PLY presenta dentro de sí dos scripts que no son más que Lex y Yacc escritos en Python (Lex.py y Yacc.py), de manera que se permite la integración de ambos en programas en los que se desee desarrollar análisis léxico de otros scripts o instrucciones, estas instrucciones se evalúan en una colección de tokens suministrados y reglas de expresiones regulares, Yacc.py se utiliza para reconocer la sintaxis del lenguaje que se ha especificado en la forma de una gramática libre de contexto.

Las dos herramientas están destinadas a trabajar juntos. En concreto, lex.py proporciona una interfaz externa en forma de un símbolo () función que devuelve el siguiente token válido del flujo de entrada. Yacc.py llama a esto varias veces para recuperar los símbolos e invocar las reglas gramaticales.

Yacc está dentro de Unix por eso al usar un sistema basado en Unix (alguna distribución de Linux) encontraremos el programa Yacc, sin embargo Yacc.py tiene algunas diferencias con este, la principal entre yacc.py y Unix Yacc es que yacc.py no implica un proceso de generación de código independiente, a diferencia tradicional lex / yacc que requieren un archivo de entrada especial que se convierte en un archivo fuente separado, las especificaciones dadas para ejercer son programas Python válidos. Esto significa que no hay archivos de origen adicionales ni hay un paso especial construcción del compilador (por ejemplo, correr yacc para generar código Python para el compilador).

Lex:
lex.py se utiliza para dividir una cadena de entrada. Por ejemplo, supongamos que usted está escribiendo un lenguaje de programación y un usuario se suministra la siguiente cadena de entrada:
x = 3 + 42 * (s - t)
            Lex separa en tokens la cadena de texto ingresada.
'X', '=', '3', '+', '42', '*', '(', 's', '-', 't', ')'

Los créditos son por lo general dan nombres para indicar cuáles son. Por ejemplo:

"ID", "iguales", "Número", "más", "Número", "tiempos",
'LPAREN', 'ID', 'menos', 'ID', 'RPAREN'

Más específicamente, la entrada se divide en pares de tipos y valores de tokens. Por ejemplo:

( 'ID', 'x'), ( 'es igual a', '='), ( 'Cantidad', '3'),
( 'PLUS', '+'), ( 'Cantidad', '42), (' TIMES ',' * '),
( 'LPAREN', '('), ( 'ID', 's'), ( 'MENOS', '-'),
( 'ID', 't'), ( 'RPAREN', ')'
           
(Writing Parsers and Compilers with PLY, David Beazley, 2007)

            Estructura del Script del analizador personalizado.
            PLY nos permite crear un analizador personalizado, en el cual podemos crear una serie de definiciones que nos permitirán evaluar las expresiones que ingresemos en un script o en la consola de comandos, el cual recibirá una evaluación certera o negada, en cada uno de sus tokens, en este caso serán presentados una serie de ejemplos y directrices necesarias para la construcción de un analizador léxico personalizado, no contemplan el todo de la api a usar, en el caso que se requiera toda la información, se puede dirigir a la documentación oficial de dicha interfaz de programación de aplicaciones (API).

Se debe proporcionar una lista de tokens: en dicha lista se deben definir un grupo de nombres simbólicos que se pueden producir por el analizador léxico, esta lista también es usada por el Yacc.py. Ejemplo:
tokens = (
   'NÚMERO',
   'MÁS',
   'MENOS',
   'VECES',
   'DIVIDIR',
   'LPAREN',
   'RPAREN',
)

Se agrega una definición a los tokens: se crean fichas, o definiciones de cada uno de los tokens, estableciendo una expresión regular para cada uno, en esta api se debe identificar con un prefijo ‘t_’ que indica que es una definición de token, el calor siguiente debe coincidir exactamente con un valor suministado en la lista de tokens. Ejemplo.

t_MAS = r’\ +’
Palabras reservadas: Para manejar las palabras reservadas, se debe escribir una sola regla para que coincida con un identificador y hacer una búsqueda de nombre especial en una función. Ejemplo.
reserved = {
   'if' : 'IF',
   'then' : 'THEN',
   'else' : 'ELSE',
   'while' : 'WHILE',
   ...
}

tokens = ['LPAREN','RPAREN',...,'ID'] + list(reserved.values())
 
def t_ID(t):
    r'[a-zA-Z_][a-zA-Z_0-9]*'
    t.type = reserved.get(t.value,'ID')  
    return t

Comentarios: Para descartar una ficha, tal como un comentario, sólo se tiene que definir una regla de token que no devuelve nada. Ejemplo:

def T_COMMENT (t):
    r '\ #. *'
    pass
    # No hay valor de retorno. Token descartados
Numeros de línea e información posicional: Para actualizar esta información, se debe escribir una regla especial. En el ejemplo, el t_newline () regla muestra cómo hacer esto.
def t_newline(t):
    r'\n+'
    t.lexer.lineno += len(t.value)
 
               La palabra reservada lineno, toma el número de las líneas y esta información se le asigna más el valor de la línea actual, en resultado un incremento progresivo de las líneas de código escritas.
 
            Caracteres literales: Los caracteres literales se pueden especificar mediante la definición de una variable literal en su módulo léxico. Por ejemplo:
               literals = [ '+','-','*','/' ]
 
O alternativamente

               literals = "+ - * /"

Un carácter literal es simplemente un único carácter que se devuelve tal cual cuando se encuentran por el analizador léxico. Los literales se comprueban después de todas las reglas de expresiones regulares definidas. Por lo tanto, si una norma comienza con uno de los caracteres literales, siempre tendrá prioridad.

Errores de manipulación: se debe agregar una función que se utiliza para controlar los errores léxicos, que se producen cuando se detectan caracteres no válidos. Su definición se da de la siguiente manera:

def t_error(t):
    print("Caracter ilegal '%s'" % t.value[0])
    t.lexer.skip(1)

Fin de archivo: la función de fin de archivo denota que no se ingresó más contenido para ser analizado o que el script que se proporcionó llego a su fin. Ejemplo:

def t_eof(t):
    more = raw_input('... ')
    if more:
        self.lexer.input(more)
        return self.lexer.token()
    return None




               Construccion y utilización del léxico: para la construcción del analizador, se usa la función lex.lex()
 
               Lexer = lex.lex()
               
               Esta función inspecciona las reglas de expresiones regulares, fuera del contexto de llamada y construye el analizador léxico, una vez este esta construido se utilizan dos métodos para controlarlo.
 
               Lexer.input(datos): restablece el analizador y almacena una nueva cadena de entrada.
 
               Lexer.token(): devuelve el siguiente token, devuelve una respuesta de éxito o fracaso en el análisis de la entrada.
 
               (Documentación de PLY Python; Teaching Compilers with Python, Matthieu Amiguet, 2010)
 
 
2.    Analizador léxico para lenguaje de expresiones matemáticas básicas.

Se eligió para esta asignación el lenguaje de programación Python, debido a su sintaxis bastante simple y a su dinámica de código, en esta ocasión se presenta la estructura del analizador léxico personalizado de expresiones matemáticas simples.
·         Importacion de la API contenedora de Lex y Yacc, en este caso solo usaremos lex debido a que solo se pide un analizador léxico, hacemos la abreviación “as lex” para usar la api en el script con el nombre de “lex”


·         Paso siguiente, se agrega la lista de tokens.



·         Luego se agregan las expresiones regulares para cada token declarado en la lista anterior que sea una expresión simple.



·         Se agregan las expresiones regulares de los tokens que representan una definición mayor, en este caso para el token “NUMBER” que representa una expresión numérica o un número entero.



·         Se agrega la definición de saltos de línea lo cual nos permite evaluar varias expresiones.



·         Se agrega posteriormente la definición de caracteres ignorados, esto nos permite incluir espacios y tabulaciones



·         Gestión de errores, dada por la función que permite mostrar caracteres ilegales no presentes en la lista inicial de tokens.



·         Finalizando las definiciones tenemos la construcción del analizador, creando así un objeto analizador.


                        Todo el script presentado, estará adjunto a este documento, el paso siguiente es la construcción de expresiones que puedan ser leídas por el analizador, estas nos permitirán ver la precisión de dicho lexema y su contenido.
Para la evaluación de las expresiones matemáticas y los ejemplos, creamos otro script en el cual incluimos la llamada de un archivo .txt y la integración del analizador antes creado, los comentarios nos permiten entender más el script.


3.    5 Ejemplos, en prueba del analizador.
Se ejecutaron varios ejemplos guardados en el archivo textlex.txt, los cuales se presentan a continuación
·         Expresión: x = (1 + 5) * 20 / 5
Esta expresión como es de notarse tiene correspondencia con tokens, y por ende no arroja errores léxicos.



Es notorio mostrar la secuencia de verificación que nos va indicando, a que token pertenece cada elemento ingresado, cuando llega al final de la expresión no existen errores, recordemos y tengamos en cuenta que el resultado será aceptación del léxico, y no un resultado matemático ponderado, así ajustándose a los requerimientos pedidos.

·         Expresión: y = 25 + (5 / 6) - 100 + w
En esta expresión podemos notar un elemento en una posición que podría causar un poco de incertidumbre, el elemento w no debería permitir la operación, pero recordemos que es un análisis léxico, es saber si la expresión tiene correspondencia con lo definido, y por ende está bien definido y no contiene errores.



·         Expresión: y = 45 - (30/2) * 12
En este tercer caso también se presenta una expresión válida para nuestro analizador y como vemos el resultado es válido en la consola, en donde recibimos el resultado.



·         Expresión: z = {23}{23}
En este caso la expresión no tiene sentido matemático, pero no es por esto que sea errónea para el analizador, si no que no tiene correspondencia con los tokens definidos.



Y en el resultado podemos observar que nos devuelve los 4 caracteres ilegales que no tienen correspondencia.

·         Expresión: w= 32 # 5
En este caso esta expresión no es válida, los números si lo son pero el elemento “#” no está dentro de los tokens.



Como vemos en la evaluación es devuelto como carácter ilegal.



Referencias Bibliográficas.

Writing Parsers and Compilers with PLY, David Beazley, 2007
Documentación de PLY Python.

Teaching Compilers with Python, Matthieu Amiguet, 2010.

2 comentarios:

  1. hola, que version de python utilizas?

    ResponderEliminar
  2. Poker - JtmHub
    Check the Casino Online Poker Room in the 오산 출장샵 United States, United 충청북도 출장안마 Kingdom. 평택 출장샵 Poker Online. 1-Click. Poker Online. 경산 출장마사지 2-Click. Poker Online. 안동 출장안마 3-Click.

    ResponderEliminar