Richtiger Name für einen rekursiven Abstiegsparser, der Schleifen verwendet, um die linke Rekursion zu behandeln?


8

Diese Grammatik bleibt rekursiv:

Expression  ::= AdditionExpression

AdditionExpression  ::=
    MultiplicationExpression
        | AdditionExpression '+' MultiplicationExpression
        | AdditionExpression '-' MultiplicationExpression

MultiplicationExpression    ::=
    Term
        | MultiplicationExpression '*' Term
        | MultiplicationExpression '/' Term

Term    ::=
    Number
        | '(' AdditionExpression ')'

Number  ::=
    [+-]?[0-9]+(\.[0-9]+)?

Theoretisch funktioniert ein rekursiver Abstieg also nicht. Durch Ausnutzen der Eigenschaften der Grammatik, dass jede linksrekursive Regel einer bestimmten Prioritätsebene entspricht und der Lookahead eines einzelnen Tokens ausreicht, um die richtige Produktion auszuwählen, können die linksrekursiven Regeln einzeln mit while-Schleifen analysiert werden.

Um beispielsweise das nicht-terminale AdditionExpression zu analysieren, reicht dieser Pseudocode aus:

function parse_addition_expression() {
    num = parse_multiplication_expression()
    while (has_token()) {
        get_token()
        if (current_token == PLUS)
            num += parse_multiplication_expression()
        else if (current_token == MINUS)
            num -= parse_multiplication_expression()
        else {
            unget_token()
            return num
        }
    }
    return num
}

Wie lautet der richtige Name für diesen Parsertyp? In diesem informativen Artikel wird es nur als "klassische Lösung" bezeichnet: https://www.engr.mun.ca/~theo/Misc/exp_parsing.htm

Für diesen Parsertyp muss ein Eigenname vorhanden sein.


Für mich ist es keine Art Parser, sondern nur die Anwendung der Entfernung linker Rekursionen in Kombination mit einem Parser rekursiver Abstammung. In dieser Frage finden Sie eine Technik zum Entfernen der linken Rekursion.
AProgrammer

Ich denke, Sie könnten richtig sein. Es ähnelt einem Laufzeitäquivalent des Algorithmus zum Entfernen der linken Rekursion.
user71015

1
Bitte benutzen Sie nicht das Antwortfeld, um Kommentare oder andere Bemerkungen zu posten. Wenn Sie ein Konto erstellen , behalten Sie den Zugriff und können die Antwort akzeptieren, die Ihnen am meisten geholfen hat. Wenn Sie eine E-Mail eingegeben und den Zugriff verloren haben, können Sie den Zugriff wiederherstellen . Wenn Sie keine E-Mail-Adresse eingegeben haben und keinen Zugriff auf den Browser / die Cookies haben, mit denen Sie die Frage gestellt haben, haben Sie wahrscheinlich kein Glück. Niemand sonst kann die Antwort für Sie akzeptieren - nicht einmal Moderatoren.
DW

Antworten:


11

Es ist nur ein LL (1) -Parser, der mit rekursivem Abstieg implementiert ist.

Beginnt mit:

AdditionExpression  ::=
    MultiplicationExpression
        | AdditionExpression '+' MultiplicationExpression
        | AdditionExpression '-' MultiplicationExpression

gelten links Beseitigung der Rekursion eine LL (1) Grammatik zu erhalten:

AdditionExpression  ::= 
    MultiplicationExpression AdditionExpressionTail

AdditionExpressionTail ::=
        | '+' MultiplicationExpression AdditionExpressionTail
        | '-' MultiplicationExpression AdditionExpressionTail

Schreiben Sie die entsprechenden Funktionen:

function parse_AdditionExpression() {
    parse_MultiplicationExpression()
    parse_AdditionExpressionTail()
}

function parse_AdditionExpressionTail() {
    if (has_token()) {
        get_token()
        if (current_token == PLUS) {
            parse_MultiplicationExpression()
            parse_AdditionExpressionTail()
        } else if (current_token == MINUS) {
            parse_MultiplicationExpression()
            parse_AdditionExpressionTail()
        } else {
            unget_token()
        }
    }
}

Schwanzrekursion entfernen:

function parse_AdditionExpressionTail() {
    while (has_token()) {
        get_token()
        if (current_token == PLUS)
            parse_MultiplicationExpression()
        else if (current_token == MINUS)
            parse_MultiplicationExpression()
        else {
            unget_token()
            return
        }
    }
}

in der Reihe:

function parse_AdditionExpression() {
    parse_MultiplicationExpression()
    while (has_token()) {
        get_token()
        if (current_token == PLUS)
            parse_MultiplicationExpression()
        else if (current_token == MINUS)
            parse_MultiplicationExpression()
        else {
            unget_token()
            return
        }
    }
}

und Sie müssen nur die semantische Verarbeitung hinzufügen, um Ihre Funktion zu erhalten.


6

kk

Sehen Sie hier für einen umfassenden Überblick darüber , wie mächtig diese Klasse von Parsern ist.


1
Ich sehe nicht, wie das zusammenhängt. Der Code verwendet nicht mehr als ein Vorausschau-Symbol.
AProgrammer

@AProgrammer Es ist also ein LL (1) -Parser oder sehr eng verwandt.
Raphael

Es ist ein LL (1) -Parser. Ich habe meinen Kommentar zu einer Antwort erweitert.
AProgrammer

2
@ AProgrammer Ich sehe nicht, wie eine zweite Antwort benötigt wurde. LL (1) ist LL (k) für k = 1 (ist das nicht offensichtlich?). Aber gut.
Raphael
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.