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