viernes, 3 de junio de 2016

Eportafolio



Universidad Gerardo Barios

Catedrático: ing. Osmaro parada

Catedra: Compiladores e interprete

Contenido:
Unidad 1
Introducción a los traductores
Unidad 2
Análisis léxico
Unidad 3
Análisis sintáctico
Unidad 4
Análisis semántico
Unidad 5
Lenguaje intermedio





UNIDAD #1


UNIVERSIDAD CAPITAN GENERAL “GERARDO BARRIOS”
COMPILADORES E INTÉRPRETES, CICLO I – 2016
DOCENTE: ING. MARVIN OSMARO PARADA
CLASE # 12
EJEMPLO DE ANALIZADOR LEXICO USANDO DEV C++
                                                                       
OBJETIVOS
*      Estudiar el código fuente de un programa prototipo de análisis léxico.
*      Aplicar el análisis léxico utilizando código en lenguaje C++ creado con Dev C++

PROTOTIPO DE UN ANALIZADOR LEXICO
Suponga que se desea construir una mini simulación de un compilador, tomando en cuenta nada más el análisis léxico de un programa. El programa fuente será un código escrito en un lenguaje definido por el usuario (podemos llamarlo MiniDev). En este caso el código ha sido escrito en lenguaje C++ y se debe trabajar con el programa Dev C++ v4.9.

Generalmente un compilador toma el programa fuente, lo interpreta y crea un programa objeto (normalmente en lenguaje máquina). Por ahora nos limitaremos a comprender y analizar una de las formas, de cómo se llevaría a cabo un analizador léxico según las características de un lenguaje.

La definición de los componentes léxicos del lenguaje MiniDev es la siguiente:

*      Identificadores, que sólo son nombres de variables y están compuestos por una única letra minúscula de rango de a – z.
*      Constantes: numéricas utilizando dígitos en el rango 0 – 9.
*      Operadores: +, -, *, / y %.
*      Símbolo: asignación :=, paréntesis (  ), separador de sentencias punto y coma, indicadores de principio y fin de bloque {  }.
*      Palabras reservadas que están formadas por una letra mayúscula, las cuales son: R (lectura), W (escritura) y M (programa principal).

Observe que en este lenguaje, todos los tokens son de un sólo carácter. Además se considera que se tiene un solo tipo de dato: entero, y que las variables están formadas por una única letra minúscula, y las constantes son de un dígito. Se asume que para identificar la sintaxis de cada sentencia, se conoce que reglas de programa se han de seguir, con solo conocer el token por el que comienza la sentencia.

Programa de ejemplo escrito con código fuente reconocido por el lenguaje MiniDev.


Conociendo la gramática del lenguaje definido, realice la descripción de lo que realiza cada una de las líneas escritas en el programa.
1.    ______________________________________________________________________________
2.    ______________________________________________________________________________
3.    ______________________________________________________________________________
4.    ______________________________________________________________________________
5.    ______________________________________________________________________________
6.    ______________________________________________________________________________
7.    ______________________________________________________________________________

El análisis léxico debe separar el fichero fuente en componentes léxicos o tokens, y enviarlos al analizador sintáctico (en este guía no se detallara el analizador sintáctico).

Habitualmente se envían los componentes léxicos y sus atributos. En este caso solo se enviaran los tokens, ya que el atributo va implícito en el token (tan sólo se tiene el tipo de dato entero).

A continuación se muestra la definición de clase Léxico, la cual contiene las funciones necesarias para poder implementar un análisis léxico adecuado para el lenguaje DEVC.

#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 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");
}
}

Programa Principal

A continuación se muestra un pequeño programa para observar como es realizado el proceso de análisis léxico por la clase. (SI Ud. desea puede implementar otro tipo de proceso dentro de main).

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

}






UNIDAD #2

Archivos  del Analizador
Lexico.h
Sintactico.h
Lexico.cpp
Sintactico.cpp
prueba_lexico.txt (Archivo código fuente de ejemplo para léxico)
prueba_sintactico.txt (Archivo código fuente de ejemplo para sintáctico)


Directorio del Analizador


Estructura del Analizador

Archivos analizados
Archivo Lexico.h
Archivo Sintactico.h
Analizar la estructura de código.
Determinar las funciones o clases implementadas.

Deduzca el tipo de programación utilizada para lograr el análisis sintáctico.


Cuántas clases tiene Lexico.h?

Cuántas clases tiene Sintactico.h?

VISOR DE CLASES Y FUNCIONES



LLAMANDO ARCHIVO Lexico.h
Analizar el archivo Lexico.cpp

Que incluye el código de éste archivo?


El archivo Lexico.cpp

LLAMANDO ARCHIVO Sintactico.h
Analizar el archivo Sintactico.cpp

Que incluye el código de éste archivo?


El archivo Sintactico.cpp

CREAR UN EJEMPLO
En la guía se incluyen dos ejemplos de código fuente que reconoce el analizador Dev c++.
Proponga dos ejemplos de código fuente tomando en cuenta la gramática del lenguaje.

CAPTURE EL RESULTADO

Pruebe los ejemplos propuestos y capture el resultado en consola.
Supongamos que escribimos un tercer ejemplo con el siguiente código fuente:

RESULTADO DEL ANALISIS


UNIDAD #3


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

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.


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;
}

No hay comentarios:

Publicar un comentario