Post on 02-Apr-2015
COMPILADORES HERRAMIENTAS LEX Y YACC
LEX
Es una herramienta utilizada para especificar analizadores léxicos. Suele llamarsele compilador Lex a la herramienta, y lenguaje Lex a sus especificaciones de entrada.
YACC
Genera un analizador sintáctico (la parte de un compilador que comprueba que la
estructura del código fuente se ajusta a la especificación sintáctica del lenguaje).
Como se realiza
Lex genera el código C para un analizador léxico, y yacc genera el código para un parser.
Tanto lex como yacc toman como entrada un archivo de especificaciones que es
típicamente más corto que un programa hecho a medida y más fácil de leer y entender.
Por convención, la extensión del archivo de las especificaciones para lex es .l y para
yacc es .y. La salida de lex y yacc es código fuente C. Lex crea una rutina llamada yylex
en un archivo llamado lex.yy.c. Yacc crea una rutina llamada yyparse en un archivo
llamado y.tab.c.
Estas rutinas son combinadas con código fuente C provisto por el usuario, que se ubica
típicamente en un archivo separado pero puede ser ubicado en el archivo de
especificaciones de yacc. El código provisto por el usuario consiste de una rutina main
que llama a yyparse, que en su momento, llama a yylex.
Diagrama lex y yacc
Compilador C
COMPILADOR
Librerías
yylex() yyparse()
Rutinas Clex.yy.c y.tab.c
lex yacc
Especific.
Lex
Especific.
Yacc
nombre_archivo.ynombre_archivo.l
CONSTRUCCIÓN DEL COMPILADOR
Para llegar a la construcción del compilador el usuario debe tener instalados el
compilador MINGW y el paquete de YACC.
Pasos para la instalación del paquete yacc
Asumiendo que usted ha instalado este paquete en el directorio c:\yacc, prepare su
ambiente de la siguiente manera:
Bajo la consola DOS de Windows escriba el siguiente PATH, como se ilustra en la
“figura A”.
SET PATH=c:\yacc\bin;%PATH%
SET BISON_SIMPLE=c:\yacc\bin\bison.simple
SET BISON_HAIRY=c:\yacc\bin\bison.hairy
Esta versión de YACC y LEX funcionan sin problemas con la versión del compilador
MINGW32.
Esta es una distribución mínima del compilador MINGW solo soporta el modo consola
de Windows.
Su uso básicamente es para compilar algunos ejemplos sencillos y muy útil para el
proyecto de lenguajes y compiladores. Si usted ya tiene instalada la versión completa
del mingw, no tiene sentido usar esta versión
- Su ventaja principal es su pequeño tamaño que facilita su descarga, y traslado
de una máquina a otra sin complicaciones.
Pasos para la instalación del paquete MgwCon
Copie la carpeta llamada "\MgwCon" en el disco local C.
En XP se puede, ejecutando el comando SET PATH=... estando en el modo consola de
Dos, ponga la ruta en el PATH : como se ilustra en la “figura B”
SET PATH=%PATH%;C:\MgwCon\Bin;
FIGURA B
Asumimos que instalo el compilador en la unidad C: aunque podría haber sido
cualquier otra.
Usted puede tener otra distribución del mingw instalada en su disco duro
(normalmente \MinGW) no habrá problemas ya que trabajarán en forma
independiente.
Uso de los archivos .l .y
Para trabajar con los archivos escritos en lex y yacc .l y .y por ejemplo con los nombres
de COM_BAS.l y COM_BAS.y.
Los dos últimos archivos (COM_BAS.L y COM_BAS.Y) cópielos a la dirección c:\yacc\bin
anteriormente instalada.
Bajo consola DOS coloque la dirección o ruta donde se encuentran los archivos
(COM_BAS.L y COM_BAS.Y) mediante comandos básicos como “CD”
FIGURA C
Una vez en la carpeta c:\yacc\bin escriba <lex com_bas.l> como se muetra en la “figura
C” y se creará el archivo lex.yy.c, donde lex.yy.c es una representación tabulada de un
diagrama de transiciones construido a partir de las expresiones regulares de
COM_BAS.L.
Las acciones asociadas a las expresiones regulares de COM_BAS.L son partes de código
en C y se transfieren directamente a lex.yy.c.
Ahora escriba <yacc –d com_bas.y> se especifica que –d es para generar un fichero de
cabecera llamado y.tab.h.
COM_BAS.Y constituye una especificación en yacc, luego al someter COM_BAS.Y al
compilador yacc so obtiene un programa en C llamado y.tab.c. El archivo y.tab.c es el
analizador sintáctico en C incluye además otras rutinas de apoyo que pudo generar el
usuario.
Copie todos los archivos (COM_BAS.L, COM_BAS.Y, lex.yy.c, y.tab.c, y.tab.h) a la
dirección c:\mgwcon\bin.
Bajo consola DOS, para generar el programa ejecutable .exe deberá escribir la
siguiente línea de código, (asegúrese de encontrarse en la carpeta c:\mgwcon\bin en
DOS).
Se puede cambiar el nombre del programa .exe solamente indicando otro nombre de
su elección por ejemplo gcc y.tab.c lex.yy.c –o COMPILADOR.exe.
Para nuestro ejemplo el programa ejecutable tendrá nombre com_bas.exe como se
muestra en la siguiente figura.
Nota: Si esta trabajando en modo DOS y aparece un error como el siguiente debe
volver a escribir las líneas de código del PATH. Estas se encuentra en la “figura A” y
“figura B”
COMPILADORES CREADOS
TRADUCTOR DE EXPRESIONES INFIJAS A POSTFIJAS
Archivo lex (.l)
%{#include "y.tab.h"
%}
%%
"EOF"|"eof" {return SALIR;}
[Dd][Ii][Vv] {return DIV;}[Mm][Oo][Dd] {return MOD;}
[A-Za-z]([A-Za-z]|[0-9])* {yylval = *yytext;printf("%s ",yytext);return VARIABLE;
}
[0-9]+ {yylval = strtol(yytext, (char **)NULL, *yytext=='0' ? 8:10);return INTEGER;
}
[0-9]+(\.[0-9]+)?(E[+\-]?[0-9]+)? {yylval = *yytext;
printf("%s ",yytext);return REAL;
}
[-()=+/*;\n] {//printf("\n\n ");return *yytext;
}
[ \t]+ ;
[~`!#%^&_'":<>?] {ECHO;yyerror("es caracter Desconocido !Error¡");
}
%%
int yywrap(void) { return 1;
}
---------------------%token INTEGER REAL VARIABLE DIV MOD SALIR%left '+' '-'%left '*' '/'
%{static int variables[100];static int dim[80];int i=1;int j=1;%}
%%
lineas:'\n'
| lineas declaracion '\n' ={ i=i+1; }| lineas SALIR '\n' { for(i=1;i<=80;i++)
{ if(dim[i]!=0) printf("\n!Error Sintactico --> linea %d \n",dim[i]);
}
printf("cerrando programa"); getch();
exit(1); }
| lineas error '\n' = { i=i+1;}| SALIR '\n' {printf("Cerrando programa...\n");exit(0);}|;
declaracion:expr ';' ={/*printf("%d\n",$1);*/}
| VARIABLE '=' expr ';' = { variables[$1] = $3; };expr:
VARIABLE { $$ = variables[$1]; }
| expr '+' expr = { printf("+ ");}| expr '-' expr = { printf("- ");}| expr '*' expr = { printf("* ");}| expr '/' expr = { printf("/ "); }| expr DIV expr = { printf("div");}| expr MOD expr = { printf("mod");}| '(' expr ')' = { $$ = $2; }| statement;
statement: INTEGER = {printf("%d ",$1); }| VARIABLE = { }| REAL = { };
%%
int yyerror(char *s){
dim[j] = i; j++; return 0;}
int main(void) { printf("\t\tUNIVERSIDAD CENTRAL DEL ECUADOR\n"); printf("\t\tDISEÑO DE COMPILADORES\n");
printf("\nFabián Silva Muñoz\n");printf("\nIngrese las expresiones \n\n");
yyparse();
return 0;}EJECUCION
CALCULADORA AVANZADA
Archivo lex (.l)/*PARTE DE DECLARACIONES*/%{ #include "y.tab.h" #include <string.h>
char cadena[255]; int linea = 1;%}
%%
/*PARTE DE REGLAS*/ /* */[a-z] { yylval = *yytext - 'a'; return VARIABLE; }
/* enteros */[0-9]+ { yylval = atoi(yytext); return ENTERO; }
/* nueva linea */[\n] { linea++; return *yytext; }
/* operadores */[-+()=/*] { return *yytext; }
/* otros simbolos */[;,] { return *yytext; }
/* salta espacios en blanco */[ \t] ;
/* comando print */print return CMD_PRINT;
/* cadena */\".*\" { strncpy( cadena, ++yytext, yyleng - 2 ); cadena[ yyleng - 2 ] = '\0'; return CADENA; }
/* funciones */"abs" return FUNC_ABS;"max" return FUNC_MAX;
/* cualquier otra cosa es un error */. yyerror("caracter invalido");
%%/*PARTE DE DEFINICIONES DE USUARIO*/
int yywrap(void) { return 1;
}
/*PARTE DE DECLARACIONES*/%token ENTERO VARIABLE CMD_PRINT CADENA FUNC_ABS FUNC_MAX FUNC_DIV%left '+' '-'%left '*' '/'%{ int sim[26]; extern char cadena[255]; extern linea;%}
%%/*PARTE DE REGLAS*/
linea: linea declaracion '\n' | ;
declaracion: expr { printf("%d\n", $1); } | VARIABLE '=' expr { sim[$1] = $3; } | CMD_PRINT CADENA { printf("%s\n",cadena); } | CMD_PRINT CADENA ';' { printf("%s",cadena); } | ;
expr: ENTERO | VARIABLE { $$ = sim[$1]; } | expr '+' expr { $$ = $1 + $3; } | expr '-' expr { $$ = $1 - $3; } | expr '*' expr { $$ = $1 * $3; } | expr '/' expr {
if ( $3 == 0.0 ){ printf( "Error, Divisi¢n para cero", "" );} else{ $$ = $1 / $3;}}
| '(' expr ')' { $$ = $2; } | FUNC_ABS '(' expr ')' { $$ = abs( $3 ); } | FUNC_MAX '(' expr ',' expr ')' { if ( $3 > $5 ) $$ = $3; else $$ = $5; } | expr FUNC_DIV expr { $$=$1; printf(" div "); } ;
%%/*PARTE DE DEFINICIONES DE USUARIO*/
int yyerror(char *s) {
char mensaje[100];
if ( !strcmp( s, "parse error" ) )
strcpy( mensaje, "Error de sintaxis" ); else strcpy( mensaje, s );
fprintf(stderr, "Error en linea %d: %s\n", linea, mensaje); printf("ha ocurrido un error\n"); getch(); return 0;}
int main(void) { printf("\t\tUNIVERSIDAD CENTRAL DEL ECUADOR"); printf("\t\tDISEÑO DE COMPILADORES"); printf("\nFabián Silva Muñoz\n"); printf("\n\nIngrese la expresion a calcular: "); yyparse(); return 0;}
EJECUTABLE
CONVIERTE DE ENTEROS A ROMANOS
Archivo lex (.y)%{#include<stdio.h>#include<ctype.h>/*#include<conio.h>*/char *ts[30]={ "I","II","III","IV","V","VI","VII","VIII","IX","X","XX","XXX","XL","L","LX","LXX","LXXX","XC","C","CC","CCC","CD","D","DC","DCC","DCCC","CM","M","MM","MMM"};void mil(int);void cien(int);void decena(int);void unidad(int);void yyerror(char *s);
%}%token NUMERO
%%expresion: NUMERO ;%%yylex(){ int c; scanf("%d",&c); while(c!=0){
if(c>999) mil(c);
else if(c>99) cien(c); else if(c>9) decena(c);
else unidad(c); return NUMERO;
} return c;
}
void mil(int c){ int a; a=c%1000; c=c/1000; printf("%s",ts[26+c]); if(a>99) cien(a); else if(a>9) decena(a); else unidad(a); } void cien(int c){ int a; a=c%100; c=c/100; printf("%s",ts[17+c]); if(a>9) decena(a); else unidad(a); } void decena(int c){ int a; a=c%10; c=c/10; printf("%s",ts[8+c]); unidad(a); } void unidad(int c){ if(c>0) printf("%s",ts[c-1]); else yyerror;}
void yyerror(char *s){ printf("%s", s);
}
void main(){ printf("Ingrese un nùmero: "); yyparse();/*llama a la yylex para tener otro componente lexico*/
getch(); }
EJECUTABLE