Vor einiger Zeit hörte ich, dass es einen Compiler gab, der versuchte, Syntaxfehler zu beheben, indem er den Kontext analysierte und daraus folgerte, was beabsichtigt war.
Gibt es einen solchen Compiler wirklich? Offensichtlich hat es wenig praktischen Wert, aber es wäre sehr interessant, damit zu spielen und daraus zu lernen.
Antworten:
In gewissem Sinne ist der Akt der Compilierung wird Folgern , was bestimmte Syntax tun sollte, und somit ein Syntaxfehler ist , wenn der Compiler nicht in der Lage ist , es herauszufinden. Sie können weitere "Vermutungen" hinzufügen, um den Compiler weitere Dinge ableiten zu lassen und flexibler mit der Syntax umzugehen. Dies muss jedoch durch einen bestimmten Satz von Regeln erfolgen. Und diese Regeln werden dann ein Teil der Sprache und sind keine Fehler mehr.
Also, nein, es gibt wirklich keine solchen Compiler, weil die Frage keinen Sinn ergibt. Das Erraten, was Syntaxfehler nach bestimmten Regeln bewirken sollen, wird nur ein Teil der Syntax.
In diesem Sinne gibt es ein gutes Beispiel für einen Compiler, der dies tut: Beliebiger C-Compiler. Sie drucken oft nur eine Warnung aus, die nicht so ist, wie sie sein sollte, und gehen dann davon aus, dass Sie X gemeint haben, und fahren fort. Dies ist in der Tat das "Erraten" von unklarem Code (obwohl es sich meistens nicht um Syntax an sich handelt), etwas, das ebenso gut die Kompilierung mit einem Fehler hätte stoppen und daher als Fehler qualifizieren können.
quelle
Klingt sehr gefährlich. Wenn ein Compiler versucht, auf Ihre Absicht zu schließen, sie falsch einleitet, den Code repariert und Sie dann nicht informiert (oder in einer Warnung darauf hinweist, dass Sie wie jeder andere auch ignorieren), können Sie möglicherweise Code ausführen ernsthaft etwas Schaden anrichten.
Ein solcher Compiler wurde wahrscheinlich absichtlich NICHT erstellt.
quelle
In der IDE für eine Programmiersprache wird heutzutage normalerweise ein Compiler im Hintergrund ausgeführt, sodass Analysedienste wie Syntax-Coloring, IntelliSense, Fehler usw. bereitgestellt werden können. Offensichtlich muss ein solcher Compiler in der Lage sein, tief gebrochenen Code zu verstehen. Meistens ist der Code beim Bearbeiten nicht korrekt. Aber wir müssen noch einen Sinn daraus machen.
Normalerweise wird die Fehlerbehebungsfunktion jedoch nur während der Bearbeitung verwendet. Es macht wenig Sinn, dies für die eigentliche Kompilierung in "Mainline" -Szenarien zuzulassen.
Interessanterweise haben wir diese Funktion in den JScript.NET-Compiler eingebaut. Grundsätzlich ist es möglich, den Compiler in einen Modus zu versetzen, in dem wir dem Compiler erlauben, fortzufahren, selbst wenn ein Fehler auftritt, wenn die IDE sich davon erholt hätte. Sie können Visual Basic- Code eingeben, den JScript.NET-Compiler darauf ausführen und haben eine vernünftige Chance, dass am anderen Ende ein funktionierendes Programm herauskommt!
Dies ist eine amüsante Demo, die sich jedoch aus vielen Gründen als nicht sehr gut für "Mainline" -Szenarien herausstellt. Eine vollständige Erklärung wäre ziemlich langwierig. Die kurze Erklärung ist, dass es Programme gibt, die unvorhersehbar und versehentlich funktionieren , und dass es schwierig ist, denselben Code über mehrere Compiler oder mehrere Versionen desselben Compilers auszuführen. Die hohen Kosten, die die Funktion verursacht, sind nicht durch die geringen Vorteile gerechtfertigt.
Peter Torr, der das Feature damals als Premierminister hatte, diskutiert es kurz in diesem Blogbeitrag aus dem Jahr 2003 .
Obwohl wir diese Funktion über die Skript-Hosting-APIs der JScript .NET-Engine bereitstellen, sind mir keine echten Kunden bekannt, die sie jemals verwendet haben.
quelle
Das erste, was mir in den Sinn kommt, ist das automatische Einfügen von Semikolons in Javascript . Eine schreckliche, schreckliche Eigenschaft, die niemals in die Sprache hätte gelangen dürfen.
Das soll nicht heißen, dass es keinen besseren Job hätte machen können. Wenn es in der folgenden Zeile nach vorn schaute, könnte es eine bessere Einschätzung der Absicht des Programmierers geben, aber am Ende des Tages, wenn es mehrere gültige Wege gibt, auf denen die Syntax hätte verschwinden können, gibt es wirklich keinen Ersatz für den Programmierer explizit zu sein.
quelle
Ich denke, wenn ein Compiler eine falsche Syntax korrigieren könnte, sollte diese Syntax in der Sprache dokumentiert sein.
Der Grund für Syntaxfehler ist, dass ein Parser den abstrakten Syntaxbaum nicht aus dem Programm heraus erstellen konnte. Dies passiert, wenn ein Token nicht am richtigen Ort ist. Um zu erraten, wo sich dieses Token befinden sollte, ob es entfernt werden sollte oder ob ein anderes Token hinzugefügt werden sollte, um den Fehler zu beheben, benötigen Sie eine Art Computer, der die Absicht eines Programmierers erraten kann. Wie könnte eine Maschine das erraten:
Sollte sein:
Es könnte genauso gut eine der folgenden sein:
56
,5 - 6
,5 & 6
. Ein Compiler kann das nicht wissen.Diese Technologie existiert noch nicht.
quelle
Obwohl dies nicht ganz dasselbe ist, hat sich HTML sozusagen in die Katastrophe verwandelt. Browser haben schlechtes Markup toleriert und als nächstes wussten Sie, dass Browser A nicht so rendern konnte wie Browser B (ja, es gibt andere Gründe, aber dies war einer der ersten, besonders vor ungefähr 10 Jahren, bevor einige der Lockerungsregeln zur Konvention wurden ).
Wie Eric Lippert schlussfolgert, werden viele dieser Dinge am besten von der IDE erledigt, nicht vom Compiler. So können Sie sehen, was die automatischen Bits für Sie zu vermasseln versuchen.
Die Strategie, von der ich denke, dass sie jetzt vorherrscht, ist die kontinuierliche Verbesserung der Sprache, anstatt den Compiler zu lockern: Wenn es wirklich etwas ist, das der Compiler automatisch herausfinden kann, dann führe ein gut definiertes Sprachkonstrukt darum herum ein.
Als unmittelbares Beispiel kommen Autoeigenschaften in C # in Frage (nicht die einzige Sprache mit ähnlichen Eigenschaften): Da die Mehrheit der Getter / Setter in einer App eigentlich nur Wrapper um ein Feld sind, lassen Sie den Entwickler nur deren Eigenschaften angeben Absicht und lassen Sie den Compiler den Rest injizieren.
Was mich dann zum Nachdenken bringt: Die meisten Sprachen im C-Stil tun dies bereits zu einem gewissen Grad. Für Dinge, die automatisch herausgefunden werden können, verfeinern Sie einfach die Syntax:
Kann reduziert werden auf:
Letztendlich denke ich, dass es darauf ankommt: Der Trend ist, dass Sie den Compiler nicht "intelligenter" oder "lockerer" machen. Es ist die Sprache , die schlauer oder lockerer gemacht wird.
Außerdem kann zu viel "Hilfe" gefährlich sein, wie der klassische "if" -Fehler:
quelle
if (x && y) dothis(); else dothat();
würde etwas besser aussehen.true
oder vergleichtfalse
.Als ich in den späten 80ern und frühen 90ern FORTRAN und PL / I auf DEC- und IBM-Minicomputer- und Mainframe-Systemen codierte, erinnere ich mich an die regelmäßigen Abmeldungen der Compiler wie "bla bla Fehler". ". Damals war dies ein Erbe der (noch früheren, vor meiner Zeit) Tage der Stapelverarbeitung und Lochkarten, als es wahrscheinlich eine enorme Wartezeit zwischen dem Einreichen Ihres Codes zum Ausführen und dem Zurückerhalten der Ergebnisse gab. Daher war es für Compiler sehr sinnvoll, den Programmierer zu überdenken und den ersten aufgetretenen Fehler nicht abzubrechen, sondern fortzusetzen. Wohlgemerkt, ich erinnere mich nicht, dass die "Korrekturen" besonders raffiniert waren. Als ich schließlich auf interaktive Unix-Workstations (Sun, SGI usw.) wechselte,
quelle
Das Ziel eines Compilers ist es, ausführbare Dateien zu erstellen, die sich wie gewünscht verhalten. Wenn ein Programmierer etwas Ungültiges schreibt, selbst wenn der Compiler mit einer Wahrscheinlichkeit von 90% erraten kann, was beabsichtigt war, ist es im Allgemeinen besser, den Programmierer zu bitten, das Programm zu reparieren, um die Absicht klar zu machen, als den Compiler voranzutreiben und eine ausführbare Datei zu erstellen das hätte eine erhebliche Chance, einen Fehler zu verbergen.
Natürlich sollten Sprachen im Allgemeinen so gestaltet sein, dass Code, der Absichten klar ausdrückt, legal ist, und Code, der Absichten nicht klar ausdrückt, sollte verboten sein, aber das bedeutet nicht, dass dies der Fall ist. Betrachten Sie den folgenden Code [Java oder C #]
Es
f1
wäre hilfreich, wenn ein Compiler eine implizite Typumwandlung für die Zuweisung hinzufügt , da der Programmierer nur eine logische Sachef1
enthalten möchte (denfloat
Wert, der 1/10 am nächsten kommt). Anstatt Compiler zu ermutigen, unzulässige Programme zu akzeptieren, ist es für die Spezifikation jedoch besser , implizite Double-to-Float-Konvertierungen in bestimmten Kontexten zuzulassen. Auf der anderen Seite ist die Zuweisung zud1
möglicherweise oder möglicherweise nicht das, was der Programmierer wirklich beabsichtigt hat, aber es gibt keine Sprachregel, die dies verbietet.Die schlimmsten Arten von Sprachregeln sind solche, bei denen Compiler Rückschlüsse auf Fälle ziehen, in denen etwas nicht legitimerweise anders kompiliert werden könnte, ein Programm jedoch "aus Versehen" in einem Fall gültig sein könnte, in dem ein Rückschluss beabsichtigt war. Viele Situationen mit implizitem Ende der Aussage fallen in diese Kategorie. Wenn ein Programmierer, der zwei separate Anweisungen schreiben möchte, einen Anweisungsabschluss weglässt, kann ein Compiler normalerweise auf die Anweisungsgrenze schließen, kann aber gelegentlich als eine Anweisung etwas betrachten, das als zwei verarbeitet werden sollte.
quelle
Syntaxfehler sind besonders schwer zu korrigieren. Nehmen
)
wir den Fall eines fehlenden Rechts : Wir wissen, dass wir den Code durch Einfügen eines reparieren können, aber es gibt normalerweise viele Stellen, an denen wir einen Code einfügen und ein syntaktisch korrektes Programm erhalten könnten.Ein viel einfacherer Punkt sind falsch geschriebene Bezeichner (beachten Sie jedoch, dass dies keine Syntaxfehler sind). Man kann den Bearbeitungsabstand zwischen dem nicht auflösbaren Bezeichner und allen Bezeichnern im Gültigkeitsbereich berechnen und durch Ersetzen des nicht auflösbaren Wortes durch dasjenige, das der Benutzer höchstwahrscheinlich gemeint hat, würde man in vielen Fällen ein korrektes Programm finden. Es stellt sich jedoch heraus, dass es immer noch besser ist, den Fehler zu kennzeichnen und die IDE gültige Ersetzungen vorschlagen zu lassen.
quelle
Ein solcher Compiler wäre einfach eine entspannte, nicht standardmäßige Implementierung der zu kompilierenden Sprache.
quelle
Es wurde mehrmals ausprobiert, aber oft hat es nicht den gewünschten Effekt erzielt: Denken Sie an HAL 9000 oder GlaDOS.
quelle
In C können Sie keine Arrays nach Wert übergeben, aber der Compiler ermöglicht Ihnen das Schreiben von:
was dann stillschweigend umgeschrieben wird als:
Wie dumm ist das denn? Ich würde hier lieber einen harten Fehler als ein stilles Umschreiben bevorzugen, da diese Sonderregel viele Programmierer zu der Annahme veranlasst hat, dass Arrays und Zeiger im Grunde dasselbe sind. Sie sind nicht.
quelle