Está en la página 1de 17

COMPILADOR VISUAL BASIC

Igor Gómez Gil de San Vicente


Expediente: 051701 FM-41
Miguel Tapia González-Valcárcel
Expediente:061513 FM-41

Grupo 24
Índice

Fases del compilador

Tabla de símbolos

Gestión de errores

Acciones semánticas más importantes

Conclusiones

Bibliografía
Fases del compilador

En la primera fase del compilador, que se corresponde con la primera entrega del 14 de
Mayo, empezamos a implementar la parte correspondiente a la tabla de símbolos. En
nuestro caso ibamos realizando la implementación de las clases y métodos según
avanzabamos y fueramos necesitando nuevos métodos que al principio no conociamos.

En cuanto a la comprobación de tipos


Tabla de símbolos

Implementamos la tabla de símbolos con la siguiente clase JAVA:

package proyectocompiladorvb;

import java.util.*;

public class tablasimbolos{

private tablasimbolos tabla_previa;


private Hashtable t;
private int tam_locales;
private int tam_param;

public tablasimbolos(){t=new Hashtable();};


public void set_previa(tablasimbolos previa) {this.tabla_previa = previa;}
public void insertar ( entrada e){t.put(e.lex(),e);};
public boolean esta(String s){return (t.containsKey(s));};
public boolean esta_vacia(){return (t.isEmpty());};
public entrada obtener_entrada(String s){return (entrada)t.get(s);};
public void añadir_tamdatos(int tam_v, int tam_p) {
this.tam_locales = tam_v; this.tam_param = tam_p;
}
public tablasimbolos crear_tabla(tablasimbolos tabla_previa) {
tablasimbolos nuevatabla;

nuevatabla = new tablasimbolos();


nuevatabla.set_previa(tabla_previa);
nuevatabla.añadir_tamdatos(0, 0);
return nuevatabla;
}
};

Los atributos de la tabla de símbolos son los siguientes:

- tabla_previa: referencia a la tabla de símbolos del ámbito inmediatamente superior al


actual.

- t: tabla hash (se utiliza la clase Hashtable disponible en las librerías de java) en la que
almacenaremos las entradas de la tabla de símbolos.

- tam_locales: valor de tipo entero que indica el número de bytes que ocupan las
variables locales el ámbito actual.

- tam_param: valor de tipo entero que indica el número de bytes que ocupan los
parámetros del ámbito actual.
Los métodos implementados para acceder a a la tabla de símbolos son:

- tablasimbolos(): constructor, crea una nueva tabla hash.

- void set_previa(tablasimbolos previa): asigna al atributo tabla_previa la referencia a


una tabla de símbolos pasada como parámetro.

- void insertar ( entrada e): añade la entrada e a la tabla de símbolos.

- boolean esta(String s): devuelve TRUE si en la tabla de símbolos existe una entrada
cuyo campo lexema coincide con la cadena pasada como parámetro. En caso contrario
devuelve FALSE.

- boolean esta_vacia(): devuelve TRUE si la tabla de símbolos no contiene ninguna


entrada y FALSE en caso contrario.

- entrada obtener_entrada(String s): devuelve la entrada cuyo campo lexema coincide


con la cadena pasada como parámetro.

- void añadir_tamdatos(int tam_v, int tam_p): actualiza los atributos tam_locales y


tam_param con los valores pasados como parámetro.

- tablasimbolos crear_tabla(tablasimbolos tabla_previa): crea una nueva tabla de


símbolos con su atributo tabla_previa apuntando a la tabla que se pasa como parámetro,
inicializa los atributos tam_locales y tam_param a cero y devuelve una referencia a la
tabla creada.

Cada entrada de la tabla de símbolos es un objeto instancia de la clase entrada:

public class entrada{

private String lexema;


private tipos tipo;
private String tipovar;
private String tipoacceso;

public entrada(String l, tipos tip, String tvar, String tacc){lexema=l; tipo=tip; tipovar =
tvar; tipoacceso = tacc;}
public String lex() {return lexema;}
public tipos obtener_tipo(){return tipo;}
public String obtener_tipovar(){return tipovar;}
public String obtener_tipoacceso(){return tipoacceso;}
};

Los campos de una entrada son:

-lexema: lexema del elemento definido.


-tipo: tipo de dato del elemento definido.
-tipovar: cadena de carácteres que indica que clase de elemento representa la entrada.
Los posibles valores que puede tomar son:
"VAR": el elemento corresponde a una declaración de variable.
"CONST": el elemento corresponde a una declaración de constante.
"PROC": el elemento corresponde a una declaración de procedimiento.
"FUNC": el elemento corresponde a una declaración de función.
"ENUMERADO": el elemento corresponde a una declaración de enumerado.
"ESTRUCTURA": el elemento corresponde a una declaración de estructura.
"INTERFAZ": el elemento corresponde a una declaración de interfaz.
"CLASS": el elemento corresponde a una declaración de clase.

-tipoacceso: cadena de carácteres que indica los posibles modificadores del elemento.

Los métodos de la clase entrada son:

- entrada(String l, tipos tip, String tvar, String tacc) constructor, crea una nueva entrada
inicializando sus atributos con los valores pasados como parámetros.

- String lex(): devuelve el lexema de la entrada.

- tipos obtener_tipo(): devuelve el tipo de la entrada.

- String obtener_tipovar(): devuelve el tipo de entrada.

- String obtener_tipoacceso(): devuelve los modificadores de la entrada.

Para implementar el sistema de tipos utilizamos la clase abstracta tipos:

abstract public class tipos extends Object{

public abstract String estipo();


public abstract boolean esigual(tipos t);
};

Partiendo de esta clase implementamos cada tipo del lenguaje con una clase que hereda
de tipos e implementa los métodos abstractos estipo y esigual según la característica del
tipo implementado. Además las clases correspondientes a los tipos del lenguaje pueden
implementar otros métodos específicos del tipo.

Las clases que implementan los tipos son:

- t_array:
public class t_array extends tipos{
private tipos elemento;
public t_array(tipos el){elemento=el;};
public String estipo(){return "array";}
public tipos elementos(){return elemento;}
public boolean esigual(tipos t){if (t.estipo().equals("array")) return
(((t_array)t ).elementos().esigual(elemento));else return false;}
};

-t_entero:
public class t_entero extends tipos{
public t_entero(){;};
public String estipo(){return "entero";}
public boolean esigual(tipos t){return (t.estipo().equals("entero"));}
};

- t_char:
public class t_char extends tipos{
public t_char(){;};
public String estipo(){return "char";}
public boolean esigual(tipos t){return (t.estipo().equals("char"));}
};

- t_logico:
public class t_logico extends tipos{
public t_logico(){;};
public String estipo(){return "booleano";}
public boolean esigual(tipos t){return (t.estipo().equals("booleano"));}
};

- t_puntero:
public class t_puntero extends tipos{
tipos elemento;
public t_puntero(tipos el){elemento=el;};
public String estipo(){return "puntero";}
public tipos elementos(){return elemento;}
public boolean esigual(tipos t){if (t.estipo().equals("puntero")) return
(((t_puntero)t ).elementos().esigual(elemento));else return false;}
};

- t_func:
public class t_func extends tipos{
private listatipos parametros;
private tipos tiporetorno;

public t_func(listatipos param, tipos retorno){


this.parametros = param;
this.tiporetorno = retorno;}
public String estipo(){return "funcion";}
public boolean esigual(tipos t){return (t.estipo().equals("funcion"));}
public listatipos obtener_parametros(){return parametros;}
public tipos obtener_retorno(){return tiporetorno;}
};
- t_clase:
public class t_clase extends tipos{
private tablasimbolos ts_clase;

public t_clase(tablasimbolos ts){this.ts_clase = ts;};


public String estipo(){return "clase";}
public boolean esigual(tipos t){return (t.estipo().equals("clase"));}
public tablasimbolos obtener_tablasimbolos(){return ts_clase;}
};

- t_proc:
public class t_proc extends tipos{
private listatipos parametros;

public t_proc(listatipos param){


this.parametros = param;
}
public String estipo(){return "procedimiento";}
public boolean esigual(tipos t){return (t.estipo().equals("procedimiento"));}
public listatipos obtener_parametros(){return parametros;}
};

- t_enumerado:
public class t_enumerado extends tipos{
private int tam = 2;
public int tamano() {return tam;}
public t_enumerado(){;};
public String estipo(){return "enumerado";}
public boolean esigual(tipos t){return (t.estipo().equals("enumerado"));}

};

- t_interfaz:
public class t_interfaz extends tipos{

public t_interfaz(){;};
public String estipo(){return "interfaz";}
public boolean esigual(tipos t){return (t.estipo().equals("interfaz"));}
};

- t_estructura:
public class t_estructura extends tipos{

public t_estructura(){;};
public String estipo(){return "estructura";}
public boolean esigual(tipos t){return (t.estipo().equals("estructura"));}
};
- t_error:
public class t_error extends tipos{
public t_error(){;};
public String estipo(){return "error";}
public boolean esigual(tipos t){ return (t.estipo().equals("error"));}
};

- t_vacio:
public class t_vacio extends tipos{
public t_vacio(){;};
public String estipo(){return "vacio";}
public boolean esigual(tipos t){return (t.estipo().equals("vacio"));}
};

Para gestionar y acceder a las tablas de símbolos que se crean en los diferentes ámbitos
utilizamos una pila de tablas implementada en la clase pila_tablas:

import java.util.Stack;
public class pila_tablas {

Stack p_tablas;

public void setp_tablas(Stack ptablas) {


this.p_tablas = ptablas;
}

public pila_tablas(){p_tablas=new Stack();};


public void apilar(tablasimbolos ts){p_tablas.push(ts);};
public tablasimbolos desapilar(){return (tablasimbolos) p_tablas.pop();};
public tablasimbolos cima(){return (tablasimbolos) p_tablas.peek();};
public Stack obtener(){return p_tablas;};
public boolean vacia(){return p_tablas.empty();};
}

Para implementar la pila de tablas hemos utilizado la clase Stack disponible en las
librerías de JAVA.
Gestión de errores

- Errores en declaraciones: al detectar un error en una declaración, el elemento que se


está declarando no se añade a la tabla de símbolos y se genera un mensaje de
advertencia indicando la causa del error. La causa de error más común en las
declaraciones es que el lexema identificador del elemento a declarar ya está presente en
la tabla de símbolos.

- Errores en sentencias y expresiones: comprobamos que los identificadores presentes


en las sentencias y expresiones estén declarados. Para ello buscamos los lexemas de los
identificadores que intervienen en la producción en la tabla de símbolos y si están
generamos un mensaje de error indicando que existen elementos sin declarar.
La otra fuente importante de errores en expresiones y sentencias proviene de la
comprobación de tipos. En caso de incompatibilidad generamos un mensaje de error
indicando el fallo.

Cuando detectamos un error al símbolo de la parte izquierda de la producción le


asignamos el tipo "error" para propagar el error hacia las producciones superiores.
Acciones semánticas más importantes

Asignación: Al no tener en nuestro compilador que tratar los arrays, la asignación no


ha sido demasiado laboriosa. En primer lugar , en cuanto a las sentencias de asignación
normal, hemos hecho la comprobación de tipos preceptiva, teniendo en cuenta que se
trata de tipos iguales y que no son erróneos. Después, realizamos la asignación normal
de la forma:

if ($$.tipo.estipo()!= "error")
{

lcuadr.generar('ASIG', $3.lex, $1.lex, NULL);


}
Ponemos el último elemento a NULL, puesto que se trata de asignaciones normales, no
de arrays.
En cuanto a las asignaciones compuestas de la forma Expresion Operador_binario '='
Expresion Terminador_sentencia realizamos igualmente en primer lugar la
comprobación de tipos. Seguidamente, realizmas el siguiente código:

aux = nueva_temp_int(ptablas.cima());

if ($2.lex == '+') lcuadr.generar('+', $1.lex, $3.lex, aux.l


else if ($2.lex == '-') lcuadr.generar('-', $1.lex, $3.lex, aux.lex);
else if ($2.lex == '*') lcuadr.generar('*', $1.lex, $3.lex, aux.lex);
else if ($2.lex == '/') lcuadr.generar('/', $1.lex, $3.lex, aux.lex);
else if ($2.lex == '^') lcuadr.generar('^', $1.lex, $3.lex, aux.lex);

lcuadr.generar('ASIG', aux.lex, $1.lex, NULL);


}

Primero creamos una variable temporal aux y realizamos un If..elseif, puesto que
tenemos que tener en cuenta el operador binario que corresponda en cada caso.

Sentencia While: En cuanto a la sentencia while hemos generado el código de la


siguiente forma:
WHILE M Expresion Terminador_sentencia M Bloque END WHILE
Terminador_sentencia

{ if ($3.tipo.estipo() == "booleano")
{$$.tipo = new t_vacio() lc.generar(GOTO,
$2.cuad,-,-);
$3.verdad.rellenar($5.cuad);
$6.sig.rellenar($2.cuad);
$6.cont.rellenar($2.cuad); $
$.sig=mezclar($3.falso,$6.bk);
}

else
{
system.out.println("Error,expresion no lógica");
$$.tipo= new t_error();
}
}

En primer lugar comprobamos que la expresión se trata de una expresión de tipo


booleano. Después generamos un GOTO para evaluar la expresión y si es verdad se
rellena la lista de verdad con el inicio del bloque . Sólo se sale si se realiza un break o si
la condición es falsa: $$.sig=mezclar($3.falso,$6.bk);

THROW: En cuanto a la sentencia throw la hemos implementado de la siguiente


manera:
Sentencia_throw: THROW Expresion Terminador_sentencia
{$$.sig.crear_lista(sigcuad(lcuadr));
lcuadr.generar(GOTO, , , );
$$.throu =TRUE;
$$.tipo = $2.tipo;
};

|THROW Terminador_sentencia
{$$.sig.crear_lista(sigcuad(lcuadr));
lcuadr.generar(GOTO, , , );
$$.throu =TRUE;
$$.tipo = NULL;
};
;

En primer lugar hemos creado una lista de cuadruplas y después hemos generado un
GOTO. Al tener en el primer caso asociado una expresión hemos puesto el atributo
throu a TRUE y le hemos pasado el tipo.

En la segunda opción, al no tener el THROW una expresión asociada, la diferencia


fundamental es que hemos puesto el tipo como tipo null, de manera que sea un Throw
universal.
Sentencia TRY: Para la sentencia Try hemos realizado lo siguiente:
Sentencia_try:TRY Terminador_sentencia Bloque Lista_sentencias_catch END TRY
Terminador_sentencia
{
if ($3.throu)
{
if ($3.tipo == NULL)
{
system.out.println("Error,THROW en TRY sin tipo");
$$.tipo= new t_error();
}
else
{
int i = 1;
do
{

if ($3.tipo == $4.l_catch.elem(i).get_tipo().estipo())
{ $3.sig.rellenar($4.l_catch.elem(i).get_cuad()); break;}
else if ($4.l_catch.elem(i).get_tipo() == NULL)
{ $3.sig.rellenar($4.l_catch.elem(i).get_cuad()); break;}
i++;
}
while (i <= $4.l_catch.num_elem());
if (i == ($4.l_catch.num_elem() + 1))
{
$$.throu = $3.throu; $$.tipo = $3.tipo; $$.sig = $3.sig;
}
}

Primero realizamos la comprobación de si existe un Throw y, en caso de que esté a


NULL, mandamos un mensaje de error. En el caso de que no se trate de esta opción,
realizamos un do while hasta que lleguemos al final de la lista de catch. En cada
iteración buscamos la coincidencia entre el tipo del try y de cada catch de la lista. Si
coinciden se coge la cuadrupla y se sale del bucle con un break. En caso contrario se
busca por si hubiera un catch universal, en cuyo caso se haria de la misma forma.
Sentencia CATCH: Antes de introducirnos en la sentencia Catch, es importante
definir la lista de sentencias catch y su creación que se ha hecho de la forma:
Lista_sentencias_catch:
Sentencia_catch { if ($1.tipo.estipo() != "error")
{
$$.l_catch = new listacatch(); $$.l_catch = $$.l_catch.insertar(new catch($1.cuad,
$1.tipo))
}
else $$.tipo= new t_error();
}
|Lista_sentencias_catch Sentencia_catch
{if ($3.tipo.estipo() != "error") $$.l_catch = $1.l_catch.insertar(new catch($2.cuad,
$2.tipo));
else $$.tipo= new t_error();
}

Si es una única sentencia catch, se crea la lista catch y se inserta la nueva pareja de
valores con la cuadrupla correspondiente y el tipo de catch, que luego usaremos para
realizar correspondencias con el Try.
Si se trata por el contrario de una lista ya creada de sentencias, lo que se hace es añadir a
la lista de catch ya creada anteriormente.

Sentencia_catch:
CATCH ID AS Nombre_tipo WHEN Expresion_booleana Terminador_sentencia M
Bloque
{
if (pila_tablas.cima().esta($2.lex)) {$$.tipo = $4.tipo; $$.cuad = $8.cuad;}
else
{
system.out.println(“Error,id no declarado”);
$$.tipo= new t_error();
}
}

|CATCH WHEN Expresion_booleana Terminador_sentencia M Bloque


{$$.tipo = NULL; $$.cuad = $5.cuad;}
|CATCH ID AS Nombre_tipo Terminador_sentencia M Bloque
{
if (pila_tablas.cima().esta($2.lex))

{$$.tipo = $4.tipo; $$.cuad = $6.cuad;}


else
{
system.out.println(“Error,id no declarado”);
$$.tipo= new t_error();
}
}
|CATCH Terminador_sentencia M Bloque
{ $$.tipo = NULL; $$.cuad = $3.cuad;}
;

En la primera opción, aparte de mirar si existe el Id, lo que se realiza es pasar el tipo del
identificador y la cuadrupla correspondiente. En todos los demás casos se realiza de
igual forma, con la salvedad de que cuando no existe Id, el tipo se pone a Null.

De esta forma, mediante la implementación del Try, catch y Throw realizamos la


gestión de las excepciones.

En el caso de las asignaciones su realización e implementación es relativamente


sencilla, por lo que no se comentan en este apartado. Por lo que respecta a los demás
bucles Do while, Do until, son semejantes ,aunque con algunas diferencias
significativas, al bucle While, por lo que tampoco aparecen en este apartado.
Conclusiones

La realización de este compilador en lenguaje Java la hemos ido implementando en


varias etapas, siguiendo el modelo propuesto de entregas de la asignatura, a pesar de
tener ciertos problemas con las entregas en el campus virtual de la facultad.

Al no estar demasiado familiarizados con el lenguaje de programación de Visual Basic,


hemos tenido que realizar algunas consultas para resolver ciertas dudas en cuanto a
formas de implementación de ciertas estructuras y el tratamiento de las mismas por
dicho lenguaje. En especial, hemos tenido algunas dificultades en cuanto al tratamiento
de las excepciones en Visual Basic .
Bibliografía

www.vbtutor.net/vbtutor.html - 62k - Manual de Visual Basic que hemos utilizado para


aclarar conceptos referentes a visual basic.

Manual “Java desde cero”- Autor Jorge Bourdette

Java2 Caracteristicas Avanzadas 6a edicion – Autor Cay Horstmann

“COMPILADORES.PRINCIPIOS,TECNICAS Y HERRAMIENTAS” ;Autor AHO /


SETHI / ULLMAN; Editorial ADDISSON-WESLEY IBEROAMERICANA

"The Microsoft Visual Basic Language Specification Version 9.0" Paul Vick
Microsoft Corporation

También podría gustarte