Post on 20-Mar-2016
description
INSTITUTO TECNOLOGICO SUPERIOR DE LIBRES
INGENIERIA EN SISTEMAS
COMPUTACIONALES
ALUMNA: ANDREA VELAZQUEZ RICO
TRABAJO: COMPILADOR LEX
MATERIA: PROGRAMACION DE SISTEMAS
MAESTRA: DIANA MARICELA
5to. “A”
Fecha: 3/octubre/2011
COMPILADORES “Un compilador es un programa que lee un programa escrito en un lenguaje, y lo traduce a un programa equivalente en otro lenguaje.” Durante la traducción el compilador informa de la presencia de errores en el programa fuente.
ANÁLISIS LÉXICO Convierte una cadena de caracteres que conforma el programa fuente en un grupo de “palabras”, que son secuencias de caracteres con significado propio. Ejemplo: if Existe then
posicion:=60;
end if;
1. la palabra reservada “if”
2. la expresión booleana “Existe”
3. la palabra reservada “then”
4. el identificador “posicion”
5. el símbolo de asignación “:=”
6. la constante “60”
7. el final de instrucción “;”
8. la palabra reservada “end”
9. la palabra reservada “if”
10. el final de instrucción “;”
LEX LEX es un generador de programas diseñado para el proceso léxico de cadenas de caracteres de input. El programa acepta una especificación, orientada a resolver un problema de alto nivel para comparar literales de caracteres, y produce un programa C que reconoce expresiones regulares. Estas expresiones las especifica el usuario en las especificaciones fuente que se le dan al lex. El código lex reconoce estas expresiones en una cadena de input y divide este input en cadenas de caracteres que coinciden con las expresiones
HIATORIA En 1975, con la aparición de LEX surge el concepto de un generador automático de analizadores léxicos a partir de expresiones regulares, basado en el sistema operativo UNIX. A partir de los trabajos de Chomsky ya citados, se produce una sistematización de la sintaxis de los lenguajes de programación, y con ello un desarrollo de diversos métodos de análisis sintáctico. FLEX es una herramienta para generar escáneres: programas que reconocen patrones léxicos en un texto. Flex lee los ficheros de entrada dados, o la entrada estándar si no se le ha indicado ningún nombre de fichero, con la descripción de un escáner a generar.
EL CONSTRUCTOR DE ANALIZADORES
LÉXICOS LEX LEX es un constructor de analizadores léxicos.
Opera mediante una descripción de la gramática hecha mediante expresiones regulares. Genera un programa en lenguaje C que sirve como analizador léxico. Existe un equivalente en lenguaje Ada: aflex
Lex es una herramienta que se ha utilizado para especificar analizadores léxicos para una variedad de lenguajes. Normalmente se le llama compilador Lex a la herramienta, y lenguaje Lex a sus especificaciones de entrada. Existe un equivalente a “lex” en Ada, denominado “aflex”. La herramienta lex genera un programa C que sirve como analizador léxico; aflex genera también un analizador léxico, pero en lenguaje Ada. Generalmente lex o aflex se utilizan de la siguiente forma: Primero se prepara una especificación de la gramática en lenguaje Lex.
Posteriormente, se utiliza la herramienta para producir el código fuente del
programa analizador léxico. Este código fuente debe ser compilado, lo que produce el analizador léxico. Con el analizador léxico resultante, se puede realizar el análisis léxico de un
código fuente tantas veces como sea necesario. La herramienta aflex crea ficheros Ada terminados en “.a”, que por tanto no se
adhieren a las convenciones de nombres del compilador gnat. Además, crea los paquetes en un solo fichero, con la especificación y el cuerpo en el mismo fichero. Esto también es contrario a las reglas del gnat.
Para estas situaciones, existe una herramienta llamada “gnatchop”, que
permite crear los ficheros con los nombres apropiados, a partir de otros ficheros.
En el caso del ejemplo de la figura, habrá que ejecutar: gnatchop -w name.a
gnatchop -w name_dfa.a
gnatchop -w name_io.a
Donde “name” es el nombre de la especificación lex original. Luego hay que construir el ejecutable:
gnatmake name
ESPECIFICACIONES EN LEX Definiciones: Las definiciones son definiciones regulares que
toman la forma: nombre expresión_regular POR EJEMPLO: letra [a-zA-Z]
digito [0-9]
identificador {letra}({letra}|{digito}|_)*
Reglas de traducción: se describen de la forma: patrón {acción} Patrón es una expresión regular; Acción es un trozo de código.
Código auxiliar
Estructura del código auxiliar El código auxiliar se escribe con la estructura: sección inicial de código
##
sección final de código
El código Ada generado tendrá la estructura siguiente: with Name_Dfa, Name_IO, Text_IO;
sección inicial de código (debe incluir el tipo Token)
function YYLex return Token is
begin
-- definida por la herramienta lex
end;
sección final de código
Un ejemplo de código auxiliar:
procedure Name is
type Token is (End_Of_Input, Error);
Tok : Token;
##
begin
while Tok /= End_of_Input loop
Tok:=YYLex;
end loop;
end Name;
La función YYLex se crea automáticamente, y se coloca en el lugar donde se han escrito los caracteres ##. Para que esta función sea válida, es imprescindible que en la sección inicial de código se haya creado el tipo enumerado Token, con al menos los dos valores End_Of_Input y Error.
ASPECTOS A TENER EN CUENTA EN
LA ESPECIFICACIÓN LEX El texto que verifica el patrón de una regla de traducción se puede obtener con la
función predefinida YYText.
Es habitual que el código de una regla de traducción acabe con una instrucción:
return valor; donde valor es un valor del tipo enumerado Token, creado en la
sección inicial de código auxiliar. Esto es especialmente habitual si se enlaza lex
con yacc (analizador sintáctico) Cuando un string puede cumplir dos reglas de
traducción, se elige: 1. El string más largo
2. Si son iguales, la regla que aparece en primer lugar.
Ejemplo con lex El siguiente ejemplo convierte un texto con insultos en otro con palabras más “correctas” :-) Especificación Lex, en el fichero bien_educado.l:
-- definiciones
espacio " "|\n
palabra [a-zA-Z]+{espacio}
tonto ("tonto"{espacio})|("ignorante"{espacio})
tonta "tonta"{espacio}
tonto_de "tonto"{espacio}"de"l?{espacio}{palabra}
idiota "idiota"{espacio}
nueva_linea \n
%%
-- reglas de traducción
{tonto} {Put("listo ");}
{tonta} {Put("lista ");}
{idiota} {Put("distinguido ");}
{tonto_de} {Put("amable caballero ");}
{nueva_linea} {New_Line;}
. {Put(YYText);}
%%
-- Código auxiliar inicial
with Ada.Text_IO; Use Ada.Text_IO;
procedure Bien_Educado is
type Token is (end_of_input,error);
tok : token;
OTRA DEFINICIÒN
Lex
Lex es un programa para generar analizadores léxicos (en inglés scanners o lexers).
Lex se utiliza comúnmente con el programa yacc que se utiliza para generar análisis
sintáctico. Lex, escrito originalmente por Eric Schmidt y Mike Lesk, es el analizador
léxico estándar en los sistemas Unix, y se incluye en el estándar de POSIX. Lex toma
como entrada una especificación de analizador léxico y devuelve como salida el
código fuente implementando el analizador léxico en C.
Aunque tradicionalmente se trata de software propietario, existen versiones libres de lex basadas en el código original de AT&T en sistemas como OpenSolaris y Plan 9 de los laboratorios Bell. Otra versión popular de software libre de lex es Flex.
Estructura de un archivo de lex
La estructura de un archivo de lex es intencionadamente similar a la de un archivo del yacc; los archivos se dividen en tres secciones, separadas por líneas que contienen solamente dos símbolos "%", como sigue:
Sección de declaraciones
%%
Sección de reglas
%%
Sección de código en C
La sección de declaraciones es el lugar para definir macros y para importar los archivos de cabecera escritos en C. También es posible escribir cualquier código de C aquí, que será copiado en el archivo fuente generado. Este código en C debe ir entre los símbolos %{ %}.
También se pueden incluir "atajos" para definir patrones de la Sección de Reglas, por ejemplo en vez del patrón [0-9]* (cero o más dígitos que reconocerían cualquier número natural), se puede definir en esta sección el "atajo": números [0-9]*, así, en la sección de código pondríamos el patrón {números} {acción_en_C;}. Con esto se clarifica la escritura del código en lex.
La sección de reglas es la sección más importante; asocia patrones a sentencias de C. Los patrones son simplemente expresiones regulares. Cuando el lexer encuentra un texto en la entrada que es asociable a un patrón dado, ejecuta el código asociado de C. Ésta es la base de del funcionamiento de lex.
La sección de código C contiene sentencias en C y funciones que serán copiadas en el archivo fuente generada. Estas sentencias contienen generalmente el código llamado por las reglas en la sección de las reglas. En
programas grandes es más conveniente poner este código en un archivo separado y enlazarlo en tiempo de compilación.
Ejemplo de archivo Flex
Lo siguiente es un ejemplo de archivo lex para la versión Flex de lex. Reconoce cadenas de números (números enteros) en la entrada, y simplemente los imprime en la salida.
/*** Sección de declaraciones ***/
%{
/* Código en C que será copiado */
#include <stdio.h>
%}
/* Esto indica a Flex que lea sólo un fichero de entrada */
%option noyywrap
%%
/*** Sección de reglas ***/
/* [0-9]+ identifica una cadena de uno o más dígitos */
[0-9]+ {
/* yytext es una cadena que contiene el texto coincidente.
*/
printf("Encontrado un entero: %s\n", yytext);
}
. { /* Ignora todos los demás caracteres. */ }
%%
/*** Sección de código en C ***/
int main(void)
{
/* Ejecuta el ''lexer'', y después termina. */
yylex();
return 0;
}
Si se da esta entrada a flex, será convertida en un archivo de C, lex.yy.c. Esto se puede compilar en un ejecutable que encuentre y haga salir cadenas de números enteros. Por ejemplo, dando la entrada:
abc123z.!&*2ghj6
El programa imprimirá:
Encontrado un entero: 123
Encontrado un entero: 2
Encontrado un entero: 6
Uso de Lex con Yacc
Lex y Yacc (un generador de analizadores sintácticos) suelen ser utilizados juntos. Yacc utiliza una gramática formal para analizar un flujo de entradas, algo que Lex no puede hacer con expresiones regulares simples (Lex se limita a los autómatas de estados finitos simples). Sin embargo, Yacc no puede leer en un flujo de entradas simple - requiere una serie de símbolos. Lex se utiliza a menudo para proporcionar a Yacc estos símbolos.
Ejemplos
• Sustituir las palabras ‘el’ y ‘la’, ‘los’ y ‘las’ por la palabra ‘ARTICULO’. %%
el|la|los|las printf ("ARTICULO");
ó %%
el |
la |
los |
las printf ("ARTICULO");
• Lo mismo, pero sin afectar a palabras como ‘lanza’: %%
[Ee]l |
[Ll][oa]s? printf ("articulo");
[A-Za-z]+ ECHO;
• Pasar a mayúsculas los artículos determinados: %%
[Ee]l |
[Ll][ao]s? { int i;
for (i=0;i<yyleng;i++)
printf ("%c",toupper(yytext[i]));
}
• Contar el número de artículos determinados: %{
/* Cuenta el número de artículos determinados */
int num=0;
%}
%%
[Ee]l |
[Ll][oa]s? num++ ;
[A-Za-z]+ ;
.|\n ;
%%
main(){
yylex();
printf ("Número de artículos: %d\n", num);
BIBLIOGRAFIA:
http://www.infor.uva.es/~mluisa/talf/docs/labo/L3.pdf
http://www.slideshare.net/PauNyo/lex-5496077
http://www.ctr.unican.es/asignaturas/lan/compila-2en1.pdf