LABORATORIO DE PROCESADORES DE LENGUAJE Curso: 2008-2009 Práctica 2: Analizador léxico/sintáctico/semántico con Flex y Bison Planteamiento del problema En esta práctica se trata de realizar, mediante el generador de analizadores léxicos FLEX y sintácticos BISON, un analizador léxico, sintáctico y semántico que reconozca una simplificación del lenguaje de alto nivel VisualBASIC. Además, la práctica deberá incluir la construcción de la Tabla de Símbolos (TS) correspondiente. Especificación a nivel léxico Consideraremos como comentario todo aquello que vaya precedido por la palabra reservada REM y hasta final de línea. Por ejemplo: REM Esto es un comentario. Los identificadores (ID) constarán de una letra seguida opcionalmente de cualquier grupo de letras, dígitos y símbolos de subrayado „_‟. Existen dos tipos de constantes numéricas; los números enteros (TKN_NUMENT) formada por 1 o más dígitos y los números reales (TKN_NUMREAL) formado por 1 ó más dígitos seguidos de un punto y 1 o más dígitos. Los símbolos especiales son: ( ) “ , + - * / = ; Todas las palabras reservadas son con MAYUSCULAS. Estas palabras reservadas son: SUB FUNCTION END REM AS DIM SINGLE INTEGER STRING INPUT PRINT LEN CALL Especificación a nivel sintáctico VisualBASIC es un lenguaje de alto nivel que nos va a permitir definir funciones (devuelven un valor y se especificará con la palabra FUNCTION) o procedimientos (no devuelven valor y se especificará con SUB) al igual que permite definir distintos tipos de variables, que serán de ámbito local o global. La definición de una función termina con las palabras reservadas END FUNCTION, de un procedimiento con END SUB y el programa con la palabra END únicamente. La llamada a procedimientos se hace mediante la palabra reservada CALL. En las funciones VisualBasic utiliza el propio nombre de la función para devolver el valor de retorno de la misma. Ejemplo: Si la función se declara como FUNCTION Mifuncion () AS INTEGER Mifuncion = 4; REM Esto equivalente en C sería return(4) END FUNCTION En nuestra versión simplificada del lenguaje vamos a trabajar con los tipos de datos básicos: enteros (las variables se definen mediante INTEGER), los tipos reales (las variables se definen mediante SINGLE) y tipos cadenas de caracteres que podrán ser de longitud variable (únicamente la palabra reservada STRING), o de longitud fija (se añade a continuación de la palabra reservada STRING un asterisco y el numero de elementos de la cadena). A su vez, podemos definir arrays de estos tipos de datos básicos (los vectores en VisualBasic introducen una complejidad adicional pues utilizan paréntesis al igual que las funciones). Las palabras reservadas DIM y AS se usan en la definición de variables de estos tipos de datos. REM Ejemplo de declaracion de una cadena de longitud variable DIM cad1 AS STRING REM Ejemplo de cadena de longitud 10 1 DIM cad2 AS STRING*10 REM Ejemplo de definicion de vectores REM Deficion de un array de dimensiones 2x3 DIM v(2,3) AS INTEGER Se han incluido la función de tratamiento de cadenas LEN. LEN devuelve la longitud de la variable. Ejem: DIM cad1, cad2 AS STRING DIM longitud AS INTEGER cad1 = “El coche es rojo” longitud = LEN(cad1) REM en longitud se almacenara el valor 16 Para la petición de información se utiliza la función INPUT, dicha función devuelve un valor que es el dato introducido por el usuario y tiene un argumento que será el mensaje que se le mostrará al usuario cuando se realice la petición del dato. Para la impresión de información por pantalla se utiliza el comando PRINT, dicho comando mostrará por pantalla todos los literales o contenido de variables que haya a continuación del comando separados por comas (véase el ejemplo 1). Habrá que tener en cuenta que, tanto las variables como las funciones deben ser insertadas en la Tabla de Símbolos (TS), quedando reflejado de qué tipo son para las futuras comprobaciones semánticas. Por otra parte, habrá que diferenciar entre variables globales y locales, pudiendo tener variables con el mismo nombre siempre y cuando el ámbito de aplicación sea diferente. Cualquier programa en este lenguaje de alto nivel tendrá la estructura especificada en la siguiente gramática: Importante: Habrá que tener en cuenta la precedencia entre operadores y el menos unario en las expresiones que trabajan con dichos operadores. Por otra parte, deberemos indicar la fila y columna de los posibles errores, tanto léxicos como sintácticos. Por último, se deberá poder visualizar la tabla de símbolos una vez esta haya sido completamente generada. Nota: Se podrán incluir modificaciones a la gramática siempre que se genere el mismo lenguaje. 2 Programa Subrutinas Bloque Subrutinas Funcion Subrutinas | Procedimiento Subrutinas | Procedimiento TKN_SUB TKN_ID TKN_( Argumentos Bloque TKN_SUB Funcion TKN_FUNCTION TKN_ID TKN_( Argumentos TKN_) TKN_AS Tipo Bloque TKN_FUNCTION Argumentos TKN_ID DeclaraVector TKN_AS Tipo MasArgumentos | DeclaraVector TKN_( TKN_) | MasArgumentos TKN_, TKN_ID DeclaraVector TKN_AS Tipo MasArgumentos | Tipo TKN_INTEGER | TKN_SINGLE | TKN_STRING Tamano Tamano TKN_* TKN_NUMENT | Bloque Bdeclaraciones BSentencias Bdeclaraciones Declara BDeclaraciones | Declara TKN_DIM TKN_ID DefVector MasVariables TKN_AS Tipo DefVector TKN_( TKN_NUMENT MasDim TKN_) | MasDim TKN_, TKN_NUMENT MasDim | MasVariables TKN_, TKN_ID DefVector MasVariables | Bsentencias Instruccion TKN_; MasInstruccion Instruccion TKN_ID Opcion | TKN_PRINT Impresion | TKN_LEN TKN_( TKN_ID TKN_) | TKN_CALL TKN_ID TKN_( Args TKN_) MasInstruccion Instruccion TKN_; MasInstruccion | TKN_END Impresión TKN_ID DefVector MasImp | TKN_” Cadena TKN_” MasImp | Expresión MasImp Cadena TKN_ID Cadena | MasImp TKN_, Impresión MasImp | Args Contenido MasArgs | Contenido TKN_ID DeclaraVector | TKN_NUMENT | TKN_NUMREAL | TKN_” Cadena TKN_” MasArgs TKN_, Contenido MasArgs | Opcion DefVector TKN_= Informacion Información Expresion | TKN_” Cadena TKN_” Frase TKN_ID | TKN_” Cadena TKN_” Expresión | TKN_INPUT TKN_( Frase TKN_) Expresion TKN_+ Expresion | Expresion TKN_- Expresion | Expresion TKN_* Expresion | Expresion TKN_/ Expresion | TKN_- Expresion | TKN_ID DefGen | TKN_NUMENT | TKN_NUMREAL DefGen TKN_( Args TKN_) | 3 Ejemplos del lenguaje definido por la gramática: Ejemplo 1: DIM i AS INTEGER DIM nombre AS STRING*20 i = INPUT(“introduce tu edad”); nombre = INPUT(“Introduce tu nombre”); PRINT “Hola”, nombre, “tienes”, i, “anyos”; END Ejemplo 2: FUNCTION Suma(d() AS INTEGER, i AS INTEGER) AS INTEGER DIM total AS INTEGER total = d(1) + d(i); Suma = total; END FUNCTION SUB Comienzo(cad AS STRING) PRINT cad; END SUB DIM v(2) , result AS INTEGER DIM total AS INTEGER CALL Comienzo(“Este programa suma dos numeros”); v(1) = INPUT(“Introduce un numero”); v(2) = INPUT(“Otro”); result= Suma(v(),2); PRINT “La suma es ”, result; END Generación de la tabla de símbolos En este apartado se trata de generar la tabla de símbolos. Esta estructura, junto con el árbol sintáctico, se usará también en la siguiente práctica para generar código intermedio. A la hora de generar la tabla de símbolos se debe tener en cuenta que es necesario almacenar tanto las variables como las funciones, para ello tendremos que diferenciarlas mediante un campo que nos indique de que tipo de símbolo se trata. Para el caso de las variables, deberemos contemplar la posibilidad de que estén definidas en el cuerpo del programa (que serán globales) o dentro de alguna función (que serán locales). Necesitaremos un campo que nos almacene el ámbito al que pertenece la variable. La primera función definida tiene ámbito uno, la segunda tiene ámbito dos, así sucesivamente. También habrá que tener en cuenta el número, tipo y nombre de los argumentos que se le pasa a las funciones. 4 Comprobaciones semánticas Se deberán realizar las siguientes comprobaciones semánticas básicas con la tabla de símbolos: No insertar un identificador de una variable o función dos veces con el mismo nombre y con el mismo ámbito. Dado que los vectores utilizan paréntesis, no podrá haber funciones y variables con el mismo nombre independientemente del ámbito en el que esté declarado el vector. En las llamadas a funciones, deberemos comprobar que esa función ha sido definida y que el número de argumentos que se le pasa es el correcto y, además, que los argumentos son del mismo tipo. Cuando se usen las variables deberemos comprobar que dichas variable hayan sido previamente declaradas y que tienen el ámbito adecuado. Igualmente, no se puede llamar a una subrutina o función si está no existe. Se comprobará que en la parte izquierda de una asignación no hay llamadas a funciones. Exceptuando el nombre de la propia función sin argumentos, ya que este es el método que utiliza VisualBasic para devolver valores en las funciones. Ejemplo FUNCTION Mifuncion (a AS INTEGER) AS INTEGER REM Permitido, devolución de un valor entero por la función Mifuncion = a*2; END FUNCTION Dim v(3) AS INTEGER REM La siguiente instrucción es la asignación de un valor a un elemento de REM un vector v(1) = Mifuncion(4); REM La siguiente instruccion esta prohibida pues no tiene sentido asignarle un REM valor a una funcion Mifuncion(3) = 8; END Nota: Opcionalmente se podrán incluir otro tipo de comprobaciones. Gestión de errores Siempre que se produzca un error, tanto léxico como sintáctico como semántico, habrá que indicar el tipo de error de que se trata así como la fila y la columna donde se ha producido dicho error. Fecha de entrega: Todos los grupos deberán entregar la práctica con fecha máxima el 25 de Marzo DURACIÓN: 2 sesiones 5