Sei sulla pagina 1di 29

TEORÍA: RECUPERACIÓN DE

ERRORES

DISEÑO Y CONSTRUCCIÓN DE
COMPILADORES

LICENCIATURA EN CIENCIAS DE LA
COMPUTACIÓN
Profesora Responsable: Dra. Victoria Aragón
Jefe de Trabajos Prácticos: Dr. Edgardo Ferretti
Auxiliar de Práctico: Lic. María José Garciarena Ucelay

https://sites.google.com/site/ddcompilersunsl/

Diseño y Construcción de Compiladores


UNSL
TRATAMIENTO DE ERRORES
Un programa puede contener errores en la distintas fases:

Lexicográficos

DCC- UNSL
Sintácticos
Semánticos
De ejecución
De lógica
Ante la presencia de Errores

Detectar tantos errores como sea posible en una pasada sobre


el archivo fuente
Indicar la ubicación del error (línea y columna)

Efectos adicionales deseables


El manejo de errores no debería hacer que el parser se haga
lento 2
Su tamaño no debería crecer demasiado
TRATAMIENTO DE ERRORES

Causas

DCC- UNSL
1. No poseer conocimiento del lenguaje
 usar construcciones inválidas
2. No aplicar reglas del lenguaje
 no declarar identicadores antes su uso
3. Escribir incorrectamente símbolos del lenguaje
 lexicográficos  scanner

Estrategias de Recuperación:
Pánico
Antipánico 3
ESTRATEGIAS DE RECUPERACIÓN:
Pánico: ANTE LA PRESENCIA DE UN ERROR SE SALTA SOBRE
SÍMBOLOS DEL TEXTO FUENTE HASTA QUE APAREZCA UN
SÍMBOLO ADECUADO QUE PERTENEZCA A UN CONJUNTO DE
TOKENS (sincronización) DE RECUPERACIÓN.
VENTAJA: FACIL IMPLEMENTACION.

DCC- UNSL
DESVENTAJA: PUEDEN QUEDAR SECUENCIAS LARGAS DEL
PROGRAMA SIN ANALIZAR.
Antipánico: LA IDEA ES CONTINUAR SALTANDO SOBRE
SÍMBOLOS DE LA ENTRADA, ANTE LA PRESENCIA DE UN ERROR,
PERO TRATANDO DE PERDER LA MENOR CANTIDAD POSIBLE DE
SÍMBOLOS DEL TEXTO FUENTE.

EJEMPLO:
A = A 3 + B ; pánico → salta hasta el primer fin de sentencia, es decir “ ;”
4
error antipánico → Avanza hasta el 3
ESTRATEGIA DE RECUPERACIÓN: PÁNICO Y ANTIPÁNICO
CARACTERÍSTICAS DESEABLES DEL LENGUAJE DE PROGRAMACIÓN
 PALABRAS CLAVES.

APTO PARA SER IMPLEMENTADO EN UN ENTORNO DE


PARSER DESCENDENTE RECURSIVO.

DCC- UNSL
If <eb> then <ss> fi ;

pánico Pánico Antipánico

Símbolos de
sincronización
If <eb> then <ss> fi ;

antipánico

Ejemplo: If (> 4) then a=6; fi pánico se 5


reconfigura de ser posible en ;, mientras que
antipánico es posible en then
REQUERIMIENTOS DE IMPLEMENTACION

A) TODO PROCEDIMIENTO DEBE DEFINIRSE CON UN PARAMETRO FORMAL


folset :
PA(folset:conjunto de símbolos);

DCC- UNSL
folset = {conjunto de tokens que pueden seguir a esa invocación del procedimiento A}.

Si dentro del procedimiento A se invoca a un procedimiento B   una producción


A  ... B ...
PA(folset: conjunto de símbolos); (1)

PB(folset + folset (B)); (2)


A
END: {PA}
(1) folset = {cjto. de tokens que siguen a A en dicha invocación}.
(2) el folset de A + {el conjunto de tokens que pueden seguir a
B en dicha invocación}
B

TODO PROCEDIMIENTO SUBORDINADO (B) HEREDA EL FOLSET DEL


SUBORDINANTE (A)
6

PANICO Ejemplo: P  X A t
AgBCDj
REQUERIMIENTOS DE IMPLEMENTACION
B) AGREGAR UN NUEVO PROCEDIMIENTO test, que salte sobre el texto
fuente hasta encontrar un token de reconfiguración (por ejemplo una
palabra clave):

test (cjto1, cjto2: cjto de símbolos; n: integer);

DCC- UNSL
cjto1 = { símbolos válidos que se espera en la entrada }.
cjto2 = { posibles símbolos de reconfiguración }.
n = número de error, que identifica el tipo de error.

test (cjto1, cjto2: cjto de símbolos; n: integer);


begin
if not (lookahead in cjto1) then
begin
error(n);
cjto1 := cjto1+cjto2;
while not(lookahead in cjto1) // ahora cjto1 es el conjunto de
do // sincronización
lookahead:= get_next_token
7
od
end
end; {test}
REQUERIMIENTOS DE IMPLEMENTACION
C) USO DEL PROCEDIMIENO TEST

1. COMO PRIMERA SENTENCIA DEL CUERPO DE UN


PROCEDIMIENTO: Cuando un procedimiento A se invoca, al menos
una vez, en forma incondicional y la primera sentencia de su cuerpo no
es una invocación a procedimiento.

P  X ..... y X  if E then S else S fi | .......

DCC- UNSL
Procedure X(folset:cjto de sbolos);
begin
test (c1,c2, m);//la 1° sentencia no es una llamada a procedimiento
match(if )
......
end {X}

¿ En este caso cuál es el contenido de c1 y c2 ?


c1 = FIRST(X)  folset(X) SI X   o FIRST(X) SI X  
c2 depende de la estrategia utilizada:
 Pánico folset de X
 Antpánico folset de X  {posibles puntos de reconfiguración
dentro de X} = {then, else, fi}. Para un No Terminal con más de una
alternativa los posibles puntos de reconfiguración para cada 8
alternativa deben ser disjuntos. Ej: A → U a b x| L k a | P b
REQUERIMIENTOS DE IMPLEMENTACION
C) USO DEL PROCEDIMIENO TEST

2.COMO ULTIMA SENTENCIA DEL CUERPO DE UN


PROCEDIMIENTO: Antes de retornar de un procedimiento A si la
última sentencia de su cuerpo no es una invocación a un procedimiento.
En un proc con más de una alternativa, si alguna de ellas no es llamada
a procedimiento entonces va test (Match no se considera procedimiento
ya que es auxiliar).

DCC- UNSL
X  .........a
Procedure X(folset:cjto de sbolos);
begin
.....
match(asymbol)
test (c1,c2, m)
end {X}

¿ En este caso cuál es el contenido de c1 y c2 ?

c1 = folset

c2 = {posibles puntos de reconfiguración} (en nuestro caso Ø)


9
LLAMADAS CONDICIONALES E INCONDICIONALES

Suponga G:
S → AuB | CaA S → AuB | CaA

DCC- UNSL
A → b | dd A → b | dd
B → AnA B → AnA
C → kk |  C → kk | 

No Test Test
terminal inicial final
S  x
A  
B x x
10
C x 
EJEMPLO: CONSTRUCCIÓN DEL PDR CON LA INCLUSIÓN
DEL ESQUEMA DE RECUPERACIÓN ANTIPÁNICO

1. <programa> ::= BEGIN <listsent> END


2. <listsent> ::= <sent> <listsenttail>
3. < listsenttail > ::=   <sent> <listsenttail>

DCC- UNSL
4. <sent> ::= ID := <expr> ; 
READ ( <idlist>) ; 
WRITE ( <listexpr> ) ;
5. <idlist> ::= ID <listidtail>
6. <listidtail> ::=  , ID <listidtail>
7. <listexpr> ::= <expr> <listexprtail>
8. <listexprtail> ::=  , <expr> <listexprtail>
9. <expr> ::= <factor> <exprtail>
10. <exprtail> ::=   <op> <factor> <exprtail>
11. <factor> ::= ( <expr> )  ID  CTEENT
12. <op> ::= +  -
11
1º PASO: CALCULAR LOS CONJUNTOS
FIRST1 Y FOLLOW1

NO TERMINALES FIRST1 FOLLOW1


<programa> BEGIN $  EOF
<listsent> ID READ WRITE END

DCC- UNSL
<listsenttail> ID READ WRITE,  END
<sent> ID, READ, WRITE ID READ WRITE END
<idlist> ID )
<listidtail>  , )
<listexpr> ( ID CTEENT )
<listexprtail>  , )
<expr> ( ID CTEENT ;,)
<exprtail> + - ;,)
<factor> ( ID CTEENT +-;,)
<op> + - ( ID CTEENT
12
2° PASO:
DETERMINAR QUE PROCESOS LLEVAN INVOCACIONES A
TEST Y DÓNDE
Test Test
inicial final
<programa>::= BEGIN <listsent> END

DCC- UNSL
<listsent>::= <sent> <listsenttail>
< listsenttail >::=   <sent><listsenttail>
<sent>::= ID := <expr> ; |READ ( <idlist>) ;
| WRITE ( <listexpr> );
<listexpr>::= <expr> <listexprtail>
<listexprtail>::=  , <expr> <listexprtail>
<expr>::= <factor> <exprtail>
<exprtail>::=   <op> <factor> <exprtail>
<factor> ::= ( <expr> )  ID  CTEENT
<op>::= +  -
13
<idlist> ::= ID <listidtail>
<listidtail>::=  , ID <listidtail>
2° PASO:
DETERMINAR QUE PROCESOS LLEVAN INVOCACIONES A
TEST Y DÓNDE
Test Test
inicial final
<programa>::= BEGIN <listsent> END  

DCC- UNSL
<listsent>::= <sent> <listsenttail> X X
< listsenttail >::=   <sent><listsenttail>  X
<sent>::= ID := <expr> ; |READ ( <idlist>) ;  
| WRITE ( <listexpr> );
<listexpr>::= <expr> <listexprtail> X X
<listexprtail>::=  , <expr> <listexprtail>  X
<expr>::= <factor> <exprtail> X X
<exprtail>::=   <op> <factor> <exprtail>  X
<factor> ::= ( <expr> )  ID  CTEENT  
<op>::= +  - X 
14
<idlist> ::= ID <listidtail>  X
<listidtail>::=  , ID <listidtail>  X
3° PASO:
ESCRIBIR EL PARSER DESCENDENTE RECURSIVO CON
EL ESQUEMA DE RECUPERACION DE ERRORES

PROGRAM parser;

DCC- UNSL
{
//inicializaciones para el scanner, si fuere necesario
lookahead := get_next_token
programa([eof]);
match(eof);
}

15
PROCEDIMIENTO PARA <PROGRAMA> ::= BEGIN <LISTSENT> END

DCC- UNSL
procedure programa(folset: conjunto de símbolos);
{
test([BEGIN], [ID READ WRITE] +[END] +folset, n1);
match(BEGIN);
listsent(folset + [END]);
match(END);
test(folset,[], n2);
}(*procedure programa*)

16
PROCEDIMIENTO PARA <PROGRAMA> ::= BEGIN <LISTSENT> END

Puntos de
procedure programa(folset: conjunto de símbolos); reconfiguración
de la estrategia
{ Puntos de
pánico
reconfiguración

DCC- UNSL
de la estrategia
antipánico

test([BEGIN], [ID READ WRITE] +[END] +folset, n1);


eof
match(BEGIN);
listsent(folset + [END]);
match(END);
test(folset,[], n2);
}(*procedure programa*)

17
Ejemplo: BEGIN READ(g); END END eof
PROCEDIMIENTO PARA <LISTSENT>::= <SENT> <LISTSENTTAIL>
procedure listsent ( folset: conjunto de símbolos);
{
sent (folset + [ ID READ WRITE] );
listsenttail ( folset );
} (*listsent*)

DCC- UNSL
PROCEDIMIENTO PARA <LISTSENTTAIL ::=   <SENT> <LISTSENTTAIL>

procedure listsenttail ( folset: conjunto de símbolos);


{
test ([ID READ WRITE] + folset, [ID READ WRITE] ,n3);
if lookahead in ( [ID READ WRITE] )
then
{ sent ( folset + [ ID READ WRITE] );
listsenttail ( folset );
} 18
} (*listsenttail*)
¿Alguno de los puntos de reconfiguración tiene efecto?
PROCEDIMIENTO PARA <SENT>:= ID := <EXPR> ;READ (<IDLIST>) ;WRITE (<LISTEXPR>);
procedure sent ( folset: conjunto de símbolos);
{ test ( [ID READ WRITE], folset + [:=], n5 );
case lookahead of
ID := : { match(ID);
match (:=);
expr ( folset + [ ; ] );
match (;)

DCC- UNSL
}
READ: { lookahead := get_next_token;
match (();
idlist ( folset + [ ) ;] );
match ());
match(;);
}
WRITE: { lookahead := get_next_token;
match (();
listexpr( folset + [ ) ; ] );
match ());
match(;);
}
default: error(....);
19
endcase
test (folset ,[], n6); ¿qué pasa con los ()?
} (*sent*)
PROCEDIMIENTOS PARA
<IDLIST> ::= ID <LISTIDTAIL>
<LISTIDTAIL> ::=  , ID <LISTIDTAIL>

procedure idlist ( folset: conjunto de símbolos);


{
test ( [ID], folset + [,], n7 );

DCC- UNSL
match(ID);
listidtalil ( folset );
} (*idlist*)

procedure listidtail ( folset: conjunto de símbolos);


{
test ([,]+ folset, [ ID], n8);
if (lookahead = , || lookahead = ID ) then
{ match(,);
match (ID);
listidtail ( folset );
}
} (*listidtail*)
20
POCEDIMIENTOS PARA
<LISTEXPR> ::= <EXPR> <LISTEXPRTAIL>
<LISTEXPRTAIL> ::=  , <EXPR> <LISTEXPRTAIL>

procedure listexpr ( folset: conjunto de símbolos);


{
expr ( folset + [ , ] );

DCC- UNSL
listexprtail ( folset );
} (*listexpr*)

procedure listexprtail ( folset: conjunto de símbolos);


{
test ([,]+ folset, [( ID CTEENT ], n9);
if lookahead in ( [, ID CTEENT ( ] )then
{ match(,);
expr ( folset + [ , ] );
listexprtail ( folset );
}
} (*listexprtail*)

21
PROCEDIMIENTOS PARA
<EXPR> ::= <FACTOR> <EXPRTAIL>
<EXPRTAIL> ::=   <OP> <FACTOR> <EXPRTAIL>

procedure expr ( folset: conjunto de símbolos);


{
factor ( folset + [ + - ] );

DCC- UNSL
exprtail ( folset );
} (*expr*)

procedure exprtail ( folset: conjunto de símbolos);


{
test ( [+ - ]+ folset, [( ID CTEENT + - ], n10 );
if lookahead in [ + - ID CTEENT (] then
{ op ( folset + [ ( ID CTEENT + - ] );
factor ( folset + [ + -] );
exprtail ( folset );
}
} (*exprtail*)
22
PROCEDIMIENTO PARA <FACTOR> ::= (<EXPR>) | ID | CTEENT
procedure factor ( folset: conjunto de símbolos);;
{
test ( [( ID CTEENT], folset + [)], n11 );
case lookahead of
() : { match(();
expr(folset +[ ) ]);
match( )) }
ID : lookahead := get_next_symbol;

DCC- UNSL
CTEENT : lookahead := get_next_symbol;
endcase
test ( folset, [ ], n12)
}(*factor*)

PROCEDIMIENTO PARA <OP> ::= + | -


procedure op ( folset: conjunto de símbolos);
{ case lookahead of
+ : lookahead := get_next_token;
- : lookahead := get_next_token;
endcase
23
test (folset, [ ], n12 );
}(*op*)
OBSERVACIONES 1
<listsent>  <sent> <listsenttail>
<listsenttail>   | <sent> <listsenttail>

procedure listsent ( folset: conjunto de símbolos);

DCC- UNSL
{
sent (folset + [ ID READ WRITE] );
listsenttail ( folset );
} end; (*listsent*)

procedure listsenttail ( folset: conjunto de símbolos);


{
test ( first(listsenttail) + folset, [] ,n);
if lookahead in ( [ID READ WRITE] ) then
{ sent ( folset + [ ID READ WRITE]);
listsenttail ( folset ); }
} end; (*listsenttail*)
24
SI SE UNIFICAN LAS DOS PRODUCCIONES SE OBTIENE
<listsent>  <sent> { <sent> }*

Su código asociado es:

DCC- UNSL
procedure listsent ( folset: conjunto de símbolos);
{
sent (folset + [ID READ WRITE] );
while lookahead in first( sent)
{
sent (folset + [ ID READ WRITE] );
test( first(sent) + folset, [], n);
}
} (*listsent*)

25
SI SE UNIFICAN LAS DOS PRODUCCIONES SE OBTIENE

DCC- UNSL
<listsent>  <sent> { <sent> }*

Su código asociado es:


procedure listsent ( folset: conjunto de símbolos); procedure listsent ( folset: conjunto de
{ símbolos);
{
sent (folset + [ID READ WRITE] ); sent (folset + [ ID READ WRITE] );
listsenttail ( folset );
while lookahead in first( sent) } end; (*listsent*)

{ procedure listsenttail ( folset: conjunto de


símbolos);
sent (folset + [ ID READ WRITE] ); {
test ( first(listsenttail) + folset, [] ,n);
test( first(sent) + folset, [], n); if lookahead in ( [ID READ WRITE] ) then
{sent ( folset + [ ID READ WRITE]);
} listsenttail ( folset ); }
} end; (*listsenttail*)
}
end; (*listsent*)

Se debe colocar un test como última sentencia del cuerpo de la


iteración para que se obtenga el mismo comportamiento que se 26
tenía anteriormente con las otras dos producciones.
OBSERVACIONES 2
<idlist> ::= ID <listidtail>
<listidtail> ::=  , ID <listidtail>

procedure idlist ( folset: conjunto de símbolos);

DCC- UNSL
{ test ( first(idlist), folset + [,], n1 );
match(ID);
listidtail ( folset );
}end; (*idlist*)

procedure listidtail ( folset: conjunto de símbolos);


{ test (first(listidtail) + folset , [ID], n2);
if lookahead in [, ID] then
{ match(,);
match (ID);
listidtail ( folset );
}
} end; (*listidtail*)
27
SI SE UNIFICAN LAS DOS PRODUCCIONES SE OBTIENE
<idlist>  ID { , ID }*

procedure idlist ( folset: conjunto de símbolos);


{

DCC- UNSL
test ( first(idlist), folset + [,], n1 );
match(ID);
while lookahead in [, ID]
{
match(,);
match(ID);
test ([,] + folset, [ID], n2);
}
}

28
SI SE UNIFICAN LAS DOS PRODUCCIONES SE OBTIENE
<idlist>  ID { , ID }*

procedure idlist ( folset: conjunto de símbolos);


{ procedure idlist ( folset: conjunto de símbolos);

DCC- UNSL
{ test ( first(idlist), folset + [,], n1 );
test ( first(idlist), folset + [,], n1 ); match(ID);
listidtail ( folset );
match(ID); }end; (*idlist*)
while lookahead in [, ID] procedure listidtail ( folset: conjunto de símbolos);
{ test (first(listidtail) + folset , [ID], n2);
{ if lookahead in [, ID] then
match(,); {match(,);
match (ID);
match(ID); }
listidtail ( folset );

test ([,] + folset, [ID], n2); } end; (*listidtail*)

}
}
Se debe colocar un test como última sentencia del cuerpo de la
iteración para que se obtenga el mismo comportamiento que se
tenía anteriormente con las otras dos producciones. Se mantiene
el test del inicio. 29

Potrebbero piacerti anche