LL1 con llamadas a funciones.

Anuncio
Anexo A. LL1 con llamadas a funciones
Este material no es obligatorio ni se requiere para el examen. Las prácticas implementadas de esta
manera son legitimas.
En este anexo se considera una pequeña modificación del método de la teoría, que no requiere
transformación de la gramática en forma normal de pre-Greibach. En cambio este método si requiere
comprobación que la gramática es gramática del tipo LL1. En forma normal de Greibach es evidente si el
lenguaje es LL1. Otro termino que se utiliza para esta técnica – “recursive descendant approach”.
Consideramos un ejemplo: (examen 09.99 de teoría):
El lenguaje es:
S -> an p bn+m q cm+i r di
n,m,i >= 0
Construir un analizador sintáctico del tipo LL1 con llamadas a funciones:
1.
Paso 1 – transformación del lenguaje en forma LL1.
S -> A B C
A -> a A b
A-> p
B-> b B c
B-> q
C-> c C d
C-> r
2. Comprobación del tipo del lenguaje:
S -> A B C
símbolo.
A -> a A b
A-> p
B-> b B c
B-> q
C-> c C d
C-> r
- una sola clausura para S no recursiva -> puede empezar con cualquier
- FIRST(a A b) = a
- FIRST(p)= p, p != a – A - OK
- FIRST(b B c) = b
- FIRST(q)= r, q != b – B - OK
- FIRST(c C d) = c
- FIRST(r)= r, r != c – C - OK
No hay recursividad a la izquierda.
 El lenguaje es un lenguaje del tipo LL1.
3. Para cada símbolo no terminal S, A, B, C escribimos una función S(), A(), B(), C():
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
// el 'analizador' morfológico - elimina los CR y LF
char token=0;
long numchar=0;
long numline=1;
void get_next_token(){
for(;token=getchar();) {
if (token==EOF) break;
numchar++;
if (token=10) numline++; // Linefead
if (!(iscntrl(token))) break;
}
}
// el manejo de errores
void synt_error() {
fprintf(stderr,"Syntax error line %ld position %ld\n",numline,numchar);
exit (1);
}
// manejo de símbolo terminal
#define TERM(a) { if ((a)==token) get_next_token(); else synt_error(); }
void A() {
if (token=='a') { TERM('a'); A(); TERM('b'); } // A -> a A b, first(A)='a'
else if (token=='p') { TERM('p'); }
// A-> p
else synt_error();
}
void B() {
if (token=='b') { TERM('b'); B(); TERM('c'); }
else if (token=='q') { TERM('q'); }
else synt_error();
}
void C() {
if (token=='c') { TERM('c'); C(); TERM('d'); }
else if (token=='r') { TERM('r'); }
else synt_error();
}
void S() { A(); B(); C(); }
int main() {
get_next_token(); // read the first charater
S();
if (token!=EOF) synt_error();
return 0;
}
// B -> b B c, first(B)='b'
// B -> r
// C -> c C d, first(C)='c'
// C-> r
// S -> A B C
Notar:
1.
2.
3.
4.
5.
6.
7.
8.
El main() corresponde a la gramática aumentada y es siempre el mismo programa.
El main() lee el primer símbolo y comprueba si el fichero termina correctamente.
El TERM siempre es el mismo.
El analizador morfológico siempre tiene esta estructura (devuelve token, numero línea,
numero posición y el valor del token sí hay). Por ejemplo token=NUMERO, valor=5.23 o
token=IDENTIFICADOR, valor=”MYVAR”
El programa sigue uno a uno el lenguaje.
Si el lenguaje no es LL1 el programa puede entrar en bucles infinitos.
Efectivamente el programa al principio de cada clausura predice cual será la entrada.
Se lee un carácter solo después de comprobar si el token es el símbolo terminal
correcto. ¡NO SE LEE EL SIGUIENTE CARÁCTER SI SE COMPRUEBA UN NOTERMINAL o EOF!
Convencíais:
1.
2.
3.
Es un programa con estructura evidente.
El método es difícil de sobrevolararlo si se necesita un analizador de ficheros que cumplen
una sintaxis desconocida y se necesita construir un analizador sintáctico y la gramática a
partir de estos ficheros.
Tal como se trata de un programa, incluir acciones o excepciones es trivial (añadimos
código).
Inconveniencias:
1.
2.
3.
4.
El programa del analizador es particular para cada gramática.
El método es muy susceptible a errores, cada línea de código puede incluir un error.
Es muy difícil reaccionar en manera no trivial y no muy complicada a errores en el fichero
fuente. Normalmente se usa longjmp(). Véase también CSC303 cap. 7 de qub.ac.uk
http://www.cs.qub.ac.uk/csc303/Lectures/part7.html.
El programa se puede verificar sólo ejecutando todas las bifurcaciones del mismo, que con
lenguajes razonablemente complicados no es posible.
Nota general:
La calidad más importante de cualquier programa es si el programa es correcto. Utilizando este
método no es posible de comprobar el programa – si hay otra posibilidad – no utilizar este método.
Ejercicios
1.
2.
3.
Escribir un programa que a partir de una gramática en forma MBS escriba el programa del
analizador LL1 con llamadas a funciones.
Las funciones A(), B() y C() en el programa son muy parecidas. Escribir una única función
para A, B y C con parámetros.
Utilizando la estructura de las funciones de arriba es posible construir un ‘analizador’ de un
lenguaje que no es LL1, por ejemplo incluyendo construcciones como:
.. if (token==’a’ || token==’b’) {...}
else if (token==’a’ || token==’c’) {...}.
Cambiando los if-s con switch()... case ... este error se elimina. Comprobar el siguiente:
4.
5.
Si un lenguaje no es recursivo a la izquierda y su analizador con ‘switch ... case ...’ compila,
el lenguaje es LL1.
** Al comprimir voz (f(t)) se calcula el siguiente valor más probable (f’(t+1)) en cada
momento y se comprime la diferencia (f(t+1)-f’(t+1)). Tal como la diferencia es pequeña
necesita menos bits para guardarla o trasmitirla. Un analizador LL1 es predicativo, es decir
al analizar un símbolo (if (token=’...’)) el analizador sabe que se puede esperar. ¿Se puede
construir un programa compresor a partir del analizador? ¿Cómo? ¿Que tipo de ficheros se
pueden comprimir en esta manera?
**** Escribir un programa (o conjunto de programas) que a partir de un fichero de ejemplos
de construcciones correctos de un lenguaje LL1 construye un analizador morfológico LL1
con llamadas a funciones.
El problema esta mal definido. Según la teoría no es posible escribir este programa (no
existe algoritmo de producir el analizador en todos los casos a partir de ejemplos). Sin
embargo, es posible construir programa que construye un LL1 con probabilidad 1. Este
problema es un pequeño proyecto de unos 2-3 meses.
Documentos relacionados
Descargar