Está en la página 1de 21

Analizador Lexicográfico

Software de Sistemas
Mónica Pinto Alarcón
Curso 2005/2006

Introducción

„ Programa Fuente = Serie de Símbolos


‰ Los símbolos representan las construcciones del
lenguaje
„ Variables, etiquetas, palabras reservadas, constantes,
operadores
„ El analizador léxico identifica los significados
de estas construcciones
„ Lee el programa fuente carácter a carácter
„ Los compara con patrones que representan
unidades sintácticas primarias o tokens

2/38

1
Introducción

„ Un analizador léxico:

Transforma el programa fuente a tiras de


tokens
„ Cada token pueden tener asociado uno o
varios atributos
‰ Ejemplo: Un atributo de un token puede ser un
puntero a la tabla de símbolos o un puntero a la
tabla de constantes.
3/38

Ejemplo 1

posición := principal + velocidad * 60

IDENT ASIGNACION IDENT MAS IDENT POR ENTERO

Tabla de Símbolos
TOKEN ATRIBUTO SIMBOLO INFORMACIÓN
IDENT posición Ej. tipo de la variable
IDENT principal ...
IDENT velocidad ...
ENTERO 60

4/38

2
Funciones del Analizador Lexicográfico

„ Funciones Básicas
‰ Leer carácter a carácter del programa fuente.
‰ Entregarle los tokens identificados al analizador sintáctico
‰ Producir parte del listado con los errores de compilación
„ Funciones Complementarias
‰ Ignorar del programa fuente los comentarios, espacios en
blanco y tabuladores.
‰ Reconocer las palabras reservadas del lenguaje.
‰ Reconocer las variables y asignarles una posición en la
tabla de símbolos.
‰ Relacionar mensajes de error con el número de línea en el
que aparecen.

5/38

Lexemas, expresiones regulares y tokens


perimetro := radio + 47

Token Lexema Expr. Regular Expr. Reg. LEX


IDENT perimetro, (a+...+z+_)(a+...+z+_+0+...+9)* [a-zA-Z_][a-zA-
radio, pi, hola Z0-9_]*

ASIG := := :=

MAS + + +
ENTERO 47, 1234567, (0+...+9)(0+...+9)* [0-9]+
0
PR_FOR For, for, FOR (F+f)(O+o)(R+r) [Ff][Oo][Rr]

IDENT ASIG IDENT MAS ENTERO

6/38

3
Lexemas, expresiones regulares y tokens

„ Lexemas:
‰ Son caracteres o conjuntos de caracteres (palabras) que
pertenecen al léxico del lenguaje.
„ Expresiones Regulares (Patrones):
‰ Definen las reglas que permiten identificar los componentes
léxicos o tokens.
„ Tokens:
‰ Son los componentes léxicos generados por el analizador
lexicográfico
„ Atributos:
‰ Son información adicional para cada componente léxico que
serán utilizadas en el análisis semántico y/o en la fase de
síntesis (ej. Lexema, Tipo, Valor, Línea).
‰ Depende del token

7/38

Ejemplo 2

„ Expresiones Regulares
‰ a*(b | c)+ Æ L1 = {w : w=a*(b | c)+}
„ bccbcbccbc
„ abbbccc
„ abbcbcccbbc
‰ (0-9)*.(0-9)+ Æ L2 = {w: w=(0-9)*.(0-9)+}
„ 0.236425
„ 3567.45627 ‰ a* Æ 0 o más “a”
„ .753473 ‰ (b | c) Æ “b” o “c”
„ 5.0 ‰ c+ Æ 1 o más “c”
‰ 0-9 Æ 0 ó 1 2 ó …ó 9
8/38

4
Ejemplo 3
Expresión Regular Token Atributos
end end -
loopif loopif -
read read -
start start -
var var -
write write -
[0-9]+ entero valor
[a-zA-Z](_?([a-zA-Z0-9]))* id Puntero tabla símbolos
, coma -
; pyc -
( pari -
) pard -
[+-] opsum Constante identificando + o –
[*/] opmul Constante identificando * o /
“<“|”>”|”<=“|”=>”|”<>”|”=“ oprel Constante identificando op.
:= asig -
[ \n] - -
. - - 9/38

Implementación del Analizador


Lexicográfico
„ Estrategias de Implementación
‰ Implementación automática
„ Especificación de los patrones de la gramática
„ Uso de LEX
‰ Implementación manual
„ Codificación con estructuras condicionales (if, case, …)

10/38

5
LEX

„ Uso básico:
‰ Implementación de la fase de Análisis
Lexicográfico de un compilador
‰ Uso combinado con el Analizador sintático YACC
„ Otros usos de Lex:
‰ Transformaciones sencillas de ficheros fuente
„ Ej: Dado un texto completamente en mayúsculas
convertirlo en un texto en formato “frase”: mayúscula
sólo la primera letra de una palabra tras un punto.

11/38

LEX

„ Acepta una especificación del lenguaje de


programación mediante un conjunto de expresiones
regulares
„ A cada expresión regular se le puede asociar
código C que se ejecutará cuando se el
correspondiente lexema en el programa de entrada
„ Genera un programa en C (yylex) que reconoce
dichas expresiones regulares
„ Si se usa conjuntamente con YACC los tokens
identificados se pasan directamente al analizador
sintáctico.

12/38

6
Ejemplo 4

„ Programa para borrar de la entrada todos los espacios en blanco


y todos los tabuladores del final de línea:

%%
[ \t]+$ ;

‰ %% Indica el inicio de las órdenes


‰ Expresión Regular: Una o más (+) apariciones del espacio en
blanco (“ “) o tabulador (\t) antes del final de la línea ($)
‰ Acción: No se hace nada si está al final
‰ ¿Qué se hace con el resto de los caracteres?
„ Se pasan todos directamente a la salida

13/38

Formato del Fichero Fuente

„ El formato general de un fichero lex es:


{definiciones}
%%
{órdenes}
%%
{subrutinas del usuario}
„ Las definiciones y subrutinas se omiten a menudo
„ Programa lex mínimo:
%%
‰ Copia la entrada exactamente igual en la sálida

14/38

7
Ejemplo 6

„ Órdenes:

%%
integer printf(“Localizada palabra reservada INT”);
float printf(“Localizada palabra reservada FLOAT”);

‰ Columna izquierda: Expresiones regulares


‰ Columna derecha: Fragmentos de programa o
Acciones

15/38

Ejemplo 7

„ Programa que cambia palabras de la


ortografía británica a la ortografía americana
%%
colour printf(“color”);
mechanise printf(“mechanize”);
petrol printf(“gas”);
„ ¿Qué ocurriría si el fichero de entrada
contiene la palabra “petroleum”?
‰ En la salida tendría petroleum??
‰ En la salida tendría gaseum??

16/38

8
Expresiones Regulares en Lex

„ Expresión :: Conjunto de literales


„ Literales :: caracteres de texto | operadores
„ Caracteres de texto :: Carácter
correspondiente del literal que se compara
‰ Las letras del alfabeto y los dígitos son siempre
caracteres de texto
„ Operadores ::“ \ [ ] ^ - ? , * + | ( ) $ / { } % < >
‰ Para usarlos como caracteres de texto incluirlos
entre comillas dobles o usar “\” delante

17/38

Expresiones Regulares en Lex

„ Clases de Caracteres
‰ [abc]
„ Cualquier carácter que sea una “a” o una “b” o una “c”
‰ [a-z0-9<>_]
„ Cualquier carácter desde la “a” a la “z” o un dígito del “0” al
“9”, o “<“ o “>” o “_”
‰ [-+0-9]
„ Cualquier dígito o los signos “-” y “+”
„ Como “-” es un operador para incluirlo como carácter debe ir
al principio de la clase de caracteres
‰ [^abc]
„ Todos los caracteres excepto “a”, “b” y “c”

18/38

9
Expresiones Regulares en Lex

„ Expresiones opcionales – Uso de “?”


‰ ab?c
„ Coincide con “ac” y con “abc”. La “b” es opcional
„ Expresiones repetidas – Uso de “*” o “+”
‰ a*
„ 0 o más repeticiones del carácter “a”
‰ a+
„ 1 o más repeticiones del carácter “a”
‰ [A-Za-z][A-Za-z0-9]*
„ Identificadores que empiezan por una letra (mayúscula
o minúscula) y siguen por 0 o más letras o dígitos

19/38

Expresiones Regulares en Lex

„ Expresión de “alternación” – Uso de “|”


‰ (ab|cd)
„ Coincide con “ab” o con “cd”.
„ Expresión de agrupamiento – Uso de “( )”
‰ (ab | cd+)?(ef)*
„ Coincide con literales como “abefefef”, “efefefef”,
“cdefefef”, “cddddd”, “cddddef”.
„ No coincide con literales como “abc” o “abcddd”

20/38

10
Expresiones Regulares en Lex

„ Sensitividad de Contexto – Uso de “^” y “$” y “/”


‰ ^ Æ Identifica comienzo de línea
‰ $ Æ Identifica fin de línea
‰ / Æ Identifica contexto al final
‰ ab/cd
„ Reconoce “ab” pero sólo si va seguido de “cd”.
‰ ab$
„ Reconoce “ab” pero sólo si está al final de línea
„ Es equivalente a “ab/\n”
‰ ^ab
„ Reconoce “ab” pero sólo si se encuentra al comienzo de línea

21/38

Acciones en LEX

„ Acción por defecto


‰ Copiar los literales de la entrada a la salida
‰ Se realiza por defecto con todos los literales que no
coinciden con ninguna expresión regular
‰ Cuando se usa LEX con YACC hay que asegurarse que
todos los literales coinciden con alguna expresión regular
„ Acción nula
‰ Se descarta la entrada de datos y no se pasa nada a la
salida
‰ Ejemplo:
„ [ \t\n] ;

22/38

11
Acciones en LEX

„ Conocer el lexema que se ha reconocido


‰ Lex deja este texto en una matriz de caracteres llamada
yytext
‰ Ejemplo:
„ [a-z]+ printf(“%s”, yytext);
‰ Alternativa:
„ [a-z]+ ECHO;
„ Conocer el tamaño del lexema leído
‰ Ejemplo: Contar número de palabras de entrada y
caracteres en esas palabras
„ [a-zA-Z]+ {words++; chars+=yyleng;}

23/38

Manejo de Especificaciones Ambiguas

„ Cuando más de una expresión puede coincidir con


la entrada analizada:
‰ Se prefiere la coincidencia más larga
‰ De entre las coincidencia de la misma longitud se elige la
que aparezca primera en la definición
„ Ejemplo:
%%
integer printf(“palabra reservada INT”);
[a-zA-Z]+ printf(“Identificador);
„ ¿Cómo se reconoce “integer”? ¿Y “integers”?¿y int?

24/38

12
Sección de Definiciones en LEX

„ Se especifican antes del primer delimitador %%


„ Zona de definición de variables
‰ Para uso del programa que se generará
‰ Para uso del LEX

„ Cualquier definición que comience en la columna 1


define “literales de sustitución del LEX”
‰ Se utilizan para simplificar la definición de las órdenes
‰ Formato: nombre interpretación
„ El nombre tiene que empezar por una letra

25/38

Ejemplo 8

„ Sección de definiciones
D [0-9]
E [DEde][-+]?{D}+
„ Sección de órdenes
%%
{D}+ printf(“integer”);
{D}+”.”{D}*({E})?|
{D}*”.”{D}+({E})?|
{D}+{E} printf(“real”);

26/38

13
LEX y YACC

„ Para utilizar de forma conjunta LEX y YACC


cada orden LEX debe acabar con:
‰ return(token);
‰ Se le indica al YACC el token leído
„ Además si se trata de un analizador léxico
para construir un compilador:
‰ será necesario añadir información a las tablas de
símbolos
‰ será necesario guardar información sobre los
atributos de cada token

27/38

Ejercicio 1

„ Construir un analizador léxico que sea capaz de


reconocer sentencias de la forma:
nuevo := viejo * RAZON + 2
‰ Los identificadores tienen que empezar por una letra
‰ Los números pueden ser enteros o reales
‰ Las operaciones válidas son la de +, -, * y /
‰ No puede haber mas de un 0 a la izquierda de un número
‰ La salida será:
„ IDENT ASIGNACION IDENT POR IDENT MAS ENTERO

28/38

14
Solución Ejercicio 1
%%

[a-zA-Z][0-9a-zA-Z]* { printf(" IDENT "); }


(0|[1-9][0-9]*) { printf(" ENTERO "); }
(0|[1-9][0-9]*)\.[0-9]* { printf(" REAL "); }
"+" { printf(" MAS "); }
":=" { printf(" ASIGNACION "); }
"-" { printf(" MENOS "); }
"*" { printf(" POR "); }
"/" { printf(" DIV "); }
"" ;
\t ;
\n ECHO;
. { printf(" Caracter inesperado: %c",yytext[0]); }
%%

int main()
{
yylex();
} 29/38

Ejercicio 2

„ Modificar el analizador anterior para que acepte


sentencias condicionales de la forma:
IF (x==5) THEN
var := 4
ENDIF
„ Usar como operadores lógicos sólo “==“
„ Las palabras claves del lenguaje se pueden escribir
tanto en minúsculas como en mayúsculas
‰ IF, if, If, iF Æ Todas representan el inicio de una
sentencia condicional

30/38

15
Solución Ejercicio 2
%%

[If][fF] { printf(" IF "); }


[Ee][Nn][Dd][If][Ff] { printf(" ENDIF "); } Palabras claves del lenguaje
[Tt][Hh][Ee][Nn] { printf(" THEN "); }
[a-zA-Z][0-9a-zA-Z]* { printf(" IDENT "); }
(0|[1-9][0-9]*) { printf(" ENTERO "); }
(0|[1-9][0-9]*\.[0-9]*) { printf(" REAL "); }
"+" { printf(" MAS "); }
":=" { printf(" ASIGNACION "); }
"-" { printf(" MENOS "); }
"*" { printf(" POR "); }
"/" { printf(" DIV "); }
"==" { printf(" IGUAL_A ");}
[ \t] ;
[\n\(\)] ECHO;
. { printf(" Caracter inesperado: %c",yytext[0]); }
%%

int main()
{
yylex(); 31/38
}

Ejercicios 3, 4, 5 y 6

„ Escribir un analizador léxico que reciba como


entrada un texto y muestre como salida el número
de caracteres, el número de palabras y el número
de líneas que hay en el texto
„ Escribir un analizador léxico para cifrar un texto de
entrada invirtiendo el orden de las letras de cada
palabra
„ Modificar el programa anterior para que cifre todo
menos los números, que deben mantenerse en el
orden en el que aparecen
„ Modificar el programa anterior para que invierta
línea a línea y no palabra a palabra

32/38

16
Solución Ejercicio 3
%{
#include <stdlib.h>
static unsigned ncaracteres = 0; /* número de caracteres*/
static unsigned npalabras = 0; /* número de palabras*/
static unsigned nlineas = 0; /* número de lineas*/
%}
%%
\n ncaracteres += 2, ++nlineas; /* fin de linea es CR LF*/
[^ \t\n]+ ++npalabras, ncaracteres += yyleng;
. ++ncaracteres;
%%
main()
{
yylex();
printf("%d %d %d\n",ncaracteres,npalabras,nlineas);
exit(0);
}
33/38

Ejercicios 3, 4, 5 y 6

„ Escribir un analizador léxico que reciba como


entrada un texto y muestre como salida el número
de caracteres, el número de palabras y el número
de líneas que hay en el texto
„ Escribir un analizador léxico para cifrar un texto de
entrada invirtiendo el orden de las letras de cada
palabra
„ Modificar el programa anterior para que cifre todo
menos los números, que deben mantenerse en el
orden en el que aparecen
„ Modificar el programa anterior para que invierta
línea a línea y no palabra a palabra

34/38

17
Solución Ejercicio 4
%%
[^ \t\n]* {
char auxiliar;
int cont;
for(cont = 1; cont <= (yyleng / 2); cont++)
{
auxiliar = yytext[cont - 1];
yytext[cont - 1] = yytext[yyleng - cont];
yytext[yyleng - cont] = auxiliar;
};
ECHO;
}
%%
int main()
{
yylex();
}
35/38

Ejercicios 3, 4, 5 y 6

„ Escribir un analizador léxico que reciba como


entrada un texto y muestre como salida el número
de caracteres, el número de palabras y el número
de líneas que hay en el texto
„ Escribir un analizador léxico para cifrar un texto de
entrada invirtiendo el orden de las letras de cada
palabra
„ Modificar el programa anterior para que cifre todo
menos los números, que deben mantenerse en el
orden en el que aparecen
„ Modificar el programa anterior para que invierta
línea a línea y no palabra a palabra

36/38

18
Solución Ejercicio 5
%%
[0-9]+ ECHO;
[^ \t\n]* {
char auxiliar;
int cont;
for(cont = 1; cont <= (yyleng / 2); cont++)
{
auxiliar = yytext[cont - 1];
yytext[cont - 1] = yytext[yyleng - cont];
yytext[yyleng - cont] = auxiliar;
};
ECHO;
}
%%
¿Cuál sería el resultado de cifrar
int main()
{
yylex(); 1. C/ Barbero, nº 28
} 2. C/ Barbero, nº28?
37/38

Ejercicios 3, 4, 5 y 6

„ Escribir un analizador léxico que reciba como


entrada un texto y muestre como salida el número
de caracteres, el número de palabras y el número
de líneas que hay en el texto
„ Escribir un analizador léxico para cifrar un texto de
entrada invirtiendo el orden de las letras de cada
palabra
„ Modificar el programa anterior para que cifre todo
menos los números, que deben mantenerse en el
orden en el que aparecen
„ Modificar el programa anterior para que invierta
línea a línea y no palabra a palabra

38/38

19
Solución Ejercicio 6
%%
[^\n]* {
char auxiliar;
int cont;
for(cont = 1; cont <= (yyleng / 2); cont++)
{
auxiliar = yytext[cont - 1];
yytext[cont - 1] = yytext[yyleng - cont];
yytext[yyleng - cont] = auxiliar;
};
ECHO;
}
%%
int main()
{
yylex();
}
39/38

Ejercicio 7

„ Escribir un analizador léxico para cifrar un


texto de la siguiente forma:
‰ Tamaño(palabra) <= 4 letras Æ inversa
‰ Tamaño(palabra) == 5 ó 6 letras Æ inversa en
bloques de dos caracteres
‰ Tamaño(palabra) == 7,8 ó 9 letras Æ en bloques
de 3 caracteres
‰ Tamaño(palabra) > 9 Æ en bloques de 4
caracteres

40/38

20
Solución Ejercicio 7
%{
char auxiliar;
int cont, agrupador;
#define REVES(paso) \
cont = yyleng - paso; \
do \
{ \
for(agrupador = 0; agrupador < paso; agrupador ++){ \
if (yytext[cont + agrupador] != '\0') \
{ printf("%c", yytext[cont + agrupador]); \
yytext[cont + agrupador] = '\0'; \
} \
} \
if (cont > 0) \
{ cont -= paso; \
if (cont < 0) \
cont = 0; \
} \
else \
cont = -1;
} while (cont >= 0);
%}
%%
[^ \t\n]{1,4} { REVES(1); }
[^ \t\n]{5,6} { REVES(2); }
[^ \t\n]{7,9} { REVES(3); }
[^ \t\n]* { REVES(4); } 41/38
%%

Ejercicio 8

„ La Secretaría de la E.T.S.I. de Informática recibe de los


Departamentos las notas de los alumnos en un fichero formato
texto, en el que cada línea posee tres campos separados por
espacios: D.N.I. del alumno, Convocatoria del examen (Diciembre,
Febrero o Junio), y la Nota. Hacer un programa LEX que efectúe la
lectura de dicho fichero, emitiendo al final la media de las notas
recuperadas. Asimismo informará de los errores de formato que se
pueda encontrar: líneas en las que falten campos, valores
incorrectos, etc…

„ NOTAS: 1. Para convertir un array de caracteres a un número usar


sscanf(yytext,”%d”,&nota);
donde “nota” es una variable de tipo entero.

42/38

21

También podría gustarte