Anda di halaman 1dari 91

Documento de Ayuda

GOLD Parser Hecho en Guatemala


USAC
Facultad de Ingeniería
Índice
Caratula 1
Índice 2
Quienes somos, visión, misión 3
Objetivos 4
Introducción GOLD Parser Build 5
Ejemplos 12
ANSI C y GOLD PARSER 14
C Sharp Y GOLD PARSER 34
Java Y GOLD Parser 69
Visual Basic y GOLD Parser 75
Integrantes 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
ritmo para implementar un analizador:

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
nticas, ya que la construcción
código o acciones semánticas n del analizador LALR es
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 estee archivo y
Para cada lenguaje existen
dependiendo del lenguaje de
diferentes motores los
programación analiza el archivo cuales deben de
fuente, crea el árbol de análisis descargarlos en librerias o
sintáctico,, permite asociar objetos a complementos para poder
cada símbolo de la gramática
gramática, e utilizarlos en sus proyectos
implementa la tabla de análisis
sintáctico
ico para esa gramática
gramática.
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 INSTRUCCION DESCRIPCION
Conocido como Tab, escribe una
Tabulador {HT}
tabulación en la línea.
Se utiliza para bajar una línea en los
Salto de Línea {LF}
documentos
Se usa para saltase a la siguiente línea
Tabulación Vertical {VT}
marcada
Se usa para saltar toda la pantalla por
Limpia pantalla {FF}
ejemplo CLR o clear
Retorno de Carro Sirve retornar el apuntador al inicio de
{CR}
la línea
Espacio {Space} Se utiliza para separar caracteres
Se utiliza para los espacio donde el salto
Espacio sin Romper {NBSP}
de línea no es permitido
Símbolo del Euro {Euro Sign} Representa el símbolo del euro
Conjuntos de Caracteres comunes
NOMBRE INSTRUCCION DESCRIPCION
Numero {Number} Números del 0 al 9.
Esta instrucción es similar a number,
Digito {Digit} recomiendan NO USAR ESTA
INSTRUCCIÓN.
Reconoce una simple letra del alfabeto
Letra {Letter} en minúsculas o mayúsculas no incluye
la ñ.
Es la unión de las instrucciones Letter y
Alfanumérico {AlphaNumeric}
Number.
Reconoce cualquier carácter desde el
Cualquier Carácter {Printable} #32-#127 y #160 (No espacios
quebrados).
Reconoce todas las letra incluyendo los
Letra Extendida {Letter Extended}
caracteres especiales como ñ
Cualquier Carácter Reconoce todos los caracteres arriba del
{Printable Extended}
extendido carácter #127
Espacio en blanco Reconoce los caracteres como espacio,
{Whitespace}
salto de line.
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.
Notar la línea ‘Start Symbol’ que
Ver la ayuda de GP indica la regla inicial de la
Builder para una gramática.
descripcion detalla de los La estructura de las reglas consiste,
conjuntos ya solo un <No terminal> de la
prefabricados para uso. 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 !* *!

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 Ver la ayuda de GP
gramática),
), Author (autor de la gramática), Builder para mayor
Case Sensitive (Para restricción de
detalle de los parametros
mayúsculas y minúsculas).
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>

<lista> ::= '{' <numeros> '}'

<numeros> ::= <numeros> ',' numero


| numero

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" = <lenguaje> ! Define la producción inicial.

Numero = {Digit}+ ! Define el terminal número.

<lenguaje> ::= <Listas>

<Listas> ::= <Listas> ',' <lista>


| <lista>

<lista> ::= '{' <numeros> '}'

<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/van-
loenhout/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:
v Debemos declarar la variable global Resultado de tipo Cadena en
nuestra clase parser (Listas_Sumadas.cs) para poder utilizarlo dentro
del metodo AcceptEvent.
v 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> 'class' id '{' <def_vars> <def_met> '}'

<acceso> ::= 'public'


| 'private'
| 'protected'
<def_vars> ::= <def_vars> <def_var>
| <def_var>

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


|

<tipo> ::= 'String'


| 'int'
| 'double'
| 'char'

<asigna> ::= '=' <valor>


|
<valor> ::= texto
| entero
| real
| char
| id

<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.

v Clase:
1. Acceso
2. Nombre
3. Def_variables o nulo
4. Def_metodos

v Def_variables:
1. Tipo
2. Nombre
3. Valor, puede ser nulo

v 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>

<lista> ::= '{' <numeros> '}'

<numeros> ::= <numeros> ',' Number


| number

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 2004-12979
Joel Jimenez 2004-13135
Walter Ajanel 2005-15897
Mariano Sandoval 2007-15303
Jhony Quiem 2008-19401

Anda mungkin juga menyukai