Projeto do compilador - recuperação de erros
Um analisador deve ser capaz de detectar e relatar qualquer erro no programa. Espera-se que, quando um erro for encontrado, o analisador seja capaz de tratá-lo e continuar analisando o resto da entrada. Geralmente, espera-se que o analisador verifique se há erros, mas podem ser encontrados erros em vários estágios do processo de compilação. Um programa pode ter os seguintes tipos de erros em vários estágios:
Lexical : nome de algum identificador digitado incorretamente
Syntactical : ponto-e-vírgula ausente ou parêntese não balanceado
Semantical : atribuição de valor incompatível
Logical : código não alcançável, loop infinito
Existem quatro estratégias comuns de recuperação de erros que podem ser implementadas no analisador para lidar com erros no código.
Modo de pânico
Quando um analisador encontra um erro em qualquer lugar da instrução, ele ignora o resto da instrução, não processando a entrada errada para o delimitador, como ponto e vírgula. Esta é a maneira mais fácil de recuperação de erros e também evita que o analisador desenvolva loops infinitos.
Modo de declaração
Quando um analisador encontra um erro, ele tenta tomar medidas corretivas para que o resto das entradas da instrução permitam que o analisador analise adiante. Por exemplo, inserir um ponto-e-vírgula ausente, substituir a vírgula por um ponto-e-vírgula etc. Os projetistas do analisador devem ser cuidadosos aqui porque uma correção errada pode levar a um loop infinito.
Produções de erro
Alguns erros comuns são conhecidos pelos designers do compilador que podem ocorrer no código. Além disso, os designers podem criar gramática aumentada para ser usada, como produções que geram construções errôneas quando esses erros são encontrados.
Correção global
O analisador considera o programa em mãos como um todo e tenta descobrir o que o programa se destina a fazer e tenta encontrar uma correspondência mais próxima para ele, que é livre de erros. Quando uma entrada errônea (instrução) X é alimentada, ele cria uma árvore de análise para alguma instrução Y sem erros mais próxima. Isso pode permitir que o analisador faça alterações mínimas no código-fonte, mas devido à complexidade (tempo e espaço) de esta estratégia, ainda não foi implementada na prática.
Árvores de sintaxe abstrata
As representações da árvore de análise não são fáceis de serem analisadas pelo compilador, pois contêm mais detalhes do que o realmente necessário. Veja a seguinte árvore de análise como exemplo:
Se observado de perto, descobrimos que a maioria dos nós folha são filhos únicos de seus nós pais. Essas informações podem ser eliminadas antes de passar para a próxima fase. Ao ocultar informações extras, podemos obter uma árvore conforme mostrado abaixo:
A árvore abstrata pode ser representada como:
ASTs são estruturas de dados importantes em um compilador com menos informações desnecessárias. Os ASTs são mais compactos do que uma árvore de análise e podem ser facilmente usados por um compilador.