Antlr4 „primitiv“ Rekursion

stimmen
0

Im Anschluss an http://blog.ptsecurity.com/2016/06/theory-and-practice-of-source-code.html#java--and-java8-grammars versuche ich links Rekursion in meinem ziemlich zu reduzieren komplexe Grammatik. Von dem, was ich verstehe, kann die nicht-primitive Form der Rekursion zu Performance - Problemen sowohl in Bezug auf Speicher und Prozesszeit führen.

So versuche ich, diese Regeln in meiner Grammatik Refactoring nur „primitiv“ Rekursion zu verwenden. Natürlich ist die Blog-Post das einzige Mal, dass ich den Begriff „primitiv“ Rekursion in Bezug auf Antlr gesehen haben. So bin Erraten ich gerade an seine Bedeutung / Absicht. Mir scheint es eine Regel bedeutet, dass für höchstens nur einer einzigen Regel Zweig als lhs auf sich selbst verweist. Richtig?

Im Moment habe ich einen Ausdruck der Regel wie:

expression
    : expression DOUBLE_PIPE expression         # ConcatenationExpression
    | expression PLUS expression                # AdditionExpression
    | expression MINUS expression               # SubtractionExpression
    | expression ASTERISK expression            # MultiplicationExpression
    | expression SLASH expression               # DivisionExpression
    | expression PERCENT expression             # ModuloExpression
    ...
    ;

Das ...beinhaltet eine ganze Reihe von Unterregeln , die auch verweisen expression. Aber das sind die einzigen , die mit direkten Rekursion.

Wenn ich richtig verstehe, Refactoring diese „primitive“ Rekursion wäre etwas wie folgt aussehen:

expression
    : binaryOpExpression                        # BinaryOpExpression
    ...
    ;

binaryOpExpression
    : expression DOUBLE_PIPE expression         # ConcatenationExpression
    | expression PLUS expression                # AdditionExpression
    | expression MINUS expression               # SubtractionExpression
    | expression ASTERISK expression            # MultiplicationExpression
    | expression SLASH expression               # DivisionExpression
    | expression PERCENT expression             # ModuloExpression
    ;

Erstens ist, dass das richtige Refactoring?

Zweitens wird die wirklich Leistung helfen? Am Ende des Tages ist es immer noch die gleichen Entscheidungen, so dass ich nicht wirklich verstehen , wie diese Leistung hilft (abgesehen von vielleicht produziert weniger ATNConfig Objekte).

Vielen Dank

Veröffentlicht am 09/10/2019 um 19:01
quelle vom benutzer
In anderen Sprachen...                            


1 antworten

stimmen
0

Ich habe nicht „primitive Rekursion“, bevor in diesem Zusammenhang gehört und der Autor wahrscheinlich bedeutet, dass nur eine spezifische Form der Rekursion in ANTLR4 zu nennen.

Tatsache ist, gibt es drei relevante Formen der Rekursion in ANTLR4:

  • Direkt Linksrekursion: Rekursion von der ersten Regel Referenz in der Regel (in der gleichen Regel). Zum Beispiel:a: ab | c;
  • Indirekte Linksrekursion: Rekursion nicht direkt aus der gleichen Regel verlassen. Zum Beispiel:a: b | c; b: c | d; c: a | e;
  • Recht Rekursion: andere Rekursion in der Regel. Zum Beispiel: a: ba | c;. Der Name „richtige Rekursion“ ist jedoch nur korrekt in Fällen von binären Ausdruck, wird aber häufig verwendet , von links Rekursion zu unterscheiden.

Nachdem das nun gesagt, dass es klar wird, dass Ihre Rewrite falsch ist, da sie indirekt Linksrekursion schaffen würde, die ANLTR4 nicht unterstützt. Direkt links Rekursion ist in der Regel kein Problem dar (aus einem Speicher oder Performance-Gesichtspunkten), weil ANTLR4 wandelt sie in nicht-rekursive ATN Regel Graphen.

Was kann ein Problem richtig Rekursion sind geworden, weil sie durch den Code Rekursion (rekursive Funktionsaufrufe in der Runtime) umgesetzt werden, die qickly die CPU Stapel erschöpfen kann. Ich habe Fälle gesehen, mit großen Ausdrücke, die nicht in einem separaten Thread analysiert werden konnte, weil ich nicht die Thread-Stapelgröße auf einen größeren Wert (die Haupt-Thread-Stack-Größe in der Regel über Linker-Einstellungen angepasst werden) einstellen könnte.

Die einzige Lösung für den letzteren Fall, die ich nützlich gefunden haben, ist die Anzahl der Parser Regeln in der Grammatik zu senken , die sich gegenseitig anrufen. Natürlich ist es eine Frage der Struktur, Lesbarkeit usw. bestimmte Ausdruckselemente in unterschiedlichen Regeln (zum Beispiel zu setzen andExpression, orExpression, bitExpressionetc.), aber das zu recht tiefen Aufrufstapeln führen kann, was den CPU - Stack erschöpfen kann und / oder eine Menge benötigen die Zeit , sie zu verarbeiten.

Beantwortet am 10/10/2019 um 10:28
quelle vom benutzer

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more