Kategorier: Alle - variables - símbolos - identificadores - análisis

af SANCAN MACIAS SANCAN MACIAS 4 år siden

426

Unidad 4: IMPLEMENTACION DE ANALIZADORES LÉXICO/ SINTÁTICO

La implementación de analizadores léxicos y sintácticos es crucial en el desarrollo de compiladores. Un aspecto fundamental es la gestión de identificadores de usuario, que implica buscar y almacenar estos identificadores en una tabla de símbolos.

Unidad 4: IMPLEMENTACION DE ANALIZADORES LÉXICO/ SINTÁTICO

REFERENCIA: http://www.lcc.uma.es/~galvez/ftp/tci/tictema5.pdf https://sites.google.com/site/clsecompiladores/home/project-updates http://repositori.uji.es/xmlui/bitstream/handle/10234/5877/lexico.apun.pdf?sequence=1&isAllowed=y https://docplayer.es/25036146-Integracion-de-jflex-y-cup-analizadores-lexico-y-sintactico.html

El programa lex : Si se encuentra un número lo convierte a int y devuelve el token NUMERO. Si se encuentra un identificador de usuario: Primero lo busca en la tabla de símbolos, Si lo encuentra, entonces devuelve su valor Si no lo encuentra, lo inserta

Unidad 4: IMPLEMENTACION DE ANALIZADORES LÉXICO/ SINTÁTICO

IMPLEMENTACIÓN DE ANALIZADOR LÉXICO SINTACTICO

Se usa la definición léxica (expresiones regulares) para diseñar un reconocedor del lenguaje (autómata finito determinista)
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”
Añadir otra ER con lo necesario para tratar de separadores, comentarios, reconocer el final del fichero, etc.
Considerar las ER's de las definiciones regulares de cada categoría léxica.
Hasta ahora hemos visto cómo especificar los lenguajes asociados a las diferentes categorías léxicas. Sin embargo, el analizador léxico no se utiliza para comprobar si una cadena pertenece no a un lenguaje. Lo que debe hacer es dividir la entrada en una serie de componente léxicos, realizando en cada uno de ellos determinadas acciones. Algunas de estas acciones son: comprobar alguna restricción adicional (por ejemplo que el valor de un literal entero este dentro de un rango), preparar los atributos del componente y emitir u omitir dicho componente. Así pues, la especificación del analizador léxico deber ́a incluir por cada categoría léxica del lenguaje el conjunto de atributos y acciones asociadas.

INTEGRACION DE UN ANALIZADOR LÉXICO / SINTÁCTICO

Es un meta-compilador que permite generar rápidamente analizadores léxicos que se integran con Java
Tiene una sintaxis cómoda de manipular y fácil de interpretar.
Permite generar analizadores léxicos rápidamente
Soporte completo con caracteres unicode
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.

INFORMACIÓN SOBRE DE IDENTIFICADORES DE USUARIO

Tipos de los parámetros formales. Si el identificador a almacenar pertenece a una función o procedimiento, es necesario almacenar los tipos de los parámetros formales para controlar que toda invocación a esta función sea hecha con parámetros reales coherentes.
Número de dimensiones. Si la variable a almacenar es un array, también pueden almacenarse sus dimensiones.
Valor del elemento. Cuando se trabaja con intérpretes sencillos, y dado que en un intérprete se solapan los tiempos de compilación y ejecución, puede resultar más fácil gestionar las variables si almacenamos sus valores en la tabla de símbolos.
Nombre del elemento. El nombre o identificador puede almacenarse limitando o no la longitud del mismo.
Dirección de memoria en que se almacenará su valor en tiempo de ejecución. Esta dirección es necesaria, porque las instrucciones que referencian a una variable deben saber donde encontrar el valor de esa variable en tiempo de ejecución con objeto de poder generar código máquina, tanto si se trata de variables globales como de locales
Tipo del elemento. Cuando se almacenan variables, resulta fundamental conocer el tipo de datos a que pertenece cada una de ellas, tanto si es primitivo como si no, con objeto de poder controlar que el uso que se hace de tales variables es coherente con el tipo con que fueron declaradas.
La información que el desarrollador decida almacenar en esta tabla dependerá de las características concretas del traductor que esté desarrollando

CONSIDERACIONES SOBRE LA TABLA DE SIMBOLOS

CARACTERÍSTICAS
La tabla de símbolos puede iniciarse con cierta información útil, tal como: - Constantes: PI, E, etc. - Funciones de librería: EXP, LOG, etc. - Palabras reservadas. Esto facilita el trabajo al lexicográfico, que tras reconocer un identificador lo busca en la tabla de símbolos, y si es palabra reservada devuelve un token asociado. Bien estructurado puede ser una alternativa más eficiente al lex tal y como lo hemos visto (hash perfecto).
CONCEPTO
Conforme van apareciendo nuevas declaraciones de identificadores, el analizador léxico, o el analizador sintáctico según la estrategia que sigamos, insertará nuevas entradas en la tabla de símbolos, evitando siempre la existencia de entradas repetidas.

EJEMPLO DE LA TABLA DE SIMBOLO

TablaSimbolo.c #include #include 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; } };
EJEMPLO2Y.YAC %{ #include "TablaSimbolo.c" simbolo * t; %} %union { int numero; simbolo * ptr_simbolo; } %token NUMERO %token ID %token ASIG %type 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 "Ejemplo.c" #include "errorlib.c" void main() { t = crear(); yyparse (); imprimir(t); }
Fichero Ejemplo.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];}