Existem compiladores que tentam corrigir os erros de sintaxe por conta própria? [fechadas]

15

Ouvi um tempo atrás que costumava haver um compilador que tentava corrigir erros de sintaxe analisando o contexto e inferindo o que era pretendido.

Esse compilador realmente existe? Obviamente, ele tem pouco valor prático, mas seria muito interessante para brincar e aprender.

Nathan Osman
fonte
3
O IntelliSense se enquadra nessa categoria? Muitos compiladores têm erros semelhantes ao esperado [ponto e vírgula].
Robert Harvey
1
@ Robert: Não, mas esse é um bom argumento.
Nathan Osman
1
Um amigo meu invadiu bastante o pré-processador C, por exemplo, 'inlcude -> include', e alguns tentaram descobrir onde os condicionais abertos deveriam ter sido fechados. Era a tese de mestrado, que ele abandonou rapidamente para algo mais fácil. Ainda assim, uma pergunta bastante interessante!
Tim Post
3
O compilador AC # falha com mensagens de erro MUITO úteis. Isso combinado com a boa documentação disponível on-line para cada código de erro funciona bastante bem. É uma má idéia corrigir automaticamente a sintaxe, embora os intérpretes HTML (por exemplo, navegadores) o façam de qualquer maneira.
Job
1
O compilador ao qual você está se referindo foi o PL / I original. Ele assumiu o que o programador escreveu deve ter significado alguma coisa e tentou adivinhar o que poderia ser. Na minha experiência, adivinhou muito mesmo!
David.pfx 22/03

Respostas:

28

Em certo sentido, o ato de compilar está inferindo o que determinada sintaxe deve fazer e, portanto, um erro de sintaxe ocorre quando o compilador não é capaz de descobrir isso. Você pode adicionar mais "suposições" para que o compilador deduza outras coisas e seja mais flexível com a sintaxe, mas isso deve ser inferido por um conjunto específico de regras. E essas regras tornam-se parte da linguagem e não são mais erros.

Então, não, não existem tais compiladores, realmente, porque a pergunta não faz sentido. Adivinhar o que os erros de sintaxe devem fazer de acordo com algum conjunto de regras se torna parte da sintaxe.

Nesse sentido, há um bom exemplo de um compilador que faz isso: Qualquer compilador C. Eles geralmente imprimem um aviso de algo que não é como deveria ser e assumem que você quis dizer X e continuam. Na verdade, isso é "adivinhar" um código pouco claro (embora na maioria das vezes não seja sintaxe), algo que também poderia ter interrompido a compilação com um erro e, portanto, qualificado como um erro.

Lennart Regebro
fonte
4
Esta é a resposta certa. Depois que um compilador pode se recuperar de um erro, ele não é mais um erro. O Perl é (in?) Famoso por esse comportamento "Faça o que eu quero dizer", escolhendo o que o programador provavelmente quis dizer com uma fonte ambígua.
quer
O Perl sacrifica a verbosidade pelo tamanho do código-fonte.
Nathan Osman
@ George Edison: Isso é uma tautologia ou uma contradição.
quer
Ou uma visão profunda. :)
Lennart Regebro
23

Parece realmente perigoso. Se um compilador tentar inferir sua intenção, inferir errado, corrigir o código e depois não informar (ou avisar em algum aviso que você, como todo mundo, ignora), você está prestes a executar um código que pode seriamente causar algum dano.

Um compilador como esse é provavelmente algo que intencionalmente NÃO foi criado.

nganju
fonte
5
Eu sei disso. Esse compilador não teria utilidade para compilar, mas o conceito é bastante interessante e tem potencial de aprendizado.
Nathan Osman
2
quase todo o IDE mais recente fornece sugestões de sintaxe e é realmente útil. e para o resto da parte concordar com nganju
Jigar Joshi
Eu não usaria esse compilador. Ele vem sob o título de 'magia negra'.
Michael K
Hmmm, onde você classificaria a inferência de tipo de Scala nessa escala? Depois de tentar, diria que é uma grande contribuição para o código conciso. Por outro lado, ele ocasionalmente me deu um tiro no pé (por exemplo, porque eu pensei que estava lidando com listas, mas na verdade ainda estava lidando com sets).
timday
Temos coisas como o autoscópio no OMP, então um pouco disso é possível. É claro que o código em que trabalho foi desativado, porque não confiamos nele. Eu pude ver um compilador interativo que pergunta "você quis dizer XXX?". Isso é tanto quanto eu estaria disposto a ir. E mesmo isso é provavelmente muito perigoso.
Omega Centauri
12

O IDE para uma linguagem de programação normalmente hoje em dia tem um compilador sendo executado em segundo plano de alguma forma, para que ele possa fornecer serviços de análise como sintaxe de cores, IntelliSense, erros e assim por diante. Obviamente, esse compilador precisa ser capaz de entender o código profundamente quebrado; Na maioria das vezes, ao editar, o código não está correto. Mas ainda temos que entender isso.

No entanto, geralmente o recurso de recuperação de erros é usado apenas durante a edição; não faz muito sentido permitir isso para compilação real em cenários "principais".

Curiosamente, criamos esse recurso no compilador JScript.NET; basicamente, é possível colocar o compilador em um modo em que permitimos que o compilador prossiga mesmo se um erro for encontrado, se o IDE tivesse se recuperado dele. Você pode digitar o código do Visual Basic , executar o compilador JScript.NET nele e ter uma chance razoável de um programa de trabalho sair do outro lado!

Esta é uma demonstração divertida, mas acaba não sendo um recurso muito bom para cenários "principais" por vários motivos. Uma explicação completa seria bastante longa; a breve explicação é que ela cria programas que funcionam imprevisivelmente e por acidente e dificulta a execução do mesmo código por meio de vários compiladores ou de várias versões do mesmo compilador. As grandes despesas adicionadas pelo recurso não são justificadas pelos pequenos benefícios.

Peter Torr, que gerenciou o recurso de volta no dia, discute brevemente neste post de 2003 .

Embora exponha esse recurso por meio das APIs de hospedagem de scripts do mecanismo JScript .NET, não conheço nenhum cliente real que já o tenha usado.

Eric Lippert
fonte
Eu gostaria que meu empregador tivesse os recursos para experimentar assim; nem sequer executamos testes de unidade à noite, porque há muitos recursos a serem adicionados e bugs a serem corrigidos :(
Job
1
Esse é o tipo de resposta que eu esperava ... como mencionei antes - obviamente esse recurso tem pouco uso prático, mas forneceria uma ótima maneira de aprender algumas técnicas que poderiam ser aplicadas a outras coisas. (Análise de idioma etc.)
Nathan Osman
1
@ Job: O senso comum é que, se você não executar regularmente os testes de unidade, terá muito mais bugs para corrigir .
Eric Lippert
Eu já sei o que preciso fazer sobre o meu trabalho, em vez de me lamentar aqui. Em algumas empresas de software, as pessoas no topo realmente não entendem a diferença entre um protótipo e um produto acabado. Afinal, em termos de pixel, muitas vezes não há muita diferença. Não é aconselhável não começar com um protótipo, para que o tempo não seja desperdiçado. Mas a terrível resposta "parece boa, quantos dias para colocar isso em produção?". Essas são as mesmas pessoas que suspeitariam se os engenheiros dissessem que precisam gastar tempo na infraestrutura ou na refatoração. Ouvi dizer que mesmo Spolsky não gosta.
Job
10

A primeira coisa que me vem à mente é a inserção automática de ponto e vírgula do Javascript . Um recurso horrível e horrível que nunca deveria ter chegado ao idioma.

Isso não quer dizer que não poderia ter feito um trabalho melhor. Se ele olhou para a frente no seguinte a linha, então ele pode ser capaz de fazer uma estimativa melhor como a intenção do programador, mas no final do dia, se há múltiplas maneiras válidas a sintaxe poderia ter ido, então não há realmente nenhum substituto para o programador ser explícito.

Dean Harding
fonte
1
Concordo plenamente com o recurso de inserção de ponto e vírgula JavaScript - completamente inútil.
Nathan Osman
7

Parece-me que, se um compilador puder corrigir uma sintaxe incorreta, essa sintaxe deverá ser documentada no idioma.

O motivo dos erros de sintaxe é porque um analisador não pôde criar a árvore de sintaxe abstrata fora do programa. Isso acontece quando um token está fora do lugar. Para adivinhar onde esse token deve estar, se deve ser removido ou se algum outro token deve ser adicionado para corrigir o erro, você precisará de algum tipo de computador que possa adivinhar a intenção de um programador. Como uma máquina poderia adivinhar isso:

int x = 5 6;

Era suposto ser:

int x = 5 + 6;

Ele poderia facilmente ser qualquer um dos seguintes: 56, 5 - 6, 5 & 6. Não há como um compilador saber.

Essa tecnologia ainda não existe.

jjnguy
fonte
1
Essa tecnologia não pode existir. A leitura da mente não é permitida; todas as instruções devem vir sem ambiguidade do código.
Job
É verdade, mas o que eu realmente quis dizer foi "Existem compiladores que tentam corrigir a sintaxe inválida fazendo suposições baseadas no contexto". O fato de o compilador corrigir a sintaxe inválida não torna a sintaxe válida. Além disso, percebo que essa ferramenta seria inútil para o desenvolvimento de código.
Nathan Osman
6

Embora não seja exatamente a mesma coisa, é por isso que o HTML se transformou no desastre. Os navegadores toleraram a marcação incorreta e, em seguida, o navegador A não conseguiu renderizar da mesma maneira que o navegador B (sim, existem outros motivos, mas esse foi um dos poucos mais importantes, especialmente cerca de 10 anos atrás, antes que algumas regras de folga se tornassem convenções )

Como Eric Lippert deduz, muitas dessas coisas são melhor tratadas pelo IDE, não pelo compilador. Vamos ver o que os bits automáticos estão tentando estragar para você.

A estratégia que acho predominante agora é o aprimoramento contínuo da linguagem, em vez de afrouxar o compilador: se realmente é algo que o compilador pode descobrir automaticamente, introduza uma construção de linguagem bem definida em torno dele.

O exemplo imediato que vem à mente são as propriedades automáticas em C # (não o único idioma que possui algo semelhante): dado que a maioria dos getters / setters em qualquer aplicativo são realmente apenas invólucros em torno de um campo, permita ao desenvolvedor indicar seus intenção e deixe o compilador injetar o resto.

O que me leva a pensar: a maioria das linguagens no estilo C já faz isso em certa medida. Para coisas que podem ser descobertas automaticamente, basta refinar a sintaxe:

 if (true == x)
 {
    dothis();
 }
 else
 {
    dothat();
 }

Pode ser reduzido para:

if (true == x)
    dothis();
else
    dothat();

No final, acho que tudo se resume a isso: a tendência é que você não torne o compilador "mais inteligente" ou "mais flexível". É a linguagem que se torna mais inteligente ou mais flexível.

Além disso, muita "ajuda" pode ser perigosa, como o bug clássico "se":

if (true == x)
    if (true == y)
       dothis();
else
    dothat();
MIA
fonte
Note-se que o XHTML forneceu uma solução para a bagunça que as más especificações do HTML criaram.
Nathan Osman
2
if (x && y) dothis(); else dothat();ficaria um pouco melhor.
Job
1
Um gato morre toda vez que alguém compara contra trueou false.
JensG
2

Quando eu estava codificando FORTRAN e PL / I no final dos anos 80 e início dos anos 90 nos sistemas de minicomputadores e mainframe DEC e IBM, pareço lembrar que os compiladores efetuavam logoff regularmente de mensagens como "erro blá blá; assumindo blá blá e continuando .." . " Naquela época, esse era um legado dos dias (ainda antes, antes do meu tempo) de processamento em lote e cartões perfurados, quando havia provavelmente uma enorme espera entre o envio do código para execução e a recuperação dos resultados. Portanto, fazia muito sentido que os compiladores tentassem adivinhar o programador e continuar, em vez de abortar, o primeiro erro encontrado. Veja bem, não me lembro das "correções" serem particularmente sofisticadas. Quando finalmente mudei para estações de trabalho Unix interativas (Sun, SGI, etc.),

timday
fonte
2
Esses compiladores continuariam, mas continuariam SOMENTE com o objetivo de tentar encontrar mais erros, para que você pudesse (potencialmente) corrigir várias coisas antes de reenviar. PCs modernos são rápidos o suficiente para que seja totalmente viável que um compilador "interativo" pare no primeiro erro de sintaxe e o leve a um editor. (E, na verdade, o original Turbo Pascal, no início de 1980, funcionou exatamente dessa forma Foi bom..)
John R. Strohm
1
Sim, lembro-me de que o compilador de otimização IBM PL / I forneceria ocasionalmente instruções BEGIN e END ausentes, enquanto ISTR também forneceria ponto e vírgula ausente.
TMN
1

O objetivo de um compilador é produzir executáveis ​​que se comportem conforme desejado. Se um programador escreve algo inválido, mesmo que o compilador consiga adivinhar com 90% de probabilidade o que foi planejado, geralmente é melhor exigir que o programador conserte o programa para esclarecer a intenção do que fazer com que o compilador vá em frente e produza um executável o que teria uma chance significativa de ocultar um bug.

Obviamente, as linguagens geralmente devem ser projetadas para que o código que expressa claramente a intenção seja legal, e o código que não expressa claramente a intenção seja proibido, mas isso não significa que seja. Considere o seguinte código [Java ou C #]

const double oneTenth = 0.1;
const float  oneTenthF = 0.1f;
...
float f1 = oneTenth;
double d1 = oneTenthF;

Ter um compilador adicionando uma conversão de texto implícita para a atribuição f1seria útil, pois há apenas uma coisa lógica que o programador pode querer f1conter (o floatvalor mais próximo de 1/10). Porém, em vez de incentivar os compiladores a aceitar programas impróprios, seria melhor para as especificações permitirem conversões implícitas de duplo para flutuar em alguns contextos. Por outro lado, a atribuição de d1pode ou não ser o que o programador realmente pretendia, mas não há nenhuma regra de idioma que o proíba.

Os piores tipos de regras de linguagem são aqueles em que os compiladores farão inferências nos casos em que algo não poderia ser legitimamente compilado de outra forma, mas onde um programa pode "acidentalmente" ser válido no caso em que a inferência foi planejada. Muitas situações envolvendo final de declaração implícito se enquadram nessa categoria. Se um programador que pretende escrever duas instruções separadas omitir um terminador de instruções, um compilador geralmente consegue inferir o limite da instrução, mas ocasionalmente pode considerar uma instrução como algo que deveria ser processado como duas.

supercat
fonte
0

Os erros de sintaxe são especialmente difíceis de corrigir. Tome o caso de um direito que falta ): sabemos que podemos reparar o código inserindo um, mas geralmente há muitos lugares onde podemos inserir um e obter um programa sintaticamente correto.

Um ponto muito mais fácil são os identificadores com erros ortográficos (mas observe que não são erros de sintaxe). Pode-se calcular a distância de edição entre o identificador não resolvível e todos os identificadores no escopo e, substituindo a palavra não resolvível pela que o usuário provavelmente quis dizer, seria possível criar um programa correto em muitos casos. Entretanto, ainda é melhor sinalizar o erro e permitir que o IDE sugira substituições válidas.

Ingo
fonte
-1

Um compilador desse tipo seria simplesmente uma implementação descontraída e não padrão de qualquer linguagem que esteja compilando.

Rei Miyasaka
fonte
-2

Foi testado várias vezes, mas muitas vezes não alcançou o efeito desejado: pense no HAL 9000 ou no GlaDOS.

cbrandolino
fonte
-3

Em C, você não pode passar matrizes por valor, mas o compilador permite que você escreva:

void foo(int array[10]);

que é reescrito silenciosamente como:

void foo(int* array);

Quão estúpido é isso? Eu preferiria um erro grave aqui em vez de reescrever silenciosamente, porque essa regra especial levou muitos programadores a acreditar que matrizes e ponteiros são basicamente a mesma coisa. Eles não são.

fredoverflow
fonte