1. CIS-IXB-001
UNIVERSIDAD
NACIONAL
DE LOJA
´Area de la Energ´ıa las Industrias y los Recursos Naturales No Renovables
Carrera de Ingenier´ıa en Sistemas
“COMPILADOR DIVISOR DE
CANTIDADES”
MODULO IX B
Autores:
SORAYA ISAMAR LARA TAPIA
Docente:
ING. HENRY PAZ
Fecha:
13 FEBRERO 2014
Loja-Ecuador
Septiembre 2014 - Julio 2015
1
3. 1. Problema:
Un compilador que permita dividir en partes iguales el total de una cantidad de dinero
para un numero determinado de personas las cuales tienen que ser diferentes de cero.
1.1. Ejemplos
El Ingreso de datos debe ser: 35/7; y el resultado obtenido sera igual 2,833333
2. Aut´omata
A continuaci´on presentamos la representaci´on del aut´omata que es la estructura del
compilador Figura 1.
Figura 1: Aut´omata del compilador
3. Desarrollo
Para el desarrollo del compilador se esa utilizando la librer´ıa JFLEX y CUP que son
la parte l´exica y sint´actica del compilador.
4. JFlex
Es desarrollada en Java, la cual genera un programa en Java a partir de una especifi-
caci´on en el que se indican los tokens permitidos por nuestro lenguaje.
Un archivo de especificaci´on para JFLex esta organizado en tres secciones, separadas
por: “ % % ”.
3
4. 4.1. C´odigo de usuario.
En esta secci´on se crean las clases necesarias para nuestro analizador l´exico, las cuales
ser´an copiadas directamente al inicio del archivo de salida y se importan los paquetes
necesarios. Primero se declara el nombre del paquete en el cual esta contenido y la librer´ıas
a utilizar. Figura 2.
Figura 2: C´odigo de usuario
4.2. Directivas JFLex.
En esta secci´on se incluyen algunas reglas propias de JFLex. Tambi´en se pueden definir
macros, que resuman ciertas expresiones regulares que nos ser´an ´utiles al momento de
identificar tokens en la siguiente secci´on, y estados. Figura 3.
Figura 3: Directivas de Jflex
4
5. Cambiamos el nombre de la clase del analizador a Lexer. % class AnalizadorLexico
Realizamos la activaci´on del contador de lineas, variable yyline y el contador de co-
lumna, variable yycolumn.
%line
%column
Luego hay que activar la compatibilidad con Java CUP para analizadores sintacticos.
% cup
Generamos un java cup.Symbol para guardar el tipo de token encontrado.
private Symbol symbol(int type) {
return new Symbol(type, yyline, yycolumn);
}
Tambi´en generamos un Symbol para el tipo de token encontrado junto con su valor.
private Symbol symbol(int type, Object value) {
return new Symbol(type, yyline, yycolumn, value);
}
Las Macro declaraciones Figura 4.
Figura 4: Las Macro declaraciones
Un salto de linea es un n, r.
Salto = r|n|rn
Espacio es un espacio en blanco, tabulador t, salto de linea o avance de pagina f,
normalmente son ignorados.
Espacio = {Salto} | [ tf]
para que reconozca n´umeros enteros:
Entero = 0 | [1-9][0-9]*
5
6. 4.3. Reglas l´exicas
Esta secci´on contiene expresiones regulares y acciones. Las acciones son c´odigo en
Java Figura 5. que se ejecutara cuando se encuentre una entrada valida para la expresi´on
regular correspondiente.
Figura 5: Reglas l´exicas
YYINITIAL es el estado inicial del analizador l´exico al escanear. Las expresiones
regulares solo ser´an comparadas si se encuentra en ese estado inicial. Es decir, cada vez
que se encuentra una coincidencia el scanner vuelve al estado inicial.
<YYINITIAL> {
/* Regresa que el token FINLINEA declarado en la clase sym fue encontrado.*/
";" { System.out.print(yytext()+" FinLinea "+" ["+yyline+","
+yycolumn+"] n");
return symbol(sym.FINLINEA);}
/*Regresa que el token OP_DIVISION declarado en la clase sym fue encontrado.*/
"/" { System.out.print( yytext()+" dividido "+" ["+yyline+","
+yycolumn+"] n");
return symbol(sym.OP_DIVISION);}
/* Regresa que el token OP_CERO declarado en la clase sym fue encontrado.*/
"0" { System.out.print( yytext()+" cero "+" ["+yyline+","
+yycolumn+"] n");
return symbol(sym.OP_CERO);}
/* Si se encuentra un n´umero, se imprime, se regresa un token numero
que representa un entero y el valor que se obtuvo de la cadena yytext
al convertirla a double. yytext es el token encontrado. */
6
7. {Entero} { System.out.print(yytext()+" numero "+" ["+yyline+","
+yycolumn+"] n");
return symbol(sym.ENTERO, new Double(yytext())); }
/* Se ignora si se encuentra el espacio en blanco */
{Espacio} { /* Ignora el espacio */ }
}
/* Si el car´acter ingresado no coincide con ninguna regla
Entonces se marca un token ilegal */
[ˆ] { System.err.println("El caracter ingresado es
invaido <"+yytext()+">"+"posicion"+"("+yyline+" "+yycolumn+")"); }
5. CUP
Para construir un compilador el segundo paso que debemos dar es el de desarrollar el
analizador sint´actico de nuestro lenguaje.
CUP desarrollada en Java para crear analizadores sint´acticos. Genera dos clases en
Java, por default sym y parser, a partir de una especificaci´on en la que se indica una
gram´atica formal as´ı como tambi´en se asocian una serie de acciones a los s´ımbolos apare-
cidos en cada regla gramatical. La clase sym esta constituida por los s´ımbolos terminales
declarados en la gram´atica,la cual es utilizada para hacer referencia a los mismos.
5.1. Definici´on de paquete e importaci´on de paquetes necesa-
rios.
En este secci´on se incluyen las construcciones para indicar que las clases Java generadas
a partir de este archivo pertenecen a un determinado paquete y/o tambi´en importar las
clases Java necesarias. Figura 6.
Figura 6: Paquetes e importaciones
package ejemplocup;
import java_cup.runtime.*;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.List;
7
8. 5.2. C´odigo de usuario.
En esta secci´on se puede incluir c´odigo Java del analizador sint´actico que se va a obte-
ner con CUP. En la primera parte tenemos el c´odigo para reportar los errores generados
al realizar un dato err´oneo figura 7.
Figura 7: M´etodo report error
Luego tenemos el m´etodo Main donde se llama al analizador l´exico y presenta la
gram´atica ingresada, tambi´en esta el m´etodo Divisor que es que realiza la operaci´on que
recibe como entrada dos cantidades y devuelve una cantidad tipo double figura 8.
8
9. Figura 8: Metodo Main y divisi´on
/* C´odigo del parser, se copia ´ıntegramente a la clase final.
Agregamos el manejo de errores, el m´etodo de divisor y el main*/
parser code {:
/* Reporte de error encontrado. */
/* Creamos el meto report_error el cual recibe un mensaje y un objeto */
public void report_error(String message, Object info) {
/* Declaramos un StringBufer el cual contendr´a el mensaje*/
StringBuilder m = new StringBuilder("Error");
/*Agregamos un if el cual se analiza el objeto recibido instanceof
Sirve para conocer si un objeto de un tipo java_cup.runtime.Symbol*/
if (info instanceof java_cup.runtime.Symbol) {
//imprimimos objeto info para conocer su identificador
System.out.println("INFO ="+info);
/* Declaramos la variable s de tipo java_cup.runtime.Symbol
Donde se almacena el castin del info*/
java_cup.runtime.Symbol s = ((java_cup.runtime.Symbol) info);
/*if nos va a obtener la l´ınea y columna donde se encuentra el symbol*/
if (s.left >= 0) {
//agregamos al mensaje la l´ınea
m.append(" linea "+(s.left+1));
if (s.right >= 0)
//agregamos al mensaje la columna
m.append(", columna "+((s.right+1)-1));
}
/*Este if verifica el identificador es igual a 2 entonces
9
10. se trata del fin de l´ınea*/
if(s.sym==2){ message="est´a mal o no existe el fin de l´ınea"; }
/*Este if verifica el identificador es igual a 3
entonces se trata del OP_DIVISION*/
if(s.sym==3){message="tiene q existir numerador";}
/*Este if verifica el identificador es igual a 5
entonces se trata del ENTERO*/
if(s.sym==5){message="no puede existir dos numeros
continuos sin el operador";}
/*Este if verifica el identificador es igual a 4
entonces se trata del OP_CERO*/
if(s.sym==4){message="El numero para el cual se
divide debe ser mayor a cero ";}
}
//al mensaje le agregamos (:) para una comprensi´on mejor
m.append(" : "+message);
//imprimimos el error
System.err.println(m);
}
/* M´etodo main para garantizar la ejecuci´on del analizador l´exico y
sint´actico, Adem´as que se pase como par´ametro la tabla de s´ımbolos
correspondiente. */
public static void main(String[] args){
try {
AnalizadorSintactico asin = new AnalizadorSintactico(
new AnalizadorLexico( new FileReader(args[0])));
Object result = asin.parse().value;
} catch (Exception ex) {
// Imprimimos que existe un error al realizar la ejecuci´on
System.err.println("ERROR EN EL INGRESO DE DATOS");
}
}
/*Realizamos el m´etodo divisor que nos devuelve un double al
realizar la Operaci´on y recibe como para metro dos n´umeros */
public Double division(Double num1, Double mun2) {
// Variable para almacenar el resultado
Double todo;
//ejecuci´on de la operaci´on
todo= num1/mun2;
// Retornamos el valor de la operaci´on
return todo;
}
:};
10
11. 5.3. Declaraci´on de s´ımbolos terminales y no terminales.
En esta secci´on se declaran los s´ımbolos terminales y no terminales figura 9. de la
gram´atica que define el analizador sint´actico que deseamos producir. Tanto los s´ımbolos
no terminales como los s´ımbolos terminales pueden tener asociado un objeto Java de una
cierta clase.
Figura 9: Declaraci´on de terminales y no terminales
/* ---Declaraci´on de s´ımbolos terminales y no terminales--- */
/* Terminales (tokens obtenidos por el analizador lexico).*/
terminal FINLINEA, OP_DIVISION, OP_CERO;
terminal Double ENTERO;
/* No terminales usados en la secci´on gramatical.e lista los no terminales que tien
un valor Object queNo tienen tipo, pudiendo ser entero o String. */
non terminal Object expr1, expr2;
non terminal Object sentencia;
5.4. Definici´on del s´ımbolo inicial de la gram´atica y las reglas
de producci´on
Las reglas de producci´on tienen esta sintaxis:
expresion ::= expresion <sımbolo terminal> expresion { : c´odigo java: } ;
Se pueden definir todas las reglas de producci´on que tengan un mismo s´ımbolo no
terminal figure 10. como antecedente separado por el s´ımbolo |.
11
12. Figura 10: Secci´on Gramatical
/* ------------------- Seccion de la gramatica ------------------------ */
/* La | sirve para indicar que es una producci´on u otra. Debemos pasar
de s´ımbolos no terminales a s´ımbolos terminales. Una gram´atica que no Termina en s´ı
nunca se finaliza Su procesado.*/
expr1 ::= expr1 expr2
|
expr2
;
/* En esta expresi´on se llama a la expresi´on sentencia para poder imprimir el Resul
expr2 ::= sentencia:e
{:
System.out.println(" igual "+e);
:}
;
/*Puede ser una expresi´on que inicia por numero op_divido, de esa forma
se realiza Una divisi´on. En RESULT se almacena el valor de las acciones y
se pasa al siguiente nivel de la gram´atica.
*/
sentencia ::=
12
13. //sentencia incorrecta de la operaci´on
ENTERO:n OP_DIVISION ENTERO:m
{:
// C´odigo para obtener el objeto info del fin de l´ınea
CUP$AnalizadorSintactico$result = parser.getSymbolFactory().
newSymbol("sentencia",2,((java_cup.runtime.Symbol)
CUP$AnalizadorSintactico$stack.elementAt(CUP$
AnalizadorSintactico$top-2))((java_cup.runtime.Symbol)
CUP$AnalizadorSintactico$stack.peek()), RESULT);
// Llamamos al m´etodo report_error y enviamos el
//mensaje y el objeto tipo info
parser.report_error("Falta fin", CUP$AnalizadorSintactico$result);
:}
// o podemos tener la sentencia correcta
|
ENTERO:n OP_DIVISION ENTERO:m FINLINEA
{:
//El RESULT almacena el resultado de haber llamado el m´etodo divisi´on
RESULT=parser.division(n.doubleValue(), m.doubleValue());
:} ;
6. Sym
En esta clase java se generan los Tokens declarados y utilizados en la secci´on sint´actica
figura 11.
Figura 11: Codigo java de la clase sym
package ejemplocup; /** CUP generated class containing symbol constants. */
public class sym { /* terminals */
public static final int OP_CERO = 4;
public static final int FINLINEA = 2;
13
14. public static final int error = 1;
public static final int OP_DIVISION = 3;
public static final int EOF = 0;
public static final int ENTERO = 5;}
7. Control de errores
En la secci´on de errores podemos observar que el control se realiza en la parte de el
analizador sint´actico en el m´etodo de report error figura 12.
Figura 12: Errores sint´acticos
Y la parte de control de caracteres se realiza en la secci´on l´exica Figura 13.
Figura 13: Errores l´exicos
14
15. 8. Funcionamiento del compilador
Lo que primero hacemos es escoger la opci´on 1 Figura 14. Generar del men´u en la cual
se generan la clase sym, AnalizadorLexico y AnalizadorSintactico en c´odigo java.
Figura 14: Genraci´on de clase sym, AnalizadorLexico y AnalizadorSintactico
Luego realizamos el ingreso de caracteres validos y escogemos la opci´on 2 del men´u para
la ejecuci´on de los datos ingresados. Ingresamos: 43/9; Figura 15.
Figura 15: Ejecuci´on correcta
15
16. 9. Ejecuci´on de Errores
Ahora vamos a presentar el control de algunos errores al ingresar datos errores como
entrada.
1. Cuando falta fin de linea ”43/9”. Figura 16.
Figura 16: Falta Fin de linea
2. Cuando se ingresa dos cantidades seguidas y sin operador ”4 3 / 9;”. Figura 17.
Figura 17: Sin operador
16
17. 3. Cuando dividimos para cero ”43 /0;”Figura 18.
Figura 18: Denominador cero
4. Cuando no existe denominar el error interpreta como fin de linea al s´ımbolo del
divisor ”43 /;”Figura 19.
Figura 19: Sin denominador
17
18. 5. Cuando no existe numerador /9;”Figura 20.
Figura 20: Sin numerador
6. Cuando se ingresa mal un car´acter ”43/hola;”Figura 21.
Figura 21: Caracteres inv´alidos
18
19. 10. Conclusiones
Con la construcci´on del compilador se pudo ampliar el conocimiento y elaboraci´on
de copiladores, dejando atr´as los t´ıpicos ejemplos y centr´andonos en colaborar para
ampliar el estudio de esta materia.
El c´odigo Jflex es la parte l´exica de un compilador donde se realizan las macro
declaraciones y los m´etodos que guardan los Tokens tambi´en esta la parte de reglas
l´exicas que es donde se buscan las coincidencias de los datos ingresado.
La realizaci´on del aut´omata sera la gu´ıa para realizar la parte gramatical del c´odigo
Cup.
11. Recomendaciones
Al momento de Realizar la parte l´exica declara de % line % column para poder
activar el contador de lineas y columnas para facilitar el reporte de errores.
Las expresiones regulares y acciones de c´odigo Jflex deben ser realizadas con pre-
cauci´on pues es la parte en que el scanner encontrara las coincidencias.
En el c´odigo Cup realizar el control de errores para el correcto funcionamiento del
compilador.
19
20. 12. Referencia del c´odigo fuente
La c´odigo de este compilador se lo puede encontrar en: https://code.google.com/
p/compiladoresdivisor/source/browse/trunk/EjemploCUP.zip
20
21. 13. Bibliogr´afica
Referencias
[1] Antonio De Miguel Vicenti.2007 C¸ompilador de Pascal”. Disponible en:
http%3A%2F%2Fplg07082.googlecode.com%2Fsvn%2Ftrunk%2FDocumentaci%
25C3%25B3n%2FDOCUMENTACION%2520ENTREGA%2520FINAL%2FDOCUMENTACION%
2FANALISIS%2520LEXICO%2FDocumentacion%2520Analizador%2520Lexico.
pdf&ei=0gOOVNemE43asASVqYL4Bw&usg=AFQjCNEAOrPRo7wH_L7KLJ4bvbjCwvKzlQ
[2] Carlos III de Madrid, Departamento de ingenier´ıa telematoca, ” Fundamentos de
Ordenadores I: Breve Introducci´on a CUP” Disponible en: http://www.it.uc3m.
es/luis/fo1/p/CUP.html
[3] Compiladores: principios, t´ecnicas y herramientas. A.V. Aho, R. Sethi, J.D. Ull-
man. Addison-Wesley Iberoamerica. 1990. Disponible en: http://loscompiladores.
wordpress.com/category/analizador-sintactico/
[4] Enrique Arangurenn. .A
nalizador Sint´actico”, 2011. Disponible en: http://
loscompiladores.wordpress.com/category/analizador-sintactico/
[5] Open(fecks();). .Estructura Archivo JFLex”. Disponible en: http://openfecks.
wordpress.com/jFlex-y-cup/plantilla-archivo-jFlex/
[6] Salvador Sanchez, Daniel Rodrıguez, Departamento de Ciencias de Universidad
de Alcala, ”Procesadores de Lenguaje” Disponible en:http://www.cc.uah.es/ie/
docencia/ProcesadoresDeLenguaje/CUP.pdf
21