Esistono compilatori che tentano di correggere da soli gli errori di sintassi? [chiuso]


15

Ho sentito qualche tempo fa che un tempo c'era un compilatore che tentava di correggere errori di sintassi analizzando il contesto e deducendo ciò che era previsto.

Esiste davvero un compilatore del genere? Ovviamente ha poco valore pratico, ma sarebbe molto interessante giocare e imparare da.


3
IntelliSense rientra in questa categoria? Molti compilatori hanno errori simili a [punto e virgola] previsti.
Robert Harvey,

1
@Robert: No, ma questo è un buon punto.
Nathan Osman,

1
Un mio amico ha fatto un po 'di hacking sul preprocessore C, ad esempio "inlcude -> include", e alcuni lavori per cercare di capire dove avrebbero dovuto essere chiusi i condizionali aperti. Era la tesi del suo maestro, che abbandonò rapidamente per qualcosa di più semplice. Comunque, una domanda abbastanza interessante!
Tim Post

3
Il compilatore AC # ha esito negativo con messaggi di errore MOLTO utili. Questo combinato con una buona documentazione disponibile online per ogni codice di errore funziona piuttosto bene. È una cattiva idea correggere automaticamente la sintassi, anche se gli interpreti HTML (ad esempio i browser) lo fanno spesso.
Giobbe

1
Il compilatore a cui ti riferivi era il PL / I originale. Presumeva che qualunque cosa il programmatore avesse scritto doveva significare qualcosa e cercava di indovinare quale potesse essere. Nella mia esperienza, ha indovinato davvero molto!
david.pfx,

Risposte:


28

In un certo senso, l'atto della compilazione sta inferendo ciò che una certa sintassi è destinata a fare, e quindi un errore di sintassi è quando il compilatore non è in grado di capirlo. Puoi aggiungere più "indovinelli" per fare in modo che il compilatore deduca ulteriori cose e sia più flessibile con la sintassi, ma deve fare questo inferendo da un insieme specifico di regole. E quelle regole diventano quindi parte della lingua e non sono più errori.

Quindi, no, non ci sono compilatori del genere, davvero, perché la domanda non ha senso. Indovinare che cosa gli errori di sintassi devono fare in base a un insieme di regole diventa solo una parte della sintassi.

In tal senso, esiste un buon esempio di compilatore che esegue questa operazione: qualsiasi compilatore C. Spesso stampano solo un avvertimento di qualcosa che non è come dovrebbe essere, quindi assumono che tu intendessi X, e continuano. In realtà si tratta di "indovinare" un codice poco chiaro (sebbene non sia per lo più sintassi di per sé), qualcosa che potrebbe anche aver interrotto la compilazione con un errore e quindi qualificarsi come errore.


4
Questa è la risposta esatta. Una volta che un compilatore può recuperare da un errore, non è più un errore. Perl è (in?) Famoso per questo comportamento "Do What I Mean", scegliendo ciò che è più probabile che il programmatore abbia inteso per una fonte ambigua.
Jon Purdy,

Perl sacrifica la verbosità per la dimensione del codice sorgente.
Nathan Osman,

@ George Edison: è una tautologia o una contraddizione.
Jon Purdy,

O una visione profonda. :)
Lennart Regebro,

23

Sembra davvero pericoloso. Se un compilatore tenta di inferire il tuo intento, lo inserisce in modo errato, corregge il codice e quindi non ti dice (o ti dice in qualche avviso che tu, come tutti, ignori), allora stai per eseguire codice che potrebbe seriamente fare qualche danno.

Un compilatore come questo è probabilmente qualcosa che NON è stato creato intenzionalmente.


5
Lo so. Un compilatore del genere non avrebbe alcuna utilità per la compilazione, ma il concetto è piuttosto interessante e ha un potenziale di apprendimento.
Nathan Osman,

2
quasi tutti gli IDE più recenti forniscono suggerimenti per la sintassi ed è davvero utile. e per il resto la parte concorda con nganju
Jigar Joshi il

Non userei un tale compilatore. Viene sotto il titolo di "magia nera".
Michael K,

Hmmm dove valuteresti l'inferenza del tipo di Scala su questa scala? Avendolo provato, direbbe che è un grande contributo al codice conciso. D'altra parte, a volte mi ha sparato ai piedi (ad es. Perché pensavo di avere a che fare con le liste ma in realtà avevo ancora a che fare con i set).
giorno

Abbiamo cose come l'autoscopio in OMP, quindi un po 'è fattibile. Ovviamente il codice su cui lavoro ha disattivato l'autoscoping perché non ci fidiamo. Ho potuto vedere un compilatore interattivo che chiedeva "volevi dire XXX?". Questo è quanto sarei disposto ad andare. E anche questo è probabilmente troppo pericoloso.
Omega Centauri,

12

L'IDE per un linguaggio di programmazione di solito in questi giorni ha un compilatore in esecuzione in background in qualche modo, in modo che possa fornire servizi di analisi come la colorazione della sintassi, IntelliSense, errori e così via. Ovviamente un tale compilatore deve essere in grado di dare un senso al codice profondamente rotto; il più delle volte durante la modifica, il codice non è corretto. Ma dobbiamo ancora dare un senso.

Tuttavia, in genere la funzione di recupero errori viene utilizzata solo durante la modifica; non ha molto senso permetterlo per la compilazione effettiva in scenari "mainline".

È interessante notare che abbiamo creato quella funzione nel compilatore JScript.NET; fondamentalmente è possibile mettere il compilatore in una modalità in cui consentiamo al compilatore di procedere anche se si verifica un errore, se l'IDE si sarebbe ripristinato da esso. È possibile digitare il codice Visual Basic , eseguire il compilatore JScript.NET su di esso e avere una ragionevole possibilità che un programma di lavoro esca dall'altra parte!

Questa è una demo divertente, ma si rivela non un'ottima funzionalità per gli scenari "mainline" per molte ragioni. Una spiegazione completa sarebbe piuttosto lunga; la breve spiegazione è che rende i programmi che funzionano in modo imprevedibile e per caso e rende difficile eseguire lo stesso codice attraverso più compilatori o più versioni dello stesso compilatore. Le grandi spese che la funzionalità aggiunge non sono giustificate dai piccoli vantaggi.

Peter Torr, che in passato ha pubblicato il film, ne discute brevemente in questo post sul blog del 2003 .

Sebbene esponiamo questa funzione tramite le API di hosting script del motore JScript .NET, non conosco alcun cliente reale che l'abbia mai utilizzata.


Vorrei che il mio datore di lavoro avesse le risorse per sperimentare in quel modo; non eseguiamo nemmeno test unitari di notte perché ci sono così tante funzioni da aggiungere e bug da correggere :(
Giobbe

1
Questo è il tipo di risposta che speravo ... come ho già detto in precedenza - ovviamente una tale funzione ha un uso poco pratico, ma fornirebbe un ottimo modo per apprendere alcune tecniche che potrebbero essere applicate ad altre cose. (Analisi della lingua, ecc.)
Nathan Osman,

1
@Job: la saggezza generale è che se non esegui regolarmente i test unitari, avrai molti più bug da correggere .
Eric Lippert,

So già cosa devo fare per il mio lavoro invece di lamentarmi qui. In alcune società di software le persone al vertice non comprendono davvero la differenza tra un prototipo e un prodotto finito. Dopotutto, per quanto riguarda i pixel, spesso non c'è molta differenza. Non è saggio non iniziare con un prototipo, in modo da non perdere tempo. Ma la terribile risposta "ha un bell'aspetto, in quanti giorni è possibile passare alla produzione?". Quelle sono le stesse persone che sarebbero sospettose se gli ingegneri dicessero loro che devono trascorrere del tempo sull'infrastruttura o sul refactoring. Ho sentito che anche a Spolsky non piace.
Giobbe

10

La prima cosa che mi viene in mente è l' inserimento automatico dei punti e virgola di Javascript . Una caratteristica orribile, orribile che non avrebbe mai dovuto farsi strada nella lingua.

Questo non vuol dire che non avrebbe potuto fare un lavoro migliore. Se guardasse avanti alla seguente riga, allora potrebbe essere in grado di fare un'ipotesi migliore sull'intenzione del programmatore, ma alla fine, se ci sono molti modi validi in cui la sintassi avrebbe potuto andare, allora non c'è davvero alcun sostituto perché il programmatore è esplicito.


1
Sono pienamente d'accordo con la funzione di inserimento dei punti e virgola di JavaScript - completamente inutile.
Nathan Osman,

7

Mi sembra che se un compilatore potesse correggere una sintassi errata, tale sintassi dovrebbe essere documentata nella lingua.

Il motivo degli errori di sintassi è perché un parser non è stato in grado di creare l'albero di sintassi astratto dal programma. Questo accade quando un token è fuori posto. Per indovinare dove dovrebbe essere quel token, se dovrebbe essere rimosso, o se fosse necessario aggiungere qualche altro token per correggere l'errore, avresti bisogno di una sorta di computer in grado di indovinare l'intento di un programmatore. Come può una macchina indovinare che:

int x = 5 6;

Si supponeva che fosse:

int x = 5 + 6;

Potrebbe benissimo essere uno dei seguenti: 56, 5 - 6, 5 & 6. Non c'è modo che un compilatore lo sappia.

Quella tecnologia non esiste ancora.


1
Tale tecnologia non può esistere. La lettura della mente non è consentita; tutte le istruzioni devono provenire inequivocabilmente dal codice.
Giobbe

Vero, ma quello che intendevo veramente era "Esistono compilatori che tentano di correggere la sintassi non valida facendo ipotesi basate sul contesto". Il fatto che il compilatore corregga la sintassi non valida non rende valida la sintassi. Inoltre, mi rendo conto che un tale strumento sarebbe inutile per lo sviluppo del codice.
Nathan Osman,

6

Sebbene non sia esattamente la stessa cosa, questo è il motivo per cui l'HTML si è trasformato nel disastro che è. I browser tolleravano il markup errato e la prossima cosa che sapevi, il browser A non poteva essere eseguito allo stesso modo del browser B (sì, ci sono altri motivi, ma questo era uno dei pochi, specialmente circa 10 anni fa prima che alcune delle regole di scioltezza diventassero convenzionali ).

Come sostiene Eric Lippert, molte di queste cose sono meglio gestite dall'IDE, non dal compilatore. Vediamo quali sono i bit automatici che stanno tentando di rovinare.

La strategia che ritengo predominante ora è il perfezionamento continuo del linguaggio invece di allentare il compilatore: se è veramente qualcosa che il compilatore può capire automaticamente, quindi introdurre un costrutto linguistico ben definito attorno ad esso.

L'esempio immediato che viene in mente sono le proprietà automatiche in C # (non l'unico linguaggio che ha qualcosa di simile): dato che la maggior parte dei getter / setter in qualsiasi app è in realtà solo un involucro attorno a un campo, consenti allo sviluppatore di indicare il proprio intento e lasciare che il compilatore inietti il ​​resto.

Il che poi mi fa pensare: la maggior parte dei linguaggi in stile C lo fa già in una certa misura. Per cose che possono essere capite automaticamente, basta affinare la sintassi:

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

Può essere ridotto a:

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

Alla fine, penso che ciò dipenda da questo: la tendenza è di non rendere il compilatore "più intelligente" o "più flessibile". È la lingua che è resa più intelligente o meno.

Inoltre, troppo "aiuto" può essere pericoloso, come il classico bug "if":

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

Va notato che XHTML ha fornito una soluzione per il caos creato dalle scarse specifiche HTML.
Nathan Osman,

2
if (x && y) dothis(); else dothat();apparirebbe leggermente migliore.
Giobbe

1
Un gatto muore ogni volta che qualcuno confronta trueo false.
JensG,

2

Quando stavo codificando FORTRAN e PL / I alla fine degli anni '80 e all'inizio degli anni '90 su sistemi di minicomputer e mainframe DEC e IBM, mi sembra di ricordare che i compilatori disconnettessero regolarmente messaggi come "errore di blah blah; assumendo blah blah e continuando .. . ". All'epoca, questa era un'eredità dei (anche prima, prima del mio tempo) giorni di elaborazione batch e schede perforate quando c'era probabilmente un'enorme attesa tra l'invio del codice per l'esecuzione e il recupero dei risultati. Quindi ha molto senso per i compilatori fare un tentativo di indovinare il programmatore e continuare invece di interrompere il primo errore riscontrato. Intendiamoci, non ricordo che le "correzioni" siano particolarmente sofisticate. Quando alla fine sono passato alle workstation interattive Unix (Sun, SGI ecc.),


2
Quei compilatori continuerebbero, ma continuerebbero SOLO allo scopo di provare a trovare ulteriori errori, in modo da poter (potenzialmente) risolvere diverse cose prima di inviare nuovamente. I PC moderni sono abbastanza veloci da consentire a un compilatore "interattivo" di fermarsi al primo errore di sintassi e rilasciarti in un editor. (E, in effetti, l'originale Turbo Pascal, nei primi anni '80, ha funzionato esattamente in questo modo. È stato bello.)
John R. Strohm,

1
Sì, ricordo che il compilatore di ottimizzazione PL / I IBM avrebbe fornito occasionalmente le istruzioni BEGIN ed END mancanti, ISTR avrebbe anche fornito i punti e virgola mancanti.
TMN,

1

L'obiettivo di un compilatore è produrre eseguibili che si comportino come desiderato. Se un programmatore scrive qualcosa che non è valido, anche se il compilatore può con il 90% di probabilità indovinare ciò che era previsto, sarebbe generalmente meglio richiedere al programmatore di correggere il programma per chiarire l'intenzione, piuttosto che il compilatore vada avanti e produca un eseguibile che avrebbe una significativa possibilità di nascondere un bug.

Naturalmente, le lingue dovrebbero generalmente essere progettate in modo tale che il codice che esprima chiaramente l'intenzione sia legale e che il codice che non esprima chiaramente l'intenzione dovrebbe essere proibito, ma ciò non significa che lo siano. Considera il seguente codice [Java o C #]

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

Fare in modo che un compilatore aggiunga un typecast implicito per il compito f1sarebbe utile, dato che c'è solo una cosa logica che il programmatore potrebbe voler f1contenere (il floatvalore più vicino a 1/10). Invece di incoraggiare i compilatori ad accettare programmi impropri, tuttavia, sarebbe meglio per le specifiche consentire conversioni implicite da doppio a galleggiante in alcuni contesti. Il rovescio della medaglia, l'incarico d1potrebbe essere o meno ciò che il programmatore intendeva realmente, ma non esiste alcuna regola linguistica che lo proibisca.

Il peggior tipo di regole del linguaggio sono quelle in cui i compilatori faranno inferenze nei casi in cui qualcosa non potrebbe legittimamente compilare diversamente, ma in cui un programma potrebbe "accidentalmente" essere valido nel caso in cui l'inferenza fosse stata intesa. Molte situazioni che implicano la fine implicita della dichiarazione rientrano in questa categoria. Se un programmatore che intende scrivere due istruzioni separate omette un terminatore di istruzioni, un compilatore potrebbe in genere riuscire a inferire il limite dell'istruzione, ma potrebbe occasionalmente considerare come un'istruzione qualcosa che doveva essere elaborato come due.


0

Gli errori di sintassi sono particolarmente difficili da correggere. Prendiamo il caso di un diritto mancante ): sappiamo che possiamo riparare il codice inserendone uno, ma di solito ci sono molti posti in cui possiamo inserirne uno e ottenere un programma sintatticamente corretto.

Un punto molto più semplice sono gli identificatori errati (ma si noti che non si tratta di errori di sintassi). Si può calcolare la distanza di modifica tra l'identificatore irrisolvibile e tutti gli identificatori nell'ambito e, sostituendo la parola irrisolvibile con quella che l'utente ha probabilmente inteso, si potrebbe trovare un programma corretto in molti casi. Tuttavia, risulta che è ancora meglio contrassegnare l'errore e lasciare che l'IDE suggerisca sostituzioni valide.


-1

Un compilatore del genere sarebbe semplicemente un'implementazione rilassata e non standard di qualunque linguaggio stia compilando.


-2

È stato provato più volte, ma spesso non ha ottenuto l'effetto desiderato: pensa a HAL 9000 o GlaDOS.


-3

In C, non è possibile passare matrici per valore, ma il compilatore consente di scrivere:

void foo(int array[10]);

che viene poi silenziosamente riscritto come:

void foo(int* array);

Quanto è stupido? Preferirei un errore grave qui invece della riscrittura silenziosa, perché questa regola speciale ha portato molti programmatori a credere che gli array e i puntatori siano sostanzialmente la stessa cosa. Non sono.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.