Como construir um compilador utilizando ferramentas Java

Propaganda
Como construir um compilador utilizando
ferramentas Java
Aula 8 – Recuperação de Erros Sintáticos
Prof. Márcio Delamaro
[email protected]
Como construir um compilador utilizando ferramentas Java – p. 1/2
O que temos até agora
A.S. lê entrada.
Se entrada estiver de acordo com a gramática,
execução termina OK.
Se existir algum erro sintático, uma execeção é lançada.
ParseException é tratada no método main.
Uma mensagem de erro é dada.
Como construir um compilador utilizando ferramentas Java – p. 2/2
Tratamento da exceção
try {
parser.program();
}
catch (ParseException e)
{
System.err.println(e.getMessage());
parser.contParseError = 1;
}
finally {
System.out.println(parser.token_source.foundLexError() +
" Lexical Errors found");
System.out.println(parser.contParseError +
" Syntactic Errors found");
}
Como construir um compilador utilizando ferramentas Java – p. 3/2
A saída é...
X++ Compiler - Version 1.0 - 2004
Reading from file bintree-erro-sintatico.x . . .
Encountered "mes" at line 21, column 4.
Was expecting one of:
"[" ...
";" ...
"." ...
">" ...
"<" ...
"==" ...
"<=" ...
">=" ...
"!=" ...
0 Lexical Errors found
1 Syntactic Errors found
Como construir um compilador utilizando ferramentas Java – p. 4/2
Recuperação de erros
Encountered "mes" at line 21, column 4.
Was expecting one of:
"[" ...
";" ...
"." ...
">" ...
"<" ...
"==" ...
"<=" ...
">=" ...
"!=" ...
Encountered "<" at line 27, column 14.
Was expecting one of:
<int_constant> ...
<string_constant> ...
"null" ...
<IDENT> ...
"(" ...
"+" ...
"-" ...
Como construir um compilador utilizando ferramentas Java – p. 5/2
Recuperação de erros
Encountered "right" at line 43, column 14.
Was expecting one of:
"(" ...
"[" ...
"," ...
";" ...
Encountered "1" at line 69, column 14.
Was expecting one of:
"[" ...
"." ...
"=" ...
<IDENT> ...
0 Lexical Errors found
4 Syntactic Errors found
Como construir um compilador utilizando ferramentas Java – p. 6/2
Método de resincronização (do pânico)
S → aAcd
A → gh
Como construir um compilador utilizando ferramentas Java – p. 7/2
Método de resincronização (do pânico)
S → aAcd
A → gh
Analisar: agabcd
Como construir um compilador utilizando ferramentas Java – p. 7/2
Método de resincronização (do pânico)
S → aAcd
A → gh
Analisar: agabcd
Método S não deve ser afetado por esse erro sintático.
Como construir um compilador utilizando ferramentas Java – p. 7/2
Método de resincronização (do pânico)
S → aAcd
A → gh
Analisar: agabcd
Método S não deve ser afetado por esse erro sintático.
O método A deve ressincronizar a entrada com o
não-terminal que se espera reconhecer (S ).
Como construir um compilador utilizando ferramentas Java – p. 7/2
Método de resincronização (do pânico)
S → aAcd
A → gh
Analisar: agabcd
Método S não deve ser afetado por esse erro sintático.
O método A deve ressincronizar a entrada com o
não-terminal que se espera reconhecer (S ).
Consumir tokens até que apareça algum que possibilite
a continuidade da análise.
Como construir um compilador utilizando ferramentas Java – p. 7/2
Método de resincronização (do pânico)
S → aAcd
A → gh
Analisar: agabcd
Método S não deve ser afetado por esse erro sintático.
O método A deve ressincronizar a entrada com o
não-terminal que se espera reconhecer (S ).
Consumir tokens até que apareça algum que possibilite
a continuidade da análise.
Método A precisa saber até onde ler.
Como construir um compilador utilizando ferramentas Java – p. 7/2
Método de resincronização (do pânico)
S → aAcd
A → gh
Analisar: agabcd
Método S não deve ser afetado por esse erro sintático.
O método A deve ressincronizar a entrada com o
não-terminal que se espera reconhecer (S ).
Consumir tokens até que apareça algum que possibilite
a continuidade da análise.
Método A precisa saber até onde ler.
Usar FOLLOW de A.
Como construir um compilador utilizando ferramentas Java – p. 7/2
Um pouco melhor
S → aAcd | bAef
A → gh
Como construir um compilador utilizando ferramentas Java – p. 8/2
Um pouco melhor
S → aAcd | bAef
A → gh
FOLLOW(A) = {c, e}
Como construir um compilador utilizando ferramentas Java – p. 8/2
Um pouco melhor
S → aAcd | bAef
A → gh
FOLLOW(A) = {c, e}
Se estivermos utilizando a primeira produção de S,
desejaremos utilizar o c para fazer a recuperação de
erros, e não o e.
Como construir um compilador utilizando ferramentas Java – p. 8/2
Um pouco melhor
S → aAcd | bAef
A → gh
FOLLOW(A) = {c, e}
Se estivermos utilizando a primeira produção de S,
desejaremos utilizar o c para fazer a recuperação de
erros, e não o e.
Devemos permitir que a cada chamada de A seja
informado, por meio de um parâmetro, qual é o token de
sincronização a ser utilizado.
Como construir um compilador utilizando ferramentas Java – p. 8/2
No JavaCC
Construções try/catch
Dessa forma, caso não haja um casamento esperado, o
método pode fazer a ressincronização.
Um erro de sintaxe é sinalizado com um ParseException
Como construir um compilador utilizando ferramentas Java – p. 9/2
Tratamento de erro
void A()
{
}
{
try {
"g" "h"
}
catch (ParseException e)
{
// tratamento de erro
}
}
Como construir um compilador utilizando ferramentas Java – p. 10/2
Chamada a não-terminais
void A()
{
}
{
try {
"g" B() "h"
}
catch (ParseException e)
{
// tratamento de erros de A ou de B
}
}
Como construir um compilador utilizando ferramentas Java – p. 11/2
Chamada a não-terminais
Nesse último caso, o não-terminal B pode ou não
implementar o tratamento de erro.
Se tratar, o método A não muda.
Se não tratar, um erro pode ser propagado e tratado em
A.
Para cada chamada de não-terminal que trata dos erros
deve ser passado um conjunto de ressincronização.
Como construir um compilador utilizando ferramentas Java – p. 12/2
Esquema geral
void S()
{
RecoverySet x =
y =
}
{
( <a> A(x) <c>
<b> A(y) <e>
)
}
new RecoverySet(<c>),
new RecoverySet(<e>);
<d> |
<f>
Como construir um compilador utilizando ferramentas Java – p. 13/2
Esquema geral
void A(RecoverySet r)
{
}
{
try {
<g> <h>
}
catch (ParseException e)
{
consumeUntil(r, e, "A");
}
}
Como construir um compilador utilizando ferramentas Java – p. 14/2
Método consumeUntil
Dá mensagem sobre recuperação de erros (ver main);
Como construir um compilador utilizando ferramentas Java – p. 15/2
Método consumeUntil
Dá mensagem sobre recuperação de erros (ver main);
Se conjunto de sincronização não null, vai consumindo
os tokens da entrada até achar algum no conjunto.
Como construir um compilador utilizando ferramentas Java – p. 15/2
Método consumeUntil
Dá mensagem sobre recuperação de erros (ver main);
Se conjunto de sincronização não null, vai consumindo
os tokens da entrada até achar algum no conjunto.
Se um <EOF> for achado, lança outro tipo de exceção
ParseEOFException
Como construir um compilador utilizando ferramentas Java – p. 15/2
Método consumeUntil
Dá mensagem sobre recuperação de erros (ver main);
Se conjunto de sincronização não null, vai consumindo
os tokens da entrada até achar algum no conjunto.
Se um <EOF> for achado, lança outro tipo de exceção
ParseEOFException
Por isso, todos os métodos devem declarar esse tipo de
exceção.
Como construir um compilador utilizando ferramentas Java – p. 15/2
Método consumeUntil
Dá mensagem sobre recuperação de erros (ver main);
Se conjunto de sincronização não null, vai consumindo
os tokens da entrada até achar algum no conjunto.
Se um <EOF> for achado, lança outro tipo de exceção
ParseEOFException
Por isso, todos os métodos devem declarar esse tipo de
exceção.
Incremnta número de erros encontrados.
Como construir um compilador utilizando ferramentas Java – p. 15/2
Do começo
void program()
throws ParseEOFException : {
RecoverySet g = new RecoverySet(EOF);
}
{
try {
[ classlist(g) ] <EOF>
}
catch (ParseException e) {
consumeUntil(g, e, "program");
}
}
Como construir um compilador utilizando ferramentas Java – p. 16/2
RecoverySet
Implementa um conjunto de inteiros, com algumas
operações específicas
Construtor RecoverySet(int)
boolean contains(int)
RecoverySet union(RecoverySet)
RecoverySet add(in)
RecoverySet remove(in)
String toString()
Como construir um compilador utilizando ferramentas Java – p. 17/2
classlist
void classlist(RecoverySet g)
throws ParseEOFException : {
RecoverySet f = First.classlist.union(g);
}
{
classdecl(f) [ classlist(g) ]
}
Não há recuperação de erros.
Não há possibilidade de erros sintático.
Uso dos conjuntos da classe First
Como construir um compilador utilizando ferramentas Java – p. 18/2
classbody
void classbody(RecoverySet g) throws ParseEOFException : {
RecoverySet f1 = new RecoverySet(RBRACE),
f2 = new RecoverySet(SEMICOLON),
f3 = First.methoddecl.union(f1),
f4 = First.constructdecl.union(f3),
f5 = First.vardecl.union(f4);
}
{
try {
<LBRACE>
[classlist(f5)]
(LOOKAHEAD(3) vardecl(f2) <SEMICOLON>)*
(constructdecl(f4))*
(methoddecl(f3))*
<RBRACE>
}
catch (ParseException e) {
consumeUntil(g, e, "classbody");
}
}
Como construir um compilador utilizando ferramentas Java – p. 19/2
Algumas exceções
void lvalue(RecoverySet g) throws ParseEOFException :
{}
{
try {
<IDENT> (
<LBRACKET> expression(null) <RBRACKET> |
<DOT> <IDENT> [<LPAREN> arglist(null) <RPAREN>]
)*
}
catch (ParseException e) {
consumeUntil(g, e, "lvalue");
}
}
É o ponto “mais baixo” onde se realiza
recuperação de erros.
a[i + * 3].x = 123;
Como construir um compilador utilizando ferramentas Java – p. 20/2
Expression
void expression(RecoverySet g)
throws ParseEOFException :
{}
{
try {
numexpr()
[(<LT>|<GT>|<LE>|<GE>|<EQ>|<NEQ>)
numexpr()]
}
catch (ParseException e) {
consumeUntil(g, e, "expression");
}
}
Como construir um compilador utilizando ferramentas Java – p. 21/2
Algumas melhorias
A forma de cálculo do conjunto de sincronização é
bastante simples.
Esse conjunto é muito importante no sucesso da
recuperação.
Nem sempre é eficiente.
Uma análise caso-a-caso pode melhorar a eficiência da
estratégia.
Ver descrição no capítulo 5.
Como construir um compilador utilizando ferramentas Java – p. 22/2
Download