PRACTICA 3

Anuncio
LABORATORIO DE PROCESADORES DE LENGUAJE – Curso 2007-2008
Práctica 2: Analizador léxico/sintáctico/semántico con Flex y Bison
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 un sencillo lenguaje de programación, que
llamaremos MiniModula, cuyas especificaciones léxicas y sintácticas se detallan a continuación.
Además se deberá incluir la construcción de la tabla de símbolos (TS) y realización de
comprobaciones semánticas.
Especificación a nivel léxico
Consideraremos como comentario todo aquello que vaya entre los símbolos (* y *).
Los identificadores, id, constarán de una letra seguida opcionalmente de cualquier número de
letras, dígitos y símbolos de subrayado ‘_’.
Existen constantes numéricas de tipo entero, num_integer, un dígito seguido de uno o más dígitos,
o de tipo real, num_real, un dígito o más dígitos seguidos de un punto más un dígito o más dígitos.
Los símbolos especiales son: (
>
.
:
..
)
[
] ;
,
+
-
*
/
Las palabras clave son: integer
real
char boolean
if
while do read write begin end function return
var array of record and or not true false
=
==
then
module
<
else
type
Especificación a nivel sintáctico
La gramática que utilizaremos representa un sencillo lenguaje de programación que incluye como
tipos simples de datos el tipo char, integer y real. Como tipos compuestos permite la
definición de vectores y estructuras. Como sentencias incluye las sentencias condicionales
(if_then_else), sentencias repetitivas (while_do), asignaciones, llamadas y retorno de
funciones y E/S de datos. También permite trabajar con expresiones aritméticas (+,-,*,/),
relacionales (<,==, >) y lógicas (and, or, not). Al final de la práctica se incluye ejemplos
de código fuente que reconoce esta gramática.
Generación de la Tabla de Símbolos y de la Tabla de Tipos
A la hora de generar la tabla de símbolos se debe tener en cuenta que es necesario almacenar tanto
variables globales como locales, para ello tendremos que diferenciar las variables mediante el
alcance que cada una de ellas tiene. A la hora de implementar la tabla de símbolos deberá utilizar
un campo para el alcance de los símbolos siendo, por ejemplo, su valor cero para las variables
globales e ir incrementándose para las variables locales dependiendo de la función en la que están
declaradas. La tabla debe contener información de si se trata de una variable o de una función, su
nombre, el ámbito y tipo de dato. Si se trata de una función debe almacenar el tipo del valor de
retorno, número y tipo de argumentos.
Cuando se definan un nuevo tipo de dato se almacenarán dentro una tabla de tipos donde
guardaremos información de cada tipo de dato definido. Si es una estructura se guardará su
nombre, tipo de dato de los campos y su nombre. Cuando se defina un tipo de dato vector, se
almacenará el nombre, tamaño y tipo base. Ejemplos de definiciones de tipos:
type objeto = record
color : char;
peso: integer;
end;
type vector = array [1..100] of integer;
1
La gramática que define el lenguaje es:
Program → module id ; Declarations begin StatementList end id .
Declarations → type id = TypeDenoter ; TypeList Declarations
| var id IdList : TypeDenoter ; VarList Declarations
| function id ( Parameter ParameterList ) : SimpleType ; Declarations
begin StatementList end id ; Declarations | ε
TypeList → id = TypeDenoter ; TypeList | ε
VarList → id IdList : TypeDenoter ; VarList | ε
IdList → , id IdList | ε
Parameter → TypeDenoter id | ε
ParameterList → , Parameter ParameterList | ε
SimpleType → char | integer |real | boolean
TypeDenoter → SimpleType | id | CompositeType
CompositeType → array [ num_integer .. num_integer ] of SimpleType
| record id IdList : SimpleType ; FieldList end
FieldList → id IdList : SimpleType ; FieldList | ε
StatementList → Statement ; StatementList | ε
Statement → AssignStm |IfStm | WhileStm | FunctionStm | ReturnStm | WriteStm |
ReadStm
AssignStm → LeftValue = Expression
LeftValue → id | id [ Expression ] | id . id
IfStm → if Expression then StatementList ElseStm end
ElseStm → else StatementList | ε
WhileStm → while Expression do StatementList end
FunctionStm → id (
Arg ArgList )
ReturnStm → return Expression
WriteStm → write Expression
ReadStm → read LeftValue
Arg → Num | - Num | id | - id |
ε
Num → num_integer | num_real
ArgList → , Arg ArgList | ε
Expression → LeftValue
Expression *
Expression |
Expression |
< Expression
| ( Expression ) | true | false | Num | FunctionStm |
Expression | Expression / Expression | Expression Expression + Expression | - Expression | Expression or
Expression and Expression | not Expression | Expression
| Expression > Expression | Expression == Expression
Nota: Se podrán incluir modificaciones a la gramática siempre que se genere el mismo lenguaje.
2
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.
Los operadores =, <, >, == no son asociativos. La precedencia de los operadores es, de menor a
mayor, la siguiente:
< > ==
+ - or
* / and
menos unario
not
=
Comprobaciones semánticas
Se deberán realizar todas las siguientes comprobaciones semánticas básicas:
•
Comprobaciones de tipos en asignaciones, en paso de parámetros a funciones y en
expresiones aritmético-lógicas. Todos los operandos en una expresión deben de ser del
mismo tipo y los operadores deben estar definidos para ese tipo de variables.
Asumiremos que, para variables de tipo entero y real, tenemos definidos los operadores
aritméticos y relacionales. Para variables booleanas sólo están definidos los operadores
lógicos. Para variables tipo carácter sólo están definidos los operadores relacionales.
• Comprobaciones relacionadas con la tabla de símbolos:
No insertar un identificador de una función o variable dos veces con el mismo
nombre y con el mismo ámbito.
En las llamadas a funciones el número y tipo de los de argumentos y valor de
retorno debe coincidir con la definición de la función.
Dentro de las funciones cuando se usen variables deben estar previamente
almacenadas en la tabla de símbolos y con el ámbito adecuado.
•
El índice de un tipo array debe ser entero y no debe salirse de rango. En la definición del
rango de un array se debe tener en cuenta que el límite inferior, que no tiene porqué ser
cero, debe ser menor que el superior.
•
Sólo se pueden asignar variables de tipo array entre sí en el caso de que tengan el mismo
tamaño y sean del mismo tipo. Se pueden asignar variables de tipo estructura entre sí,
siempre que los campos tengan el mismo nombre, tamaño y tipo de dato. No se pueden
hacer operaciones relacionales o artiméticológicas sobre tipos compuestos.
•
Los identificadores al principio y al final del programa principal y de las funciones
deben coincidir.
•
Siempre que se usen variables de tipo estructura se deberá comprobar que el
identificador del campo de la estructura coincide con el valor en la definición de dicho
tipo.
•
No se pueden definir variables de tipos, que no sean simples o compuestos, que no hayan
sido previamente definidos por el programador.
Nota: Opcionalmente se podrán incluir otro tipo de comprobaciones.
Fecha de entrega:
Todos los grupos, el día 3 de abril de 2007 en pizarra.uv.es
3
Ejemplo estadistica.mod
module Estadistica ;
(* Este programa calcula e imprime el valor medio de un vector de
100 enteros leido desde el teclado *)
type vector = array [1..100] of integer;
var datos : vector;
n:integer;
media:real;
function fnc_media(vector x, integer n): real;
var
temp:real;
i:integer;
begin (* calculo de la media*)
temp = 0;
i=1;
while (i< (n+1)) do
temp=temp+x[i];
i=i+1;
end;
return (temp/n);
end fnc_media ;
begin
n=1;
while n<101 do
read datos[n];
n=n+1;
end;
media=fnc_media(datos,n);
write media;
end Estadistica .
Ejemplo objetos.mod
module Objetos ;
type objeto = record
color : char;
peso: integer;
end;
var x,y : objeto;
begin
read x.color;
read x.peso;
read y.color;
read y.peso;
if (y.peso==x.peso) and (y.color== x.color) then
write 0;
else
write 1;
end;
end Objetos .
4
Descargar