Documento de Ayuda

GOLD Parser
Hecho en Guatemala USAC Facultad de Ingeniería

Índice
Caratula Índice Quienes somos, visión, misión Objetivos Introducción GOLD Parser Build Ejemplos ANSI C y GOLD PARSER C Sharp Y GOLD PARSER Java Y GOLD Parser Visual Basic y GOLD Parser Integrantes 1 2 3 4 5 12 14 34 69 75 91

¿Quiénes somos?
Somos un grupo de estudiantes de la facultad de Ingenierías en ciencias y sistemas de la universidad de san calos de Guatemala USAC.

Nuestra Misión
Hacer uso de las herramientas tecnológicas tanto de hardware y software, para poder desarrollar productos de alta calidad, que ayude a mejorar la vida ser humano y su entorno.

Nuestra Visión
Ayudar a mejorar o facilitar la situación de nuestro entorno, por medio del desarrollo de software en distintas áreas de la sociedad.

OBJETIVOS de este documento
Generales
Facilitar el uso de la herramienta GOLD Parser en el uso de analizadores. Explicar fácil y gráficamente los pasos a seguir para pode realizar un analizador a partir de una gramática.

Específicos
Realizar una gramática desde cero con GOLD Parser Implementar la gramática para los lenguajes ANSI C (C puro), C#, Java y Visual Basic Ayudar al lector con información en español de GOLD Parser

INTRODUCION
GOLD Parser es una herramienta desarrollada por Devin Cook, implementando un LALR (Look Ahead Left to Right- Rightmost derivation), se pueden construir proyectos con base de analizadores, o construir versiones propias de un lenguaje de programación. GOLD Parser es la herramienta con más capacidad de ser implementada en varios lenguajes de programación, ya que guarda un archivo aparte conteniendo información de tablas de parseo y en cada lenguaje se implementa el autómata simple para el análisis de dichas tablas. Otra ventaja es el soporte que todavía se le brinda a la herramienta y es GRATIS. Algunos lenguajes soportados y con implementación disponibles son los siguientes:

Funcionamiento
Como la instalación de GOLD Parser es sencilla no se explicara en este documento. (Véase http://www.devincook.com/goldparser/download.htm para la descarga del instalador y los complementos que vamos a usar en cada lenguaje).Algoritmo para implementar un analizador: ritmo 1. Crear una gramática valida (sin errores de ningún tipo). 2. Guardar el archivo que nos genera (CGT “Compiler Grammar Table” se explicara más adelante). 3. Crear un esqueleto del lenguaje que deseemos. 4. Ingresar las acciones a nuestro proyecto.

Tabla Compilada de la GRAMATICA (GCT)
La tabla de cada analizador es un archivo (.cgt), esta tabla de gramática compilada posee la información del autómata para análisis léxico y sintáctico. Como vemos no se necesita insertar en la construcción de la gramática gramática, código o acciones semánticas ya que la construcción del analizador LALR es nticas, n independiente del lenguaje en que estemos trabajando. Hasta este punto se utiliza la herramienta Gold Parser BUILDER, si se desea existen Skeletons, ya disponibles para varios lenguajes. Un Skeleton (Esqueleto o plantilla) es un archivo con la implementac implementación de nuestra gramática lista para introducirles acciones en el lenguaje que estemos usando.

El engine(Motor) del lenguaje de programación utiliza este archivo y e dependiendo del lenguaje de programación analiza el archivo fuente, crea el árbol de análisis sintáctico, permite asociar objetos a , cada símbolo de la gramática e gramática, implementa la tabla de análisis sintáctico para esa gramática ico gramática.

Para cada lenguaje existen diferentes motores los cuales deben de descargarlos en librerias o complementos para poder utilizarlos en sus proyectos

Escritura de Gramática y Más
GOLD Parser utiliza notación BNF (Backus Naur Form), por lo que todos los No terminales deben estar encerrados en brackets angulares, por ejemplo <NoTerminal> o <Inicio>. También permite definir tokens terminales entre comillas, por ejemplo ‘terminal1’ o ‘nombreCompleto’. Ahora noten que el terminal ‘terminal1’ corresponde a la palabra exactamente encerrada, pero no fue declarado al inicio como un terminal, terminal1 correspondería a una expresión regular. Caracteres especiales para realizar la gramática:

Caracteres comunes
NOMBRE
Tabulador Salto de Línea Tabulación Vertical Limpia pantalla Retorno de Carro Espacio Espacio sin Romper Símbolo del Euro

INSTRUCCION DESCRIPCION
{HT} {LF} {VT} {FF} {CR} {Space} {NBSP} {Euro Sign} Conocido como Tab, escribe una tabulación en la línea. Se utiliza para bajar una línea en los documentos Se usa para saltase a la siguiente línea marcada Se usa para saltar toda la pantalla por ejemplo CLR o clear Sirve retornar el apuntador al inicio de la línea Se utiliza para separar caracteres Se utiliza para los espacio donde el salto de línea no es permitido Representa el símbolo del euro

Conjuntos de Caracteres comunes
NOMBRE
Numero Digito

INSTRUCCION
{Number} {Digit}

DESCRIPCION
Números del 0 al 9. Esta instrucción es similar a number, recomiendan NO USAR ESTA INSTRUCCIÓN. Reconoce una simple letra del alfabeto en minúsculas o mayúsculas no incluye la ñ. Es la unión de las instrucciones Letter y Number. Reconoce cualquier carácter desde el #32-#127 y #160 (No espacios quebrados). Reconoce todas las letra incluyendo los caracteres especiales como ñ Reconoce todos los caracteres arriba del carácter #127 Reconoce los caracteres como espacio, salto de line.

Letra Alfanumérico Cualquier Carácter Letra Extendida Cualquier Carácter extendido Espacio en blanco

{Letter} {AlphaNumeric} {Printable} {Letter Extended} {Printable Extended} {Whitespace}

Ejemplo:
!--comentario (parte I) {String Char} = {Printable} - ["] {IdLetter} = {Letter} + [_$] {IdAlphaNumeric} = {Alphanumeric} + [_$] !-- parte I define todos los conjuntos para exp. regulares !-- parte II (Expresiones regulares) Identifier = {IdLetter} {IdAlphaNumeric}* StringLiteral = '"'{String Char}*'"' Integer = {Digit}+ terminal1 = {Digit}+'.'{Digit}+ !-- define diferentes expresiones regulares para la gramatica "Start Symbol" = <inicio> <inicio>::= terminal1 | ‘terminal1’ <mas_>

En el breve ejemplo de arriba se nota lo principal entre la expresión regular, nuestra gramática inicia con un terminal1 (numero FLOAT) o con la palabra reservada ‘terminal1’. Esto implica la barra vertical en una regla la bifurcación (OR). También el primer bloque posee conjuntos utilizados para la construcción de las expresiones regulares.

La estructura de las reglas consiste, solo un <No terminal> de la izquierdo luego definimos ‘produce’ colocando ::= y nuestro lado derecho del produce. Los comentarios son muy recomendables para la explicación de cada parte de la gramática, GP permite , colocar comentarios de una sola línea con ! al inicio o bloques de varias líneas entre !* *!

Ver la ayuda de GP Builder para una descripcion detalla de los conjuntos ya prefabricados para uso.

Notar la línea ‘Start Symbol’ que indica la regla inicial de la gramática.

También GP Builder cuenta con parámetros para detallar o permitir ciertas funcionalidades que se insertan al inicio de la gramática. Como Name (nombre de la . gramática), Author (autor de la gramática), ), Case Sensitive (Para restricción de mayúsculas y minúsculas).

Ver la ayuda de GP Builder para mayor detalle de los parametros disponibles en la version que se este utilizando.

Ejemplos
Prácticos

Lista de Lenguajes
Para mostrar los diferentes usos de que se le pueden dar a GOLD Parser, presentamos 4 lenguajes de programación, en los cuales damos paso a paso las instrucciones para implementarlo:

ANSI C C# JAVA Visual Basic

ANSI C
Generado por GOLD Parser

GOLD PARSER Y ANSI C
El lenguaje de Ansi C es uno de los lenguajes de programación que dio lugar a muchos lenguajes más como C++, java, C#. Entre otros. Es un lenguaje muy simple pero poderoso, de el están hechos muchos sistemas operativos. Como en todo programa se necesita de información y esta debe de ser filtrada para un mejor aprovechamiento de los recursos. El uso de un analizador es una de las mejores prácticas para poder filtrar la información. GoldParser es una herramienta que nos ayuda a crear un analizador definiendo una gramática con BNF (Backus-Naur Form), como se muestra en la siguiente imagen:

Siguiendo la gramática siguiente:
<lenguaje> <listas> ::= <Listas> ::= <listas> ',' <lista> | <lista> ::= '{' <numeros> '}' ::= <numeros> ',' numero | numero

<lista> <numeros>

Para poder realizar las acciones deseadas para esta gramática. Debemos de pasar por 4 pasos en GOL Parser:

PASO 1:

Verificar que la gramática este correcta ( Sin errores léxicos, sintácticos, etc.)

PASO 2:

Construir el analizador LALR (Look-Ahead Left Right), verifica que no existan conflictos de reducción-reducción o desplazamiento-reducción.

PASO 3:

Construye el Autómata finito determinantico DFA.

PASO 4:

En este paso se guarda la gramática analizada en forma de tabla. (Esto nos servirá para crear un esqueleto para unirlo a nuestro lenguaje Ansi C).

Cuando pasamos por el paso 4 vamos a guardar la tabla compilada de nuestra gramática, este lo vamos a utilizar más adelante

Para verificar que nuestro GCT esta correcto, vamos a comprobarlo con un archivo de entrada por medio de la herramienta que nos provee GOLD Parser Builder, Le damos Clic en el icono de un cheque verde (ver figura)

Cuando hayamos hecho lo anterior vamos a ingresar una cadena valida según nuestro lenguaje para poder probarlo.

Para probar le damos clic en el icono verde que nos permite ir probando paso a paso, la forma en que va leyendo nuestro archivo la tabla compilada de nuestra gramática, también podemos ir de un solo al final del análisis ya sea algún error o como esta en este documento VALIDA (Acecept)

Ya que tenemos nuestra Gramática Compilada en Tabla, vamos a proceder a crear un esqueleto para poderlo utilizar con nuestro lenguaje.

Existen 3 tipos de Motores (Engine) para ANSI C, pero nosotros para mayor facilidad vamos a utilizar el 3 motor, KESSELS ENGINE, creado por J.C. Kessels (http://kessels.com/Gold/index.html)

Guardamos el primer archivo .h (no importa el orden .h/.c) que contiene las declaraciones de los símbolos.

El segundo archivo es el .c, vamos a guardarlo igual que el .h, este archivo contiene un main por defecto como se verá más adelante

Una vez creados los 2 archivos, le damos clic en “Done” para poder proceder a ingresar las acciones a nuestra gramática en ANSI C. (ambos archivos deben de estar en el directorio del proyecto)

Ahora abrimos nuestro archivo *.c con algún compilador o editor para C/C++, en este ejemplo yo utilizo Borland C++, pero pueden usan VC++.net o VC++ 6, asi como cualquier compilador de Linux ya que el motor kessels es aceptado por compilador de C para Windows y Linux.

Creando un Nuevo proyecto VC++ 6

Vamos Agregar los archivos que están en esta carpeta el grammar.h y template.c

Dentro de los archivos deben de ir los Engine.h y engine.c que se pueden descargar de la página del creador de estos motores http://kessels.com/Gold/index.html

Como menciona en la página anterior, ya descargados y descomprimidos solo queda copiarlos a la carpeta donde tenemos nuestro proyecto y agregarlos.

Ahora vamos a agregar los esqueletos que fueron creados en GOLD Parser Build.

El archivo de gramatica.h tiene un pequeño problema con los caracteres, ya que yo tengo el sistema español Latino (GUATEMALA) y me da un pequeño error a la hora de generarlo, como se explica a continuación:

Otro pequeño problema que me tope es que cuando se ha construyendo el .exe se bloquean los archivos y aparece el siguiente mensaje:

Antes de proceder a Construir vamos a cambiar el archivo de entrada que viene por default

Procedemos a Construir nuestro proyecto de ejemplo:

Les debería de Salir un mensaje exitoso de la construcción del archivo .exe

Como menciona la imagen a mi me dio problemas a tratar de Debugear la aplicación, asi que les recomiendo mejor ejecuten y no debugeen

Como ven en la imagen he modificado la salida en la parte de Gramática aceptada

C Sharp
Generado por GOLD Parser

GOLD PARSER CON C#
El presente documento estará dividido en 2 ejemplos, un ejemplo sencillo para ver las funcionalidades básicas de las herramientas y un ejemplo con cierta mayor dificultad. Nota: antes de empezar el presente manual el lector debe tener conocimientos básicos en la definición de gramáticas y sintaxis utilizada en GOLD Parser. La primera gramática utilizada será la siguiente: Una gramática que reconoce un conjunto de números enteros separados por coma y agrupados entre llaves Start Symbol" Numero = <lenguaje> = {Digit}+ ! Define la producción inicial. ! Define el terminal número.

<lenguaje> ::= <Listas> <Listas> ::= <Listas> ',' <lista> | <lista> ::= '{' <numeros> '}'

<lista>

<numeros> ::= <numeros> ',' Numero | Numero
Ejemplo de Entrada valida seria: {1,85,8,3,8},{5,8,4,3,0},{1,2}

CONEXIÓN GOLDEN PARSER CON C#
Para realizar esto necesitamos: Archivo *.cgt (compiled grammar table): Este archivos es generado por Golden Parser. Archivo *.cs: archivo generado por Golden Parser con sintaxis de C# el cual contiene las producciones definidas en la gramática. Librerías de Golden Parser (CalithaLib.dll y GoldParserEngine.dll): Estas librerías se pueden descargar de la Pagina Oficial de Golden Parser (http://www.devincook.com/goldparser/engine/dot-net/vanloenhout/GoldParserEngine_v1.13_bin.zip)

Generación del archivo *.cgt:
Paso 1: En la parte inferior derecha se encuentra el botón “continue”, realiza 4 pasos.

Paso 2:

Si la gramática es correcta se mostrara la ventana para guardar el archivo *.cgt.

Generación del archivo *.cs:
Paso 1: Vamos a Tools Create a Skeleton Program

Nota: Para crear el esqueleto del programa debemos realizar los 4 pasos para crear el archivo *.cgt (visto anteriormente, sino lo realizamos el botón estará deshabilitado)

Paso 2:

Seleccionamos Calitha Engine, Event Based y presionamos Create.

Paso 3:

Seleccionamos una ubicación para nuestro archivo *.cs y lo nombramos. Por último presionamos guardar.

Obtenemos las librerías:

UNIR LOS ELEMENTOS PARA REALIZAR LA CONEXIÓN
Paso 1: Creamos un nuevo proyecto de C# y extraemos las librerías del archivo .zip anterior, vamos al área de referencias y seleccionamos Add Reference.

Paso 2:

Seleccionamos la pestaña Browse y las 2 librerias de Golden Parser, presionamos Ok.

Paso 3:

Añadir el archivo *.cs a nuestro proyecto. Damos clic derecho a nuestro proyecto y seleccionamos Add Existing Item.

Paso 4:

Seleccionamos nuestro archivo y presionamos el botón Add.

Paso 5:

Al código de nuestro formulario importamos la librería com.calitha.goldenparser

Paso 6:

Crear la variable global “Myparser parser;” en el formulario

Paso 7:

En el constructor de nuestro formulario inicializamos la variable “parser” indicando donde esta el archivo .cgt. parser = new MyParser(Application.StartupPath "\\Listas_sumadas.cgt"); +

Nota: El archivo .cgt debe estar en la misma ubicación donde se encuentra el ejecutable de nuestra aplicación.

Paso 8:

Crear un textbox y un botón en nuestra interfaz grafica.

Paso 9:

Generamos un evento al botón “Analizar” (button1). Agregamos la instrucción “parser.Parse(textBox1.Text);” . La anterior instrucción envía al parser el texto que tengamos en nuestro textBox para ser analizado.

AÑADIR FUNCIONALIDAD A NUESTRO PARSER.
Una vez completado los pasos de conexión añadiremos acciones a nuestro parser. Existen 3 métodos principales: private Object CreateObject(TerminalToken token): método encargado de los símbolos terminales y no terminales. Devuelve los valores leídos a los elementos de las producciones. public static Object CreateObject(NonterminalToken token): Este método se encarga de las producciones. Permite obtener los datos de los elementos de las producciones(los hijos) y devolverlos al padre. private void AcceptEvent(LALRParser parser, AcceptEventArgs args): Este método es invocado cuando el parser acepta la cadena o archivo de entrada.

private Object CreateObject(TerminalToken token): //Necesitamos el texto leido por el terminal Numero y el no terminal //<numeros> por ese motivo devolvemos el valor (el texto leido). case (int)SymbolConstants.SYMBOL_NUMERO : //Numero return token.Text; case (int)SymbolConstants.SYMBOL_NUMEROS : //<numeros> return token.Text;

//No necesitamos el valor de la coma “,” o de la llave “{“ cuando son leidos //por ese motivo devolvemos null case (int)SymbolConstants.SYMBOL_COMMA : //',' //todo: Create a new object that corresponds to the symbol return null; case (int)SymbolConstants.SYMBOL_LBRACE : //'{' //todo: Create a new object that corresponds to the symbol return null;

public static Object CreateObject(NonterminalToken token): case (int)RuleConstants.RULE_LISTA_LBRACE_RBRACE : //<lista> ::= '{' <numeros> '}' //todo: Create a new object using the stored user objects. return token.Tokens[1].UserObject;

Lo que podemos observar allí: token.Tokens es un array q tiene los tokens del lado derecho de nuestra producción. token.Tokens[n].UserObject tiene el valor del terminal o no terminal en la posición n. En nuestro ejemplo <numeros> tiene la posición 1. UserObject es el objeto que hemos asignado al array en la posición n. return lo que retornamos es lo q le vamos a asignar al símbolo q esta del lado izquierdo de nuestra producción (<lista>). En nuestro ejemplo lo que asignaremos a <lista> será el valor del no terminal <numeros>.

case (int)RuleConstants.RULE_NUMEROS_COMMA_NUMERO : //<numeros> ::= <numeros> ',' Numero //todo: Create a new object using the stored user objects. return null;

Lo que podemos observar allí: De la producción <numeros> <numeros> ',' Numero Tenemos la regla semantica numeros.val=numeros.val + Numero. token.Tokens es un array q tiene los tokens del lado derecho de nuestra producción. token.Tokens[n].UserObject tiene el valor del terminal o no terminal en la posición n. En nuestro ejemplo <numeros> tiene la posición 0 y Numero la posición 2. UserObject es el objeto que hemos asignado al array en la posición n. return lo que retornamos es lo q le vamos a asignar al símbolo q esta del lado izquierdo de nuestra producción (<numeros>). En nuestro ejemplo lo que asignaremos a <numeros> será el valor de la suma del no terminal <numeros> con el terminal Numero. Quedando de la siguiente forma: return(int)token.Tokens[0].UserObject + Int32.Parse((string)token.Tokens[2].UserObject);

El valor de <numeros> lo obtenemos con la instrucción: (int)token.Tokens[0].UserObject. Ya que lo devuelto por el array es un objeto debemos indicar que el objeto retornado es de tipo entero. El valor de Numero lo obtenemos con la instrucción: Int32.Parse((string)token.Tokens[2].UserObject). Debido a que el valor devuelto es un Objeto debemos indicar el tipo de objeto contenido, Numero viene de la cadena de entrada por lo tanto es de tipo texto, con la instrucción

(string) indicamos que el objeto es de tipo texto, lo que necesitamos es un valor numerico, por lo tanto debemos hacer otra converción de tipos, en este caso la cadena debemos pasarla a un valor entero, esto se consigue con el metodo Int32.Parse(cadena); case (int)RuleConstants.RULE_LENGUAJE : //<lenguaje> ::= <Listas> Resultado = ordenar((ArrayList)token.Tokens[0].UserObject); return null;

Lo que podemos observar allí: <lenguaje> es la produccion inicial de nuestra gramatica, siendo un analizador ascendente sera la ultima reducción realizada, por lo tanto almacenaremos el resultado final en la variable resultado obteniendo su valor del metodo ordenar enviando como parametro las listas leidas.

Nota: Debemos declarar la variable global Resultado de tipo Cadena en nuestra clase parser (Listas_Sumadas.cs) para poder utilizarlo dentro del metodo AcceptEvent. Para utilizar la clase ArrayList debemos importar la librería System.Collections;. private void AcceptEvent(LALRParser parser, AcceptEventArgs args): Este método es invocado al momento que es aceptada la cadena de entrada. En el presente ejemplo desplegaremos el resultado en un mensaje de texto (MessageBox). System.Windows.Forms.MessageBox.Show("El resultado es " + resultado); Nota: Definición método Ordenar: public static string Ordenar(ArrayList lista) { string valores = ""; lista.Sort(); for (int i = 0; i < lista.Count; i++) { valores = valores + ", [" + lista[i] + "]"; } lista.Clear(); return valores; }

EJEMPLO 2
Para este ejemplo utilizaremos una gramática que reciba la definición de clases simples (variables y métodos), y una definición dirigida por la sintaxis que analice la entrada y despliegue el significado o describa su uso dentro de la clase. La gramática utilizada para este ejemplo es la siguiente:
"Start Symbol" = <lenguaje> {String Char} = {Printable} - ["] id ={Letter}{Alphanumeric}* texto = '"'{String Char}*'"' char = ''{String Char}*'' entero = {Number}+ real = {Number}+'.'{Number}* Comment Start = '/*' Comment End = '*/' Comment Line = '//' "Case Sensitive" = 'False' "Start Symbol" = <lenguaje>

<lenguaje>

::= <def_clases>

<def_clases> ::= <def_clases> <def_clase> | <def_clase> <def_clase> <acceso> ::= <acceso> 'class' id '{' <def_vars> <def_met> '}' ::= 'public' | 'private' | 'protected'

<def_vars>

::= <def_vars> <def_var> | <def_var> ::= <tipo> id <asigna> ';' |

<def_var>

<tipo>

::= 'String' | 'int' | 'double' | 'char' ::= '=' <valor> ::= texto entero real char id

<asigna> | <valor> | | | |

<def_met> ::= <metodo> <def_met> | <metodo> <metodo> ::= <acceso> <tipo> id '(' ')' '{' <cuerpo_m> 'return' <valor> ';' '}' | <acceso> 'void' id '(' ')' '{' <cuerpo_m>'}' <cuerpo_m> ::= <cuerpo_m> id <asigna> | <cuerpo_m> <def_var> | id <asigna> | <def_var>

Nota: Para continuar con este ejemplo el lector debe haber antes estudiado o tener conocimientos sobre los elementos necesarios para la conexión con C# y como se unen los mismos (se puede encontrar en el ejemplo 1).

Luego de realizar la unión de los elementos (añadir el parser, las librerías y definir el archivo *.cgt) vamos a añadir funcionalidad a nuestro parser. Como vimos en el ejemplo 1 los métodos principales son 3, iremos añadiendo funcionalidad a cada uno. private Object CreateObject(TerminalToken token): Devuelve los valores leídos a los elementos de las producciones. Estos elementos son los que queremos recibir exactamente como se lee en la entrada. En nuestra gramática seria principalmente los elementos de la producción: <valor> texto | entero | real | char | id. Por lo tanto en este método algunas modificaciones serian.
case (int)SymbolConstants.SYMBOL_DOUBLE : //double return token.Text;

case (int)SymbolConstants.SYMBOL_ENTERO : //entero return token.Text; case (int)SymbolConstants.SYMBOL_ID : //id return token.Text;

Indicando token.Text le decimos al parser que devuelva el valor leído, por ejemplo si leyéramos la cadena Clase1 en nuestro parser se convertiría en un “id” y lo que devolvemos es la cadena “Clase1” para ser utilizada en las producciones. Otro ejemplo seria si leyéramos el valor 15 en nuestro parser se convertiría en un “entero” colocando return token.Text el valor que contendría “entero” es 15.

Los lectores se podrían preguntar, ¿se pueden devolver mas valores?, y la respuesta es si, por ejemplo de la producción <acceso> 'public' | 'private' | 'protected' se tiene:
case (int)SymbolConstants.SYMBOL_PRIVATE : //private return null;

Pero, ¿por que devolvemos null? En nuestro ejemplo devolveremos null por que el valor ‘private’ es estático, es decir siempre será el mismo, no así valores infinitos como id, entero, texto, etc. ¿Pero si quisiera podría devolver el valor? Y la respuesta es de nuevo si, podríamos retornar token.Text y lo que devolveríamos seria el valor “private”. ¿Por que no lo hacemos? Por que en nuestra gramática ya “sabemos” que vino private por lo tanto devolver “private” seria algo redundante.

public static Object CreateObject(NonterminalToken token): Este método es el mas complejo ya que en el se agrega la mayoría de las funcionalidades de nuestro parser, es donde se realizan las reducciones y producciones. Empezaremos por lo mas sencillo devolveremos los valores de las producciones <acceso> y <tipo>
case (int)RuleConstants.RULE_ACCESO_PRIVATE : //<acceso> ::= private return "private";

case (int)RuleConstants.RULE_ACCESO_PROTECTED :

//<acceso> ::= protected return "protected";

case (int)RuleConstants.RULE_TIPO_STRING : //<tipo> ::= String return "String"; case (int)RuleConstants.RULE_TIPO_INT : //<tipo> ::= int return "int";

En las producciones anteriores únicamente devolvimos texto, ahora veamos como es utilizando los valores dentro de las producciones. Teniendo la producción <valor>
case (int)RuleConstants.RULE_VALOR_TEXTO : //<valor> ::= texto return token.Tokens[0].UserObject; case (int)RuleConstants.RULE_VALOR_ENTERO : //<valor> ::= entero return token.Tokens[0].UserObject;

Recordando del ejemplo 1, sabemos que Tokens es un array que contiene los valores de la producción del lado derecho, indicando Tokens[0].UserObject obtenemos el valor en la posición 1, el lector podría preguntarse ¿de donde viene el valor de texto y entero? Esos valores provienen del método 1, donde retornamos “token.Text”. Ahora veamos la producción <asigna>:
case (int)RuleConstants.RULE_ASIGNA_EQ : //<asigna> ::= '=' <valor> return token.Tokens[1].UserObject; case (int)RuleConstants.RULE_ASIGNA : //<asigna> ::= //todo: Create a new object using the stored user objects. return null;

Esta producción tiene 2 valores posibles, nulo o <asigna> recibirá el dato <valor>. La siguiente producción es la definición de una variable, su tipo, su nombre y el valor asignado.
case (int)RuleConstants.RULE_DEF_VAR_ID_SEMI : //<def_var> ::= <tipo> id <asigna> ';' String[] variable = { (string)token.Tokens[0].UserObject, (string)token.Tokens[1].UserObject, (string)token.Tokens[2].UserObject }; return variable;

En nuestra solución definiremos un Array de Strings de 3 valores, en el primero se almacenara el tipo, en el segundo el identificador y en el tercero el valor, el tercer valor puede ser nulo?, si, si puede ser nulo, recordemos que asigna produce valor o nulo, lo que asignaremos en nuestro String sera nulo si no trae valor, pero mas adelante validaremos si viene nulo o trae un valor. Ahora veamos como almacenamos varias variables y vamos “subiendo” el valor en nuestra gramatica. Esto se realiza con la produccion <def_vars>.
case (int)RuleConstants.RULE_DEF_VARS : //<def_vars> ::= <def_vars> <def_var> ArrayList aux2 = (ArrayList)token.Tokens[0].UserObject; aux2.Add(token.Tokens[1].UserObject); return aux2; case (int)RuleConstants.RULE_DEF_VARS2 : //<def_vars> ::= <def_var> if (token.Tokens[0].UserObject != null) { varaux = new ArrayList(); varaux.Add(token.Tokens[0].UserObject); return varaux; } return null;

Siendo una gramatica recursiva por la izquierda el primer valor reducido sera <def_vars> <def_var> por lo tanto aca crearemos un arraylist que ira agregando las definiciones de las variables. Antes de continuar debemos realizar una validacion, recordemos que <def_var> puede producir nulo, por lo mismo verificamos si trae valor y viene con valor nulo. Lo que retornaremos si trae valor es “varaux” sino trae valor retornaremos nulo. <def_vars> <def_vars> <def_var> en esta produccion lo que haremos es obtener el arraylist que creamos en <def_vars> <def_var> y añadir la nueva definicion de variable <def_vars> <def_vars> <def_var> , asi sucesivamente hasta recorer todas las variables definidas en nuestra clase. La definición de métodos y clases se realiza de forma similar a la de variables, serán ArrayList y cada uno añadira nuevos valores (Todas las definiciones se pueden encontrar en el codigo fuente del ejemplo).
case (int)RuleConstants.RULE_LENGUAJE : //<lenguaje> ::= <def_clases> Resultado = (ArrayList)token.Tokens[0].UserObject; return null;

Al final tendremos un ArrayList Resultado con todo lo que necesitamos (las clases, las variables y métodos).

private void AcceptEvent(LALRParser parser, AcceptEventArgs args): Método invocado cuando el parser acepta la cadena de entrada. En este método utilizaremos el ArrayList creado en el método anterior. El ArrayList “Resultado” posee la siguiente estructura. Clase: 1. Acceso 2. Nombre 3. Def_variables o nulo 4. Def_metodos Def_variables: 1. Tipo 2. Nombre 3. Valor, puede ser nulo Def_metodos: 1. Acceso 2. Tipo 3. nombre 4. variables, puede ser nulo

System.Windows.Forms.MessageBox.Show("Entrada correcta "); String cadenaR = ""; for (int i = 0; i < Resultado.Count; i++) { ArrayList auxclases = (ArrayList)Resultado[i]; cadenaR = cadenaR+"Definicion de la Clase '" + auxclases[1]+"'\n"; cadenaR = cadenaR + "Acceso: " + auxclases[0]+"\n"; if (auxclases[2] != null) { ArrayList auxvariables = (ArrayList)auxclases[2]; String cadena = ""; for (int y = 0; y < auxvariables.Count; y++) { String[] var = (String[])auxvariables[y]; cadena = cadena + "Tipo: " + var[0] + " variable: " + var[1] + " valor: " + var[2] + "\n"; } cadenaR= cadenaR + "\n Listado de variables Globales\n" + cadena; } cadenaR = cadenaR + "\nListado de Metodos\n"; ArrayList auxmetodos = (ArrayList)auxclases[3]; for (int z = 0; z < auxmetodos.Count; z++) { ArrayList auxmetodos2 = (ArrayList)auxmetodos[z]; cadenaR = cadenaR + "\nDefinicion metodo: '" + auxmetodos2[2]+"'\n"; cadenaR = cadenaR + "Acceso: " + auxmetodos2[0]+" Tipo: "+auxmetodos2[1]+"\n"; if (auxmetodos2[3] != null) { ArrayList auxvariables = (ArrayList)auxmetodos2[3]; String cadena = "";

for (int y = 0; y < auxvariables.Count; y++) { String[] var = (String[])auxvariables[y]; cadena = cadena + "Tipo: " + var[0] + " variable: " + var[1] + " valor: " + var[2] + "\n"; } cadenaR = cadenaR + "\n Listado de variables Locales del metodo "+ auxmetodos2[2]+"\n" + cadena; } } cadenaR = cadenaR + "\n\n\n"; } result = cadenaR;

Nota: Las variables Resultado de tipo ArrayList y result de tipo string son variables globales a la clase.

EXPLICACIÓN DE FUNCIONALIDAD
PASO 1: Se ingresa la definición de clases con variables y métodos y se presiona. ”Analizar”

Paso 2:

Si los datos son correctos se muestra el mensaje “Entrada correcta”

Paso 3:

Se presiona aceptar y se presentara lo siguiente.

Paso4:

Cuando presionamos “Analizar” el programa divide la entrada en clases, muestra sus atributos, cuales son sus variables globales y sus métodos, además de mostrar las variables locales de los métodos.

Entrada: private class Clase1 { String cadena = "texto"; int numero = 10; double porcentaje = 12.5;

protected int contador() { int var = 15; return var; }

public void mensaje () { String cadena2 = "nada"; double promedio = 90.5; } public void mensaje2 () { String cadena2 = "nada"; double promedio = 90.5; } } protected class ClaseDos { int cantidad= 1; private void metodounico() { } }

Salida: Definicion de la Clase 'Clase1' Acceso: private Listado de variables Globales Tipo: String variable: cadena valor: "texto" Tipo: int variable: numero valor: 10 Tipo: double variable: porcentaje valor: 12.5 Listado de Metodos Definicion metodo: 'mensaje2' Acceso: public Tipo: void Listado de variables Locales del metodo mensaje2 Tipo: String variable: cadena2 valor: "nada" Tipo: double variable: promedio valor: 90.5

Definicion metodo: 'mensaje' Acceso: public Tipo: void Listado de variables Locales del metodo mensaje Tipo: String variable: cadena2 valor: "nada" Tipo: double variable: promedio valor: 90.5 Definicion metodo: 'contador' Acceso: protected Tipo: int Listado de variables Locales del metodo contador Tipo: int variable: var valor: 15 Definicion de la Clase 'ClaseDos'

Listado de Metodos Definicion metodo: 'metodounico' Acceso: private Tipo: void Acceso: protected Listado de variables Globales Tipo: int variable: cantidad valor: 1

JAVA
Generado por GOLD Parser

Java y GOLD Parser Builder
Primero: Bajamos el modulo jar compatible para Netbeans y ecplipse

Segundo:

Lo guardamos en un lugar accesible

Cuarto:

Hacemos un Nuevo proyecto en Netbeans y agregamos el jar como libreria.

Quinto:

Lo agregamos a nuestro proyecto para poder hacer uso de el.

Sexto:

Asegurarse que el nombre del Skeleton que hizo Goldparser se llame MyParser y luego incluirlo en el scr del proyecto.

Séptimo: Debería de quedar el archive java sin errores.

Octavo:

Instanciamos una variable de tipo MyParser

Noveno:

Incuimos el archivo config Este tiene que tener 2 lienas La primera la ubicacion del archivo cgt. La segunda la ubicación del archivo de entrada

Listo ya se pueden implementar las acciones necesarias para realizar el análisis de cualquier lenguaje que obedezca la gramática

Visual Basic
Generado por GOLD Parser

GOLD Parser con VB
En esta parte de la documentación se tratara sobre cómo generar gramáticas desde GOLD Parser, para luego utilizarlas desde el lenguaje de Visual Basic. A continuación se da una descripción detallada de los aspectos más importantes para la generación de una gramática. Encabezado de gramática: En esta parte se debe indicar ciertos aspectos sobre la gramática, algunos considerados de importancia son los siguientes: • Name: Este especifica el nombre de la gramatica. • Author: Indica el autor de la elaboracion de la gramatica. • Version: La version de la gramatica, para tener un control adecuado en caso de que se lleve cierto versionamiento de la misma. • About: Este muestra la descripcion de la gramatica. • Case Sensitive: Este es requerido si en caso se desea que la gramatica que se elaborará, distinga entre mayúsculas y minúsculas. En caso se desee esta distinción se debe indicar con el parámetro true, de lo contrario será false. Si este atributo no se indica, la opcion default que se tomará en la gramatica será false. Start Symbol: Se debe de indicar el simbolo no terminal, inicial de la gramatica. Al cual el LALR debe reducirse. Este es el unico parametro que debe indicarse como obligatorio.

Gold Parser proporciona cuatro pasos para la compilación de la gramática y que son necesarios para la generación de las salidas que pueda construir esta herramienta, tal el caso de los skeleton, y las opciones que pueden ser de utilidad como mostrar tabla de estados del LALR, tabla de estados del DFA, además de las pruebas que pueda realizarse para comprobar el funcionamiento de la gramática dentro de la herramienta. Estos cuatro pasos que se mencionan se llevan a cabo por medio de un asistente, este se utiliza únicamente presionando el botón Next. El primer paso verifica los errores de sintaxis de la gramática y advierte de los terminales no utilizados.

El segundo paso calcula la tabla de estados de LALR, y de no haber errores lo genera. Dando lugar al paso tres.

El tercer paso se basa en la construcción de autómatas finitos determinÍsticos (DFA)

El cuarto y último paso es el encargado de guardar tanto las tablas generadas en el paso 2(LALR) como las tablas generadas en el paso 3(DFA). Estas son guardadas en un archivo con extensión .cgt.

Se trabajara con el siguiente gramatica:

<lenguaje> <listas>

::= <Listas> ::= <listas> ',' <lista> | <lista> ::= '{' <numeros> '}' ::= <numeros> ',' Number | number

<lista> <numeros>

Procede a realizar los cuatro pasos para la compilación de la gramatica y se guarda las tablas en el archivo .cgt.

Habiendo compilado la gramática debemos de crear los skeleton que se usaran en el programa, en este caso se trata de Visual Basic.

Descargar el Motor .NET a utilizar En la página de Gold Parser, ir a download

En la parte de Engines, dirigirse a Visual Basic .NET

Donde se debe de descargar el motor Klimstra

Selecciona el DLL

Archivo GoldParser.dll

El archivo descargado dll debe de copiarse en la carpeta del proyecto en /bin/Debug. Es mejor si esta en esta ubicación ya que es donde se encuentra el ejecutable del proyecto, de lo contrario podría copiarse en donde este ese ejecutable.

Dentro del proyecto se debe agregar como referencia la el archivo dll, Se debe dirigir hacia Proyecto Agregar Referencia.

En la pestaña de Examinar se busca el archivo GoldParser.dll que se copio en la carpeta Debug o bien donde se halla ubicado el ejecutable.

Lo que sigue es agregar el archivo .cgt que se genero al momento de la compilación de la gramática. Realizamos los siguientes pasos: Clic derecho en la carpeta Agregar Elemento existente…

Se busca el archivo .cgt y agrega al proyecto.

Lo que sigue es darle el tipo de acceso que tendrá el archivo. Entonces se selecciona las propiedades del archivo .cgt agregado

En la opcion de Accion de Compilacion se debe seleccionar Recurso Incrustado.

Guatemala Centro América Universidad San Carlos de Guatemala Facultad de Ingeniería Escuela de ciencias y Sistemas Org. De Lenguajes y compiladores 2

Integrantes
Juan J. Cruz Joel Jimenez Walter Ajanel Mariano Sandoval Jhony Quiem 2004-12979 2004-13135 2005-15897 2007-15303 2008-19401