Está en la página 1de 15

CIS-IXB-001

UNIVERSIDAD
NACIONAL
DE LOJA

Area
de la Energa las Industrias y los Recursos Naturales No Renovables

Carrera de Ingeniera en Sistemas

Compilados usando Jflex y Cup,


para la suma, resta o multiplicaci
on
de enteros o palabras

Trabajo Final
Noveno B

Autores:
Juan Pablo Guaman Rodrguez

Docente: Ing. Henry Paz,

Loja - Ecuador
2015
1

Indice
A. Introducci
on

B. Palabras reservadas

C. Operadores

D. Aut
omata

E. Archivo punto flex


E.1. Codigo de Usuario . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
E.2. Directivas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
E.3. Expresiones Regulares . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

4
5
5
6

F. Archivo punto cup


F.1. Importaciones de java . . . . . . . . . . . . .
F.2. Codigo del usuario para el parser . . . . . .
F.3. Codigo del usuario, acciones de la gramatica
F.4. Declaracion de variables para la gramatica .
F.5. Gramatica . . . . . . . . . . . . . . . . . . .

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

8
8
8
9
9
10

G. Ejecuci
on compilador

12

H. Captura de errores

13

I. C
odigo fuente

14

J. BIBLIOGRAFIA

15

A.

Introducci
on

La idea del presente compilador nace por la curiosidad de permitirle al usuario sumar
no solo n
umeros enteros como tales si no que, el mismo juegue con el compilador ingresando palabras.
Como funciona el compilador, pues bien en el mismo puede entender una suma, resta
y/o multiplicacion teniendo como terminos n
umeros enteros y/o palabras las mismas que
pueden ser compuestas por varios caracteres o ser uno solo.
El compilador al encontrar una palabra lo que hace es consultar el codigo ASCII de
cada caracter que forma esta palabra y sumar cada uno de ellos entre si para ese valor
devolverlo como entero, el cual matematicamente si es posible sumarlo con otras enteros.
Para entender mejor eso vamos a ingresar en nuestra entrada del compilador la siguiente
expresion:
1 + 19 - hola;
Nuestro compilador primero se dara cuenta que el primer token es un entero 1el cual
se le esta pidiendo que se le sume otro entero en este caso el 19 seguidamente se le sumara
la palabra holapara por ultimo restarle la palabra mundo, generando la siguiente salida:
ENTERO <1> SUMA ENTERO <19> RESTA CADENA <hola(104:111:108:97) > = -400
Como se puede observar en la salida se muestra lo que estamos pretendiendo operar as,
al encontrar una cadena, la misma se descompone y muestra el ASCII de cada caracter.

B.

Palabras reservadas

Nuestro compilador cuenta con una sola palabra reservada la cual se utiliza para
finalizar una expresion matematica, designado con el smbolo punto y coma ;.

C.

Operadores

Nuestro compilador cuenta con los siguientes operadores:


+ operador suma.
operador resta.
operador multiplicacion.
( operador de agrupacion inicial.
) operador de agrupacion final.

D.

Aut
omata

Una vez que sabemos que vamos hacer debemos plantearnos la idea en un automata,
as con este poder seguir la secuencia de pasaos para la validacion de nuestras expresiones.
El automata en nuestro compilador quedo diagramado de la siguiente manera:

Figura 1: automata del compilador

E.

Archivo punto flex

Uno de los dos archivos mas importantes para la creacion de nuestro compilador, es
el archivo punto flex, ya que es aqu donde creamos nuestro analizador lexico, el mismo
que nos servira para agregar las reglas lexicas que nuestro compilador poseera.
Pues para este punto nosotros ya deberamos saber que un archivo punto flex posee tres
grandes partes; Codigo de usuario, Directivas y las reglas para las expresiones regulares;
todas las partes separadas por doble porcentaje.
Describamos cada una de estas partes usando el codigo necesario para la creacion de
nuestro compilador.

E.1.

C
odigo de Usuario

package lexico.sintactico;
import java_cup.runtime.*;
import java.io.Reader;
import java.util.HashMap;
Se puede observar que este codigo es, codigo integro que se copiara al archivo punto java
que generaremos, por hende es obvio pensar y estar en lo correcto al decir que la primera
linea es el nombre del paquete que nuestro punto java tendra, ademas las siguientes lineas
son importaciones dos de ellas indispensables para la cremacion y ejecucion de nuestro
flex, la ultima que es una importacion de HashMap se usa en nuestro caso para el control
de errores que mas adelante detallaremos.

E.2.

Directivas

%%
%class AnalizadorLexico
%line
%column
%cup
%{
private Symbol symbol(int type) {
return new Symbol(type, yyline, yycolumn);
}
private Symbol symbol(int type, Object value) {
return new Symbol(type, yyline, yycolumn, value);
}
public static HashMap<String, String> errores = new HashMap<>();
%}
Salto = \r|\n|\r\n
Espacio = {Salto} | [ \t\f]
Entero = 0 | [1-9][0-9]*
Cadena = [a-z][a-z]* | [A-Z][A-Z]* | [a-z][A-Z]* | [A-Z][a-z]*
Para empezar esta segunda seccion escribiremos un doble porcentaje, realizado esto
observamos el nombre de la clase que nuestro punto java tendra, seguidamente nos encontramos con dos lineas mas una %line. y la otra %column las mismas que sirven para
activar el contador de lineas y de columnas en flex, %cup sirve para activar la compatibilidad con CUP que sera usado para nuestro analizador sintactico.
Despues nos encontraremos con un %{ finalizando con %} todo lo que esta dentro de
estas llaves es codigo que se copiara ntegramente a nuestro punto java, pero no fuera de
la clase si no dentro. Los dos primeros metodos son para asignar un entero a los smbolos
5

que nosotros declaremos en nuestro CUP, si este smbolo posee un valor se llamara el
segundo metodo y ese valor pasado como parametro se asignara, el atributo errores es un
HashMap en cual usaremos para almacenar cada error que se encuentre.

E.3.

Expresiones Regulares

%%
<YYINITIAL> {
";"

{
return symbol(sym.SEMI);
}

"+"

{
System.out.print(" SUMA ");
return symbol(sym.OP_SUMA);
}

"-"

{
System.out.print(" RESTA ");
return symbol(sym.OP_RESTA);
}

"*"

{
System.out.print(" MULTIPLICACION ");
return symbol(sym.OP_MULT);
}

"("

{
System.out.print(" PARENTESIS ( ");
return symbol(sym.PARENTESIS_IZQUIERDO);
}

")"

{
System.out.print(" PARENTESIS ) ");
return symbol(sym.PARENTESIS_DERECHO);
}

{Entero}

{
System.out.print("ENTERO <"+yytext()+">");
return symbol(sym.ENTERO, new Integer(yytext()));
}

{Cadena}

{
System.out.print("CADENA <"+yytext());
6

System.out.print("(");
for (int i = 0; i < yytext().length()-1; i++) {
System.out.print(yytext().codePointAt(i)+":");
}
System.out.print(yytext().codePointAt(yytext().length()-1));
System.out.print(") >");
return symbol(sym.CADENA, new StringBuffer(yytext()));
}
{Espacio}

{
}

}
[]
{
String mensaje = "";
mensaje += ("\n************************************");
mensaje += ("\n****Caracter invalido ==> "+yytext()+" <== ****");
mensaje += ("\nencontrado en la linea ");
mensaje += ((yyline + 1) + " y columna " + (yycolumn + 1));
mensaje += ("\n************************************\n");
String keyString = (yyline + 1) + (yycolumn + 1) + "";
errores.put(keyString, yytext());
System.err.println(mensaje);
}
YYINITIAL es un estado inicial el cual va a ir almacenando nuestros tokens que seran
declarados.
En nuestro compilador el caracter ; sera el smbolo que exprese el final de una excrecion matematica, para esto el compilador retornara un token con el smbolo SEMI de
ingles semi column que significa fin de linea. De esta misma manera se consideran los
caracteres:
+, , , (, y ). retornando el simbolo con el token: OP SU M A, OP REST A, OP M U LT ,
P AREN T ESIS IZQU IERDO y OP P AREN T ESIS DERECHO respectivamente.
Luego de ver esto se aprecia el token entero el mismo que esta dise
nado para retornar un
smbolo EN T ERO el mismo que sera cualesquier numero.
Cuando hablamos de una cadena el compilador fue dise
nado para aceptar cualquier de
estas en tanto las mismas no posean ning
un caracter especial y no empiecen con un entero,
por ultimo los espacios que son ignorados por el compilador.
Al final del analizador lexico se encuentra el smbolo [] en el cual se presentara un mensaje de error, cuando apreciaremos este error pues bien, el mismo se lanzara si y solo si el
7

compilador no encontro ninguna coincidencia en el estado Y Y IN IT IAL.

F.

Archivo punto cup

El segundo archivo mas importante de nuestro compilador es el punto cup, es aqu


donde pondremos todas nuestros reglas sintacticas, el mismo que esta formado por cinco
grandes partes, las cuales describiremos a continuacion.

F.1.

Importaciones de java

package lexico.sintactico;
import java_cup.runtime.*;
import java.io.FileReader;
De igual forma que en el archivo punto flex, este codigo es codigo integro a copiar el
el punto java a generar, siendo la primera linea el paquete en donde se encontrara nuestro
punto java, las dos siguientes importaciones son necesarias la una para la ejecucion del
runtime de cup, y la otra para la leda y creacion de archivos con java.

F.2.

C
odigo del usuario para el parser

parser code {:
public void report_error(String message, Object info) {
System.err.println(message);
}
public void syntax_error(Symbol s) {
String key = (s.left + 1) + s.right + "";
String mensaje = ("\nError de sintaxis en linea "
+ (s.left + 1) +" columna " + s.right);
if(AnalizadorLexico.errores.get(key) == null) {
mensaje += ("\nAl simbolo " + s.value.toString()
+ " le antecede un entero falta el operador");
report_error(mensaje, null);
}else {
mensaje += ("\nERROR: entero o cadena <CARACTER INVALIDO> entero o cadena");
mensaje += ("\nCORRECTO: entero o cadena <OPERADOR> entero o cadena");
mensaje += ("\nAl simbolo " + s.value.toString()
+ " le antecede un token invalido");
mensaje += (" ==> "+ AnalizadorLexico.errores.get(key)+" <==");
report_error(mensaje, null);
}
}
8

public void report_fatal_error(String message, Object info) {


String fatalError = ("*************************************");
fatalError += ("\n*********ERROR IRECUPERABLE**********");
fatalError += ("\n*************************************");
report_error(fatalError, info);
}
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) {
ex.printStackTrace();
}
}
:};
Este codigo sera copiado a la clase generada por nuestro punto cup, siendo metodos
que sobre escribiremos, los mismos que pos sus nombres nos dan una idea clara de lo que
aran, report error nos sirve para imprimir en consola el error del cual estaremos hablando, syntax error se llama cuando el compilador encontro un error de sintaxis eh aqui que
nosotros hemos personalizado estos errores para poder dar una idea al usuario de que esta
haciendo mal, por lo cual encontramos el HashMap errores del punto flex, si recordamos
en este guardabamos todos nuestros errores.
Cuando el error de sintaxis aparece buscamos cual fue el error y le decimos al usuario
que y como corregir. Despues tenemos el metodo report f atal error el cual es llamado
cuando ah ocurrido un error del cual nuestro compilador no podra recuperarse, por esto
imprimimos un mensaje como tal.
Por ultimo tenemos en metodo main el cual lo usamos para crear nuestro analizador
sintactico asiendo uso de nuestro analizador lexico antes creado.

F.3.

C
odigo del usuario, acciones de la gram
atica

En el ejemplo planteado no se hace uso de esta parte de la estructura, ya que las


acciones que realizara el compilador fueron implementadas directamente en la gramatica
del analizador sintactico. No generadas en un metodo para luego ser llamadas.

F.4.

Declaraci
on de variables para la gram
atica

terminal
terminal Integer

SEMI, OP_SUMA, OP_RESTA, OP_MULT,


PARENTESIS_IZQUIERDO, PARENTESIS_DERECHO;
ENTERO;
9

terminal StringBuffer

CADENA;

non terminal Object


sentencias, sentencia;
non terminal Integer
exprecion, operacion, termino;
non terminal StringBuffer palabra;
Los terminales vendran siendo los tokens declarados en el analizador lexico.
No terminales usados en la seccion gramatical, los mismos que son el resultado de nuestra
gramatica.

F.5.

Gram
atica

Nuestra gramatica se ha escrito de la siguiente manera:


/*
sentencias son la ra
z de la gram
atica. La misma puede ser una
sentencias seguida de una sentencia, o puede ser una sentencia.
*/
sentencias ::= sentencias sentencia
|
sentencia
;

/*
sentencia se compone de una exprecion seguida de SEMI.
asignacion:aestablece que a representa al objeto asociado a
asignacion, entre {: :} se coloca el c
odigo en java para las
acciones a tomar al cumplirse una producci
on.
*/
sentencia ::= exprecion:e
{:
System.out.println(" = " + e);
:}
SEMI
;

/*
exprecion puede ser una excreci
on matem
atica que empieza con numero
entero o palabra OP_SUMA exprecion, de esa forma se realizara una suma.
Tambi
en puede ser un numero entero, con esto se devuelve el valor del
entero. En RESULT se almacena el valor de las acciones, y se pasa al
siguiente nivel de la gram
atica. Si se encuentra una palaba se observa
que se recorre la misma obteniendo el ASCCI de cada caracter se suman
10

entre ellos para ese valor devolverlo en el RESULT como entero.


*/
exprecion ::= exprecion:e OP_SUMA operacion:f
{:
RESULT = new Integer(e.intValue() + f.intValue());
:}
|
exprecion:e OP_RESTA operacion:f
{:
RESULT = new Integer(e.intValue() - f.intValue());
:}
|
operacion:n
{:
RESULT = n;
:}
|
palabra:p
{:
int sumLetras = 0;
StringBuffer letras = new StringBuffer(p);
for(int i=0; i< letras.length();i++)
{
sumLetras = sumLetras + letras.codePointAt(i);
}
RESULT = sumLetras;
:}
;

/*
Al encontrarnos una palabra la debolvemos creando un StringBuffer java
para manipularlo posteriormente
*/
palabra
::= palabra:p OP_MULT termino:e
{:
RESULT = new StringBuffer(e+""+p+"");
:}
;

/*
operacion sera el termino y un OP_MULT y termino, o solo un
termino si se realiza una multiplicaci
on y una suma esto le dar
a
prioridad a la multiplicaci
on

11

*/
operacion ::= operacion:f OP_MULT termino:e
{:
RESULT = new Integer(f.intValue() * e.intValue());
:}
|
termino:t
{:
RESULT = t;
:}
;
/*
termino fue pensado para que el compilador realice las operaciones con
prioridad en las expresiones que se encuentran dentro de los parentesis.
*/
termino
::= PARENTESIS_IZQUIERDO exprecion:e PARENTESIS_DERECHO
{:
RESULT = e;
:}
|
ENTERO:e
{:
RESULT = e;
:}
|
CADENA:c
{:
int sumLetras = 0;
StringBuffer letras = new StringBuffer(c);
for(int i=0; i< letras.length();i++)
{
sumLetras = sumLetras + letras.codePointAt(i);
}
RESULT = sumLetras;
:}
;

G.

Ejecuci
on compilador

Para la ejecucion de nuestro compilador tendremos una archivo punto txt el cual nos
servira para los datos de entrada del mismo, el cual posee la siguiente informacion:
1 + 19 - hola;
1 + dos * 2;
12

Una vez corrido nuestro main, el programa nos mostrara el siguiente men
u, en el
cual tendremos dos opciones digitar uno para generar los archivos y moverlos al paquete
correspondiente, o digitar dos para leer el archivo de entrada y probar nuestro compilador,
en este caso hemos digitado dos y se puede apreciar que no ocurrio ning
un error y el
compilador nos dio la respuesta que esperabamos.
ENTERO <1> SUMA ENTERO <19> RESTA CADENA <hola(104:111:108:97) > = -400
ENTERO <1> SUMA CADENA <dos(100:111:115) > MULTIPLICACION ENTERO <2> = 653
*********************************************

H.

Captura de errores

Para dar una mejor impresion en nuestro compilador hemos credo conveniente el
control de errores, no solo en el aspecto linea columna, si no que dar una idea d ello que
el usuario esta haciendo mal as: Si el usuario ingresa los siguientes datos como entrada:
1 + h19 - hola;
1 + dos 2;
El compilador nos muestra lo siguiente:
ENTERO <1> SUMA CADENA <h(104) >ENTERO <19>
Error de sintaxis en linea 1 columna 5
Al simbolo 19 le antecede un entero falta el operador
*********************************************
*************************************
*********ERROR IRECUPERABLE**********
*************************************
Expresando la linea columna del error sintactico y sugiriendo la posible solucion. Probemos ahora con un erro lexico:
1 + 19. - hola;
1 + dos 12 - 2;
El compilador mostrara lo siguiente:
ENTERO <1> SUMA ENTERO <19> RESTA CADENA <hola(104:111:108:97) >
************************************
****Caracter invalido ==> . <== ****
encontrado en la linea 1 y columna 7
************************************
= -400
ENTERO <1> SUMA CADENA <dos(100:111:115) >ENTERO <12>
*********************************************
13

Error de sintaxis en linea 2 columna 8


Al simbolo 12 le antecede un entero falta el operador
*************************************
*********ERROR IRECUPERABLE**********
*************************************
En el cual se ve claramente linea columna del error lexico y del sintactico, sugiriendonos
de igual manera que en el error anterior cual seria la posible solucion.

I.

C
odigo fuente

Para todas aquellas personas interesadas en el codigo fuente de este proyecto el


mismo lo pueden descargar totalmente libre en el siguiente url: https://github.com/
desert-barret/compilador_jflex_cup/tree/master/Local/AnalizadorLexicoSintactico/

14

J.

BIBLIOGRAFIA

Referencias
[1] Analizador
lexico.
Disponible
en:
http://es.slideshare.net/maryr_
/actividad-2-analizador-lxico-sintctico-y-semntico
[2] Archivo
Jlex.
Disponible
en:
http://www.cc.uah.es/ie/docencia/
ProcesadoresDeLenguaje/2.3.JLex.pdf
[3] Estructura del archivo Jlex. Disponible en: http://openfecks.wordpress.com/
jlex-y-cup/plantilla-archivo-jlex/
[4] Estructura de Archivo Cup: https://openfecks.wordpress.com/jlex-y-cup/
estructura-de-archivo-cup/
[5] Cup y el analisis semantico: http://www.escet.urjc.es/procesal/pracs/Cup_
tr_clase.pdf

15

También podría gustarte