sábado, 16 de diciembre de 2017

Practica PL1 (2017-2018): Parte 1: Analizador lexico (y III)

Hoy por fin cerramos el tema del analizador lexico con el problema complicado de los comentarios anidados. En realidad, la gran mayoria de los lenguajes no soportan comentarios anidados, pero el equipo docente decidió meter el problemilla para hacernos pensar.

Este problema nos permite que lo veamos desde tres enfoques. Dos funcionan y uno no.

Comenzamos con el que no funciona.

Lo primero que se le habrá ocurrido a mas de uno es introducir una expresion regular para solucionar el problema. La idea en si misma no está mal pensada, y desde el punto de vista teorico debería funcionar, pero no es posible hacerlo con JFlex.

Veamos como sería:
COMENTARIO = \(\*.*(COMENTARIO*.*)*\*\)

Esto define que un comentario es el simbolo de apertura (*, un texto cualquiera, cero o mas comentarios separados por texto y el simbolo de cierre *).

Pero al introducir la linea que sirve para ignorar el comentario encontramos el siguiente mensaje:
[jflex] Macro COMENTARIO contains a cycle.

Ahora vamos a por otro.

Recordamos que JFlex usa Java, así que lo usaremos para resolver el problema. Para ello, usaremos una variable que actue como contador para ignorar los comentarios, que inicializaremos a cero

Para ello, agregamos un lexema "(*" y una accion {commentCount++;}. Del mismo modo, agregamos "*)" y su accion opuesta {commentCount--;}

Por ultimo, modificamos cada linea de {return nuevoToken(loquesea)} y ponemos

if(commentCount!= 0){
return nuevoToken(loquesea);
}

Tambien podemos modificar nuevoToken para añadirlo.

Ese sistema funciona y lo hace bien, pero tambien existe un sistema aparte, consistente en crear una segunda maquina. Supongo que es el sistema que quieren que se use, porque mencionan como cambiar de maquinas en la sesion de control.

Para eso agregamos en la apertura de comentarios la linea

{ABRIR_COMEN} {commentCount++; yybegin(COMMENT);}

y la segunda maquina:

<COMMENT>{
{ABRIR_COMEN} {commentCount++;}
{CERRAR_COMEN} {if ((--commentCount)==0){yybegin(YYINITIAL);}}
// Ignoramos el contenido de los comentarios
[^] {}
}

Asi cuando detecte un comentario no irá leyendo lexema tras lexema, sino que será una segunda maquina la que lo evalue.

Esta parte se encarga de detectar los comentarios, pero tenemos el problema de detectar los balanceos incorrectos.

En el primer metodo, en la accion "*)" deberemos introducir un mensaje de error si el numero de comentarios es menor que cero usando

LexicalError error = new LexicalError ("Encontrado comentario de cierre mal balanceado");
error.setLine (yyline + 1);
error.setColumn (yycolumn + 1);
error.setLexema (yytext ());
lexicalErrorManager.lexicalError (error);

En el segundo metodo, SIEMPRE que salga un comentario de cierre en la primera maquina hacemos lo mismo

En ambos casos, para los comentarios mal balanceados a la izquierda usamos

%eof{

// Verifica que no quedan comentarios sin cerrar.

if (commentCount>0){
LexicalError error = new LexicalError ("Comentario sin cerrar");
error.setLine (yyline + 1);
error.setColumn (yycolumn + 1);
error.setLexema (yytext ());
lexicalErrorManager.lexicalFatalError (error);
}

%eof}

Yo en mi caso usé el sistema de las dos maquinas. Vosotros podeis optar por el que querais.

A proposito, tambien podeis modificarlo para que salga un mensaje de "Apertura de comentarios de nivel X" y "Cierre de comentarios de nivel X".

Con esto ya teneis el analizador lexico terminado. En la siguiente parte, el analizador sintáctico.

No hay comentarios:

Publicar un comentario