Tabla de símbolos en C# y su interacción con el analizador léxico (página 2)
Enviado por FRANCISCO RIOS ACOSTA
inicio const entero MAX=10; cadena MENSAJE=”BIENVENIDOS AL SISTEMA”; real PI=3.1416;
visua “el valor de pi es = “,PI; fin _____________________________________________________________________
Ejo. 2.
inicio var entero i,cont; cadena s1,s2,s3; real x,y,area,radio;
Ing. Francisco Ríos Acosta Tabla de símbolos en C# y su interacción con el analizador léxico. Instituto Tecnológico de la Laguna, a 15 de septiembre del 2008. pag. 5 de 26 visua “teclea el valor de i : “; leer i; visua “teclea el valor del radio : “; leer radio; s1 = “hola”; i = i + 1; fin _____________________________________________________________________
Ejo. 3.
inicio visua “HOLA MUNDO “; fin _____________________________________________________________________
Ejo. 4.
inicio const entero MAX=10; cadena MENSAJE=”BIENVENIDOS AL SISTEMA”; real PI=3.1416;
var entero i,cont; cadena s1,s2,s3; real x,y,area,radio;
visua “teclea el valor de i : “; leer i; visua “teclea el valor del radio : “; leer radio; area = PI * radio * radio; fin _____________________________________________________________________
La gramática propuesta para denotar a este lenguaje es : P -> inicio C fin C -> K S | V S | K V S | S K
R ->
-> const R
R Y id = Z ; | Y id = Z ; Y -> entero | cadena | real Z -> num | cad V
B
I ->
->
-> var B
B Y I ;
I , id |
| Y I ;
id S -> S A | S L | S O | A | L | O A -> id = E ; | id = cad; E
T ->
-> E + T
T * F |
| E – T
T / F |
| T
F F -> id | num | ( E ) L
O ->
-> leer id ;
visua W ;
Ing. Francisco Ríos Acosta Tabla de símbolos en C# y su interacción con el analizador léxico. Instituto Tecnológico de la Laguna, a 15 de septiembre del 2008. pag. 6 de 26 W -> W , id | W , cad | W , num | id | num | cad Usemos cualquiera de los 2 softwares didácticos RD-NRP o bien el RA-SLR para reconocer los ejemplos del 1 al 4. Antes deberemos teclear la gramática según se muestra en la figura #3.1 en el programa RD-NRP. Fig. No. 3.1 Análisis de la gramática propuesta usando el RD-NRP.
La gramática transformada con E.R.I. y F.I. agrupada, obtenida con el RD-NRP es : P -> inicio C fin C -> K C' | V S | S C' -> S | V S K ->
R ->
R' -> const R
Y id = Z ; R'
Y id = Z ; R' | £ Y -> entero | cadena | real Z -> num | cad V ->
B ->
B' ->
I ->
I' -> var B
Y I ; B'
Y I ; B'
id I'
, id I' |
| £
£ S ->
S' -> A S'
A S' |
| L S'
L S' |
| O S'
O S' | £
Tabla de símbolos en C# y su interacción con el analizador léxico. Instituto Tecnológico de la Laguna, a 15 de septiembre del 2008. pag. 7 de 26 Ing. Francisco Ríos Acosta A -> id = A' | cad ; A' ->
E -> E ;
T E' E' -> + T E' | – T E' | £ T -> F T' T' -> * F T' | / F T' | £ F -> id | num | ( E ) L
O ->
-> leer id ;
visua W ; W -> id W' | num W' | cad W' W' -> , W | £ El ejemplo 3 correspondiente al famoso “HOLA MUNDO” simulándolo obtenemos lo que indica la figura #3.2. Fig. No. 3.2 Reconocimiento de “HOLA MUNDO”, ejo. 3.
Podemos teclear otro ejemplo en la simulación, digamos que el ejo 2 el cual debemos teclear tal y como se indica. La figura #3.3 tiene el resultado como exitoso y la derivación a la izquierda -50 producciones usadas- del conjunto de sentencias.
inicio var entero id,id; cadena id,id,id; real id,id,id,id;
visua cad; leer id; visua cad; leer id; id = cad; id = id + num; fin
Ing. Francisco Ríos Acosta Tabla de símbolos en C# y su interacción con el analizador léxico. Instituto Tecnológico de la Laguna, a 15 de septiembre del 2008. pag. 8 de 26 Fig. No. 3.3 Reconocimiento del ejo. 2. 4 Analizador léxico. El conjunto de símbolos terminales que el análisis léxico deberá reconocer, no depende del tipo de reconocedor ya sea descendente o bien ascendente, que usemos en el análisis sintáctico. El conjunto Vts de la gramática es : Vts = { inicio fin const id = ; entero cadena real num cad var , + – * / ( ) leer visua } Agrupemos a los símbolos terminales de manera que a cada grupo le corresponda un AFD en el análisis léxico : •
• • AFD id y palabras reservadas.- inicio fin const id entero cadena real var leer visua. Con este AFD reconoceremos tanto a los identificadores como a las palabras reservadas, usando el método EsId() dentro de la clase Lexico que produce el software SP-PS1. En el caso de las palabras reservadas almacenaremos la pareja lexema- lexema, para el id almacenamos la pareja token-lexema. AFD num.- Reconoceremos sólo número enteros. Almacenamos la pareja token-lexema. AFD cad.- Reconoceremos secuencias de caracteres encerradas entre comillas. Incluimos el reconocimiento de la cadena nula. Almacenamos la pareja token-lexema. • = ; , + – * / ( ). AFD otros.- En este AFD reconocemos a los demás símbolos terminales : Almacenamos la pareja lexema-lexema. • AFD delim.- Reconocemos a los delimitadores pero no los almacenamos, ni al token, ni al lexema. Recomendamos al lector que consulte el documento leeme-analex-C# para obtener información del uso del software SP-PS1 para generar código útil para construir un analizador léxico. También se sugiere consultar los documentos leeme-RD-NRP y leeme-recasc-C# donde se explica la modificación de la clase Lexico para cumplir con lo especificado en las viñetas del párrafo anterior. A continuación mostramos la expresión regular para cada token y su AFD.
AFD delim.- Sirve para reconocer a los caracteres delimitadores tales como el blanco, nueva línea, retorno de carro, tab. Su expresión regular y AFD óptimo construído por SP-PS1 son :
{delim} -> [ nrt]+ [^ nrt]
Ing. Francisco Ríos Acosta Tabla de símbolos en C# y su interacción con el analizador léxico. Instituto Tecnológico de la Laguna, a 15 de septiembre del 2008. pag. 9 de 26 AFD id.- Reconoce al lenguaje de todos los identificadores en C. La regla que usaremos está restingida a : cadenas que inicien con letra seguida de 0 o mas letras, dígitos o subrayado. También usaremos este autómata para reconocer a las palabras reservadas int y float. Su expresión regular y su AFD son : {letra} -> [A-Za-z] {dig} -> [0-9] {guionbajo} -> _ {id} -> {letra} ( {letra} | {dig} | {guionbajo} )* [^A-Za-z0-9_] AFD num.- Vamos a limitar a los lexemas del token num a sólo enteros. La expresión regular y su AFD óptimo son : {num} -> [0-9]+ [^0-9]
Ing. Francisco Ríos Acosta Tabla de símbolos en C# y su interacción con el analizador léxico. Instituto Tecnológico de la Laguna, a 15 de septiembre del 2008. pag. 10 de 26 AFD cad.- Reconoce a las cadenas de caracteres encerradas entre comillas.
{cad} -> " [^"]* " AFD otros.- Su expresión regular es :
{otros} -> = | ; | , | + | – | * | / | ( | ) El código generado por SP-PS1 para la clase Lexico es –se incluyen las modificaciones- :
class Lexico { const int TOKREC = 5; const int MAXTOKENS = 500; string[] _lexemas; string[] _tokens; string _lexema; int _noTokens; int _i; int _iniToken; Automata oAFD;
public Lexico() // constructor por defecto { _lexemas = new string[MAXTOKENS]; _tokens = new string[MAXTOKENS]; oAFD = new Automata(); _i = 0; _iniToken = 0; _noTokens = 0;
Ing. Francisco Ríos Acosta Tabla de símbolos en C# y su interacción con el analizador léxico. Instituto Tecnológico de la Laguna, a 15 de septiembre del 2008. pag. 11 de 26 } }
public void Inicia() { _i = 0; _iniToken = 0; _noTokens = 0; }
public void Analiza(string texto) { bool recAuto; int noAuto; while (_i < texto.Length) { recAuto=false; noAuto=0; for(;noAuto< palres.Length; i++) if (_lexema==palres[i]) return false; return true; }
// fin de la clase Lexico La clase Automata es :
class Automata { string _textoIma; int _edoAct;
Ing. Francisco Ríos Acosta Tabla de símbolos en C# y su interacción con el analizador léxico. Instituto Tecnológico de la Laguna, a 15 de septiembre del 2008. pag. 12 de 26 char SigCar(ref int i) { if (i == _textoIma.Length) { i++; return ' '; } else return _textoIma[i++]; }
public bool Reconoce(string texto,int iniToken,ref int i,int noAuto) { char c; _textoIma = texto; string lenguaje; switch (noAuto) { //————– Automata delim————– case 0 : _edoAct = 0; break; //————– Automata id————– case 1 : _edoAct = 3; break; //————– Automata num————– case 2 : _edoAct = 6; break; //————– Automata otros————– case 3 : _edoAct = 9; break; //————– Automata cad————– case 4 : _edoAct = 11; break; } while(i=0) { i=iniToken; return false; } break; case 1 : c=SigCar(ref i); if ((lenguaje=" nrt").IndexOf(c)>=0) if ((lenguaje="!"#$%&'()*+,- ‘’ ./0123456789:;?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[/]^_`abcdefghijklmnopqrstuvwxyz{|}~ € ‚ƒ„…†‡ˆ‰Š‹Œ Ž “”•–—˜™š›œ žŸ ¡¢£¤¥¦§¨©ª«¬-®¯°±²³´µ¶·¸¹º»¼½¾¿f").IndexOf(c)>=0) _edoAct=2; else { i=iniToken; return false; } break; case 2 : i–; return true; break; //————– Automata id————– case 3 : c=SigCar(ref i); if ((lenguaje="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz").IndexOf(c)>=0) { i=iniToken; return false; } break; case 4 : c=SigCar(ref i); if ((lenguaje="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz").IndexOf(c)>=0) _edoAct=4; else
_edoAct=4; else if ((lenguaje="0123456789").IndexOf(c)>=0) _edoAct=4; else if ((lenguaje="_").IndexOf(c)>=0) _edoAct=4; else ‘’“”•–— if ((lenguaje=" !"#$%&'()*+,-./:;?@[/]^`{|}~ € ‚ƒ„…†‡ˆ‰Š‹Œ Ž ˜™š›œ žŸ ¡¢£¤¥¦§¨©ª«¬-®¯°±²³´µ¶·¸¹º»¼½¾¿ntrf").IndexOf(c)>=0) _edoAct=5; else { i=iniToken; return false; } break; case 5 : i–; return true; break;
Ing. Francisco Ríos Acosta Tabla de símbolos en C# y su interacción con el analizador léxico. Instituto Tecnológico de la Laguna, a 15 de septiembre del 2008. pag. 13 de 26 _edoAct=7; else
_edoAct=7; else //————– Automata num————– case 6 : c=SigCar(ref i); if ((lenguaje="0123456789").IndexOf(c)>=0) { i=iniToken; return false; } break; case 7 : c=SigCar(ref i); if ((lenguaje="0123456789").IndexOf(c)>=0) if ((lenguaje=" !"#$%&'()*+,- ‘’“”•–— ./:;?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[/]^_`abcdefghijklmnopqrstuvwxyz{|}~ € ‚ƒ„…†‡ˆ‰Š‹Œ Ž ˜™š›œ žŸ ¡¢£¤¥¦§¨©ª«¬-®¯°±²³´µ¶·¸¹º»¼½¾¿ntrf").IndexOf(c)>=0) _edoAct=8; else { i=iniToken; return false; } break; case 8 : i–; return true; break; //————– Automata otros————– case 9 : c=SigCar(ref i); _edoAct=10; else _edoAct=10; else _edoAct=10; else _edoAct=10; else _edoAct=10; else _edoAct=10; else _edoAct=10; else _edoAct=10; else _edoAct=10; else
_edoAct=12; else
_edoAct=13; else if ((lenguaje="=").IndexOf(c)>=0) if ((lenguaje=";").IndexOf(c)>=0) if ((lenguaje=",").IndexOf(c)>=0) if ((lenguaje="+").IndexOf(c)>=0) if ((lenguaje="-").IndexOf(c)>=0) if ((lenguaje="*").IndexOf(c)>=0) if ((lenguaje="/").IndexOf(c)>=0) if ((lenguaje="(").IndexOf(c)>=0) if ((lenguaje=")").IndexOf(c)>=0) { i=iniToken; return false; } break; case 10 : return true; break; //————– Automata cad————– case 11 : c=SigCar(ref i); if ((lenguaje=""").IndexOf(c)>=0) { i=iniToken; return false; } break; case 12 : c=SigCar(ref i); if ((lenguaje=""").IndexOf(c)>=0) if ((lenguaje=" !#$%&'()*+,- ./0123456789:;?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[/]^_`abcdefghijklmnopqrstuvwxyz{|}~ € ‚ƒ„…†‡ˆ‰Š‹Œ Ž ‘’ _edoAct=12; else “”•–—˜™š›œ žŸ ¡¢£¤¥¦§¨©ª«¬-®¯°±²³´µ¶·¸¹º»¼½¾¿ntrf").IndexOf(c)>=0) { i=iniToken; return false; } break; case 13 : return true; break; } switch (_edoAct) { case 2 : // Autómata delim case 5 : // Autómata id case 8 : // Autómata num –i; return true; } return false; }
} // fin de la clase Automata
Construyamos la aplicación Windows C# que sirva para analizar léxicamente un programa fuente de entrada, que cumpla con la sintaxis de la gramática que denota al lenguaje propuesto.
La interfase gráfica de la aplicación Windows C# contiene los componentes : 2 Label’s, 1 TextBox, 1 dataGridView y 1 Button. Agrega los componentes dejándoles su propiedad Name intacta. Caracteriza al componente dataGridView1 con la adición de sus 2 columnas TOKEN y LEXEMA.
La interfase gráfica de la aplicación es la mostrada en la figura #4.1.
Ing. Francisco Ríos Acosta Tabla de símbolos en C# y su interacción con el analizador léxico. Instituto Tecnológico de la Laguna, a 15 de septiembre del 2008. pag. 14 de 26 Fig. No. 4.1 Aplicación Windows C#, para el análisis léxico.
Agregamos la definición del objeto oAnalex en Form1.cs : Lexico oAnaLex = new Lexico(); Ahora añadimos las clases Lexico y Automata al proyecto y les pegamos el código que hemos mostrado antes en esta misma sección. Agregamos en el click del botón ANALISIS LEXICO el código siguiente :
public partial class Form1 : Form { Lexico oAnaLex = new Lexico(); public Form1() { InitializeComponent(); }
private void button1_Click(object sender, EventArgs e) { oAnaLex.Inicia(); oAnaLex.Analiza(textBox1.Text); dataGridView1.Rows.Clear(); if (oAnaLex.NoTokens > 0) dataGridView1.Rows.Add(oAnaLex.NoTokens); for (int i = 0; i < oAnaLex.NoTokens; i++) { dataGridView1.Rows[i].Cells[0].Value = oAnaLex.Token[i]; dataGridView1.Rows[i].Cells[1].Value = oAnaLex.Lexema[i]; } } }
Antes de ejecuta la aplicación, debemos agregar a la clase Lexico la propiedades siguientes :
public int NoTokens { get { return _noTokens; } }
Ing. Francisco Ríos Acosta Tabla de símbolos en C# y su interacción con el analizador léxico. Instituto Tecnológico de la Laguna, a 15 de septiembre del 2008. pag. 15 de 26 public string[] Lexema { get { return _lexemas; } } public string[] Token { get { return _tokens; } }
La figura #4.2 muestra la ejecución de la aplicación. Notemos que hemos desplazado la barra de la rejilla de visualización de las parejas token-lexema, con el fin de mostrar las últimas parejas reconocidas. Entre ellas están los tokens cad. 5 Fig. No. 4.2 Aplicación Windows C# con la entrada del ejo. 2.
Análisis de los atributos de los objetos que se almacenan en la tabla de símbolos. Vamos a limitar nuestro universo a los tokens que reconoce el analizador léxico de nuestro ejemplo y que necesiten de instalarse en la tabla de símbolos al momento del proceso del análisis léxico : • • • id num cad De los anteriores tomaremos para nuestro estudio al token id. Los tokens num y cad los dejaremos para verlos posteriormente. El token id puede representar o una variable o una constante. Los atributos que proponemos de inicio son : • • • • • • clase, sus valores posibles : variable , constante. nombre, es el lexema del token id (tal y como se encuentra en el texto de entrada). valor, representa el valor que se le asigna durante los diferentes procesos de análisis a la variable o a la constante. tipo, representa el tipo de dato al que pertenece la variable o la constante. noBytes, número de bytes en los que se almacena la variable o constante. posicion, se refiere al índice de inicio del lexema donde se reconoció al token id dentro del texto de entrada.
Ing. Francisco Ríos Acosta Tabla de símbolos en C# y su interacción con el analizador léxico. Instituto Tecnológico de la Laguna, a 15 de septiembre del 2008. pag. 16 de 26 El analizador léxico en lo que respecta al token id al momento de reconocerlo, sólo puede instalarlo en la tabla de símbolos y almacenar los atributos nombre y posicion. Los atributos clase, valor, tipo y noBytes son asignados en la etapa del análisis semántico. Por lo anterior, la clase Lexico deberá tener un método que instale a un id en la tabla de símbolos, asignando sólo los atributos nombre y posicion. Entonces, debemos pensar en que los nodos de las listas de la tabla de símbolos contienen objetos de una clase, cuyos atributos sean los mencionados. A esta clase la llamaremos TipoElem.
class TipoElem { private string _clase; private string _nombre; private string _valor; private string _tipo; private int _noBytes; private int _posicion;
}
Quizá la única confusión que pudiera existir al analizar esta definición de atributos, es el tipo string que le hemos dado al atributo valor. En cuanto a esta cuestión, pensemos en realizar una conversión de acuerdo al atributo tipo que el análisis semántico registre. Con los atributos iniciales ya definidos quedando especificado que sólo empezaremos por instalar al token id y sus atributos nombre y posicion durante el análisis léxico, estamos listos para definir la clase TablaSimbolos. 6 Clase TablaSimbolos. De acuerdo al modelo conceptual presentado en la sección 2, la tabla de símbolos es un objeto que contiene un arreglo de listas enlazadas. Iniciemos por definir este atributo con elementos de la clase Lista. Fig. No. 6.1 Aplicación Windows C# con la clase TablaSimbolos, su constructor y el método Inicia().
Ing. Francisco Ríos Acosta Tabla de símbolos en C# y su interacción con el analizador léxico. Instituto Tecnológico de la Laguna, a 15 de septiembre del 2008. pag. 17 de 26 class TablaSimbolos { Lista[] _elems;
}
Agreguemos esta clase a la aplicación Windows C# que ya contiene al analizador léxico para el lenguaje propuesto. Una vez añadida la clase TablaSimbolos al proyecto, escribamos la sentencia de definición del atributo _elems. También agregamos el constructor para la clase TablaSimbolos, además del método Inicia() utilizado tantas veces como sea necesario efectuar la inicialización del objeto tabla de símbolos al que mas tarde llamaremos oTablaSimb. La figura #6.1 contiene la aplicación Windows con la clase añadida y el código para los métodos que hemos mencionado.
El constructor de la clase TablaSimbolos permite fijar la dimensión del arreglo de listas por medio del parámetro de entrada noElems. Además crea a los objetos Lista del arreglo mediante la llamada al operador new.
A diferencia del constructor parametrizado, el método Inicia() no crea a los objetos Lista del arreglo –ya que previamente han sido creados por el constructor-, sino que asigna las cabeceras de los objetos Lista a null y su número de nodos los asigna a 0, cumpliendo de esta manera su función.
Como ya estamos manejando a los objetos Lista, debemos agregar la definición de esta clase al proyecto. La definición de la clase Lista es :
class Lista { Nodo _cabLista; int _noNodos;
public Lista() { _cabLista = null; _noNodos = 0; }
public Nodo Cab { get { return _cabLista; } set { _cabLista = value;} }
public void InsInicio(TipoElem oElem) { Nodo nuevoNodo = new Nodo(); nuevoNodo.Info = oElem; nuevoNodo.Sig = _cabLista; _cabLista = nuevoNodo; _noNodos++; }
public int NoNodos { get { return _noNodos;} set { _noNodos = value;} }
}
La clase Lista representa a objetos con nodos simplemente enlazados, con campos de información y de enlace –referencias-. En cualquier curso de estructura de datos es manejada esta clase. Realmente los métodos que se han incluido son los menos.
Una buena mejora es agregar el método InsOrden(oElem) que agrega en orden ascendente al objeto oElem, en la lista enlazada.
Notemos que la clase Lista hace referencia a otras 2 clases : Nodo y TipoElem. La figura #6.2 muestra la aplicación Windows C# con la clase Lista añadida.
Ing. Francisco Ríos Acosta Tabla de símbolos en C# y su interacción con el analizador léxico. Instituto Tecnológico de la Laguna, a 15 de septiembre del 2008. pag. 18 de 26 Fig. No. 6.2 Aplicación Windows C# con la clase Lista incluida.
Observemos que la clase Lista que hemos incluido al proyecto, contiene un constructor por defecto, 2 propiedades Cab y NoNodos, además del método InsInicio().
La clase Nodo es la encargada de representar a los elementos de la lista enlazada. La añadimos al proyecto según el código que mostramos enseguida :
class Nodo { TipoElem _oInfo; Nodo _sig;
public TipoElem Info { get { return _oInfo;} set { _oInfo = value; } }
public Nodo Sig { get { return _sig; } set { _sig = value; } }
} La clase Nodo además de sus atributos sólo contiene 2 propiedades : Info y Sig. Lo que sigue es añadir al proyecto la clase TipoElem con los atributos que definimos anteriormente en esta misma sección.
Por ahora sólo declararemos los atributos en la clase TipoElem, dejando la inserción de los métodos para después. La figura muestra a la aplicación Windows después de haber agregado las 3 clases : Lista, Nodo y TipoElem.
Ing. Francisco Ríos Acosta Tabla de símbolos en C# y su interacción con el analizador léxico. Instituto Tecnológico de la Laguna, a 15 de septiembre del 2008. pag. 19 de 26 Fig. No. 6.3 Aplicación Windows C# con las clases Nodo y TipoElem.
Sólo falta agregar al objeto oTablaSimb dentro del archivo Form1.cs, dimensionando al arreglo de listas en 26. La razón de esta dimensión, es que la función de desmenuzamiento –hash- toma al primer caracter del lexema del id de manera que si es una A(a) el id se añade a la lista con indice 0, si empieza con B(b) se agrega a la lista con indice 1, y así hasta la letra Z(z) en donde se agrega al id a la lista con indice 25.
Agrega la definición del objeto oTablaSimb en la siguiente línea a la definición del objeto oAnaLex, según se muestra en el segmento de código de la clase Form1 del archivo Form1.cs.
public partial class Form1 : Form { Lexico oAnaLex = new Lexico(); TablaSimbolos oTablaSimb = new TablaSimbolos(26);
public Form1() { InitializeComponent(); } … … …
Compilemos la aplicación sólo para observar que no existan errores en el código que hemos añadido. El resultado de la compilación es exitoso, sin embargo tenemos unas advertencias que no les vamos a poner atención. Tecleemos el código siguiente en la ventana de entrada de texto, de manera que veamos las parejas token-lexema que el analizador léxico encuentra.
inicio visua “HOLA MUNDO”; fin
Hasta este punto, tenemos la definición del objeto oTablaSimb en nuestra aplicación, sin errores. Lo que sigue es instalar a los id reconocidos durante la etapa del análisis léxico, en la tabla de símbolos. 7 Instalación de identificadores. En la sección anterior la tabla de símbolos se dimensionó a 26 listas enlazadas cada una correspondiente a una letra del abecedario.
pag. 20 de 26 Ing. Francisco Ríos Acosta A 0 Tabla de símbolos en C# y su interacción con el analizador léxico. Instituto Tecnológico de la Laguna, a 15 de septiembre del 2008. null B 1 null C 2 null D 3 null E 4 null F 5 null G 6 null …
…
… …
…
… …
…
… X 23 null Y 24 null Z 25 null La pregunta es : ¿en qué parte del código vamos a insertar la instalación de un id durante el análisis léxico?. Bueno, vayamonos por pasos, así que lo primero que vamos a hacer es enumerar los pasos a seguir : • • • Modificar la llamada al método Analiza() de la clase Lexico. Modificar la definición del método Analiza() en sus parámetros que recibe. Insertar el mensaje oTablaSimb.Instalar() dentro del método Analiza(). Llamada al método Analiza().- Inicialmente, el método tiene sólo un parámetro : el componente TextBox que contiene a la cadena que se analiza léxicamente. Ahora, tendrá 2 parámetros el que ya conocemos y el objeto oTablaSimb que enviaremos como referencia, de manera que pueda modificarse a este objeto, es decir, a la tabla de símbolos. Entonces modificamos la llamada al método Analiza() según se muestra a continuación :
private void button1_Click(object sender, EventArgs e) { oAnaLex.Inicia(); oTablaSimb.Inicia(); oAnaLex.Analiza(textBox1.Text,oTablaSimb); dataGridView1.Rows.Clear(); if (oAnaLex.NoTokens > 0) dataGridView1.Rows.Add(oAnaLex.NoTokens); for (int i = 0; i < oAnaLex.NoTokens; i++) { dataGridView1.Rows[i].Cells[0].Value = oAnaLex.Token[i]; dataGridView1.Rows[i].Cells[1].Value = oAnaLex.Lexema[i]; } }
Definición del método Analiza() en sus parámetros.- Desde luego que si compilamos existirá un error, así que debemos también modificar la definición del método Analiza() en la clase Lexico, según se te indica en el segmento de código siguiente :
public void Analiza(string texto, TablaSimbolos oTablaSimb) {
Ing. Francisco Ríos Acosta Tabla de símbolos en C# y su interacción con el analizador léxico. Instituto Tecnológico de la Laguna, a 15 de septiembre del 2008. pag. 21 de 26 Compilemos y ejecutemos sólo para observar que no existan errores al hacer nuestras modificaciones a la aplicación Windows C# que estamos construyendo.
Instalación del id dentro del método Analiza().- Es trivial que la instalación del id dentro de la tabla de símbolos deberá efectuarse al momento en que un token id sea reconocido, dentro del código del método Analiza(). Házlo según se muestra en la figura #7.1. Fig. No. 7.1 Mensaje oTablaSimb.Instalar() en la definición del método Analiza() de la clase Lexico.
Veamos los parámetros que recibe el método Instalar() :
oTablaSimb.Instalar(_lexema, _iniToken); • • El parámetro _lexema es el dato con el que se va a instanciar al atributo _nombre. El parámetro _iniToken es el valor con el que se va a instanciar al atributo _posicion. El método Instalar() lo definimos en la clase TablaSimbolos y consiste del código siguiente :
public void Instalar(string nombre, int posicion) { char car = nombre.ToUpper()[0]; int indice = Convert.ToInt32(car) – 65; if (! EncuentraToken(indice,nombre)) { TipoElem oElem=new TipoElem(nombre, posicion); _elems[indice].InsInicio(oElem); } } La función de hash está compuesta de 2 líneas de código : la primera toma al primer caracter del identificador y lo convierte a mayúscula, la segunda línea de código obtiene el índice que le corresponde a la letra en el arreglo de listas enlazadas de la tabla de símbolos. char car = nombre.ToUpper()[0]; int indice = Convert.ToInt32(car) – 65;
Ing. Francisco Ríos Acosta Tabla de símbolos en C# y su interacción con el analizador léxico. Instituto Tecnológico de la Laguna, a 15 de septiembre del 2008. pag. 22 de 26 El identificador en instalado sólo si no se encuentra en la lista enlazada correspondiente al índice que ha calculado la función de desmenuzamiento –hash-. El método EncuentraToken() es el encargado de realizar la búsqueda, si lo encuentra retorna true, false de lo contrario. Necesitamos agregar la definición de este método en la clase TablaSimbolos según lo mostramos enseguida :
public bool EncuentraToken(int indice,string nombre) { Nodo refLista = _elems[indice].Cab; while (refLista != null) { if (refLista.Info.Nombre==nombre) return true; refLista = refLista.Sig; } return false; }
Notemos que el método retorna true cuando el atributo _nombre devuelto por la propiedad Nombre, es igual al parámetro nombre recibido por el método EncuentraToken().
Si no se encuentra el identificador, entonces insertamos el nuevo elemento en la lista cuyo índice ha sido calculado por la función de desmenuzamiento, mediante el uso del método InsInicio(), definido en la clase Lista.
Antes de compilar la aplicación debemos añadir la propiedad Nombre en la clase TipoElem de acuerdo al código que mostramos a continuación :
public string Nombre { get { return _nombre; } set { _nombre = value; } }
Observemos que existe un constructor que debemos definir en la clase TipoElem. Este constructor es utilizado en el método Instalar() de la clase TablaSimbolos, como parámetro al crear el objeto que se va a instalar.
TipoElem oElem = new TipoElem(nombre, posicion);
El código del constructor es el siguiente, agreguemoslo a la clase TipoElem :
public TipoElem(string nombre, int posicion) { _clase = “”; _nombre = nombre; _posicion = posicion; }
Compilemos el programa sólo para probar que no existan errores en el código que hemos añadido. La aplicación Windows debe ejecutarse sin problemas –sólo advertencias-.
Hasta aquí, ya tenemos instalados los tokens id que hayan sido reconocidos en el análisis léxico, en la tabla de símbolos representada por el objeto oTablaSimb. Sólo resta visualizar la tabla de símbolos, cuestión que haremos en la siguiente sección. 8 Visualización de la tabla de símbolos. Para visualizar la tabla de símbolos utilizaremos una nueva forma Form2.cs, que añadimos usando la opción del menú Project | Add Windows Form. La figura #8.1 muestra a nuestro proyecto con la forma Form2.cs incluida. La propiedad Text de la forma Form2.cs se ha cambiado a : TABLA DE SIMBOLOS.
Ing. Francisco Ríos Acosta Tabla de símbolos en C# y su interacción con el analizador léxico. Instituto Tecnológico de la Laguna, a 15 de septiembre del 2008. pag. 23 de 26 Fig. No. 8.1 Adición de la nueva Form2.cs al proyecto de la aplicación.
Notemos que también hemos agregado un componente DataGridView a la forma Form2.cs. Este componente se encargará de recibir y visualizar en él, los elementos de la tabla de símbolos que se encuentran en el objeto oTablaSimb. El componente DataGridView es el que aparece con color gris oscuro. La propiedad Name de este componente es el que por defecto recibe dataGridView1.
Volvamos a la forma Form1.cs para agregar un botón que precisamente visualice a la forma Form2.cs, de manera que después llenaremos el dataGridView1 de la Forma2.cs con los elementos en el bjeto oTablaSimb. Asignemos a la proiedad Text del nuevo botón button2, el valor TABLA DE SIMBOLOS. La figura #8.2 muestra la interfase con el botón button2 insertado en la forma Form1.cs.
Agreguemos en el evento Click del button2 el código que permite visualizar a la forma Form2.cs :
private void button2_Click(object sender, EventArgs e) { Form2 formaTablaSimb = new Form2(); formaTablaSimb.Show(); }
Si compilamos y ejecutamos nuestra aplicación, veremos que al hacer click en el button2 tenemos a nuestra vista la forma Form2.cs. Lo que resta es caracterizar al dataGridView1 de la forma Form2.cs de manera que acepte a los elementos en el objeto oTablaSimb definido en la forma Form1.cs.
Ing. Francisco Ríos Acosta Tabla de símbolos en C# y su interacción con el analizador léxico. Instituto Tecnológico de la Laguna, a 15 de septiembre del 2008. pag. 24 de 26 Fig. No. 8.2 Adición del button2 para visualizar la forma Form2.cs –tabla de símbolos-.
Agreguemos ahora a la aplicación el mensaje al objeto oTablaSimb para que visualice a sus elementos en el componente dataGridView1 de Form2.cs. Este mensaje debemos añadirlo en el código para el click del button2.
private void button2_Click(object sender, EventArgs e) { Form2 formaTablaSimb = new Form2(); oTablaSimb.Visua(formaTablaSimb.dataGridView1); formaTablaSimb.Show(); }
También debemos agregar la definición del método Visua() a la clase TablaSimbolos. El código es :
public void Visua(System.Windows.Forms.DataGridView dGV) { Nodo refNodo; int col = 1; dGV.ColumnCount = this.Mayor() + 1; dGV.Rows.Add(_elems.Length); for (int i = 0; i < _elems.Length; i++) { col = 1; refNodo = _elems[i].Cab; dGV.Rows[i].Cells[0].Value = Convert.ToChar(65 + i).ToString()+" – "+i.ToString(); while (refNodo != null) { dGV.Rows[i].Cells[col++].Value = refNodo.Info.Clase+" – " + refNodo.Info.Nombre + " – "+refNodo.Info.Posicion.ToString(); refNodo = refNodo.Sig; } } }
Definimos un nuevo método Mayor() para calcular el máximo número de elementos en todas las listas enlazadas. De esta forma, podemos dimensionar al componente dataGridView1 para el manejo de las columnas del componente.
Así que debemos agregarlo a la clase TablaSimbolos.
Ing. Francisco Ríos Acosta Tabla de símbolos en C# y su interacción con el analizador léxico. Instituto Tecnológico de la Laguna, a 15 de septiembre del 2008. pag. 25 de 26 public int Mayor() { int mayor = 0; for (int i = 0; i < _elems.Length; i++) if (_elems[i].NoNodos > mayor) mayor = _elems[i].NoNodos; return mayor; }
Se nos olvidaba que debemos agregar la propiedad Posicion a la clase TipoElem, que es usada en el método Visua() de la clase TablaSimbolos.
public int Posicion { get { return _posicion; } set { _posicion = value; } }
Si compilamos la aplicación observaremos que tenemos un error referente al acceso del dataGridView1 de la forma Form2.cs. Este error es corregido fácilmente definiendo una propiedad en la forma Form2.cs, según lo indicamos en la figura #8.3. Fig. No. 8.2 Definición de la propiedad DataGridView1 en Form2.cs.
El método Mayor() es usado para calcular el número máximo de columnas en el dataGridView1, suficientes para visualizar a cada lista enlazada de la tabla de símbolos. La columna 0 del componente dataGridView1, es reservada para visualizar la letra e índice correspondiente a la lista enlazada cuyos elementos se muestran en el renglón i-ésimo. La figura #8.3 muestra la ejecución para el grupo de sentencias, donde además se visualiza la tabla de símbolos.
inicio var entero a, a2, b, b2,b4; real pi, pato, nino,x,y,z,z23; fin
Ing. Francisco Ríos Acosta Tabla de símbolos en C# y su interacción con el analizador léxico. Instituto Tecnológico de la Laguna, a 15 de septiembre del 2008. pag. 26 de 26 Fig. No. 8.3 Tabla de símbolos con elementos y atributos.
Página anterior | Volver al principio del trabajo | Página siguiente |