par Dennisse Enriquez Il y a 4 années
358
Plus de détails
El programa Yacc: %union { int numero; simbolo * ptr_simbolo; } Esto es un registro con parte variante, en el que todo es parte variante. Si ponemos %union ya no hay que poner YYSTYPE. Cosas interesantes de la gramática: prog : prog asig ... | (J forma parte de un prog). ; asig : ID ASIG expr | ID ASIG asig Como podemos observar esta regla es recursiva a la derecha. Se permiten cosas como a := b := c := 3 * 4 En cuanto a la regla expr produce ambigüedad, ésta se soluciona introduciendo las instrucciones % left ‘+’ % left ‘*’ El atributo del identificador de usuario ‘ID’, es un puntero a un símbolo.
PARTE VARIABLE
definida por el programador: con el significado de los identificadores utilizados en cada frase (programa).
PARTE FIJA
formada por las palabras clave del lenguaje (suelen ser de uso reservado y del orden de unas decenas de palabras en un lenguaje programación típico)
En general en la Tabla de símbolos (TS a partir de ahora) se realizan dos operaciones: la inserción y la búsqueda. En C la operación de inserción se realiza cuando se procesa una declaración. Hay dos posibilidades: que la TS esté ordenada (o sea, nombres de variables por orden alfabético) o que no esté ordenada.
Como ya se ha comentado, la interfaz de la tabla de símbolos debe quedar clara desde el principio de manera que cualquier modificación en la implementación de la tabla de símbolos no tenga repercusión en las fases del compilador ya desarrolladas. Las operaciones básicas que debe poseer son:
crear(): crea una tabla vacía. insertar(símbolo): añade a la tabla el símbolo dado. buscar(nombre): devuelve el símbolo cuyo nombre coincide con el parámetro. Si el símbolo no existe devuelve null. imprimir(): a efectos informativos, visualiza por la salida estándar la lista de variables almacenadas en la tabla de símbolos junto con sus valores asociados.
Cada entrada de la tabla de símbolos corresponde a al declaración de un nombre. El formato de las entradas no tiene que ser uniforme porque la información de un nombre depende del uso de dicho nombre. Cada entrada en principio puede considerarse: ( Nombre, descriptor )LEXEMA ATRIBUTOS
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.
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.
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.
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.
Si la variable a almacenar es un array, también pueden almacenarse sus dimensiones.
El nombre o identificador puede almacenarse limitando o no la longitud del mismo.
%7bit Permite usar entradas de 7 bits, es decir entre 0-127. Si una entrada es mayor que 127 se generará un error en tiempo de ejecución y se lanzará una excepción de tipo:
ArrayIndexOutofBoundsException.
El siguiente fragmento formará parte esencial dentro del funcionamiento del analizador, en este se definirán el conjunto de expresiones regulares que se utilizarán durante el proceso de análisis, a continuación se presentan unos ejemplos de este tipo de declaraciones:
FinDeLinea = \r | \n | \r\n Variable = [:jletter:][:jletterdigit:]* Si = “Si” Entero = 0 | [1-9][0-9]*
En el siguiente fragmento de código podremos incluir código Java el cual podemos utilizar en el analizador, cabe notar que el código que aquí se escriba será incluido sin ninguna alteración al resultado final del analizador, dicho fragmento ira enmarcado entre las etiquetas %{ al inicio del código y %} al final del mismo.
%{ public static void escribir(String cadena) { System.out.println(cadena); } % }