Mi primer proyecto utilizando Gold Parser

Se desarrollará un intérprete que recibe como entrada varias expresiones aritméticas y presenta como salida el resultado de dichas expresiones evaluadas.

Las tecnologías a utilizar son:

  • Gold Parser Builder: Generador de analizadores léxicos y sintácticos diseñado para funcionar en múltiples lenguajes de programación.
  • Visual Studio 2017: Entorno de desarrollo integrado para programar Visual Basic y C#, entre otros.
  • Windows 10: Sistema operativo

El proyecto completo puede descargarse del siguiente enlace:

Gold Parser

Gold Parser es un generador de analizadores léxicos y sintácticos que soporta lenguajes tales como C#, COBOL, DELPHI, Visual Basic, Java entre otros. Este programa realiza de manera conjunta el análisis léxico y sintáctico, por lo que no tenemos la necesidad de recurrir a ningún programa externo.

La principal tarea de un analizador léxico es leer los caracteres de entrada del programa fuente, agruparlos en lexemas y producir como salida una secuencia de tokens.

  • Un token es un par que consiste en un nombre de token y un valor de atributo opcional.

  • Un lexema es una secuencia de caracteres en el programa fuente, que coinciden con el patrón para un token y que el analizador léxico identifica como una instancia de este tóken.

  • Un patrón es una descripción de la forma que pueden tomar los lexemas de un token.

El analizador sintáctico obtiene una cadena de tokens del analizador léxico y verifica que dicha cadena pueda generarse con la gramática para el lenguaje fuente. Una gramática proporciona una especificación precisa y fácil de entender de un lenguaje de programación.

Pre-requisitos

Este programa puede descargarse de la página oficial de Gold Parser

Descomprimimos el archivo ZIP descargado y ejecutamos el archivo setup.exe que encontraremos dentro de los files descomprimidos.

Esto nos desplegará el asistente de instalación, en la primera ventana no debemos de seleccionar nada, por lo que únicamente presionaremos el botón de siguiente.

Posteriormente se nos preguntara en que ruta deseamos instalar Gold Parser, en este caso dejaremos la ruta por defecto que es “C:\Program Files (x86)\Gold Parser Builder”, seleccionar si queremos instalarlo para todos los usuarios o solo para nosotros, en este caso seleccionaremos “Everyone” para que todos los usuarios puedan utilizarlo. Damos click en siguiente para continuar con la instalación.

Luego se nos mostrará una ventana que pide nuestra confirmación para continuar con la instalación de Gold Parser, hacemos click en siguiente.

Por último se nos mostrará la ventana de confirmación que indica que Gold Parser fue instalado correctamente.

Generando nuestro analizador léxico y sintáctico con Gold Parser

Hacemos click en el botón de Windows y buscamos “gold parser builder”.

Ejecutamos la aplicación Gold Parser Builder y tendremos un ambiente de trabajo como el que se muestra a continuación.

Lo primero que debemos hacer para comenzar a trabajar con Gold Parser Builder es definir la gramática, el ejemplo que inspiró este tutorial fue realizado con Jlex y Cup:

La gramática planteada para Jlex y Cup era ambigua y dicha ambigüedad se resolvía indicando de forma explicita la precedencia de los operadores aritméticos:

1
2
3
precedence left MAS,MENOS;
precedence left POR,DIVIDIDO;
precedence right UMENOS;

Cup permite definir la precedencia y asociatividad de los operadores de forma explícita, en el caso de Gold Parser, esta opción no está disponible, por lo que es necesario utilizar una gramática no ambigua que respete la precedencia y asociatividad de los operadores.

Tomando en cuenta lo anterior, se propone la siguiente gramática escrita con la sintaxis propia de Gold Parser:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
"Name"    = 'Mi Primer Proyecto en Gold Parser'
"Author" = 'Luis Lizama'
"Version" = '1.0'
"About" = 'Ejemplo de una gramática simple que reconoce expresiones aritméticas'

"Case Sensitive" = False
"Start Symbol" = <Statements>

DECIMAL = {Digit}+'.'{Digit}+
ENTERO = {Digit}+

<Statements> ::= <Statement> <Statements>
| <Statement>

<Statement> ::= Evaluar '[' <Expression> ']'';'

<Expression> ::= <Expression> '+' <Mult Exp>
| <Expression> '-' <Mult Exp>
| <Mult Exp>

<Mult Exp> ::= <Mult Exp> '*' <Negate Exp>
| <Mult Exp> '/' <Negate Exp>
| <Negate Exp>

<Negate Exp> ::= '-' <Value>
| <Value>

<Value> ::= ENTERO
| DECIMAL
| '(' <Expression> ')'

Toda la documentación relacionada con la sintaxis de Gold Parser puede encontrarse en la página oficial.

Una vez tengamos lista nuestra gramática, la ingresamos en la ventana Grammar de la aplicación Gold Parser Builder (para esto basta con copiar y pegar la gramática mostrada anteriormente).

Luego procedemos a guardar la gramática seleccionando la opción “File” → “Save”, el archivo resultante tendrá extensión GRM, que es una extensión propia de Gold Parser.

El archivo GRM con la gramática utilizada para este ejemplo está disponible en la carpeta Gramática del repositorio de este ejemplo.

Posteriormente seleccionamos la opción “Project” → “Analyze the Grammar”, esto analizará la gramática y nos mostrará los conflictos si existieran.

Debemos corregir todos los errores antes de continuar, para este ejemplo no había ninguno. Esto podemos confirmarlo en la parte inferior de nuestro editor de Gold Parser Builder.

Si existiesen errores o notificaciones se nos mostrarán en una ventana emergente de la siguiente manera:

En este caso no teníamos errores, así que podemos proseguir con la creación de las tablas para el análisis LALR. Esto lo hacemos seleccionando la opción “Project” → “Create LALR Parse Tables”

Podemos confirmar que nuestras tablas LALR fueron creadas exitosamente en la parte inferior de nuestro editor de Gold Parser Builder.

Durante la creación de las tablas LALR es posible de que se detecten conflictos de desplazamiento-reducción y el asistente no nos permita continuar, en este caso debemos resolver estos conflictos y luego continuar. Por el contrario, si no tenemos conflictos que resolver, podemos continuar al último paso, crear las tablas del autómata finito determinista que será el encargado de realizar el análisis léxico. Para ello seleccionamos la opción “Project” → “Create DFA Lexer Tables”.

Podemos confirmar que nuestras tablas para el autómata finito determinista fueron creadas exitosamente en la parte inferior de nuestro editor de Gold Parser Builder.

Por último, procedemos a guardar todas las tablas, estas serán importadas posteriormente en nuestro programa para poder realizar el análisis léxico y sintáctico del texto recibido como entrada. Para ello seleccionamos la opción “Project” → “Save the Tables”.

Se nos mostrará una ventana para que indiquemos la ruta en la cual deseamos almacenar las tablas, la seleccionamos y damos click en aceptar, con esto habremos generado un archivo EGT, esta ventana se cerrará y Gold Parser nos mostrará un mensaje diciendo que se guardaron las tablas correctamente.

EGT es una extensión propia de Gold parser.

El archivo EGT con las tablas generado para este ejemplo está disponible en la carpeta Gramática del repositorio de este ejemplo.

Una de las principales ventajas de Gold Parser es que tiene un módulo de test que permite visualizar el proceso de análisis de una forma detallada. Para utilizar el módulo de test, hacemos click en el ícono correspondiente, que tiene un pequeño cheque verde.

O bien seleccionando la opción “Window” → “Test Grammar”

Esto nos desplegará una ventana de test en la que podemos ingresar en el lado izquiero una entrada y posteriormente evaluar paso a paso esta entrada con el botón verde de ejecutar que se encuentra en la parte inferior izquierda, esto nos permitirá ver el progreso del análisis en el panel derecho con el detalle de cada estado.

Luego de este pequeño paréntesis para explorar el módulo de test de Gold Parser continuaremos con nuestro proyecto.

El siguiente paso es crear el esqueleto de un programa, para ello seleccionamos “Project” → “Create a Skeleton Program…”.

Se nos desplegarán varias opciones para generar el esqueleto, para este ejemplo en específico utilizaremos Visual Basic .NET y como motor Cock .NET DLL.

Seleccionaremos la opción de crear y nos mostrará una ventana desde la cual podremos seleccionar la ruta en la cual queremos guardar el esqueleto de nuestro programa. Obtendremos como resultado un archivo con extensión VB.

El archivo VB generado con el esqueleto está disponible en la carpeta Gramática del repositorio de este ejemplo.

Esto es todo lo que haremos en Gold Parser, de acá en adelante utilizaremos Visual Studio.

Abrimos Visual Studio.

Seleccionamos “File” → “New” → “Project”, una vez abierto el wizard para crear nuevos proyectos seleccionamos el apartado “Visual Basic” → “Windows Desktop” → “Console App (.NET Framework)” y le pondremos como nombre Calculadora.

Para poder utilizar el esqueleto que generamos en Gold Parser en el proyecto que acabamos de crear necesitaremos importar la librería .NET DLL que realiza el proceso de análisis, esta libería debe descargarse en la página oficial.

Luego de descargar y descomprimir la librería obtendremos el archivo “Gold Engine.dll” que es el que debemos importar en nuestro proyecto.

Con el proyecto creado debemos de pegar el archivo de las tablas de análisis generadas en Gold Parser (Expresiones aritméticas.egt) y la librería que acabamos de descargar (GOLD Engine.dll) en la carpeta Calculadora/Calculadora/bin/debug de nuestro proyecto.

También debemos de pegar el esqueleto que generamos con Gold Parser (Expresiones aritméticas.vb) en la carpeta principal de nuestro proyecto.

Regresamos a Visual Studio y desde el explorador de soluciones debemos de realizar dos procedimientos.

El primero es importar el archivo que contiene el esqueleto generado en Gold Parser (Expresiones aritméticas.vb), para ello hacemos click derecho sobre el nombre de nuestro proyecto “Add” → “Existing Item…”.

Luego seleccionamos el archivo de nuestro esqueleto.

Veremos que ahora aparece en el explorador de soluciones.

El segundo procedimiento a realizar en el explorador de soluciones es importar la librería que acabamos de pegar en nuestra carpeta debug, para hacerlo daremos click derecho en “References” → “Add Reference…”

Esto nos desplegara una nueva ventana, seleccionamos la opción “Browse…” y seleccionamos nuestro archivo .dll y daremos click en aceptar.

Por último, abrimos el archivo que contiene el esqueleto que generamos con Gold Parser (Expresiones aritméticas.vb) y dentro de las líneas de código buscar el método con el nombre Setup. Es la única instrucción que posee este método, debemos cambiar el nombre del archivo gramar.egt por el nombre de nuestro archivo de tablas (Expresiones aritméticas.egt), es de suma importancia que hayamos pegado nuestras tablas en la carpeta debug, de otra manera nuestro programa no las podrá encontrar y nos arrojará un error en tiempo de ejecución.

Estas son todas las configuraciones que debemos de realizar para poder utilizar Gold Parser, de acá en adelante, el tutorial se enfoca en explicar el funcionamiento de los archivos que se generaron anteriormente.

Creando un archivo de entrada para nuestro analizador

Creamos un nuevo archivo de texto llamado entrada.txt. El contenido de este archivo es el siguiente:

1
2
3
4
5
Evaluar[1+1];
Evaluar[1+1*2];
Evaluar[-(1+1*6/3-5+7)];
Evaluar[-(1+1*6/3-5+1*-2)];
Evaluar[-(1.6+1.45)];

Este archivo de entrada será creado en la carpeta Calculadora/Calculadora/bin/debug de nuestro proyecto.

Utilizando el esqueleto generado con Gold Parser

En los pasos anteriores nos enfocamos en la definición de la gramática y las configuraciones que tenemos que realizar para poder utilizar los archivos que generamos con Gold Parser, pero no hemos programado ningún tipo de instrucción dentro de nuestro programa.

Gold Parser se centra en generar un árbol de análisis sintáctico, de esta manera nosotros podremos recorrer este árbol como sea más conveniente, es por ello que no nos permite incrustar acciones semánticas al momento de definir la gramática, debemos de realizarlo directamente en el esqueleto generado, este esqueleto será modificado según convenaga para lograr nuestro objetivo.

El archivo VB generado con el esqueleto (Expresiones aritméticas.vb) modificado con las acciones necesarias para evaluar las expresiones aritméticas, además de estar en la carpeta principal del proyecto dentro del repositorio, está disponible en la carpeta Gramática.

Podremos notar que el esqueleto generado, en su método parse, posee una serie de estados los cuales por defecto tienen comentado su funcionamiento, los estados que alteraremos en este ejemplo son:

  • LexicalError : Reportar errores léxicos.
  • SyntaxError : Reportar errores sintácticos.
  • Accept : Crear la raíz de nuestro árbol de análisis sintáctico.

Definiremos una variable Root de tipo Gold.Reduction que será la raíz de nuestro árbol.

Adicionalmente podremos notar que el archivo también posee una función denominada CreateNewObject que posee una serie de casos los cuales tienen comentado a que producción de la gramática pertenecen, es aquí donde debemos de introducir las acciones semánticas que deseamos que se ejecuten al momento de reducir por cada producción.

Esta función CreateNewObject viene definida únicamente como una plantilla, pero podremos darle la funcionalidad que nosotros deseemos. Para este ejemplo en específico se le cambió el nombre por “GetValue” ya que lo que necesitamos al final es obtener el valor resultante de evaluar cada expresión aritmética.

Los métodos de nuestro parser son estáticos y no es necesario crear una instancia parser, pero si es necesario ejecutar el método Setup para que cargue las tablas de análisis.

El programa por defecto está configurado para leer el archivo entrada.txt en la carpeta Calculadora/Calculadora/bin/debug del proyecto.

A continuación se muestra el resultado de ejecutar el archivo de entrada que preparamos anteriormente.

Como podemos ver, obtenemos la salida esperada.

Acerca del autor:

Este tutorial fue elaborado por el Auxiliar de Cátedra Luis Lizama, como contribución al curso de Organización de Lenguajes y Compiladores 2 de la Universidad de San Carlos de Guatemala.

Fuentes consultadas:

Compiladores, principios, técnicas y herramientas. Aho, Lam, Sethi y Ullman. Segunda Edición.

Mi primer proyecto utilizando Jison (Linux)

Se desarrollará un intérprete que recibe como entrada varias expresiones aritméticas y presenta como salida el resultado de dichas expresiones.

Las tecnologías a utilizar son:

  • Jison: Generador de analizadores léxicos y sintácticos.
  • Nodejs: Es un entorno en tiempo de ejecución, multiplataforma, capaz de ejecutar javascript fuera de un explorador.
  • Ubuntu 18.04: Sistema operativo.
  • Visual Studio Code: Es un editor de código ligero pero poderoso. Viene con soporte integrado para JavaScript, Nodejs, entre otros.

El proyecto completo lo pueden descargar del siguiente enlace:

Jison

Jison toma una gramática libre de contexto como entrada y produce código JavaScript capaz de parsear el lenguaje descrito por dicha gramática. Una vez se tenga el script generado podemos usarlo para parsear la entrada y aceptarla, rechazarla o ejecutar acciones con base en la entrada. Si se está familiarizado con Bison, Yacc o algún otro similar ya se está listo para iniciar. Jison genera tanto el analizador léxico como el analizador sintáctico.

La principal tarea de un analizador léxico es leer los caracteres de entrada del programa fuente, agruparlos en lexemas y producir como salida una secuencia de tokens.

  • Un token es un par que consiste en un nombre de token y un valor de atributo opcional.

  • Un lexema es una secuencia de caracteres en el programa fuente, que coinciden con el patrón para un token y que el analizador léxico identifica como una instancia de este tóken.

  • Un patrón es una descripción de la forma que pueden tomar los lexemas de un token.

El analizador sintáctico obtiene una cadena de tokens del analizador léxico y verifica que dicha cadena pueda generarse con la gramática para el lenguaje fuente. Una gramática proporciona una especificación precisa y fácil de entender de un lenguaje de programación.

En Jison se definen tanto el analizador léxico como el sintáctico. Esto es una gran ventaja pues podemos trabajar en una sola herramienta.

Pre-requisitos

Para este ejemplo hace falta que tengamos instalado:

Para instalar Nodejs en Ubuntu basta con ejecutar el siguiente comando:

1
$ sudo apt install nodejs

Para verificar que la instalación haya sido correcta ejecutamos el siguiente comando:

1
$ nodejs --version

Luego procedemos a instalar npm. Para esto ejecutamos el siguiente comando:

1
$ sudo apt install npm

Y verificamos la instalación con el siguiente comando:

1
$ npm --version

Instalar Jison

Instalamos Jison con el siguiente comando:

1
$ sudo npm install jison -g

La bandera -g nos sirve para indicar que instalaremos Jison de manera global, es decir, estará disponible en cualquier directorio del sistema.

Crear nuestro proyecto

Usaremos npm para crear nuestro proyecto. Primero crearemos un nuevo folder, en este caso lo llamaremos ProyectoJisonUbuntu. Para esto abrimos una nueva terminal, nos ubicamos donde queremos crear el proyecto y ejecutamos el siguiente comando:

1
$ mkdir ProyectoJisonUbuntu

Y luego ingresamos al directorio con el siguiente comando:

1
$ cd ProyectoJisonUbuntu

Ahora procedemos a iniciar el proyecto con npm. Para esto ejecutamos el siguiente comando:

1
$ npm init -y

Con esto habremos iniciado el proyecto. La bandera -y sirve para seleccionar valores por defecto en los parámetros de inicialización.

Ahora nos pasamos a nuestro editor de texto, en este caso usaremos Visual Studio Code. Ejecutamos el siguiente comando para abrir Code con nuestro proyecto directamente.

1
$ code .

Code se desplegará con nuestro proyecto llamado ProyectoJisonUbuntu

Nótese que únicamente contiene el archivo package.json el cual fue creado por el comando npm init.

Procedemos a crear un nuevo archivo llamado gramatica.jison

Código Fuente para el analizador léxico y sintáctico

En el archivo gramática.jison le indicamos a Jison la descripción de nuestra gramática.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
/**
* Ejemplo mi primer proyecto con Jison utilizando Nodejs en Ubuntu
*/

/* Definición Léxica */
%lex

%options case-insensitive

%%

"Evaluar" return 'REVALUAR';
";" return 'PTCOMA';
"(" return 'PARIZQ';
")" return 'PARDER';
"[" return 'CORIZQ';
"]" return 'CORDER';

"+" return 'MAS';
"-" return 'MENOS';
"*" return 'POR';
"/" return 'DIVIDIDO';

/* Espacios en blanco */
[ \r\t]+ {}
\n {}

[0-9]+("."[0-9]+)?\b return 'DECIMAL';
[0-9]+\b return 'ENTERO';

<<EOF>> return 'EOF';

. { console.error('Este es un error léxico: ' + yytext + ', en la linea: ' + yylloc.first_line + ', en la columna: ' + yylloc.first_column); }
/lex

/* Asociación de operadores y precedencia */

%left 'MAS' 'MENOS'
%left 'POR' 'DIVIDIDO'
%left UMENOS

%start ini

%% /* Definición de la gramática */

ini
: instrucciones EOF
;

instrucciones
: instruccion instrucciones
| instruccion
| error { console.error('Este es un error sintáctico: ' + yytext + ', en la linea: ' + this._$.first_line + ', en la columna: ' + this._$.first_column); }
;

instruccion
: REVALUAR CORIZQ expresion CORDER PTCOMA {
console.log('El valor de la expresión es: ' + $3);
}
;

expresion
: MENOS expresion %prec UMENOS { $$ = $2 *-1; }
| expresion MAS expresion { $$ = $1 + $3; }
| expresion MENOS expresion { $$ = $1 - $3; }
| expresion POR expresion { $$ = $1 * $3; }
| expresion DIVIDIDO expresion { $$ = $1 / $3; }
| ENTERO { $$ = Number($1); }
| DECIMAL { $$ = Number($1); }
| PARIZQ expresion PARDER { $$ = $2; }
;

Explicación del código fuente para el analizador léxico

Iniciamos indicando que queremos iniciar con la definición léxica, posteriormente agregamos las opciones que deseamos. En este caso indicamos que nuestro analizador no distinguirá diferencias entre mayúsculas y minúsculas.

1
2
3
4
/* Definición Léxica */
%lex

%options case-insensitive

A diferencia de otras herramientas, Jison por defecto cuenta la posición de línea y columna de los caracteres y acepta el conjunto de caracteres unicode.

Luego escribimos los patrones para los tokens que deseamos reconocer. Para cada uno de ellos debemos retornar el nombre asociado al token.

1
2
3
4
5
6
7
8
9
10
11
12
13
%%

"Evaluar" return 'REVALUAR';
";" return 'PTCOMA';
"(" return 'PARIZQ';
")" return 'PARDER';
"[" return 'CORIZQ';
"]" return 'CORDER';

"+" return 'MAS';
"-" return 'MENOS';
"*" return 'POR';
"/" return 'DIVIDIDO';

Jison también soporta el uso de expresiones regulares para identificar patrones. En las siguientes instrucciones escribimos una expresión regular para identificar espacios en blanco e indicamos que al ser reconocidos no hacemos nada. Esto se hace a través de un par de llaves vacíos.

1
2
3
/* Espacios en blanco */
[ \r\t]+ {}
\n {}

Escribimos expresiones regulares para identificar enteros y decimales.

1
2
[0-9]+("."[0-9]+)?\b    return 'DECIMAL';
[0-9]+\b return 'ENTERO';

Las últimas dos expresiones son para reconocer el fin de la entrada y caracteres no válidos.

1
2
3
4
<<EOF>>                 return 'EOF';

. { console.error('Este es un error léxico: ' + yytext + ', en la linea: ' + yylloc.first_line + ', en la columna: ' + yylloc.first_column); }
/lex

En caso de encontrarse con un error léxico lo desplegamos en consola.

Explicación del código fuente para el analizador sintáctico

Otra de las ventajas de Jison es que en el mismo archivo podemos definir nuestro análisis sintáctico haciendo uso de los tokens previamente definidos en la sección del analizador léxico.

Primeramente definimos la asociatividad y precedencia de los operadores, ya que la gramática escrita es ambigua, es necesario definir una precedencia para que el analizador no entre en conflicto al analizar, en este caso la precedencia es la misma que la de los operadores aritméticos, la precedencia más baja la tienen la suma y la resta, luego están la multiplicación y la división que tienen una precedencia más alta y por último está el signo menos de las expresiones negativas que tendría la precedencia más alta

1
2
3
4
5
/* Asociación de operadores y precedencia */

%left 'MAS' 'MENOS'
%left 'POR' 'DIVIDIDO'
%left UMENOS

Debemos indicarle a Jison cual será nuestro símbolo Inicial.

1
%start ini

Finalmente escribimos nuestras producciones, aquí vemos otra de las ventajas de Jison, cada No Terminal no debe definirse previamente, esto lo hace más práctico pero a la vez se debe de tener más cuidado con errores de escritura.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
%% /* Definición de la gramática */

ini
: instrucciones EOF
;

instrucciones
: instruccion instrucciones
| instruccion
| error { console.error('Este es un error sintáctico: ' + yytext + ', en la linea: ' + this._$.first_line + ', en la columna: ' + this._$.first_column); }
;

instruccion
: REVALUAR CORIZQ expresion CORDER PTCOMA {
console.log('El valor de la expresión es: ' + $3);
}
;

expresion
: MENOS expresion %prec UMENOS { $$ = $2 *-1; }
| expresion MAS expresion { $$ = $1 + $3; }
| expresion MENOS expresion { $$ = $1 - $3; }
| expresion POR expresion { $$ = $1 * $3; }
| expresion DIVIDIDO expresion { $$ = $1 / $3; }
| ENTERO { $$ = Number($1); }
| DECIMAL { $$ = Number($1); }
| PARIZQ expresion PARDER { $$ = $2; }
;

Al final de cada producción se puede incluir código javascript entre llaves “{ <código javascript> }”. Para sintetizar un valor asociado al no terminal de lado izquierdo de la producción hacemos uso de la variable $$. Esta variable es propia de Jison. Como podemos ver, para cada producción del no terminal “expresion” sintetizamos el valor de la operación aritmética o el valor del token aceptado.

La variable $$ puede tomar cualquier valor, recordemos que Jison al estar basado en javascript el tipo puede ser dinámico.

Nótese el terminal EOF, que indica el fin de la entrada, debe agregarse en nuestra gramática luego de haber reconocido nuestra entrada, esto indicará que hemos terminado. Si se omite este terminal obtendremos una excepción cuando nuestro analizador alcance el final del archivo.

Por último, podemos manejar también las producciones de error para el manejo de errores sintácticos.

El archivo de compilación

Para facilitar la compilación de nuestra gramática y poder obtener el script para nuestro parser procedemos a escribir un archivo sh.

Para esto creamos un nuevo archivo en Code llamado compilar.sh con el siguiente contenido:

1
2
3
4
5
6
7
#!/bin/bash

echo "Procesando gramática..."

jison gramatica.jison

echo "Gramática procesada..."

Para ejecutar nuestro script ejecutamos el siguiente comando en la terminal:

1
$ sh compilar.sh

Nos debe aparecer el siguiente resultado:

Si hubiese algún error debemos revisar que nuestra gramática esté correcta.

El comando nos generará el script en un archivo llamado gramatica.js en nuestro proyecto. Este es el script que utilizaremos para procesar nuestros archivos de entrada.

Creando un archivo de entrada para nuestro analizador

Creamos un nuevo archivo de texto utilizando nuestro editor llamado entrada.txt. El contenido de este archivo es el siguiente:

1
2
3
4
5
Evaluar[1+1];
Evaluar[1+1*2];
Evaluar[-(1+1*6/3-5+7)];
Evaluar[-(1+1*6/3-5+1*-2)];
Evaluar[-(1.6+1.45)];

Script Principal

Necesitamos de un script que nos ayude a leer el archivo de entrada e invocar a nuestro parser con su contenido. Para esto creamos un nuevo archivo de texto y lo nombramos parser.js.

Su contenido es el siguiente:

1
2
3
4
5
6
7
8
var fs = require('fs'); 
var parser = require('./gramatica');


fs.readFile('./entrada.txt', (err, data) => {
if (err) throw err;
parser.parse(data.toString());
});

Hacemos uso de la librería fs de Nodejs para leer archivos y también de nuestro parser. Esto lo hacemos a través de la función require.

Luego invocamos al método readFile el cual lee nuestro archivo de entrada ‘entrdata.txt’. Este método devuelve dos parámetros, err el cual indica si hubo algún error y data, que almacena el contenido del archivo.

Validamos que no haya ocurrido error y con el contenido de nuestro archivo de entrada invocamos a nuestro parser.

Para ejecutar este script corremos el siguiente comando:

1
$ node parser

Como podemos ver, obtenemos la salida esperada.

Acerca del autor:

Este tutorial fue elaborado por el Auxiliar de Cátedra Rainman Sián, como contribución al curso de Organización de Lenguajes y Compiladores 2 de la Universidad de San Carlos de Guatemala.

Fuentes consultadas:

Compiladores, principios, técnicas y herramientas. Aho, Lam, Sethi y Ullman. Segunda Edición.

Configurar un servidor web en AWS EC2

En este tutorial configuraremos un web server utilizando EC2, probablemente una de las cosas menos complejas que podemos hacer en AWS, básicamente levantaremos una máquina virtual en EC2 para montar una página web.

1. Crear la instancia de EC2

Lo primero es buscar en la consola de AWS:

El servicio EC2:

Una vez dentro de la consola de EC2, seleccionamos la opción Launch Instance:

Escogemos alguna imagen AMI que sea Free tier elegible, de tal manera que podamos levantar la instancia sin pagar nada.

El segundo paso es elegir el tipo de instancia, buscamos nuevamente que sea Free tier elegible, esta será una instancia con recursos muy básicos, pero útil para nuestros fines.

Configuramos los detalles de la instancia, es importante que al ser creada la instancia se le asigne una IP pública, para ello verificamos que posea la siguiente configuración: Auto-assign Public IP: Use subnet setting (Enable).

Posteriormente vienen las configuraciones de almacenamiento, acá podemos agregar más discos duros EBS si quisieramos, pero en este caso dejaremos los valores por default.

Luego podemos agregar etiquetas, que básicamente son meta-data de la instancia, esto es especialmente útil cuando tenemos muchas instancias y necesitamos información sobre qué aloja cada una.

Creamos un nuevo Security Group para nuestra instancia asegurándonos de que en las reglas permita solicitudes hacia el puerto 22 y el puerto 80 desde cualquier origen.

Creamos un nuevo key pair para nuestra instancia, estas son las llaves con las que accederemos a través de SSH a nuestra instancia de EC2.

Posteriormente escogemos la opción Launch instance y luego de algunos minutos la instancia estará corriendo y lista para ser utilizada. en el campo IPv4 Public IP, podremos ver la IP pública de la instancia, que posteriormente será utilizada para conectarse a la misma.

Si seleccionamos nuestra instancia y hacemos click en Connect, veremos el siguiente recuadro con las opciones e instrucciones para conectarnos a la instancia.

Nosotros nos conectaremos utilizando A standalone SSH client.

2.1. Conectarse a la instancia vía SSH (Windows)

Para conectarse a la instancia EC2 vía SSH en Windows es necesario descargar putty, una herramienta que puede ser utilizada como cliente SSH y cuenta con algunas otras funcionalidades.

Una vez descargado procedemos a ejecutar el asistente de instalación.

Una vez instalado, necesitamos convertir nuestro archivo .PEM a un archivo .PPK, para ello procedemos a abrir PuTTY Key Generator.

Haciendo click en load, podemos cargar nuestra llave .PEM.

Veremos un mensaje de que la llave se importó correctamente.

Guardamos la llave importada sin passphrase.

Nos aseguramos de que el archivo se guarde con la extensión .PPK.

Al finalizar procedemos a abrir PuTTY. Ingresamos la IP pública de nuestra instancia de EC2.

Desplegamos la opción Connection, posteriormente la opción SSH y por último vamos a Auth, adjuntaremos el archivo .PKK generado.

Volvemos a la pestaña de sesión y guardamos la sesión con un nombre representativo, en este caso MiWebServer.

Posteriormente la aplicación nos preguntará si confiamos en este host para agregar la llave a la cahe de PuTTY. Respondemos que sí, pues es nuestra instancia de EC2.

Con esto estaremos conectados con nuestra instancia EC2 vía SSH desde Windows.

Luego de esto ingresamos con el usuario ec2-user, no nos pedirá contraseña pues estamos usando nuestro archivo .PPK para autenticarnos.

2.2. Conectarse a la instancia vía SSH (Linux)

Para conectarse a la instancia EC2 vía SSH en Linux, es necesario descargar nuestro archivo .PEM

Nos movemos a la carpeta en la que se encuentra el archivo:

1
cd /home/erick/

Asignamos los permisos adecuados:

1
chmod 400 MiNuevaKeyPair.pem

Y accedemos remotamente vía SSH:

1
ssh -i "MiNuevaKeyPair.pem" ec2-user@ec2-18-206-137-162.compute-1.amazonaws.com

Con esto habremos ingresado a nuestra instancia:

3. Iniciar apache server

Lo siguiente será iniciar apache server, en nuestro caso la instancia de EC2 que escogimos ya lo tenía instalado, si la instancia no lo tuviera tendríamos que instalarlo. Para arrancarlo ejecutamos el siguiente comando:

1
sudo service httpd start

Luego validamos que el servicio esté corriendo ejecutando:

1
sudo service httpd status

4. Publicar nuestra página

Creamos un archivo index.html en la carpeta /var/www/html/index.html

Para ello ejecutamos el comando:

1
nano /var/www/html/index.html

Posteriormente introducimos el código html de nuestra página.

Salimos del editor nano con la combinación de teclas Ctrl + x, al salir nos preguntará si queremos guardar nuestros cambios, respondemos que sí.

Por último si accedemos a la IP pública de nuestro servidor desde un navegador veremos la página recién creada.

Con esto llegamos al final de nuestro tutorial.

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×