Was macht Java einfacher zu analysieren als C?


90

Ich bin mit der Tatsache vertraut, dass die Grammatiken von C und C ++ kontextsensitiv sind , und insbesondere benötigen Sie einen "Lexer-Hack" in C. Andererseits habe ich den Eindruck, dass Sie nur Java analysieren können 2 Zeichen Vorausschau, trotz erheblicher Ähnlichkeit zwischen den beiden Sprachen.

Was müssten Sie an C ändern, um das Parsen einfacher zu machen?

Ich frage, weil alle Beispiele, die ich für Cs Kontextsensitivität gesehen habe, technisch zulässig, aber schrecklich seltsam sind. Beispielsweise,

foo (a);

könnte die void-Funktion foomit Argument aufrufen a. Oder es könnte deklariert awerden, ein Objekt vom Typ zu sein foo, aber Sie könnten genauso gut die Klammern loswerden. Zum Teil tritt diese Verrücktheit auf, weil die Produktionsregel "direkter Deklarator" für die C-Grammatik den doppelten Zweck erfüllt, sowohl Funktionen als auch Variablen zu deklarieren.

Andererseits hat die Java-Grammatik separate Produktionsregeln für die Variablendeklaration und die Funktionsdeklaration. Wenn du schreibst

foo a;

Dann wissen Sie, dass es sich um eine Variablendeklaration handelt, foodie eindeutig als Typname analysiert werden kann. Dies ist möglicherweise kein gültiger Code, wenn die Klasse foonicht irgendwo im aktuellen Bereich definiert wurde. Dies ist jedoch ein Job für die semantische Analyse, der in einem späteren Compiler-Durchlauf ausgeführt werden kann.

Ich habe gesehen, dass C aufgrund von typedef schwer zu analysieren ist, aber Sie können Ihre eigenen Typen auch in Java deklarieren. Welche C-Grammatikregeln direct_declaratorsind dabei schuld?


7
Coole Frage. Wahrscheinlich viel zu weit gefasst oder primär meinungsbildend.
Asteri

37
Dies ist eine gültige Frage zu Parsern, und das einzige, was allgemein oder allgemein darauf basiert, sind die letzten paar Sätze (die wahrscheinlich fallengelassen oder geändert werden sollten). Beenden Sie mit den engen Stimmen.
R .. GitHub STOP HELPING ICE

1
Ich habe die Frage entsprechend bearbeitet, danke für @R .. für das Feedback.
Korrok

3
Praktisch jede (Standard-) Computersprache ist kontextsensitiv . Sie können eine Variable eines Typs nicht deklarieren und sie in den meisten Sprachen missbrauchen . Das ist anders als "alle Grammatiken für die Sprache" sind kontextsensitiv; Die meisten Benutzer, die Parser erstellen, erstellen einen kontextfreien (oder noch restriktiveren) Parser und verwenden dann Hacks außerhalb des Parsers, um die kontextfreien Eigenschaften zu überprüfen.
Ira Baxter

1
@IraBaxter Ich würde das nicht "Hacks" nennen. Die Aufteilung des Problems in zwei Teile erscheint sinnvoll, da das Parsen kontextsensitiver Sprachen nicht effizient durchgeführt werden kann (und sogar das Parsen kontextsensiver Sprachen nicht effizient ist, weshalb wir uns im Allgemeinen auf Teilmengen kontextfreier Sprachen beschränken). . Eine kontextfreie Analyse + statische Analyse, um nur kontextsensitive Eigenschaften über den AST zu überprüfen, ist eine vernünftige Sache.
Bakuriu

Antworten:


76

Das Parsen von C ++ wird schwierig. Das Parsen von Java wird genauso schwierig.

In dieser SO-Antwort wird erläutert, warum C (und C ++) "schwer" zu analysieren sind . Die kurze Zusammenfassung ist, dass C- und C ++ - Grammatiken von Natur aus mehrdeutig sind. Sie geben Ihnen mehrere Analysen und Sie müssen den Kontext verwenden, um die Mehrdeutigkeiten aufzulösen. Die Leute machen dann den Fehler anzunehmen, dass Sie beim Analysieren Unklarheiten auflösen müssen. nicht so, siehe unten. Wenn Sie beim Parsen darauf bestehen, Mehrdeutigkeiten zu lösen, wird Ihr Parser komplizierter und umso schwieriger zu erstellen. Aber diese Komplexität ist eine selbstverschuldete Wunde.

IIRC, Java 1.4s "offensichtliche" LALR (1) -Grammatik war nicht mehrdeutig, daher war es "einfach" zu analysieren. Ich bin mir nicht so sicher, ob das moderne Java nicht zumindest lokale Unklarheiten über große Entfernungen aufweist. Es besteht immer das Problem zu entscheiden, ob "... >>" zwei Vorlagen schließt oder ein "Rechtsschichtoperator" ist. Ich vermute, dass modernes Java nicht mehr mit LALR (1) analysiert wird .

Man kann das Parsing-Problem jedoch überwinden, indem man für beide Sprachen starke Parser (oder schwache Parser und Hacks für die Kontextsammlung, wie dies derzeit in C- und C ++ - Frontends meistens der Fall ist) verwendet. C und C ++ haben die zusätzliche Komplikation, einen Präprozessor zu haben; Diese sind in der Praxis komplizierter als sie aussehen. Eine Behauptung ist, dass die C- und C ++ - Parser so hart sind, dass sie von Hand geschrieben werden müssen. Es ist nicht wahr; Mit GLR-Parser-Generatoren können Sie problemlos Java- und C ++ - Parser erstellen.

Aber das Parsen ist nicht wirklich das Problem.

Sobald Sie analysiert haben, möchten Sie etwas mit dem AST / Analysebaum tun. In der Praxis müssen Sie für jeden Bezeichner wissen, wie er definiert ist und wo er verwendet wird ("Namens- und Typauflösung", schlampig, Symboltabellen erstellen). Dies stellt sich als viel mehr Arbeit heraus, als den Parser richtig zu machen, zusammengesetzt aus Vererbung, Schnittstellen, Überladung und Vorlagen, und die Tatsache, dass die Semantik für all dies in informeller natürlicher Sprache geschrieben ist, die sich über zehn bis Hunderte von Seiten erstreckt des Sprachstandards. C ++ ist hier wirklich schlecht. Java 7 und 8 werden aus dieser Sicht ziemlich schrecklich. (Und Symboltabellen sind nicht alles, was Sie brauchen; siehe meine Biografie für einen längeren Aufsatz über "Leben nach dem Parsen").

Die meisten Leute haben Probleme mit dem reinen Parsing-Teil (oft nie fertig; überprüfen Sie SO selbst auf die vielen, vielen Fragen, wie man funktionierende Parser für echte Sprachen erstellt), so dass sie das Leben nach dem Parsen nie sehen. Und dann bekommen wir Volkstheoreme darüber, was schwer zu analysieren ist, und kein Signal darüber, was nach dieser Phase passiert.

Das Korrigieren der C ++ - Syntax bringt Sie nicht weiter.

In Bezug auf das Ändern der C ++ - Syntax: Sie werden feststellen, dass Sie viele Stellen patchen müssen, um die Vielfalt lokaler und realer Mehrdeutigkeiten in jeder C ++ - Grammatik zu berücksichtigen. Wenn Sie darauf bestehen, könnte die folgende Liste ein guter Ausgangspunkt sein . Ich behaupte, es macht keinen Sinn, dies zu tun, wenn Sie nicht das C ++ - Standardkomitee sind. Wenn Sie dies tun und einen Compiler damit erstellen würden, würde es niemand vernünftig verwenden. Es wird zu viel in vorhandene C ++ - Anwendungen investiert, um für die Benutzer, die Parser erstellen, zu wechseln. Außerdem sind ihre Schmerzen vorbei und vorhandene Parser funktionieren einwandfrei.

Möglicherweise möchten Sie Ihren eigenen Parser schreiben. OK das passt; Erwarten Sie nur nicht, dass der Rest der Community Sie die Sprache ändern lässt, die sie verwenden müssen, um es Ihnen einfacher zu machen. Sie alle möchten, dass es ihnen leichter fällt, und das heißt, die Sprache so zu verwenden, wie sie dokumentiert und implementiert ist.


Gute Antwort. Siehe auch D und C +, die versuchen, einige dieser Probleme zu lösen. s / content /
contend

3
Ich habe Life After Parsing schon einmal gelesen und festgestellt, dass es ein echter Augenöffner ist. es machte mir klar, dass die semantische Analyse (Namens- / Typauflösung, ...) viel mehr Arbeit leistet als das Parsen. Ich versuche nicht , die Syntax einer Sprache zu ändern. Ich kann verstehen wollen, was die Eigenschaften einer Sprache sind , in dem Sie zuerst die syntaktische Analyse tun und dann die semantische Analyse. C ist keine solche Sprache (braucht Lexer Hack); Ich habe immer gedacht, dass Java das ist und ich möchte wissen warum.
Korrok

1
@ Korrok: Lesen Sie meine Antwort zum Erstellen von Java / C ++ mit GLR-Parsern. Sie brauchen keinen Lexer-Hack . Die Unterscheidung liegt also im Kopf von Menschen, die die falsche Parsing-Technologie verwenden. ... Zugegeben, das Erstellen eines vollständigen C ++ - Frontends (insbesondere C ++ 14, was wir getan haben) ist schwieriger als Java8, aber beide sind schwierig (in Bezug auf Aufwand und Liebe zum Detail) und analysieren ist das einfachste Stück.
Ira Baxter

1
Ich stimme Ihrem "Leben nach dem Parsen" zu: ZB kann die Überlastungsauflösung in C # jedes 3-SAT-Problem codieren und ist daher NP-hart.
Jörg W Mittag

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.