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


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