Es ist bekannt, dass rekursive Descent-Parser in einigen Fällen exponentielle Zeit erfordern können; Könnte mich jemand auf die Proben hinweisen, wo das passiert? Besonders interessiert an Fällen für PEG (d. H. Mit priorisierten Entscheidungen).Zur Komplexität von rekursiven Descent-Parsern
Antwort
Es ist weil Sie am Ende die gleichen Dinge (überprüfen Sie die gleiche Regel an der gleichen Position) oft in verschiedenen Rekursionszweigen analysieren können. Es ist ungefähr so, als würde man die n-te Fibonacci-Zahl mit Rekursion berechnen.
Grammar:
A -> xA | xB | x
B -> yA | xA | y | A
S -> A
Input:
xxyxyy
Parsing:
xA(xxyxyy)
xA(xyxyy)
xA(yxyy) fail
xB(yxyy) fail
x(yxyy) fail
xB(xyxyy)
yA(yxyy)
xA(xyy)
xA(yy) fail
xB(yy) fail
x(yy) fail
xB(xyy)
yA(yy)
xA(y) fail
xB(y) fail
x(y) fail
xA(yy) fail *
x(xyy) fail
xA(yxyy) fail *
y(yxyy) fail
A(yxyy)
xA(yxyy) fail *
xB(yxyy) fail *
x(yxyy) fail *
x(xyxyy) fail
xB(xxyxyy)
yA(xyxyy) fail
xA(xyxyy) *
xA(yxyy) fail *
xB(yxyy) fail *
...
*
- wo wir eine Regel in der gleichen Position zu analysieren, wo wir haben es bereits in einem anderen Zweig analysiert. Wenn wir die Ergebnisse gespeichert hätten - welche Regeln an welchen Positionen versagen - würden wir wissen, dass xA (xxyxy) das zweite Mal fehlschlägt und wir würden nicht noch einmal durch den gesamten Teilbaum gehen. Ich wollte die ganze Sache nicht schreiben, aber Sie können sehen, dass es die gleichen Unterbäume viele Male wiederholen wird.
Wenn es passiert - wenn Sie viele überlappende Transformationen haben. Priorisierte Auswahl ändert nichts - wenn die Regel mit der niedrigsten Priorität die einzig richtige ist (oder keine korrekt ist), mussten Sie trotzdem alle Regeln überprüfen.
Jeder Top-Down-Parser, einschließlich des rekursiven Sinkens, kann theoretisch exponentiell werden, wenn die Kombination von Eingabe und Grammatik so groß ist, dass eine große Anzahl von Rückverfolgungen erforderlich ist. Dies geschieht, wenn die Grammatik derart ist, dass am Ende von langen Sequenzen bestimmende Entscheidungen getroffen werden. Wenn Sie zum Beispiel ein Symbol wie & haben, das bedeutet "alle vorherigen Minuswerte sind tatsächlich plus" und dann Daten wie "((((a - b) - c) - d &)" dann muss der Parser gehen rückwärts und ändere alle Plus- und Minuszeichen. Wenn Sie damit beginnen, geschachtelte Ausdrücke entlang dieser Zeilen zu erstellen, können Sie eine praktisch nicht endende Menge von Eingaben erstellen.
Sie müssen erkennen, dass Sie hier in ein politisches Problem einsteigen, denn die Realität ist, dass die meisten normalen Grammatiken und Datensätze nicht so sind, aber es gibt eine Menge Leute, die rekursive Abstammung systematisch verschlingen, weil es nicht ist einfach RD automatisch zu machen. Alle frühen Parser sind LALR, weil sie viel einfacher automatisch als RD zu machen sind. Was passierte, war, dass alle nur LALR geschrieben und RD abgekanzelt hatten, denn in der alten Zeit war der einzige Weg, um einen RD zu machen, es von Hand zu programmieren. Zum Beispiel, wenn Sie das Drachenbuch lesen, werden Sie feststellen, dass Aho & Ullman nur einen Absatz auf RD schreiben, und es ist im Grunde nur eine ideologische Takedown sagen: "RD ist schlecht, mach es nicht".
Natürlich, wenn Sie Hand Codierung RDs (wie ich) starten, werden Sie feststellen, dass sie aus einer Vielzahl von Gründen viel besser als LALRs sind. Früher konnte man einem Compiler, der eine Hand-codierte RD hatte, immer sagen, dass er aussagekräftige Fehlermeldungen mit Ortsgenauigkeit hatte, während Compiler mit LALRs den Fehler wie 50 Zeilen entfernt von der tatsächlichen Position aufzeigten. Die Dinge haben sich seit den alten Zeiten stark verändert, aber man sollte sich darüber im Klaren sein, dass wenn man anfängt, die FUD auf RD zu lesen, dass es aus einer langen, langen Tradition stammt, RD in "bestimmten Kreisen" zu verbalen.
- 1. Komplexität faktorieller rekursiven Algorithmus
- 2. Komplexität des rekursiven faktoriellen Programms
- 3. Wie findet man die Komplexität von rekursiven Algorithmen allgemein?
- 4. Einige Fragen zur Komplexität
- 5. Algorithmus zur Schätzung der Komplexität von Wörtern
- 6. Wie berechnet man die Komplexität einer rekursiven Funktion?
- 7. Verarbeitung von PDF-Dateien zur Verringerung der Dateigröße und Komplexität
- 8. Zeitkomplexität eines rekursiven Algorithmus
- 9. Asymptotic Komplexität von printf
- 10. Algorithmische Komplexität von Data.Hashtable
- 11. Verwendungen von rekursiven Grenzen
- 12. Komplexität von zwei Methoden
- 13. Zeit Komplexität von Spaß()?
- 14. Komplexität von std :: Zählung
- 15. Analyse von Algorithmen (Komplexität)
- 16. Komplexität in einem Rekursionsalgorithmus
- 17. Algorithmus zum rekursiven Parsen von XML-Knoten
- 18. Stopp-Bedingung der rekursiven Methode funktioniert nicht zur richtigen Zeit
- 19. Java-Rekursion - Ausgabe von mehreren rekursiven Aufrufen
- 20. Welche Parameter werden zur Berechnung der Komplexität in SourceMonitor verwendet?
- 21. Große O von rekursiven Methoden
- 22. Zeit Komplexität von Canny Kantendetektor
- 23. Die Komplexität von Schema Vektoren
- 24. Zeit Komplexität von erlang dict
- 25. Schleifen Komplexität
- 26. Sortierzeit Komplexität
- 27. Komplexität Berechnung
- 28. Algorithmus Komplexität vs Laufzeit
- 29. Große O-Zeit-Komplexität von Worst-Case-Quick-Sort?
- 30. Was ist die Zeit Komplexität des Codes (Erzeugung von Permutationen)
Nur wenn sie zurückverfolgen. Wenn sie im richtigen 'LL (1)' Stil von links nach rechts gehen, sollten sie * O (N) * sein. – EJP
@EJP, offensichtlich. Aber selbst Backtracking führt in den meisten Fällen nicht zu exponentieller Komplexität. Ich versuche besser herauszufinden, unter welchen Umständen das passiert. – fithu
Nicht alle rekursiven Descent-Parser können exponentielles Verhalten aufweisen. Zum Beispiel erzeugt ANTLR 4 Rekursive-Descent-Parser mit [halb-] priorisierten Auswahlen, ist aber der schlechteste Fall O (n⁴) (der Beweis ist Teil eines Papiers, an dem ich gerade arbeite). –