Document 7406657

Download Report

Transcript Document 7406657

Compiladores
Tema 3
Análisis Lexicográfico
Scanners
Compiladores (23/05/2016 16:07)
- 4.1 -
Scanner
Programa fuente
(secuencia de caracteres)
Scanner
(autómata finito determinista
o específico)
Secuencia de símbolos
Símbolo
Categoría sintáctica:
número, identificador, if, suma, abrir paréntesis
Atributos:
valor, nombre, string.
Compiladores (23/05/2016 16:07)
- 4.2 -
Ejemplos de Símbolos
•
Identificador:
–
–
•
Número:
–
–
–
•
Forma: ;
Palabra clave if:
–
•
Forma: secuencia de dígitos que puede empezar con el signo
menos y puede contener un punto. Ej. 10, -3, 15.4, -54.276, .10
Atributo valor: double con el valor numérico.
Precisión: entero o real.
Punto y Coma:
–
•
Forma: una letra seguida de letras o números. Ej. a, b1, c3D
Atributo nombre: string con la secuencia de caracteres que
forma el identificador en mayúsculas. Ej. “A”, “B1”, “C3D”
Forma: if, If, IF, iF
Fin de fichero:
–
Forma: carácter EOF de C.
Compiladores (23/05/2016 16:07)
- 4.3 -
Separación en Símbolos
• Los comentarios, saltos de línea, espacios
y tabs no forman parte de la secuencia de
símbolos.
• Al definir los símbolos se ha de considerar
como se separan.
– Entre dos símbolos se encuentra cararcteres
separadores (espacios, tabs, comentarios,
etc.)
– Siempre se intenta leer el símbolo más
largo
• Ejemplos:
–
–
–
–
if ( a > 10 ) bc = 30 * - 4
if ( a >= 10 ) bc = 30 * - 4
int * * a ;
zz /* comentario */ + dd
Compiladores (23/05/2016 16:07)
- 4.4 -
Especificación
• Símbolos: identificador, abrir paréntesis, string, etc.
– Forma:
• Expresiones regulares para cada categoría
sintáctica.
– Atributos:
• Algoritmo para el cálculo de cada atributo a
partir de la secuencia de caracteres del
símbolo.
• Separadores: espacios, comentarios, salto de línea, tab,
etc.
– Forma:
• Expresión regular que especifica las
secuencias de caracteres que separan los
símbolos.
• Otros: errores, final de fichero, salto de línea, etc.
Compiladores (23/05/2016 16:07)
- 4.5 -
Expresiones Regulares
 es una expresión regular que representa el
conjunto vacío.
• l es una expresión regular que representa el
conjunto con un único elemento que es la
secuencia vacía
• un string s es una expresión regular que
representa un conjunto que solo contiene s.
Para evitar confusiones, los metacaracteres que
contenga s van entre comillas (‘|’,’-’,...).
• V es el conjunto de todos los caracteres
(vocabulario).
•
Compiladores (23/05/2016 16:07)
- 4.6 -
Expresiones Regulares
Operadores
• AB Concatenación
{ab| aA y bB}
• A|B unión {x| xA ó xB}
• A* repetición l|A|AA|AAA...
• A+ repetición de uno o más A|AA|AAA...
• An repetición de n veces.
• (A-B) resta {x| xA y xB}
Compiladores (23/05/2016 16:07)
- 4.7 -
Ejemplos de Expresiones Regulares
•
•
•
•
•
•
•
dígito d=0|1|2|3|4|5|6|7|8|9
entero_sin_signo=d+
entero=(+|-|l)d+
real=d+.d+(l|e(+|-|l) d+)
letra l=a|...|z|A...|Z
identificador=l(l|d)*
string=“(V-”)*”
Compiladores (23/05/2016 16:07)
- 4.8 -
Scanner implementado a mano
• El scanner es un procedimiento que lee un
símbolo del programa fuente
– Entrada: caracteres de un istream
istream *IScan; // Stream de entrada
– Salida: símbolo en variable global
enum Categoria {
SNumero,SIdentificador,SString, Sif...
};
Categoria ScanCat; // Categorita sintáctica
double ScanEntero; // Valor numérico
double ScanReal; // Valor numérico
bool ScanEsEntero; // Tipo de número
string ScanString; // String del símbolo
• Condiciones que cumple el scanner
– Lee caracteres hasta conseguir leer un
símbolo
– En caso de duda lee el símbolo más largo
– Al salir del scanner, el último carácter leído
pertenece al símbolo. Si se ha leído alguno
más se devuelve a la entrada
Compiladores (23/05/2016 16:07)
- 4.9 -
Scanner en C++
void Scanner()
{
int c;
for (;;) {
c=IScan->get();
switch (c) {
// Separadores
case '\r':
case '\n':
case '\t':
case ' ':
break;
default:
if ((c>='a' && c<='z') || (c>='A' && c<='Z') || (c=='_')) {
ScanIdentificador(c);
return;
}
else {
COut << "No se tratar el caracter "
<< (char) c << endl;
}
}
}
}
Compiladores (23/05/2016 16:07)
- 4.10 -
Scanner de Identificadores en C++
void ScanIdentificador(int c)
{
char buf[256];
int i;
for (i=0; (c>='a' && c<='z') ||
(c>='A' && c<='Z') ||
(c=='_') ||
(c>='0' && c<='9');) {
if (i>254) {
throw CVException(“Identificador demasiado largo");
}
buf[i++]=c;
c=IScan->get();
}
buf[i]='\0';
ScanCat=SIdentificador;
ScanString=buf;
IScan->putback(c);
}
Compiladores (23/05/2016 16:07)
- 4.11 -
Autómatas Finitos
• Autómata finito determinista (K,T,M,S,Z)
– K conjunto finito de estados.
– T conjunto de terminales (símbolos/caracteres de
entrada).
– M:KTK función de transición.
– SK estado inicial.
– ZK conjunto de estados finales.
• Autómata finito no determinista (K,T,M,S,Z)
– M:KTP(K) función de transición.
Compiladores (23/05/2016 16:07)
- 4.12 -
Representación de los Autómatas Finitos
1
Transición
Estado
Estado
inicial
1
Estado
final
1
d
a
1
b
2
c
3
4
Acepta las secuencias: abc(dc)*
Ej. abc, abcdc, abcdcdc, abcdcdc...
Compiladores (23/05/2016 16:07)
- 4.13 -
Paso de Expresión Regular a AFND
Exp. a
a
Exp. l
l
Exp. A|B
l
AFND
de A
l
AFND
de B
Compiladores (23/05/2016 16:07)
l
l
- 4.14 -
Paso de Expresión Regular a AFND
Exp. AB
l
AFND
de A
l
AFND
de B
Compiladores (23/05/2016 16:07)
l
- 4.15 -
Paso de Expresión Regular a AFND
l
Exp. A*
l
AFND
de A
l
l
Compiladores (23/05/2016 16:07)
- 4.16 -
Ejemplo del Paso de Exp. Regular a AFND
Expresión: ab|ac*
l
AFND: ab
l
l
AFND: ac*
l
Expresión: ab
l
AFND: a
l
l
AFND: b
Compiladores (23/05/2016 16:07)
Expresión: ac*
- 4.17 -
Ejemplo del Paso de Exp. Regular a AFND
Expresión: ac*
l
AFND: a
l
l
AFND: c*
Expresión: a
a
Expresión: b
b
l
l
Expresión: c*
Expresión: c
Compiladores (23/05/2016 16:07)
AFND: c
c
l
- 4.18 -
Ejemplo del Paso de Exp. Regular a AFND
Expresión: ab|ac*
AFND
a
2
b
3
1
a
4
c
• Problema:
– Un a AFND puede seguir más de un
camino durante su interpretación.
• Solución:
– Pasar de AFND a AFD.
Compiladores (23/05/2016 16:07)
- 4.19 -
Paso de AFND a AFD
• El conjunto de estados del nuevo AFD es
el conjunto de las partes del conjunto de
estados del AFND.
• El estado inicial del AFD es el mismo que
el del AFND.
• Un estado del AFD es final si contiene
algún estado final del AFND.
Compiladores (23/05/2016 16:07)
- 4.20 -
Cálculo del Conjunto de Transiciones
• Poner el estado inicial en el conjunto de
estados K del AFD. El conjunto de
transiciones M=.
• Repetir hasta que K y M no varíen:
– Para cada estado de K y carácter de entrada
aplicar las transiciones posibles del AFND
y acumular en K y M el nuevo estado y la
nueva transición.
Compiladores (23/05/2016 16:07)
- 4.21 -
Ejemplo del Paso de AFND a AFD
Expresión: ab|ac*
AFND
a
2
3
1
a
4
Tabla de Transiciones AFD
I
S
F
1
a
2,4
2,4 b
3
2,4 c
4
4
c
4
c
a
AFD
b
1
b
3
c
4
2,4
c
Compiladores (23/05/2016 16:07)
- 4.22 -
Implementación de un AFD
• Variable de estado S.
• Tabla de transiciones T: dado un estado y un
carácter de entrada específica el nuevo o error.
• Algoritmo:
– S=estado inicial.
– Repetir
• C=leer_caracter()
• si T[S][C]==error entonces salir del bucle
• S=T[S][C]
– si S no es final error
Compiladores (23/05/2016 16:07)
- 4.23 -
Ejemplo de Tabla de Transiciones
a
1
b
3
c
4
2
c
Tabla de Transiciones
1
2
3
4
Compiladores (23/05/2016 16:07)
a
2
Err
Err
Err
b
Err
3
Err
Err
c
Err
4
Err
4
- 4.24 -
Scanner Basado en AFD
• Un AFD no es un scanner. Falta
– Poder leer una secuencia de símbolos y
separadores
– Diferenciar las categorías sintácticas de los
símbolos
Compiladores (23/05/2016 16:07)
- 4.25 -
Consideraciones Prácticas
• Las palabras reservadas se pueden
considerar como identificadores para evitar
crear un AFD demasiado grande (2n
estados del AFND).
• Hay que marcar el final del código fuente.
Este indicador pertenecerá al alfabeto.
• Los símbolos tienen atributos que hay que
calcular.
Compiladores (23/05/2016 16:07)
- 4.26 -
Consideraciones Prácticas
• Los estados finales del AFD se han de
marcar con el símbolo que reconocen.
• Como hay que reconoce más de un
símbolo puede ser necesario tener que leer
varios caracteres hacia delante.
• La creación de un scanner se puede hacer
directamente sin considerar los autómatas
finitos.
Compiladores (23/05/2016 16:07)
- 4.27 -
Errores Lexicográficos
• Tener un símbolo de error que se pasa al
parser.
• Señalar el error e ignorarlo.
• Tratamiento específico.
• Falta información para corregir los errores
lexicográficos.
Compiladores (23/05/2016 16:07)
- 4.28 -