miércoles, 1 de junio de 2016

Reflexiones y Experiencias Personales

CLASE 01
Introduccion a la asignatura de Compiladores e interpretes
La cátedra de Compiladores e Intérpretes presenta una introducción al software cuya función única es compilar programas fuentes en un determinado lenguaje, y producir programas ejecutables, la asignatura cubre los fundamentos conceptuales, el principio de funcionamiento, la estructura básica; así también presenta un estudio de aspectos, léxicos, sintácticos y semánticos propios de un compilador. 
En esta clase se conocio todo lo referido a lo que trataria la asignatura, agregando a esos datos vitales para irse familiarizando con la materia.

Se pudo comprender el objetivo principal el cual es:

 Aplicar técnicas y procedimientos para traducir código fuente en código intermedio y final.

Este objetivo fue el que guio a los estudiantes durante todo el proceso que consta de 80 horas  para proceder e implementar lo que seria en si un compilador en fase terminada.

Tambien se aprecio los diferentes lenguajes que existen, asi mismo en el que se trabajaria y como es costumbre se motivo al estudiante con lo siguiente:

Para ser buen programador:
Saber como se obtiene un ejecutable permite saber más sobre corrección y eficiencia

CLASE 02
Introduccion al proceso de compilacion

Un traductor es un programa que toma como entrada un texto escrito en un lenguaje y da como salida otro salida otro texto en un lenguaje diferente.

El proceso de compilacion conlleva multiples fases, no es solamente una ejecucion y ya; en ella estan inmersas diferentes fases que es especializan en actividades especificas dando al compilador un proceso generado distinto al resto de de fases.
Una manera facil y rapida de identificar si estamos ante un compilador es cuando el lenguaje fuente esta en un lenguaje de programacion de alto nivel y el objeto generadon sea de bajo nivel ( ensamblador ).

Como esperiencia personal puedo decir que esto sera una odisea, cualquiera que va iniciar la materia de compiladores vera muchas cosas que a lo mejor ni imaginaba que existian y cuando las vean quedaran aun incredulos.

CLASE 03
Resolver una serie de preguntas creadas por el ing en cuestion con el fin de cuantificar el aprendizaje adquirido en las primeras secciones y al mismo tiempo hacer una diagnostico de como ah sido recibida la asignatura y ver si lo estudiantes andan a tono o si hay otros motivos por los cuales la materia esta resultando dificil de conllevart.

CLASE 04
Y ese momento cuando te das cuenta que se llego la hora de ver y estudiar la tabla de simbolo, la tan mesionada tabla de simbolos en las clases anteriores, tanto era la mencion que yo me la habia imaginado de diferentes formas, ejemplos son : que la tabla de simbolos es similar a la tabla periodica, que es una tabla donde estan todos los simbolos como este "+-*/-.,}{+´¿'=)(/&%$#"!°|" etc... tambien llego a cruzar por mi mente que la tabla de simblos era una tabla que se armaba a puro simblos; en fin fue tan mencionada que mi creatividad empezo a hacer de las suyas pero en esta clase al fin se habia llegado la hora, estaba a minutos de conocer como era o que representaba, estaba ancioso por saber de que se trataba; como cuando estas esperando la fnal del mundial y estas ancioso por saber quein sera el campeon o como cuando una chica te ah dejado en espera de salir con tigo y tu estas impaciente por recivir el tan anhelado si.... pero la hora se acortaba, ya se habia acabdo la espera, el misterio iba a ser revelado y es cuando te empiezas a dar cuenta que es una tabla con estructura....
Estructura..?
Si. estructura asi como lo oyes, es una tabla que almacena informacion sobre identificadores, palabras reservadas y constantes....

Aqui queda claro, es una base de datos teoricamente, ya comprendimos lo que es una tabla de simbolos, no es mas que una ficha donde se almacena informacion y es usado en el proceso de compilacion, si exacto es una tabla donde se le da el significado a los diferentes simbolos que usaremos en nuestro compilador...
Un ejemplo sencillo es el siguiente:

                           Opera            Significado
                               +                  Suma
                                -                   Resta
etc etc y todos los simbolos que se te antoje usar en tu compilador, de esta forma se le asigna el significado a cada simbolo, y a esto se le llama tabla de simbolos, pero como no se me ocurrio si esta "bacano" dira un colombiano o mejor aun, un español dira "coño" como no haberlo visto antes pero aca en el salvador diremos los mas cultos "que poca madre" o si somo de los que les vale diremos "vale gaber" en fin son tantas expresiones que podriamos encontrar para demostrar lo sorprendido que nos pudo dejar la tabla de simbolo.

CLASE 05
En esta clase se llego la hora de ver conocimientos de manera mas sofisticado, me hubiera gustado compartir el text resuelto para los del ciclo anterior por si el ign decide hacer la misma prueba para cuando ellos cursen la materia de compiladores, pero desafortunamente no tuve 10, no se si sea desafortunado para ustedes o mas para mi pero a modo de ser optimista no recuerdo que halla andado alguien presumiento su maxima nota y si alguno la tuvo y no lo presumio mis respetos, sera el proximo Albert Heisten, no busca la vanagloria sino la consagracion de sus conocimientos.
El text contaba con preguntas de se encuentran inmersas en la evidencia, preguntas que a lo mejro era de solo elegir si eran verdaderas o falsas o preguntas que pudieron ser de responder y analizar, para estas cosas hay que estar preparados, nunca se sabe con que text medio endemoniado nos saldran estos ing, dejare un bloque de codigo del cual si sali bien, me enorgullece pero para q trabajen un poco y desenpolven la maquina y el lenguaje C++ se los dejare con error para que lo resuelvan,

#include <iostream>;
#include <con

using space std;

void MaIn^*
count << hola  autor >> endl
 _getch();
{}}   

CLASE 06
Ya hemos visto mucho, pero ahora veremos el funcionamiento del analizador lexico, mas bien lo vimos, la evidencia se encuentra en su respectivo apartado, no esta completa pero si la mayoria; notar que hemos aplicado lo siguiente, "mucha informacion abruma y poca informacion descepciona, mejor ni mucha ni poca"

Dejare un codigo visto para que se haga una que otra prueba de lo que es un analizador lexico:

#include<iostream>
#include<stdio.h>
#include<ctype.h>
#include<stdlib.h>
#include<string>
#define TAM_BUFFER 100


using namespace std;

class Lexico
{
    char *nombreFichero;
    FILE* entrada;
    int n1;
    int traza;
    char buffer[TAM_BUFFER];
    int pBuffer;
    public:
    Lexico(char *unNombreFichero, int una_traza=0);
    ~Lexico(void);
    char siguienteToken(void);
    void devuelveToken(char toke);
    int lineaActual(void){return n1; };
    int existeTraza(void){if(traza)return 1; else return 0;}
};

Lexico::Lexico(char *unNombreFichero, int una_traza)
{
    entrada=fopen(unNombreFichero, "rt");
    if((entrada==NULL))
    {
        cout<<"No se puede abrir el archivo"<<endl;
        system("pause");
        exit(-2);
    }
        if(una_traza) traza=1;
        else traza = 0;
        n1=1;
        pBuffer=0;
}

Lexico::~Lexico()
{
    fclose(entrada);
}
    char Lexico::siguienteToken(void)
    {
    char car;
    while((car=((pBuffer>0) ? buffer[--pBuffer]:getc(entrada)))!=EOF)
    {
    if(car==' ') continue;
    if(car=='\n'){++n1; continue;}
    break;
    }
    if(traza) cout<<"ANALIZADOR LEXICO: Lee el token : "<<car<<endl;
    switch(car)
    {
    case'M':
    case'R':
    case'W':
    case'=':
    case'(':
    case')':
    case';':
    case'}':
    case'{':
    case'.':
    case'+':
    case'*':
    case'-':
    case'/':
    case'%':
    case'^':
    return(car);
    }
    if(islower(car))return(car);
    else if(isdigit(car)) return(car);
    else
    {
    cout<<"Error Lexico: Token Desconocido"<<endl;
    system("pause");
    exit(-4);
    }
    return(car);
}

void Lexico::devuelveToken(char token)
{
    if(pBuffer>TAM_BUFFER)
    {
    cout<<"ERROR: Desbordamiento del buffer del analizador lexico"<<endl;
    system("pause");
    exit(-5);
    }
    else
    {
    buffer[pBuffer++]=token;
    if(existeTraza())
    cout<<"ANALIZADOR LEXICO: Recibe en buffer el token"<<token<<endl;
    system("pause");
}
}

int main()
{
int traza;
char token;
Lexico obj("ejemplo_miniUGB.txt",1);
if(obj.existeTraza())
cout<<"INICIO DE ANALISIS"<<endl;
while((token=obj.siguienteToken() )!='}')
cout<<token<<endl;
system("pause");
return 0;
}

Suerte si no hos funciona, y si les funciona han hecho todo bien.

CLASE 07
Se resolvio una guia, aclarar que muchas de las evaluaciones fueron revisiones y avances del compilador, asi q no busqueis todas las evaluaciones resueltas.

¿QUÉ ES EL ANALIZADOR SINTÁCTICO?
Es la fase del analizador que se encarga de chequear el texto de entrada en base a una gramática dada. Y en caso de que el programa de entrada sea válido, suministra el árbol sintáctico que lo reconoce.
El análisis sintáctico es un análisis a nivel de sentencias, y es mucho más complejo que el análisis léxico. Su función es tomar el programa fuente en forma de tokens, que recibe del analizador léxico, y determinar la estructura de las sentencias del programa. Este proceso es similar a determinar la estructura de una frase en castellano, determinando quien es el sujeto, predicado, el verbo y los complementos. El análisis sintáctico agrupa a los tokens en clases sintácticas (denominadas no terminales en la definición de la gramática), tales como expresiones, procedimientos, etc.
En teoría, se supone que la salida del analizador sintáctico es alguna representación del árbol sintáctico que reconoce la secuencia de tokens suministrada por el analizador léxico.
El analizador sintáctico o parser obtiene un árbol sintáctico (u otra  estructura equivalente) en la cual las hojas son los tokens, y cualquier nodo que no sea una hoja, representa un tipo de clase sintáctica (operaciones). Por ejemplo el análisis sintáctico de la siguiente expresión:

(A+B)*(C+D)

Con las reglas de la gramática que se presenta a continuación dará lugar al árbol sintáctico EJEMPLO
<expresión>   ::= <término> <más términos>
<más términos>::= +<término> <más términos>| - <término> <más términos> | <vacío>
<término>    ::= <factor> <más factores>
<más factores>::= * <factor> <más factores>|/ <factor> <más factores> | <vacío>
<factor>   ::= ( <expresión> ) | <variable> | <constante>

La estructura de la gramática anterior refleja la prioridad de los operadores, así los operadores “+” y “-” tienen la prioridad más baja, mientras que “*” y “/” tienen una prioridad superior. Se evaluaran en primer lugar las constantes, variables y expresiones entre paréntesis.
Los árboles sintácticos se construyen con un conjunto de reglas conocidas como gramática, y que definen con total precisión el lenguaje fuente.
Al proceso de reconocer la estructura del lenguaje fuente se conoce con el nombre de  análisis sintáctico  (parsing).
La principal tarea del analizador sintáctico no es comprobar que la sintaxis del programa fuente sea correcta, sino construir una representación interna de ese programa y en el caso en que  sea un programa incorrecto, dar un mensaje de error.


EL ANALIZADOR SINTÁCTICO (ASN) comprueba que el orden en que el analizador léxico le va entregando los tokens es válido. Si esto es así significará que la sucesión de símbolos que representan dichos tokens puede ser generada por la gramática correspondiente al lenguaje del código fuente.

La forma más habitual de representar la sintaxis de un programa es el árbol de análisis sintáctico, y lo que hacen los analizadores sintácticos es construir una derivación por la izquierda o por la derecha del programa fuente, que en realidad son dos recorridos determinados del árbol de análisis sintáctico. A partir de ese recorrido el analizador sintáctico debe construir una representación intermedia de ese programa fuente: un árbol sintáctico abstracto o bien un programa en un lenguaje intermedio; por este motivo, es muy importante que la gramática esté bien diseñada, e incluso es frecuente rediseñar la gramática original para facilitar la tarea de obtener la representación intermedia mediante un analizador sintáctico concreto.

El ASN constituye el esqueleto principal del compilador. Habitualmente el analizador léxico se implementa como una rutina dentro del sintáctico, al que devuelve el siguiente token que encuentre en el buffer de entrada cada vez que éste se lo pide. Así mismo, gran parte del resto de etapas de un programa traductor están integradas de una u otra forma en el analizador sintáctico.

LAS PRINCIPALES FUNCIONES SON:
Identificar cada tipo de instrucción y sus componentes.
– Completar la Tabla de Símbolo s.
– Realizar comprobaciones estáticas:
• Se realizan durante la compilación del programa.
• Ejemplos: comp. de tipos, unicidad de etiquetas e identificadores, etc.
– Realizar comprobaciones dinámicas:
• Aquellas que el compilador incorpora al programa traducido.
• Hacen referencia a aspectos que sólo pueden ser conocidos en tiempo de ejecución
• Dependientes del estado de la máquina en la ejecución o del propio programa.
 – Validar las declaraciones de identificadores: en muchos lenguajes no se puede usar una variable si no ha sido declarada con anterioridad.

Hay distintas clases de analizadores o reconocedores sintácticos, pero en general se clasifican en 2 grandes grupos: A.S.
Ascendentes y A.S. Descendentes.

TIPOS DE ANÁLISIS SINTÁCTICOS
Desde el punto de vista de la teoría de Análisis Sintáctico, hay dos estrategias para construir el árbol sintáctico:

Análisis descendente: partimos de la raíz del árbol (donde estará situado el axioma o símbolo inicial de la gramática) y se van aplicando reglas por la izquierda de forma que se obtiene una derivación por la izquierda de la cadena de entrada. Para decidir qué regla  aplicar, se lee un token de la entrada. Recorriendo el árbol de análisis sintáctico resultante, en profundidad de izquierda a derecha, encontraremos en las hojas del árbol los tokens que nos devuelve el Analizador Léxico (A.L.) en ese mismo orden.

Análisis ascendente: partiendo de la cadena de entrada, se construye el árbol de análisis sintáctico empezando por las hojas (donde están los tokens) y se van creando nodos intermedios hasta llegar a la raíz (hasta el símbolo inicial), construyendo así el árbol de abajo a arriba. El recorrido del árbol se hará desde las hojas hasta la raíz. El orden en el que se van encontrando las producciones corresponde a la inversa de una derivación por la derecha.
Las dos estrategias recorren la cadena de entrada de izquierda a derecha una sola vez, y necesitan (para que el análisis sea eficiente) que la gramática no sea ambigua.
Para ello, el analizador sintáctico (A.S.) comprueba que el orden en que el analizador léxico le va entregando los tokens es válido. Si esto es así significará que la sucesión de símbolos que representan dichos tokens puede ser generada por la gramática correspondiente al lenguaje del código fuente.
MANEJO DE ERRORES SINTÁCTICOS
Si un compilador tuviera que procesar sólo programas correctos, su diseño e implantación se simplificarían mucho. Pero los programadores a menudo escriben programas incorrectos, y un buen compilador debería ayudar al programador a identificar y localizar errores. Es más, considerar desde el principio el manejo de errores puede simplificar la estructura de un compilador y mejorar su respuesta a los errores.

Los errores en la programación pueden ser de los siguientes tipos:
• Léxicos, producidos al escribir mal un identificador, una palabra clave o un operador.
• Sintácticos, por una expresión aritmética o paréntesis no equilibrados.
• Semánticos, como un operador aplicado a un operando incompatible.
• Lógicos, puede ser una llamada infinitamente recursiva.

El manejo de errores de sintaxis es el más complicado desde el punto de vista de la creación de compiladores. Nos interesa que cuando el compilador encuentre un error, se recupere y siga buscando errores.

Por lo tanto el manejador de errores de un analizador sintáctico debe tener como objetivos:
• Indicar los errores de forma clara y precisa. Aclarar el tipo de error y su localización.
• Recuperarse del error, para poder seguir examinando la entrada.
• No ralentizar significativamente la compilación.

Un buen compilador debe hacerse siempre teniendo también en mente los errores que se pueden producir; con ello se consigue:
• Simplificar la estructura del compilador.
• Mejorar la respuesta ante los errores.

Tenemos varias estrategias para corregir errores, una vez detectados:
• Ignorar el problema (Panic mode ): Consiste en ignorar el resto de la entrada hasta llegar a una condición de seguridad. Una condición tal se produce cuando nos encontramos un token especial (por ejemplo un ‘;’o un ‘END’).A partir de este punto se sigue analizando normalmente.

• Recuperación a nivel de frase: Intenta recuperar el error una vez descubierto. En el caso anterior, por ejemplo, podría haber sido lo suficientemente inteligente como para insertar el token ‘;’. Hay que tener cuidado con este método, pues puede dar lugar a recuperaciones infinitas.

GRAMÁTICAS DE ATRIBUTOS. Una gramática de atributos es una gramática libre de contexto cuyos símbolos pueden tener asociados atributos y las producciones pueden tener asociadas reglas de evaluación de los atributos. En la creación de compiladores se utilizan ecuaciones de atributos o reglas semánticas como método para expresar la relación entre el cálculo de los atributos y las reglas del lenguaje. Cada producción (regla sintáctica) tiene asociada una acción semántica que se aplica cuando se realiza una reducción en el análisis sintáctico ascendente.
Atributo: propiedad de una construcción de un lenguaje. Pueden variar mucho en cuanto a información que contienen o tiempo que tardan en determinarse durante la traducción/ejecución. Cada símbolo (terminal o no terminal) puede tener asociado un número finito de atributos. Ejemplos de atributos:


– Tipo de una variable
– Valor de una expresión
– Ubicación en memoria de una variable
–  Código objeto de un procedimiento
– Número de dígitos significativos en un número


UNIVERSIDAD “GERARDO BARRIOS”
COMPILADORES E INTÉRPRETES
CICLO I – 2016
DOCENTE: ING. MARVIN OSMARO PARADA

LABORATORIO 2 COMPUTO II – TEÓRICO 50%

INDICACIÓN. REUNIRSE EN GRUPO DE TRES INTEGRANTES y RESPONDER A LAS SIGUIENTES PREGUNTAS, ENTREGAR EL INFORME AL DOCENTE

1.   Que es un árbol sintáctico
2.   Cuál es la salida del analizar sintáctico
3.   En que cosiste la gramáticas de atributos
4.   Cuál es la principal tarea del analizador sintáctico
5.   Que son los atributos, menciona algunos ejemplos
6.   Cuál es la función principal del analizador sintáctico
7.   Cuáles son los tipos de análisis sintáctico, explica cada uno
8.   Como interactúa el manejo de errores en la fase de análisis sintáctico
9.   Define con tus propias palabras en que consiste un analizador sintáctico

10.               Cuáles suelen será los errores más comunes en la programación de esta fase


CLASE 08

En esta clase no fue algo diferente pero les dejare un ejemplo y espero que os sirva....
Mencionar que hay cosas que no las comprendera a la primera pero el exito se basa en la disponibilidad no en la rapidez.

EJEMPLO DE ANALIZADOR LEXICO-SINTACTICO MINI-DEV        
OBJETIVOS

*       Complementar conceptos teóricos del análisis Léxico y Sintáctico.
*       Estudiar el código fuente de un programa prototipo de análisis Léxico y Sintáctico desarrollado en el entorno Dev C++.
El analizador sintáctico (ASN) comprueba que el orden en que el analizador léxico le va entregando los tokens es válido. Si esto es así significará que la sucesión de símbolos que representan dichos tokens puede ser generada por la gramática correspondiente al lenguaje del código fuente.

La forma más habitual de representar la sintaxis de un programa es el árbol de análisis sintáctico, y lo que hacen los analizadores sintácticos es construir una derivación por la izquierda o por la derecha del programa fuente, que en realidad son dos recorridos determinados del árbol de análisis sintáctico.

PROTOTIPO DE UN ANALIZADOR LEXICO

Ejemplo1(prueba_lexico.txt):
M
{
R a;
R b;
C = a+ b;
W c;
}


Ejemplo2 (prueba_sintactico.txt):
M
{
R a;
R b;
c = a + b * 2;
W c;
}

 

Archivos de Código Fuente








Analizador Léxico (Lexico.h)

#ifndef Lexico_H
#define Lexico_H
#include<iostream>
#include<stdio.h>
#include<ctype.h>
#include<stdlib.h>
#include<string>

#define TAM_BUFFER 100

using namespace std;
class Lexico
{
char *nombreFichero;
FILE* entrada;
int n1;
int traza;
char buffer[TAM_BUFFER];
int pBuffer;

public:
Lexico(char *unNombreFichero, int una_traza=0);
~Lexico(void);
char siguienteToken(void);

void devuelveToken(char toke);
int lineaActual(void){return n1; };
int existeTraza(void){if(traza)return 1; else return 0;}
};
Lexico::Lexico(char *unNombreFichero, int una_traza)
{
    entrada=fopen(unNombreFichero, "rt");
    if((entrada==NULL))
    {
    cout<<"No se puede abrir el archivo"<<endl;
    system("pause");
    exit(-2);
    }
if(una_traza) traza=1;
else traza = 0;
    n1=1;
    pBuffer=0;
}

Lexico::~Lexico()
{
fclose(entrada);
}


char Lexico::siguienteToken(void)
{
char car;
while((car=((pBuffer>0) ? buffer[--pBuffer]:getc(entrada)))!=EOF)
{
    if(car==' ') continue;
    if(car=='\n'){++n1; continue;}
    break;
}
if(traza) cout<<"ANALIZADOR LEXICO: Lee el token"<<car<<endl;
switch(car)
{
    case'M':
    case'R':
    case'W':
    case'=':
    case'(':
    case')':
    case';':
    case'}':
    case'{':
    case'.':
    case'+':
    case'*':
    case'-':
    case'/':
    case'%':
    return(car);
}
if(islower(car))return(car);
else if(isdigit(car)) return(car);
else
{
    cout<<"Error Lexico: Token Desconocido"<<endl;
    system("pause");
    exit(-4);
}
return(car);
}

void Lexico::devuelveToken(char token)
{
if(pBuffer>TAM_BUFFER)
{
    cout<<"ERROR: Desbordamiento de buffer del analizador léxico"<<endl;
    system("pause");
    exit(-5);
}
else
{
    buffer[pBuffer++]=token;
    if(existeTraza())
    cout<<"ANALIZADOR LEXICO: Recibe en buffer el token"<<token<<endl;
    system("pause");
}
}
#endif

Analizador Sintáctico (Sintactico.h)

#ifndef Sintactico_H
#define Sintactico_H
#include "lexico.h"
#include <stdlib.h>

using namespace std;

class Sintactico{
void programa (void);
void bloque (void);
void sentencia (void);
void otra_sentencia (void);
void asignacion(void);
void lectura (void);
void escritura(void);
void variable(void);
void expresion(void);
void termino(void);
void mas_terminos(void);
void factor(void);
void mas_factores(void);
void constante(void);
void errores (int codigo);
Lexico lexico; //objeto léxico miembro de la clase
public:
Sintactico(char *fuente, int traza);
~Sintactico(void);
};

Sintactico::Sintactico(char *fuente, int traza):lexico(fuente, traza)
//se inicializa el constructor de la clase léxico
{
if (lexico.existeTraza())
cout<<"INICIO DE ANALISIS SINTACTICO"<<endl;
programa();
}
/********************************************************************/
Sintactico::~Sintactico(void)
{
if (lexico.existeTraza())
{
cout<<"FIN DE ANALISIS SINTACTICO"<<endl;
cout<<"FIN DE COMPILACION"<<endl;
}
}
/********************************************************************/
void Sintactico::programa(void)
{
char token;
if (lexico.existeTraza())
cout<<"ANALISIS SINTACTICO: <PROGRAMA>"<<endl;
token=lexico.siguienteToken();
if (token=='M') cout <<"M";
else errores(8);
token=lexico.siguienteToken();
if (token!='{') errores(9);
bloque();
token=lexico.siguienteToken();
if (token=='}')
{
cout<<"}";
}
else errores(2);
}
/************************************************************************/
void Sintactico::bloque(void)
{
char token=' ';
if (lexico.existeTraza())
cout<<"ANALISIS SINTACTICO: <BLOQUE>"<<endl;
sentencia();
otra_sentencia();
}

/**********************************************************************/
void Sintactico::otra_sentencia(void)
{
char token;
if (lexico.existeTraza())
cout<<"ANALISIS SINTACTICO: <OTRA_SENTENCIA>"<<endl;
token=lexico.siguienteToken();
if (token==';')
{
sentencia();
otra_sentencia();
}
else lexico.devuelveToken(token); //vacio
}
/*********************************************************************/
void Sintactico::sentencia(void)
{
char token;
if (lexico.existeTraza())
cout<<"ANALISIS SINTACTICO: <SENTENCIA>"<<endl;
token=lexico.siguienteToken();
if ((token>='a') && (token<='z'))
{
lexico.devuelveToken(token);
asignacion();
}
else if (token=='R') lectura();
else if (token=='W') escritura();
else errores(6);
}
/**********************************************************************/
void Sintactico::asignacion()
{
char token;
if (lexico.existeTraza())
cout<<"ANALISIS SINTACTICO: <ASIGNACION>"<<endl;
variable();
token=lexico.siguienteToken();
if (token!='=') errores(3);
expresion();
}
/*********************************************************************/
void Sintactico::variable(void)
{
char token;
if (lexico.existeTraza())
cout<<"ANALISIS SINTACTICO: <VARIABLE>"<<endl;
token=lexico.siguienteToken();
if ((token>='a') && (token<='z')) cout<<token;
else errores(5);
}

/********************************************************************/
void Sintactico::expresion(void)
{
if (lexico.existeTraza())
cout<<"ANALISIS SINTACTICO: <EXPRESION>"<<endl;
termino();
mas_terminos();
}
/*********************************************************************/
void Sintactico::termino(void)
{
if (lexico.existeTraza())
cout<<"ANALISIS SINTACTICO: <TERMINO>"<<endl;
factor();
mas_factores();
}
/*********************************************************************/
void Sintactico::mas_terminos(void)
{
char token;
if (lexico.existeTraza())
cout<<"ANALISIS SINTACTICO: <MAS_TERMINOS>"<<endl;
token=lexico.siguienteToken();
if (token=='+')
{
termino();
mas_terminos();
}
else if (token =='-')
{
termino();
mas_terminos();
}
else lexico.devuelveToken(token); // <vacio>
}
/*********************************************************************/
void Sintactico::factor(void)
{
char token;
if (lexico.existeTraza())
cout<<"ANALISIS SINTACTICO: <FACTOR>"<<endl;
token=lexico.siguienteToken();
if ((token>='0') && (token<='9'))
{
lexico.devuelveToken(token);
constante();
}
else if (token=='(')
{
expresion();
token=lexico.siguienteToken();
if (token!=')') errores(4);
}
else
{
lexico.devuelveToken(token);
variable();
}
}

/*********************************************************************/
void Sintactico::mas_factores(void)
{
char token;
if (lexico.existeTraza())
cout<<"ANALISIS SINTACTICO: <MAS_FACTORES>"<<endl;
token=lexico.siguienteToken();
switch (token)
{
case '*':factor();
mas_factores();
break;
case '/':factor();
mas_factores();
break;
case '%':factor();
mas_factores();
break;
default: //<vacio>
lexico.devuelveToken(token);
}
}
/*********************************************************************/
void Sintactico::lectura(void)
{
char token;
token=lexico.siguienteToken();
if (lexico.existeTraza())
cout<<"ANALISIS SINTACTICO: <LECTURA> "<<token<<endl;
if((token<'a')||(token>'z')) errores(5);
}
/**********************************************************************/
void Sintactico::escritura(void)
{
char token;
token=lexico.siguienteToken();
if (lexico.existeTraza())
cout<<"ANALISIS SINTACTICO: <ESCRITURA> "<<token<<endl;
if ((token<'a') || (token>'z')) errores(5);
}

/************************************************/
void Sintactico::constante(void)
{
char token;
if (lexico.existeTraza())
cout<<"ANALISIS SINTACTICO: <CONSTANTE>"<<endl;
token=lexico.siguienteToken();
if ((token>='0') && (token<='9')) cout<<token;
else errores(7);
}
/*******************************************************************/
void Sintactico::errores(int codigo)
{
int x;
cout<<"LINEA "<<lexico.lineaActual();
cout<<" ERROR SINTACTICO "<<codigo;
switch (codigo)
{
case 1 :cout<<" :ESPERABA UN ;"<<endl;break;
case 2 :cout<<" :ESPERABA UNA }"<<endl;break;
case 3 :cout<<" :ESPERABA UN ="<<endl;break;
case 4 :cout<<" :ESPERABA UN )"<<endl;break;
case 5 :cout<<" :ESPERABA UN IDENTIFICADOR"<<endl;break;
case 6 :cout<<" :INSTRUCCION DESCONOCIDA"<<endl;break;
case 7 :cout<<" :ESPERABA UNA CONSTANTE"<<endl;break;
case 8 :cout<<" :ESPERABA UNA M DE MAIN"<<endl;break;
case 9 :cout<<" :ESPERABA UNA {"<<endl;break;
default:
cout<<" :NO DOCUMENTADO"<<endl;
}
cin>>x;
exit(-(codigo+100));
}
#endif

Programa Principal (Lexico.cpp)

#include<iostream>

#include "Lexico.h"

using namespace std;

int main()
{
Lexico lexico("prueba_lexico.txt",1);
return 0;
}

Programa Principal (Sintactico.cpp)

#include<iostream>
#include "Sintactico.h"

using namespace std;

int main()
{
Sintactico sintactico("prueba_sintactico.txt",1);
return 0;
}


COMPILADORES E INTÉRPRETES
CICLO I – 2016                                                        
EJEMPLO DE ANALIZADOR SINTACTICO
IMPRIMIR Y ENTREGAR AL DOCENTE
ALUMNOS

Después de haber ejecutado con éxito el analizador sintáctico responda lo siguiente:

1.  Coloque en el archivo prueba.txt algún carácter no reconocido por el lenguaje MINI-DEV. Vuelva a ejecutar la aplicación generada en C++. ¿Qué observó en la ejecución? ¿Cuál es la razón del resultado? Realizar capturas de pantalla y anexar al reporte

2.  Elimine el carácter “;” de alguna de las instrucciones. Vuelva a ejecutar la aplicación. ¿Qué observó en la ejecución? ¿Cuál es la razón del resultado? Realizar capturas de pantalla y anexar al reporte

3.  Investigar cuáles son los tipos de análisis sintáctico y sus características.

4.  Investigar que es la notación LL(K)  y LLR, notación EBNF y BNF.

CLASES FUTURAS.....

He terminado mi experiencia, lo que en este apartado se encuentra representa lo que mas influyo en mi sobre esta materia, hacen falta clases pero las cuales no han sido algo que considere poner, primero porque hay cosas demasiado complicadas para explicarlas en un blog y segundo porque la informacion impartida a clase no considero necesaria en este apartado, las ultimas clases nos enfocamos mas en terminar el compilador que se construyo de manera personal que en las actividades  o clases vistas en el salon.

No hay comentarios.:

Publicar un comentario