UNIDAD 4: IMPLEMENTACIÓN DE ANALIZADORES LÉXICO / SINTACTICO
4.1. INFORMACIÓN SOBRE LOS IDENTIFICADORES DE USUARIOS
Bibliografía: https://sites.google.com/site/clsecompiladores/home/project-updates
Información que el desarrollador decida almacenar en las tablas.
La información dependerá del traductor desarrollado
En esta información puede incluir:
Nombre del elemento
El nombre o identificador puede almacenarse limitando o no la longitud del mismo.
Tipo de elemento
Tipo de dato al que pertenece cierto elemento
Dirección de memoria
Dirección en que se almacenará su valor en tiempo de ejecución.
Valor de elemento
Permite gestionar las variables fácilmente
Número de dimensiones
Almacena las dimensiones de un array
Tipos de parámetros formales
Almacena los tipos de los parámetros formales de una función o procedimiento
4.2. CONSIDERACIONES SOBRE LA TABLA DE SÍMBOLOS
Bibliografía:
http://www.lcc.uma.es/~galvez/ftp/tci/tictema5.pdf
Puede iniciar con cierta información útil
Constantes
PI, E
Funciones de librerías
EXP, LOG, etc
Palabras reservadas
Conforme aparecen nuevas declaraciones de identificadores
Insertará nuevas entradas en la tabla de símbolos
Evitará la existencia de entradas repetidas
El analizador semántico efectúa las comprobaciones sensibles al contexto.
El generador de código intermedio usa las direcciones de memoria asociada a cada identificador.
El optimizador de código no necesita hace uso de la dirección de memoria.
La tabla de simbolos contiene unformacion util
Para compilar
Existe en tiempo de compilación
No existe en tiempo de ejecución
4.5. IMPLEMENTACIÓN DE ANALIZADOR LÉXICO SINTÁCTICO.
Bibliografía:
https://www.fdi.ucm.es/profesor/fpeinado/courses/compiling/Tema1.6-Implementacion.pdf
Primero se realiza el análisis léxico y luego el sintáctico, pero en la práctica ambos se van realizando en la misma pasada.
ANALIZADOR LÉXICO
Convierte el programa de entrada en una secuencia de componentes léxicos (ocurrencias de categorías léxicas)
Cada componente léxico lleva el identificador de su categoría léxica y un conjunto de atributos léxicos
Se usa la definición léxica (expresiones regulares) para diseñar un reconocedor del lenguaje (autómata finito determinista)
Considerar las ER's de las definiciones regulares de cada categoría léxica.
Añadir otra ER con lo necesario para tratar de separadores, comentarios, reconocer el final del fichero, etc.
Solapar todos los AFNDs en un solo AFND.
Un único estado inicial para todo.
Uno o varios estados finales por cada categoría léxica
Mínimo número de estados intermedios que se puedan.
ANALIZADOR SINTÁCTICO
Dada la secuencia de componentes léxicos de entrada decide si el programa que representa es válido o no en el lenguaje propuesto.
Se usa la definición sintáctica directamente para implementarlo (no hace falta llegar a diseñar el autómata a pila que reconoce el lenguaje)
La implementación es manual, usando la gramática incontextual y las restricciones contextuales sólo como “guías”
4.4. INTEGRACIÓN DE UN ANALIZADOR LÉXICO / SINTÁCTICO
Bibliografía:
https://docplayer.es/25036146-Integracion-de-jflex-y-cup-analizadores-lexico-y-sintactico.html
La integración permite obtener un compilador mucha más complejo.
Se puede integrar cada uno de los procesos de los metacompiladores
Ahorra de manera abismal la generación de código al momento de desarrollar un compilador.
Integración del generador de analizadores léxicos (JFLEX) y Generador de analizadores Sintácticos (CUP).
JFLEX
CONCEPTO
Es un meta-compilador que permite generar rápidamente analizadores léxicos que se integran con Java
CARACTERÍSTICAS
Soporte completo con caracteres unicode
Permite generar analizadores léxicos rápidamente
Tiene una sintaxis cómoda de manipular y fácil de interpretar.
Permite la integración con CUP.
SECCIONES
Opciones y declaraciones
Código de usuario
Reglas lexicograficas
CUP
CONCEPTO
Es un meta-compilador utilizado para generar analizadores sintácticos ascendentes con algoritmos LALR.
CUP es un homólogo para Java del programa YACC utilizado en C
SINTAXIS
Definición de paquete y sentencias import
Sección de código de usuario
Declaración de símbolos terminales y no terminales
Declaración de procedencia
Definición de símbolo inicial de la gramática y reglas de producción
4.3. EJEMPLO DE LA TABLA DE SÍMBOLOS
Bibliografía:
http://www.lcc.uma.es/~galvez/ftp/tci/tictema5.pdf
FICHERO TablaSimbolo.c
#include <stdlib.h>
#include <stdio.h>
typedef struct nulo
{
struct nulo * sig;
char nombre [20];
int valor;
} simbolo;
simbolo * crear()
{
return NULL;
};
void insertar(p_t,s)
simbolo **p_t;
simbolo * s;
{
s->sig = (*p_t);
*p_t) = s;
};
simbolo * buscar(t,nombre)
simbolo * t;
char nombre[20];
{
while ( (t != NULL) && (strcmp(nombre, t->nombre)) )
t = t->sig;
return (t);
};
void imprimir(t)
simbolo * t;
{
while (t != NULL)
{
printf("%s\n", t->nombre);
t = t->sig;
}
};
FICHERO TablaSimbolo.lex
%%
[0-9]+ {
yylval.numero = atoi(yytext);
return NUMERO;
}
":=" { return ASIG; }
[a-zA-Z][a-zA-Z0-9]*{
yylval.ptr_simbolo = buscar(t,yytext);
if (yylval.ptr_simbolo == NULL)
{
yylval.ptr_simbolo=(simbolo *) malloc(sizeof(simbolo));
strcpy(yylval.ptr_simbolo->nombre, yytext);
yylval.ptr_simbolo->valor=0;
insertar(&t, yylval.ptr_simbolo);
}
return ID;
}
[ \t]+ {;}
.|\n {
return yytext[0];
}
%%
FICHERO TablaSimbolo.yacc
%{
#include "tabsimb2.c"
simbolo * t;
%}
%union {
int numero;
simbolo * ptr_simbolo;
}
%token <numero> NUMERO
%token <ptr_simbolo> ID
%token ASIG
%type <numero> expr asig prog
%start prog
%left '+'
%left '*'
%%
prog : prog asig '\n' { printf("Asignaciones efectuadas\n");}
| prog expr '\n' { printf("%d\n",$2);}
| prog error '\n' { yyerrok;}
|
;
asig : ID ASIG expr {
$$ = $3;
$1->valor = $3;
}
| ID ASIG asig {
$$ = $3;
$1->valor = $3;
}
;
expr : expr '+' expr {$$ = $1 + $3;}
| expr '*' expr {$$ = $1 * $3;}
| ID {$$ = $1->valor; }
| NUMERO {$$ = $1;}
;
%%
#include "ejem2l.c"
#include "errorlib.c"
void main()
{ t = crear();
yyparse ();
imprimir(t);
}