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